みたにっき@はてな

三谷純のブログ

GDI+

今までVC++で開発してきたアプリケーションの2Dの描画は通常のGDIを使っていたのですが、どうやらGDI+はアンチエイリアスができる、キャップスタイルを指定できるなど、かなり高機能で良さそうだということで、ここしばらくGDI+への切り替え作業を行っていました。でも、ドキュメントが少なくて苦労が多かったです。サンプルコードはC#VBばかりなのも悲しい。
とりあえずMSDNを参考に試行錯誤してました。
http://msdn2.microsoft.com/en-us/library/ms533798%28VS.85%29.aspx
で、散々に苦労したのが文字の扱い。従来のGDIとGDI+では文字の描画結果が一致しなくて、位置を正確に制御するのがとても困難です。
ネット上でもいろいろ問題の指摘は見つかるものの、解決策を見つけるまでに数時間を費やしてしまいました。
結局、Gdiplus::bitmap 上であっても、GDIで描画する方法がわかったので、以下のようなコードで解決しました。
いわゆる、バッドノウハウだなぁ。
以下、参考までに。

    Gdiplus::Bitmap *bmp;
    Gdiplus::Graphics g(bmp);
    HDC hdc = g.GetHDC();
    CDC *pDC = CDC::FromHandle(hdc);

    pDC->TextOut(100, 100, L"Hello");

    g.ReleaseHDC(hdc);

追記: Gdiplus::Bitmap で作成した描画結果を印刷しようとしたところ、うまくいかない。。どうやら次のコードでは画面描画はできても印刷はできないようでした。

    Gdiplus::Graphics g(*pDC);
    g.DrawImage(&bitmap, 0,0,w,h)

で、結局StretchDIBitsを使って解決。

    Gdiplus::BitmapData bitmapData;
    bitmap.LockBits(&Gdiplus::Rect(0,0,bitmap.GetWidth(), bitmap.GetHeight())
			,Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData);

    RGBTRIPLE*	pData;
    pData = (RGBTRIPLE*)bitmapData.Scan0;

    BITMAPINFO bmpInfo;
    bmpInfo.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    bmpInfo.bmiHeader.biWidth       = bitmap.GetWidth();
    bmpInfo.bmiHeader.biHeight      = bitmap.GetHeight();
    bmpInfo.bmiHeader.biPlanes      = 1;
    bmpInfo.bmiHeader.biBitCount    = 24;
    bmpInfo.bmiHeader.biCompression = BI_RGB;
    bmpInfo.bmiHeader.biClrUsed = 0;
    bmpInfo.bmiHeader.biClrImportant = 0;

    int lineNum = ::StretchDIBits(pDC->GetSafeHdc(), 0, 0, w, h, 0, h, w, -h, pData, &bmpInfo, DIB_RGB_COLORS, SRCCOPY);

と、思ったけれどしっかり実装しようとすると、次のURLの記述のようになるらしい。。大変だ。。
http://hp.vector.co.jp/authors/VA014436/prg_memo/windows/vcbasic/050.html

追記2: Gdiplus::Bitmap の FromFile で読み込んだ後で LockBits を行うと、GIF形式の時だけ失敗する。。よくわからない問題はまだまだ続くようです。