...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

HBITMAP(DDB)からBITMAPINFO(DIB)を得る

GetDIBits()を使う、以上。

で終わる話なのですが、BITMAPINFOを作成するために必要なメモリサイズを算出するのに手こずったので、結果だけ置いておきます。

なお、このコードで作成されるのは、スクリーンショットを撮ったときに得られるビットマップデータに合わせてbiCompressionがBI_BITFIELDSで、カラーマスクあり、カラーパレットなしの32ビットカラーDIBビットマップです。

BITMAPINFO* createBitmapInfo(HBITMAP hBitmap)
{
    BITMAP bitmap;
    GetObject(hBitmap, BITMAP.sizeof, &bitmap);
    HDC hdc = GetDC(null);

    // Allocates memory of BITMAPINFO
    const uint bitsPerPixel = bitmap.bmPlanes * 32; // 32 bits color
    const uint colorMaskBytes = {
        // Contains color mask when biCompression is BI_BITFIELDS.
        return 4 * 3; // 4 bytes * 3 masks(R,G,B)
    }();
    const uint numPallet = 0; // Wants that no color palette.
    const uint widthBytes = (bitmap.bmWidth * bitsPerPixel + 31) / 32 * 4;
    const uint bitmapBodySize = widthBytes * bitmap.bmHeight;

    BITMAPINFO* pbi = cast(BITMAPINFO*)new ubyte[
        BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet + bitmapBodySize];

    pbi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; // First 6 members
    pbi.bmiHeader.biWidth = bitmap.bmWidth;
    pbi.bmiHeader.biHeight = bitmap.bmHeight;
    pbi.bmiHeader.biPlanes = bitmap.bmPlanes;
    pbi.bmiHeader.biBitCount = 32; // 32 bits color
    pbi.bmiHeader.biCompression = BI_BITFIELDS; // Contains color mask
    if (0 == core.sys.windows.wingdi.GetDIBits(
        hdc, hBitmap, 0, bitmap.bmHeight,
        cast(ubyte*)pbi + BITMAPINFOHEADER.sizeof + colorMaskBytes + RGBQUAD.sizeof * numPallet, pbi, DIB_RGB_COLORS))
    {
        throw new Exception("createBitmapInfo failure");
    }

    ReleaseDC(null, hdc);
    return pbi;
}