BitBltはPrintOutできますか?

[戻る]
saito( ); 2002/04/14(日) 22:04:28
数回、ここで質問して、解決させて戴いてもらっている者です。

前回のここの質問でもBITMAPが
「『プレビュー』には表示できるがPrintOutできない!!!」
という質問がありました。

今回も同じ質問になりますが・・・

前回の回答は、「=GetDC()」がよいと言うことでしたが
それでもできませんでした。
 また、その『プレビュー』も表示されるにはされるのですが
縮尺が小さすぎます。
・OnDrawには、BitBlt関数を仕様しています。
・アクティブウィンドウにも設定しております。

(いま、PrintBegin,PrintEend,PrintPrepareを
 そのクラスにてオーバーロードしています
 ・・ていうか、
 AppWizardにて「印刷、・・・」を設定した
 単純なモデルソフトにても同じでした。)

どなたか教えて戴けませんか?
(APIはできるだけ使いたくない[好みです]のですが・・)

(VC++6:MFC)です

K 2002/04/15(月) 16:56:40
//MyView.h
class CMyView : public CScrollView
{
...
// インプリメンテーション
public:
protected:
   BOOL    bPrinting ;
   char*    m_BmpImage ;
   LPBITMAPINFO    m_BmpInfo ;
   BITMAPFILEHEADER    m_BmpFileHdr ;
   LONG   biWidth; 
   LONG   biHeight; 
...
}

//MyView.cpp
CMyView::CMyView()
{
    // TODO: この場所に構築用のコードを追加してください。
    bPrinting = FALSE ;
}
void CMyView::OnDraw(CDC* pDC)
{
   CMapViewDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   // TODO: この場所にネイティブ データ用の描画コードを追加します。
   HBITMAP    myDIB ;
   HBITMAP    oldDIB ;
   HDC        hDC ;
   HDC        hCompatiDC ;

   //すでにビットマップ情報を取得済とする
   hDC = pDC->GetSafeHdc () ;
   hCompatiDC = ::CreateCompatibleDC (hDC) ;

   myDIB = CreateDIBitmap (hDC, &m_BmpInfo->bmiHeader, CBM_INIT, m_BmpImage, 
m_BmpInfo, DIB_RGB_COLORS) ;
   oldDIB = (HBITMAP)::SelectObject (hCompatiDC, myDIB) ;

   //表示を大きくする[10倍]
   StretchBlt (hDC, // handle to destination device context
        0,
        0,
        biWidth * 10, // width of destination rectangle
        biHeight * 10, // height of destination rectangle
        hCompatiDC, // HDC hdcSrc, // handle to source device context
        0,
        0,
        biWidth,     // width of source rectangle
        biHeight,    // height of source rectangle
        SRCCOPY        // raster operation code
    ) ;
   //あるいは
     //biWidth * 10, 
     //biHeight * 10,の変わりに
   //プリンターデバイスコンテキストの幅、高さを指定してもいい
      //if (bPrinting) {
      //プリンター出力
   //} else {
      //画面出力
     //}

      //BitBlt を使うのならMM_TEXT以外のマップモードでは?

   if (bPrinting) {    //プリンターデバイス出力を終了する為に必要
        pDC->EndPage () ;
    pDC->EndDoc () ;
   }

   ::SelectObject (hCompatiDC, oldDIB) ;
   ::DeleteObject (myDIB) ;
   ::DeleteObject (hCompatiDC) ;
   ::ReleaseDC (m_hWnd, hDC) ;
}
void CMyView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
   // TODO: 印刷前の特別な初期化処理を追加してください。
   bPrinting = TRUE ;
}
void CMyView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
   // TODO: 印刷後の後処理を追加してください。
   bPrinting = FALSE ;
}

TAD [E-Mail] 2002/04/15(月) 17:02:22
MFC サンプルの DRAWCLI が参考になると思います。
このサンプルでは、CDrawView::OnDraw で、BltBlt による描画、印刷を行っています。
何やらビューポートをいじっているようなので、そのあたりを調べてみてください。
私も印刷に関してはあまり詳しくないので、申し訳ないのですが、ここでは回答できないです。

saito( ); 2002/04/16(火) 17:57:12
Kさん、TADさん
有難うございます。

教えていただいた事をもとに
挑戦してみます。

できなかったら、また
お聞きするかもわかりませんが
そのときは、よろしくお願いいたします。

saito( ); 2002/04/16(火) 21:49:13
Kさん、TADさん
やはり出来ませんでした。

Printer(Canon-BJF-6100)なのですが、印刷動作はするのですが、
結果として、印刷されません。

BitBltが可能かどうかも
GetDeviceCaps 関数を呼び出して RC_BITBLT にてチェック
したところ、ビット1(RC_BITBLT )が立っていて、OKでした。

プログラムの印刷(描画)部分は下記の通ですが、なにか不足しているのでしょうか?

これ以外にも、
CPrintDialog dl(FALSE);
AfxGetApp()->GetPrinterDeviceDefaults(&dl.m_pd);
HDC hDC = dl.CreatePrinterDC();
にて、プリンターのHDCを取得(したつもり・・)して
そのHDCにBitBltしても、結果は同じでした。

ご指南ください。

以下、ソフトです。
考え方は、
Docにて、ファイルの読み込み。
OnUpdateにて、メンバー変数のm_CBitにデータ-保存して、OnDraw準備。
OnDrawにてメンバー変数のm_CBitを再描画


void CpPreView::OnDraw(CDC* pDC)
{
    CpImageDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: この位置に描画用のコードを追加してください
    CSize sz = GetTotalSize();
    CDC pcDC;            //バックグラウンド用DCポインターを設定
    pcDC.CreateCompatibleDC(pDC);//バックグラウンド用DCポインターを標準DCに設定
    pcDC.SelectObject(m_CBit);
    pDC->BitBlt(0, 0, sz.cx,sz.cy, &pcDC, 0, 0, SRCCOPY);
    pcDC.DeleteDC();
}
void CpPreView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
    CpImageDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください
    CSize sizeTotal;
    CPictureHolder pH;
    LPDISPATCH ld;
    OLE_HANDLE phandle;
    HBITMAP hbm;
    BITMAP bm;
    CBitmap cbm;
    CString FileName=pDoc->m_FileName;
    CDC* pDC=GetDC();            // 標準DCポインターを取得
    CDC pcDC;                // バックグラウンド用DCポインターを設定
    HDC hcDC,hccDC;            // バックグラウンド用DCハンドルを設定
    pcDC.CreateCompatibleDC(pDC);//バックグラウンド用DCを標準DCフォーマットに設定

    if(FileName != ""){
             if(FAILED(::OleLoadPictureFile(COleVarian  
(FileName),&ld)))    return;// FALSE;
        pH.SetPictureDispatch((LPPICTUREDISP)ld);
        if(pH.GetType() != PICTYPE_BITMAP) return;// FALSE;

        pH.m_pPict->get_Handle(&phandle);    /// GDIハンドル取得。
        hbm=(HBITMAP)phandle;    /// GDIハンドルをBITMAPハンドルに変換。
        GetObject(hbm,sizeof(BITMAP),&bm);// GDI(BITMAP)Objectを取得。
        sizeTotal.cx = bm.bmWidth;        /// BITMAPの幅。
        sizeTotal.cy = bm.bmHeight;        /// BITMAPの高さ。
        if(m_CBit.m_hObject!=NULL){
            m_CBit.DeleteObject();
        }
        m_CBit.CreateCompatibleBitmap(pDC, bm.bmWidth, bm.bmHeight);
        pcDC.SelectObject(&m_CBit);    /// CBitmap m_CBit; にてメンバー変数
//        pcDC.FillSolidRect(CRect(0, 0, m_Width, m_Height),RGB
(255,255,255));
        hcDC=pcDC.GetSafeHdc();
        hccDC=CreateCompatibleDC(hcDC);// バックグラウンド用DCハンドルを標準DC
フォーマットに設定
        SelectObject(hccDC,hbm);
        BitBlt(hcDC,0,0,bm.bmWidth, bm.bmHeight,hccDC,0,0,SRCCOPY);
        DeleteObject(hccDC);
        DeleteObject(hcDC);
        DeleteObject(hbm);
        pcDC.DeleteDC();

        Invalidate();
    }
    else{
        sizeTotal.cx = sizeTotal.cy = 100;
    }
    SetScrollSizes(MM_TEXT, sizeTotal);
}

TAD [E-Mail] 2002/04/16(火) 22:07:30
こちらから質問ですが、DRAWCLI サンプルでは正しく印刷できますか?
もし印刷できないとなると、プログラム上の問題ではなく、Windows側(プリンタドライバ)に問題
があるのかもしれません。
印刷できれば、少しは希望が持てますね。

saito( ); 2002/04/16(火) 22:23:15
TADさん

以前、『スプリッタ-ウィンドウに、ToolBarを表示したい』
という私の悩みを解決して頂いたものです。
そのときは、有難うございました。

「DRAWCLI サンプル」ですが、わたしのパソコン上
で、『動作』しませんでした。
(わたしのは、Windows Me』で、95ではないため!!
と勝手に解釈したのですが・・・
でも、そのサンプルのプログラムリストをみて、
さきほどの、『きっと、プリンタードライバーのHDC』が
設定されていなかったために、印刷できないんだ!!
と思いました。(すみません、サンプルのすべてを
解読したわけではありません)

そこで、そのサンプル内のHDCを入手する(と思った・・・)、

CPrintDialog dl(FALSE);
AfxGetApp()->GetPrinterDeviceDefaults(&dl.m_pd);
HDC hDC = dl.CreatePrinterDC();

らの手法も試みました。

でも、結果は・・・・・

もうすこし、『サンプル』の解読を試みます。
いつもながら、早急で、新設なお答えに
感謝しております。

saito( ); 2002/04/16(火) 22:43:43
すみません。
補足ですが、

TextOut(・・・);
では、テキストはちゃんと印刷してくれるし

Windows付属の、『ペイント』などでは
BITMAPをちゃんと印刷してくれるので
ドライバーの問題でなく
わたしのソフトの問題と考えております。
(トホホ・・・・)

kazuma 2002/04/17(水) 02:02:44
DDBをそのままプリンタに転送してもだめです。
(何しろデバイスに依存したビットマップなので)

というわけでDIBに変換してからStretchDIBitsを使って転送するとよいです。

saito( ); 2002/04/17(水) 08:32:38
kazumaさん

ありがとうございます。
さっそく、チャレンジしてみます。

K 2002/04/17(水) 09:45:51
void CpPreView::OnDraw(CDC* pDC)
{
  CpImageDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);
  // TODO: この位置に描画用のコードを追加してください
  CSize sz = GetTotalSize();
  CDC pcDC;            //バックグラウンド用DCポインターを設定
  pDC.CreateCompatibleDC(pDC);//バックグラウンド用DCポインターを標準DCに設定
  pDC.SelectObject(m_CBit);
  pDC->BitBlt(0, 0, sz.cx,sz.cy, &pcDC, 0, 0, SRCCOPY);
 //次の2行を追加して試してください。
    pDC->EndPage () ;
    pDC->EndDoc () ;
  //Kの環境ではプリンターにビットマップが印刷されるようになりました。
  pDC.DeleteDC();
}

K 2002/04/17(水) 16:13:40
修正します。
Kの2回目では確かに印刷されません。
CDCクラスに
myDIB = CreateDIBitmap (hDC, &m_BmpInfo->bmiHeader, CBM_INIT, m_BmpImage, 
m_BmpInfo, DIB_RGB_COLORS) ;
のようなAPIが無い?ので
(APIはできるだけ使いたくない[好みです]のですが・・)
では無理かも知れません。
プログラミングVisualC++6.0[日経BPソフトプレス 11章 248P]
に記載されていました。
Kの環境ではAPIを使いました。[Kの1回目のスレッド]
そのとき次の行を省くと
if (bPrinting) {    //プリンターデバイス出力を終了する為に必要
    pDC->EndPage () ;
    pDC->EndDoc () ;
}
Kの環境でも
「『プレビュー』には表示できるがPrintOutできない!!!」
現象が起きました。

saito( ); 2002/04/17(水) 20:09:15
[[解決]]
Kさん、TADさん、Kazumaさん

ご親切に、大変有難うございました。

結局、APIを使って解決しました。
(意思薄弱で申し訳ありません)

いかに、解決したプログラム掲載します。
[まだ、印刷のサイズ設定までは至っておりませんが・・・・]

(私の気ままな[好み]のため、皆さんに
 ご迷惑かけましたこと、平にお詫び致します。)

考え方は、以前と同じで、
メンバー変数は、
    BYTE* m_Images;
    BITMAPINFO *m_bi;
です。

void CpPreView::OnDraw(CDC* pDC)
{
    CpImageDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
// TODO: この位置に描画用のコードを追加してください

    CSize sz = GetTotalSize();
    CDC pcDC;        //バックグラウンド用DCポインターを設定
    HDC hDC,hcDC;
    HBITMAP hnBMP,hoBMP;
    hDC=pDC->GetSafeHdc();
    hcDC=::CreateCompatibleDC(hDC);

    hnBMP=CreateDIBitmap(hDC, &m_bi-
>bmiHeader,CBM_INIT,m_Images,m_bi,DIB_RGB_COLORS);
    hoBMP=(HBITMAP)::SelectObject(hcDC,hnBMP);

    BitBlt(hDC,0,0,sz.cx,sz.cy,hcDC,0,0,SRCCOPY);
//    StretchBlt(hDC,0,0,sz.cx,sz.cy,hcDC,0,0,sz.cx,sz.cy,SRCCOPY);

/////////結果としては、BitBlt でも StretchBlt でもOKでした//////////////

//    SelectObject(hcDC, hoBMP);

    pcDC.DeleteDC();
    DeleteObject(hcDC);    
    DeleteObject(hnBMP);    
    DeleteObject(hoBMP);    
    pcDC.DeleteDC();
    ::ReleaseDC(m_hWnd, hDC);
    ::ReleaseDC(m_hWnd, hcDC);
}

void CpPreView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
    CpImageDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
// TODO: この位置に固有の処理を追加するか、または基本クラスを呼び出してください

    CSize sizeTotal;
    CPictureHolder pH;
    LPDISPATCH ld;
    OLE_HANDLE phandle;
    HBITMAP hbm;
    DIBSECTION ds;
    CString FileName=pDoc->m_FileName;
    CDC* pDC=GetDC();            // 標準DCポインターを取得
    HDC hDC = pDC->GetSafeHdc();    // バックグラウンド用DCハンドルを設定

    if(m_bi != NULL) delete[] m_bi;
    if(m_Images != NULL) delete[] m_Images;

    if(FileName != ""){
          if(FAILED(::OleLoadPictureFile(COleVariant(FileName),&ld)))
return;// FALSE;
        pH.SetPictureDispatch((LPPICTUREDISP)ld);
        if(pH.GetType() != PICTYPE_BITMAP) return;// FALSE;

        pH.m_pPict->get_Handle(&phandle);    /// GDIハンドル取得。
        hbm=(HBITMAP)phandle;    /// GDIハンドルをBITMAPハンドルに変換。
//    (未使用)-->    GetObject(hbm,sizeof(BITMAP),&bm);// GDI(BITMAP)Objectを取得。
             GetObject(hbm,sizeof(DIBSECTION),&ds);//GDI(BITMAP)Objectを取
得。
        sizeTotal.cx = ds.dsBm.bmWidth;    /// BITMAPの幅。
        sizeTotal.cy = ds.dsBm.bmHeight;    /// BITMAPの高さ。

        m_bi=(BITMAPINFO*)new BYTE [sizeof(BITMAPINFO)];
        m_bi->bmiHeader=ds.dsBmih;
        int hhh=GetDIBits(hDC,hbm,0,0,NULL,m_bi,DIB_RGB_COLORS);
    
        m_Images=new BYTE[m_bi->bmiHeader.biSizeImage];
                  hhh=GetDIBits(hDC,hbm,0,m_bi-
>bmiHeader.biHeight,m_Images,m_bi,DIB_RGB_COLORS);    

        pH.m_pPict->Release();        /// IPictureの開放。
        DeleteObject(hbm);            /// hbmの開放。
        ReleaseDC(pDC);            /// pDCの開放。
        ::ReleaseDC(m_hWnd, hDC);       /// hDCの開放。

        Invalidate();
    }
    else{
        sizeTotal.cx = sizeTotal.cy = 100;
    }
    SetScrollSizes(MM_TEXT, sizeTotal);
}

----------------------------------------------------------
あと、上の表示で
                  hhh=GetDIBits(hDC,hbm,0,m_bi-
>bmiHeader.biHeight,m_Images,m_bi,DIB_RGB_COLORS);
など、かってに二段になってしまうのですが、ここに、表示する場合
どうしたら、一段に表示できるのでしょうか??

古いスレッドには追加発言できません。