Windows 位图:BITMAPV5HEADER 和 BITMAPINFO 兼容吗?

Windows bitmaps: BITMAPV5HEADER and BITMAPINFO compatible?

the documentation on CreateDIBSection 我观察到 CreateDIBSection 将指向 BITMAPINFO 的指针作为第二个参数。

然而,我遇到了很多地方表明它可能被允许将指针传递给其他结构(特别是 BITMAPV5HEADER),包括

我觉得这很有道理(BITMAPV5HEADER 可以看作是 BITMAPINFO 的 "extended version" wrt struct 布局),但我找不到一个有关此主题的官方文档。

任何人都可以确认传递 BITMAPV5HEADER* 而不是 BITMAPINFO 实际上是有效的并且可能提供一些文档吗?

简短的回答必须是BITMAPV5HEADER* 不是 BITMAPINFO* 的替代品,并且在需要 BITMAPINFO* 时可能不会被传递(仅仅是因为 BITMAPINFO 包含 header 之后的调色板颜色,并且 BITMAPV5HEADER 只是一个 header).


传递 BITMAPV5HEADER* 而不是 BITMAPINFO* 当然没问题,前提是 BITMAPV5HEADERBITMAPINFO 的一部分并且在它之后需要某种调色板颜色数据.这是有记录的,虽然有点间接,通过使用说明和常识:

  • BITMAPV5HEADERdocumented 是一个 "extended version of th BITMAPINFOHEADER structure",所以这部分很清楚。

  • BITMAPINFOdocumented 组合一个 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为BITMAPV4HEADERBITMAPV5HEADER时,位图有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
    

    看起来 文档在 BITMAPINFOHEADERBITMAPV4HEADERBITMAPV5HEADER 之间被心不在焉地复制了,而本应最后修改的二。我能找到的最接近的解释是 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.

    (强调我的)。

    我们只能根据证据得出结论,这不是真的。
    它的文档比我希望的要少。