Search code examples
c++winapigdi

How to use BITMAPV5HEADER with CreateDIBitmap function


I'm trying to use a BITMAPV5HEADER to create a bitmap that has the alpha channel:

BITMAPV5HEADER bi;
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = width;
bi.bV5Height = -height;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_RGB;
bi.bV5SizeImage = 0;
bi.bV5XPelsPerMeter = 0;
bi.bV5YPelsPerMeter = 0;
bi.bV5ClrUsed = 0;
bi.bV5ClrImportant = 0;
bi.bV5AlphaMask = 0x000000FF;
bi.bV5RedMask = 0x0000FF00;
bi.bV5GreenMask = 0x00FF0000;
bi.bV5BlueMask = 0xFF000000;
bi.bV5CSType = LCS_sRGB;
bi.bV5Endpoints = CIEXYZTRIPLE();
bi.bV5GammaRed = 0;
bi.bV5GammaGreen = 0;
bi.bV5GammaBlue = 0;
bi.bV5Intent = LCS_GM_IMAGES;
bi.bV5ProfileData = 0;
bi.bV5ProfileSize = 0;
bi.bV5Reserved = 0;

*hBmp = CreateDIBitmap(hdc, (BITMAPINFOHEADER *) &bi, CBM_INIT, data, (BITMAPINFO *)&bi, DIB_RGB_COLORS);

But I'm unsure if the type-cast is correct. The CreateDIBitmap() documentation is unclear, because in the field definition it says:

In const BITMAPINFOHEADER *lpbmih,

and in the description:

lpbmih [in]
A pointer to a bitmap information header structure, BITMAPV5HEADER.


Solution

  • Yes, the type-casts are fine.

    The BITMAPV5HEADER documentation states:

    The BITMAPV5HEADER structure is the bitmap information header file. It is an extended version of the BITMAPINFOHEADER structure.

    The first 11 fields of BITMAPV5HEADER match the fields in BITMAPINFOHEADER. As such, you can safely pass in a type-casted BITMAPV5HEADER* pointer to the lpbmih parameter where a BITMAPINFOHEADER* pointer is expected.

    The lpbmi parameter, on the other hand, is another story. It is expecting a BITMAPINFO* pointer, but you are giving it a type-casted BITMAPV5HEADER* pointer instead. Technically, a BITMAPV5HEADER is not an extension of BITMAPINFO, so you should be passing in a separate BITMAPINFO variable instead of your BITMAPV5HEADER variable.

    However, BITMAPINFO starts with a BITMAPINFOHEADER, so the first 11 fields of BITMAPV5HEADER will satisfy the BITMAPINFO::bmiHeader field. And you are setting the header's biBitCount field to 32 and biCompression field to BI_RGB, so there is no color table used, so CreateDIBitmap() will not try to access the BITMAPINFO::bmiColors field and end up reading your BITMAPV5HEADER's alpha/gamma fields as RGB values. So in this particular configuration, passing a type-casted BITMAPV5HEADER* pointer to the lpbmi parameter where a BITMAPINFO* pointer is expected is also "safe".