Winapi Win32 BITMAPINFO如何为RGBQUAD数组/颜色表(bmiColors字段)可靠地分配足够的内存?

Winapi Win32 BITMAPINFO如何为RGBQUAD数组/颜色表(bmiColors字段)可靠地分配足够的内存?,winapi,colors,bitmap,Winapi,Colors,Bitmap,我有一个HBITMAP,我想从HBITMAP和相应的RGBQUAD数组中获取完整的BITMAPINFO结构,而不仅仅是BITMAPINFO 这是BITMAPINFO的结构: typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO; BITMAPINFO* pbinfo = ( BI

我有一个
HBITMAP
,我想从
HBITMAP
和相应的
RGBQUAD
数组中获取完整的
BITMAPINFO
结构,而不仅仅是
BITMAPINFO

这是BITMAPINFO的结构:

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
BITMAPINFO* pbinfo = ( BITMAPINFO* ) malloc( sizeof( BITMAPINFOHEADER ) );
...
pbinfo->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
GetDIBits( hScreenMemory, hBitmap, 0, 0, NULL, pbinfo, DIB_RGB_COLORS );
我可以使用
GetDIBits
NULL
指针来引用位缓冲区,以便将
BITMAPINFO头
放入分配的
BITMAPINFO
内存中


我不知道的是,如何从
BitMapInfo头数据
可靠地计算
RGBQUAD
数组的大小,以便分配足够的空间,允许
GetDIBits
存储整个数组。文档(以及我发现的许多代码示例)非常混乱,甚至在与此主题相关的某些部分上存在冲突。

在重新阅读文档、wiki、一些博客文章和其他来源(没有一个是内部一致的)后,这似乎是确定颜色表(RGBQUAD数组)中元素数量的最佳方法:

使用像素缓冲区的
GetDIBits
NULL
值来获取
BITMAPINFO

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
BITMAPINFO* pbinfo = ( BITMAPINFO* ) malloc( sizeof( BITMAPINFOHEADER ) );
...
pbinfo->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
GetDIBits( hScreenMemory, hBitmap, 0, 0, NULL, pbinfo, DIB_RGB_COLORS );
然后根据以下结果:

  • pbinfo->bmiHeader.bibibitcount
  • 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;
    }
    
    DWORD ColorTableLength(BitMapInfo头*h){
    DWORD结果=0;
    DWORD BICLRUSE=h->BICLRUSE;
    单词bibibitcount=h->bibibitcount;
    DWORD双压缩=h->双压缩;
    开关(双位计数){
    案例24:
    结果=二次使用;
    打破
    案例16:
    案例32:
    if(双压缩==BI_RGB)
    结果=二次使用;
    else if(双压缩==BI_位字段)
    结果=3;
    打破
    0、1、2、4和8的默认值:/
    如果(biClrUsed==0)
    
    结果=(1=>完整地记录了这一点。@GSerg没有完整地记录这一点。这取决于如何记录?他们解释了各种不同的情况,但正如我在文档中的不同地方提到的,他们有相互矛盾的信息。在一些地方,他们说只有深度在8位以下的位图有颜色表,在其他地方,他们说这就是一切低于24。我的主要问题是,我无法从文档中得到明确的答案。或者我能理解的答案。因为像素深度为8位及以下的位图不一定使用固定颜色表。相反,它们定义了一个自定义优化的8位颜色表,其中仅包含特定位图图像中使用的特定颜色。在换句话说,他们使用“选择性”调色板。请参阅:@StraiveSun MSFT是的,我知道他们将颜色放入一个“索引”表中,并仅引用它们,问题是文档/标准不清楚其他深度以及如何计算表大小(或者如何知道位图是否有颜色表).你能看一下我的答案,看看你是否能发现任何明显的缺陷吗?它现在可以工作,但我不确定所有的边缘情况。奇怪的是API没有提供一个函数,只从
    HBITMAP
    返回相关颜色表的大小。