Win32 BITMAPINFO 如何可靠地为 RGBQUAD 数组/颜色 table(bmiColors 字段)分配足够的内存?
Win32 BITMAPINFO how to reliably allocate enough memory for RGBQUAD array / color table (bmiColors field)?
我有一个 HBITMAP
,我想从 HBITMAP
中获得完整的 BITMAPINFO
结构和相应的 RGBQUAD
数组,而不仅仅是 BITMAPINFOHEADER
。
这是BITMAPINFO
的结构:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
我可以使用 GetDIBits
和 NULL
指针来引用位缓冲区,从而 只是 BITMAPINFOHEADER
进入我分配的 BITMAPINFO
记忆.
我不知道的是如何可靠地根据 BITMAPINFOHEADER
数据计算 RGBQUAD
数组的大小,以便我可以分配足够的 space 允许 GetDIBits
存储整个数组。文档(以及我发现的许多代码示例)非常混乱,甚至在有关该主题的某些部分上存在冲突。
重新阅读文档、wiki、一些博客文章和其他来源(none 其中内部一致)这似乎是确定 Color Table 中元素数量的最佳方法(RGBQUAD数组):
对像素缓冲区使用 GetDIBits
和 NULL
值以获得 BITMAPINFO
:
BITMAPINFO* pbinfo = ( BITMAPINFO* ) malloc( sizeof( BITMAPINFOHEADER ) );
...
pbinfo->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
GetDIBits( hScreenMemory, hBitmap, 0, 0, NULL, pbinfo, DIB_RGB_COLORS );
然后基于:
pbinfo->bmiHeader.biBitCount
pbinfo->bmiHeader.biClrUsed
pbinfo->bmiHeader.biCompression
我们可以使用以下逻辑确定 RGBQUAD
个数组元素的数量:
DWORD ColorTableLength( BITMAPINFOHEADER* h ) {
DWORD result = 0;
DWORD biClrUsed = h->biClrUsed;
WORD biBitCount = h->biBitCount;
DWORD biCompression = h->biCompression;
switch ( biBitCount ) {
case 24:
result = biClrUsed;
break;
case 16:
case 32:
if ( biCompression == BI_RGB )
result = biClrUsed;
else if ( biCompression == BI_BITFIELDS )
result = 3;
break;
default: // for 0, 1, 2, 4, and 8
if ( biClrUsed == 0 )
result = ( 1 << biBitCount ); // 2^biBitCount
else
result = biClrUsed;
break;
}
return result;
}
这是 "lowest common denominator",它与我在网上找到的许多资源和示例是一致的(但仍有可能并非对所有情况都适用)。
需要为RGBQUAD
数组分配的字节数可以通过sizeof(RGBQUAD) * ColorTableLength( &... )
计算得到。
在某些情况下,RGBQUAD
数组被 3 个 DWORD
替换,但是 DWORD
和 RGBQUAD
的大小相同,因此哪个 sizeof
我们乘以 ColorTableLength
值。
我不确定为什么标准没有定义一个字段来明确说明为 Color Table / RGBQUAD
array / RGB DWORD
s 保留了多少字节但是看起来就是这样。
biClrUsed
字段应该有这个目的,但并非在所有情况下都如此。
我有一个 HBITMAP
,我想从 HBITMAP
中获得完整的 BITMAPINFO
结构和相应的 RGBQUAD
数组,而不仅仅是 BITMAPINFOHEADER
。
这是BITMAPINFO
的结构:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
我可以使用 GetDIBits
和 NULL
指针来引用位缓冲区,从而 只是 BITMAPINFOHEADER
进入我分配的 BITMAPINFO
记忆.
我不知道的是如何可靠地根据 BITMAPINFOHEADER
数据计算 RGBQUAD
数组的大小,以便我可以分配足够的 space 允许 GetDIBits
存储整个数组。文档(以及我发现的许多代码示例)非常混乱,甚至在有关该主题的某些部分上存在冲突。
重新阅读文档、wiki、一些博客文章和其他来源(none 其中内部一致)这似乎是确定 Color Table 中元素数量的最佳方法(RGBQUAD数组):
对像素缓冲区使用 GetDIBits
和 NULL
值以获得 BITMAPINFO
:
BITMAPINFO* pbinfo = ( BITMAPINFO* ) malloc( sizeof( BITMAPINFOHEADER ) );
...
pbinfo->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
GetDIBits( hScreenMemory, hBitmap, 0, 0, NULL, pbinfo, DIB_RGB_COLORS );
然后基于:
pbinfo->bmiHeader.biBitCount
pbinfo->bmiHeader.biClrUsed
pbinfo->bmiHeader.biCompression
我们可以使用以下逻辑确定 RGBQUAD
个数组元素的数量:
DWORD ColorTableLength( BITMAPINFOHEADER* h ) {
DWORD result = 0;
DWORD biClrUsed = h->biClrUsed;
WORD biBitCount = h->biBitCount;
DWORD biCompression = h->biCompression;
switch ( biBitCount ) {
case 24:
result = biClrUsed;
break;
case 16:
case 32:
if ( biCompression == BI_RGB )
result = biClrUsed;
else if ( biCompression == BI_BITFIELDS )
result = 3;
break;
default: // for 0, 1, 2, 4, and 8
if ( biClrUsed == 0 )
result = ( 1 << biBitCount ); // 2^biBitCount
else
result = biClrUsed;
break;
}
return result;
}
这是 "lowest common denominator",它与我在网上找到的许多资源和示例是一致的(但仍有可能并非对所有情况都适用)。
需要为RGBQUAD
数组分配的字节数可以通过sizeof(RGBQUAD) * ColorTableLength( &... )
计算得到。
在某些情况下,RGBQUAD
数组被 3 个 DWORD
替换,但是 DWORD
和 RGBQUAD
的大小相同,因此哪个 sizeof
我们乘以 ColorTableLength
值。
我不确定为什么标准没有定义一个字段来明确说明为 Color Table / RGBQUAD
array / RGB DWORD
s 保留了多少字节但是看起来就是这样。
biClrUsed
字段应该有这个目的,但并非在所有情况下都如此。