印刷時に仮想DCを利用する方法

[戻る]
limi 2006/07/06(木) 15:00:35
毎回お世話になっております。
印刷時に仮想DCを利用し印刷内容をまとめてから印刷用DCにコピーして印刷しようと
しています。直接印刷用DCに対してTextOUTすると問題なく出力
されるのですが、仮想DCを通すと真っ白になります。
下のサンプルは単純に座標(0,0)に文字列を出力しているだけです。
たぶんBitmapのコピーとBitBltするときの座標値が違うのかと思いますが
正しくはどのように記述したらよいのかご教示願います。

void Cprint_dllView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
pDC->SetMapMode(MM_LOMETRIC);
/*  pDCから一時CDCを作製する */
////画面サイズ取得
int xsize = pDC->GetDeviceCaps(LOGPIXELSX)*10;
int ysize = pDC->GetDeviceCaps(LOGPIXELSY)*10;
//描画pDCとコンパチブルなメモリDCを生成
CDC mem_dc;
mem_dc.CreateCompatibleDC(pDC);
// pDCとコンパチブルなビットマップ生成
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC, xsize, ysize);
// ビットマップクラスを選択
CBitmap* pOldBmp = mem_dc.SelectObject(&bmp);
/*  一時CDCに印刷内容を描画 */
mem_dc.TextOut(0,0,"テスト甘太郎");
/*  一時CDCからpDCにコピー    */
pDC->BitBlt( 0, 0,xsize,ysize , &mem_dc, 0,0, SRCCOPY ) ;
//開放処理
mem_dc.SelectObject(pOldBmp);
bmp.DeleteObject();
mem_dc.DeleteDC();
}

limi 2006/07/06(木) 15:02:08
追記です。 CFormViewで印刷しようとしています。印刷用DCに直接記述すると
正常に印刷されます。

PATIO 2006/07/06(木) 16:11:40
エラー判定の処理が入っていないようです。
何処かでエラーになっている可能性があるかもしれません。
ちゃんとエラー処理を行って検討するべきでしょう。

後、気をつけないといけないことを一つ。
画面のDCと違って印刷用のDCは高解像度である場合が多いです。
この場合、高解像度設定で大きな用紙を指定すると作成される
ビットマップがとんでもないサイズになる可能性があります。
場合によってはメモリが確保できなくて印刷不可になったり、
スワップが走って急激に重くなったりする事もありえます。
個人的には印刷用処理にメモリDCを使う方法はお勧めできない
と考えています。

limi 2006/07/07(金) 14:44:05
エラー処理は今のところ入れていませんがいずれ入れる予定です。
デバッグにてチェックしたのですがどの処理においてもエラー発生してないみたいです。
画面サイズを取得する処理を
int xsize = pDC->GetDeviceCaps(HORZSIZE)*10;
int ysize = pDC->GetDeviceCaps(VERTSIZE)*10;
と変更したところ画面上部にラインだけ出ました。

高解像度のCDCの危険性についてご注意ありがとうございます。
その件については注意しながら使いたいと思います。
本来ならあんまり使いたい事ではなかったのですが直接描画ができないため
この方法を取っております。

m 2006/07/09(日) 19:20:06
始めまして。

そんなに詳しくは無いので、ちゃんとした説明は出来ないんですが、

pDC と、mem_dc のカラープレーン数や、カラービット数などが異なるためにちゃんと表示され
ない(線みたいに表示される)んだと思います。
具体的な数は、GetDeviceCaps で取得できるので確認してみてください。

CreateCompatibleDC で初期化しても、同じデバイスコンテキストにはならないみたいです。
そうなると、CreateCompatibleDC の解説の“互換性のあるメモリ デバイス コンテキストを
作成します”の互換性とは、何を指すのかよく分かりませんが。

また、CreateCompatibleDC の解説中に、“メモリ デバイス コンテキストは、ディスプレイ
表面を表すメモリのブロックです。”とさらっと書いてあるので、CreateCompatibleDC は、
ディスプレイ用にしか使えないのかもしれません。

解決方法としては、表示する部分の BitBlt をグローバル関数?の StretchDIBits に変更す
るとうまくできるみたいです。ただ、使用方法が非常に複雑です。

m 2006/07/09(日) 21:13:15
追記です。

カラービット数が異なると、色が変わってしまう可能性があるので、ビットマップを初期化する
ときも、CreateCompatibleBitmap では無く、CreateBitmap か CreateDIBSection を使った
ほうがいいと思います。(ビットマップのほうも、プレーン数と、カラービット数がプリンタ用
の DC と異なってるみたいです)

それから、mem_dc では無く、pDC に SelectObject で選択して、書き込みをして、選択を外
した後に、StretchDIBits で表示したほうがいいように思います。

こうすればうまくいくのかなと考えているだけなので、参考程度にしてください。これをしなく
ても StretchDIBits で色をうまく調節してくれるかもしれませんが。

m 2006/07/09(日) 21:57:49
何度も書き込みごめんなさい。書き込みをしていて気付いたんですが、以下のようにすると簡単
に出来るみたいです。

void CBmpPrintTestView::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/)
{
   pDC->SetMapMode(MM_LOMETRIC);
   int xsize = pDC->GetDeviceCaps(HORZSIZE)*10;
   int ysize = pDC->GetDeviceCaps(VERTSIZE)*10;
   int planes = pDC->GetDeviceCaps(PLANES);
   int bitcount = pDC->GetDeviceCaps(BITSPIXEL);
   CBitmap* oldbmp;
   CBitmap bmp;

   bmp.CreateBitmap(xsize, ysize, planes, bitcount, NULL);

   oldbmp = pDC->SelectObject(&bmp);

   pDC->TextOut(0,0,"テスト甘太郎");
    
   pDC->SelectObject(oldbmp);

   pDC->DrawState(CPoint(0, 0), CSize(xsize, ysize), &bmp, DST_BITMAP, NULL);
}

limi 2006/07/10(月) 11:24:24
mさんありがとうございます。
仮想CDCを使わずに一時BitMapを利用すればできそうですね。
上記コードを利用して記述してみたところ文字が表示されるのですが画面上部にまだライ
ンが残りました。プレーン数とカラービット数はともに1でした。
テスト的にDrawStateの行をコメントアウトしたら"テスト甘太郎"の文字は表示されたま
まで画面上部のラインが消えました。
(文字列も画面上部のラインも両方とも消えるのかと思っていました。)

今までTextOutで描画している対象は描画時にCDCに選択されているBitMapに対してだと思
っていました。"テスト甘太郎"をTextOutした時はbmpに対して描画し、そのあとoldBmpに
SelectObjectし直しているのでDrawStatusせずに表示した場合は文字列が表示されないと
思うのですが私の何かBitMapとCDCに対する認識が違っているみたいです・・。

どうなっているのか訳分からなくなっているのですが・・どなたかフォローお願いできま
せんか?

subaru 2006/07/10(月) 15:39:05
MM_LOMETRICだとY座標の正方向が上になるので
描画してる方向が逆だし、最初に作ってるビットマップも
意図した大きさのものなのでしょうか?
普通はもっと小さいビットマップで作って
描画するときにStretchBltだけでよいのでは?

よすむら 2006/07/12(水) 11:27:26
subaru様のコメントのように、Y軸はマイナス方向です。
とりあえず以下のように当初のソースを変更すれば出力します。

 int xsize = pDC->GetDeviceCaps(LOGPIXELSX);
 int ysize = pDC->GetDeviceCaps(LOGPIXELSY);
 ...
 pDC->BitBlt( 0,-ysize,xsize,ysize , &mem_dc, 0,0, SRCCOPY ) ;
 ...

理由は以下をご参考に。
http://www.codeproject.com/printing/singlepage.asp

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