Windows 位图:BITMAPV5HEADER 和 BITMAPINFO 兼容吗?
Windows bitmaps: BITMAPV5HEADER and BITMAPINFO compatible?
从 the documentation on CreateDIBSection
我观察到 CreateDIBSection
将指向 BITMAPINFO
的指针作为第二个参数。
然而,我遇到了很多地方表明它可能被允许将指针传递给其他结构(特别是 BITMAPV5HEADER
),包括
- this answer to another question
- Chromium source code
我觉得这很有道理(BITMAPV5HEADER
可以看作是 BITMAPINFO
的 "extended version" wrt struct 布局),但我找不到一个有关此主题的官方文档。
任何人都可以确认传递 BITMAPV5HEADER*
而不是 BITMAPINFO
实际上是有效的并且可能提供一些文档吗?
简短的回答必须是否。 BITMAPV5HEADER*
不是 BITMAPINFO*
的替代品,并且在需要 BITMAPINFO*
时可能不会被传递(仅仅是因为 BITMAPINFO
包含 header 之后的调色板颜色,并且 BITMAPV5HEADER
只是一个 header).
传递 BITMAPV5HEADER*
而不是 BITMAPINFO*
当然没问题,前提是 BITMAPV5HEADER
是 BITMAPINFO
的一部分并且在它之后需要某种调色板颜色数据.这是有记录的,虽然有点间接,通过使用说明和常识:
BITMAPV5HEADER
是 documented 是一个 "extended version of th BITMAPINFOHEADER
structure",所以这部分很清楚。
BITMAPINFO
是 documented 组合一个 header 和颜色数据。 header 是按值包含的,而不是按指针包含的,因此很明显 header 可能不会随心所欲地增加大小,否则将无法访问 BITMAPINFO.bmiColors
并且拥有 header 的扩展版本的整个想法将毫无意义。
然后该问题在 another place in the documentation("Remarks" 部分)中得到解决:
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));
虽然我相信这部分不会让您一开始就感到困惑。
现在是长答案。
有出现两种情况BITMAPV5HEADER*
可以通过BITMAPINFO*
。两者都没有具体的记录,如果对于第一个我们可以应用我们上面应用的相同常识,第二个似乎是文档中的错误:
- 当
BITMAPINFO.bmiColors
被记录为 NULL
时。您可以在 documentation for BITMAPINFOHEADER
. 中找到此类案例的完整列表
当header为BITMAPV4HEADER
或BITMAPV5HEADER
时,位图有16位或32位颜色,压缩设置为BI_BITFIELDS
。在这种情况下,记录在 header 之后的颜色掩码取自 header 的相应专用字段,以及 [=110= 之后的三个 DWORD
] 被忽略。
稍微修改一下 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;
}
结果:
ff0000
ff00
ff
看起来 文档在 BITMAPINFOHEADER
、BITMAPV4HEADER
和 BITMAPV5HEADER
之间被心不在焉地复制了,而本应最后修改的二。我能找到的最接近的解释是 Bitmap Header Types,它至少承认专用掩码字段的存在,但仍然暗示必须在这些字段中和 [=39 中的 header 之后提供值=]:
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.
(强调我的)。
我们只能根据证据得出结论,这不是真的。
它的文档比我希望的要少。
从 the documentation on CreateDIBSection
我观察到 CreateDIBSection
将指向 BITMAPINFO
的指针作为第二个参数。
然而,我遇到了很多地方表明它可能被允许将指针传递给其他结构(特别是 BITMAPV5HEADER
),包括
- this answer to another question
- Chromium source code
我觉得这很有道理(BITMAPV5HEADER
可以看作是 BITMAPINFO
的 "extended version" wrt struct 布局),但我找不到一个有关此主题的官方文档。
任何人都可以确认传递 BITMAPV5HEADER*
而不是 BITMAPINFO
实际上是有效的并且可能提供一些文档吗?
简短的回答必须是否。 BITMAPV5HEADER*
不是 BITMAPINFO*
的替代品,并且在需要 BITMAPINFO*
时可能不会被传递(仅仅是因为 BITMAPINFO
包含 header 之后的调色板颜色,并且 BITMAPV5HEADER
只是一个 header).
传递 BITMAPV5HEADER*
而不是 BITMAPINFO*
当然没问题,前提是 BITMAPV5HEADER
是 BITMAPINFO
的一部分并且在它之后需要某种调色板颜色数据.这是有记录的,虽然有点间接,通过使用说明和常识:
BITMAPV5HEADER
是 documented 是一个 "extended version of thBITMAPINFOHEADER
structure",所以这部分很清楚。BITMAPINFO
是 documented 组合一个 header 和颜色数据。 header 是按值包含的,而不是按指针包含的,因此很明显 header 可能不会随心所欲地增加大小,否则将无法访问BITMAPINFO.bmiColors
并且拥有 header 的扩展版本的整个想法将毫无意义。然后该问题在 another place in the documentation("Remarks" 部分)中得到解决:
An application should use the information stored in the
biSize
member to locate the color table in aBITMAPINFO
structure, as follows:pColor = ((LPSTR)pBitmapInfo + (WORD)(pBitmapInfo->bmiHeader.biSize));
虽然我相信这部分不会让您一开始就感到困惑。
现在是长答案。
有出现两种情况BITMAPV5HEADER*
可以通过BITMAPINFO*
。两者都没有具体的记录,如果对于第一个我们可以应用我们上面应用的相同常识,第二个似乎是文档中的错误:
- 当
BITMAPINFO.bmiColors
被记录为NULL
时。您可以在 documentation forBITMAPINFOHEADER
. 中找到此类案例的完整列表
当header为
BITMAPV4HEADER
或BITMAPV5HEADER
时,位图有16位或32位颜色,压缩设置为BI_BITFIELDS
。在这种情况下,记录在 header 之后的颜色掩码取自 header 的相应专用字段,以及 [=110= 之后的三个DWORD
] 被忽略。稍微修改一下 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; }
结果:
ff0000 ff00 ff
看起来 文档在
BITMAPINFOHEADER
、BITMAPV4HEADER
和BITMAPV5HEADER
之间被心不在焉地复制了,而本应最后修改的二。我能找到的最接近的解释是 Bitmap Header Types,它至少承认专用掩码字段的存在,但仍然暗示必须在这些字段中和 [=39 中的 header 之后提供值=]:The red, green, and blue bitfield masks for
BI_BITFIELD
bitmaps immediately follow theBITMAPINFOHEADER
,BITMAPV4HEADER
, andBITMAPV5HEADER
structures. TheBITMAPV4HEADER
andBITMAPV5HEADER
structures contain additional members for red, green, and blue masks as follows.(强调我的)。
我们只能根据证据得出结论,这不是真的。
它的文档比我希望的要少。