Windows 位图:BITMAPV5HEADER 和 BITMAPINFO 兼容?

Posted

技术标签:

【中文标题】Windows 位图:BITMAPV5HEADER 和 BITMAPINFO 兼容?【英文标题】:Windows bitmaps: BITMAPV5HEADER and BITMAPINFO compatible? 【发布时间】:2018-03-02 12:15:20 【问题描述】:

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

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

this answer to another question Chromium source code

我觉得这很有意义(BITMAPV5HEADER 可以看作是BITMAPINFO wrt 结构布局的“扩展版”),但我找不到关于这个主题的官方文档。

谁能确认传递BITMAPV5HEADER* 而不是BITMAPINFO 实际上是有效的并且可能提供一些文档?

【问题讨论】:

【参考方案1】:

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


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

BITMAPV5HEADER 是 documented 是“BITMAPINFOHEADER 结构的扩展版本”,所以这部分很清楚。

BITMAPINFO 是 documented 以组合标题和颜色数据。标头是按值包含的,而不是按指针包含的,所以在这一点上,很明显标头可能不会随心所欲地增长,否则就不可能访问BITMAPINFO.bmiColors 以及拥有扩展版本的整个想法标题将毫无意义。

然后这个问题在another place in the documentation(“备注”部分)中得到解决:

应用程序应使用存储在biSize 成员中的信息来定位BITMAPINFO 结构中的颜色表,如下所示:

pColor = ((LPSTR)pBitmapInfo + (WORD)(pBitmapInfo->bmiHeader.biSize));

虽然我相信这部分对你来说并没有混淆。


现在是长答案。

BITMAPV5HEADER* 可以传递给BITMAPINFO* 时,似乎两种情况。两者都没有以具体的方式记录,如果对于第一个我们可以应用我们上面应用的相同常识,那么第二个似乎是文档中的一个错误:

BITMAPINFO.bmiColors 记录为NULL 时。您可以在documentation for BITMAPINFOHEADER 中找到此类案例的完整列表。

当标头为BITMAPV4HEADERBITMAPV5HEADER时,位图有16位或32位颜色,压缩设置为BI_BITFIELDS。在这种情况下,记录在标头后面的颜色掩码取自标头的相应专用字段,并且标头后面的三个 DWORDs 将被忽略。

这很容易通过稍微修改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,它至少承认存在专用掩码字段,但仍然暗示必须在这些字段中以及bmiColors 中的标头之后提供值:

BI_BITFIELD 位图的红色、绿色和蓝色位域掩码紧跟BITMAPINFOHEADERBITMAPV4HEADERBITMAPV5HEADER 结构。 BITMAPV4HEADERBITMAPV5HEADER 结构包含红色、绿色和蓝色蒙版的附加成员,如下所示。

(强调我的)。

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

【讨论】:

@SGerg:我在 MSDN 中找到了您的第一点(即使我并不完全清楚后果)。关于第三点:pColorbmiColors一样吗?从msdn.microsoft.com/en-us/library/windows/desktop/… 我看到BI_BITFIELDS 表示bmiColors 是颜色掩码。如果我现在查看msdn.microsoft.com/en-us/library/windows/desktop/…,它会告诉我bV5RedMaskbV5GreenMaskbV5BlueMask 表示这些颜色掩码,并且偏移量应该对应于bmiColors 继续:由于相同的偏移量,我不知何故怀疑我可以只传递整个 BITMAPV5HEADER* 而不是 BITMAPINFO* 并且我假设基本上 BITMAPV5HEADER 已经“包含”了那些会否则包含在BITMAPINFObmiColors 中。它是否正确?或者我们还有bmiColors 除了这些面具吗?还有一件事:我找到了expertreplies.com/…(似乎取自一篇旧的 MSDN 文章),但我在当前的 MSDN 中没有找到类似的东西。 @phimuemue Like Mike Ransom said, BITMAPINFO 不是真正的结构。 bmiColors 成员是出于技术原因声明的,但可能无法通过名称直接访问。 pColorbmiColors 不同,它是唯一的 bmiColors,而bmiColors 实际上不是一个东西。 BITMAPV5HEADERBITMAPV4HEADER 都不包含 bmiColors 数据,它必须跟随它们以便 pColor 仍然有效。考虑当位图没有BI_BITFIELDS时会发生什么 - 如果掩码与bmiColors相同,它将无法工作。 @SGerg 非常感谢您的回答。但我不明白 - 在 Mike Ransom 的回答中 - bmiColors 如何跟随 BITMAPV5HEADER (他只是传递了 BITMAPV5HEADER 一个指针,而在呼叫站点没有任何关于 bmiColors 的线索)。然后由CreateDIBSection 处理(基本上意味着bmiColors 实际上只存在于生成的位图中)? @phimuemue 你是对的。出于某种原因,我记得BITMAPINFO 包含图像数据,但事实并非如此。我将重写/删除答案。

以上是关于Windows 位图:BITMAPV5HEADER 和 BITMAPINFO 兼容?的主要内容,如果未能解决你的问题,请参考以下文章

我的 windows-rs 脚本不渲染位图(或不创建位图)但也不会崩溃,谁能帮我查明问题?

在 Windows Metro 下使用 DirectX 绘制位图

Windows 上 C++ 中的位图操作

将透明位图添加到 Windows 按钮

从内存创建 Windows GDI 位图

Windows/C++ -- 将图标渲染为具有透明度的位图