The short answer has to be no. BITMAPV5HEADER*
is not a substitute for BITMAPINFO*
and may not be passed whenever BITMAPINFO*
is expected (simply because BITMAPINFO
contains palette colors after the header, and BITMAPV5HEADER
is just a header).
It is certainly fine to pass BITMAPV5HEADER*
instead of BITMAPINFO*
provided that the BITMAPV5HEADER
is a part of BITMAPINFO
and has required kind of palette color data after it. That is documented, although kind of indirectly, through use instructions and common sense:
BITMAPV5HEADER
is documented to be an "extended version of th BITMAPINFOHEADER
structure", so that part is clear.
BITMAPINFO
is documented to combine a header and color data. The header is included by value as opposed to by pointer, so at this point it's clear the header may not just grow in size as it pleases, otherwise it would be impossible to access BITMAPINFO.bmiColors
and the whole idea of having an extended version of the header would be pointless.
And that problem is then resolved in another place in the documentation ("Remarks" section):
An application should use the information stored in the biSize
member to locate the color table in a BITMAPINFO
structure, as follows:
pColor = ((LPSTR)pBitmapInfo + (WORD)(pBitmapInfo->bmiHeader.biSize));
Although I believe this part was not confusing for you to begin with.
Now for the long answer.
There appear to be two cases when BITMAPV5HEADER*
can be passed for BITMAPINFO*
. Neither of the two is documented in a concrete way, and if for the first one we can apply same common sense we applied above, the second one appears to be a bug in the documentation:
- When
BITMAPINFO.bmiColors
is documented to be NULL
. You can find the complete list of such cases in the documentation for BITMAPINFOHEADER
.
When the header is BITMAPV4HEADER
or BITMAPV5HEADER
, the bitmap has 16 or 32 bit colors, and compression is set to BI_BITFIELDS
. In that case the color masks that are documented to follow the header are instead taken from the respective dedicated fields of the headers, and the three DWORD
s that follow the header are ignored.
This is easy to prove by slightly modifying the original code:
typedef struct tagV5BMPINFO {
BITMAPV5HEADER bmiHeader;
DWORD bmiColors[3];
} V5BMPINFO;
int _tmain(int argc, _TCHAR* argv[])
{
V5BMPINFO bmpinfo = { 0 };
BITMAPV5HEADER bmpheader = { 0 };
bmpheader.bV5Size = sizeof(BITMAPV5HEADER);
bmpheader.bV5Width = width;
bmpheader.bV5Height = height;
bmpheader.bV5Planes = 1;
bmpheader.bV5BitCount = 32;
bmpheader.bV5Compression = BI_BITFIELDS;
bmpheader.bV5SizeImage = 400*200*4;
bmpheader.bV5RedMask = 0x00FF0000;
bmpheader.bV5GreenMask = 0x0000FF00;
bmpheader.bV5BlueMask = 0x000000FF;
bmpheader.bV5AlphaMask = 0xFF000000;
bmpheader.bV5CSType = 0x57696e20; // LCS_WINDOWS_COLOR_SPACE
bmpheader.bV5Intent = LCS_GM_BUSINESS;
bmpinfo.bmiHeader = bmpheader;
// Put them in reverse order here compared to the above
bmpinfo.bmiColors[0] = 0x000000FF;
bmpinfo.bmiColors[1] = 0x0000FF00;
bmpinfo.bmiColors[2] = 0x00FF0000;
void* converted = NULL;
HDC screen = GetDC(NULL);
HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpinfo), DIB_RGB_COLORS, &converted, NULL, 0);
ReleaseDC(NULL, screen);
DIBSECTION actual_data;
GetObject(result, sizeof(actual_data), &actual_data);
std::cout << std::hex;
std::cout << actual_data.dsBitfields[0] << std::endl;
std::cout << actual_data.dsBitfields[1] << std::endl;
std::cout << actual_data.dsBitfields[2] << std::endl;
std::cout << std::dec;
DeleteObject(result);
return 0;
}
Result:
ff0000
ff00
ff
It would appear the documentation was absentmindedly copied between BITMAPINFOHEADER
, BITMAPV4HEADER
and BITMAPV5HEADER
when it should have been amended for the last two. The closest explanation I was able to find is Bitmap Header Types that at least recognizes the existence of the dedicated mask fields, but still implies the values must be provided both in these fields and after the header in bmiColors
:
The red, green, and blue bitfield masks for BI_BITFIELD
bitmaps immediately follow the BITMAPINFOHEADER
, BITMAPV4HEADER
, and BITMAPV5HEADER
structures. The BITMAPV4HEADER
and BITMAPV5HEADER
structures contain additional members for red, green, and blue masks as follows.
(emphasis mine).
We can only conclude from evidence that it is not true.
It is less of documentation than I hoped.