gpt4 book ai didi

c++ - WinAPI/GDI : How to use GetDIBits() to get color table synthesized for a bitmap?

转载 作者:行者123 更新时间:2023-11-30 03:28:29 24 4
gpt4 key购买 nike

我发现很难理解下面摘自 MSDN 站点上关于 GetDIBits() 函数的摘录:

If lpvBits is NULL and the bit count member of BITMAPINFO is initialized to zero, GetDIBits fills in a BITMAPINFOHEADER structure or BITMAPCOREHEADER without the color table. This technique can be used to query bitmap attributes.

问题1:“BITMAPINFO的位数成员”是什么意思?这是否意味着 some_bmi.bmiHeader.biBitCount

问题2:“GetDIBits 填充BITMAPINFOHEADER 结构或BITMAPCOREHEADER 而没有颜色表”是什么意思?有什么颜色的表格可以填充这些结构?他们似乎都没有与颜色表相关的成员。这是关于数组 some_bmi.bmiColors 的吗?

问题 3:有没有办法使用 GetDIBits() 获取位图的颜色表(即数组映射索引到颜色)?


编辑:

从目前的评论来看,将问题分解成更小的部分似乎效果不佳。我会尝试另一种方式。

我开头引用MSDN的部分是这样理解的:

假设函数调用是GetDIBits(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbi, uUsage);如果 lpvBits 为 NULL 且 lpvBits->bmiHeader.biBitCount 初始化为零,则 GetDIBits() 仅填充 lpbi->bmiHeaderlpbi->bmiColors 没有被修改。

这样理解对吗?如果是这样,有没有办法让GetDIBits()填写lpbi->bmiColors,比如初始化lpvBits->bmiHeader.biBitCount到bit-depth of the位图?


我尝试按如下方式测试问题 1 的假设,但 GetDIBits() 在这种情况下失败了:

void test(HWND hWnd) {
// get a memory DC
HDC hdc = GetDC(hWnd);
HDC hdcmem = CreateCompatibleDC(hdc); // has 1x1 mono bitmap selected
// into it initially by default
// select a 16x16 mono bmp into it
const int bmp_h = 16, bmp_w = 16;
const int bits_per_px = 1;
HBITMAP hbmp = CreateCompatibleBitmap(hdcmem, bmp_h, bmp_w); // 16x16 mono bitmap
HGDIOBJ hOldBmp = SelectObject(hdcmem, hbmp);

// initialize BITMAPINFO ptr
// (make sure to allocate a buffer large enough for 2 RGBQUADs
// in case color table is retured by GetDIBits() call)
const int bmi_buf_sz =
sizeof(BITMAPINFO) + sizeof(RGBQUAD) * (1 << bits_per_px); // 2 + 1(extra) RGBQUADs allocated for pbmi->bimColors
BYTE* p_bmi_buf = new BYTE[bmi_buf_sz];
BITMAPINFO* pbmi = reinterpret_cast<BITMAPINFO*>(p_bmi_buf);
ZeroMemory(pbmi, bmi_buf_sz);

// populate BITMAPINFO
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biBitCount = 1; // set to 1 just to see if GetDIBits()
// fills in pbmi->bmiColors too
// (when set to 0, only pbmi->bmiHeader is filled)
if(!GetDIBits(hdcmem, hbmp,
0, (UINT)bmp_h,
NULL, pbmi, DIB_PAL_COLORS)) {
MessageBox(hWnd, L"GetDIBits() failed!", NULL, MB_OK);
}

// clean-up
delete[] p_bmi_buf;
SelectObject(hdcmem, hOldBmp); // push hbmp out
DeleteObject(hbmp);
DeleteDC(hdcmem);
ReleaseDC(hWnd, hdc);
}

最佳答案

获取颜色表的最简单方法是使用 GetDibColorTable:

HDC memdc = CreateCompatibleDC(NULL);
HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, hbitmap);
int ncolors = 1 << bm.bmBitsPixel;
std::vector<RGBQUAD> rgb(ncolors);
if(ncolors == GetDIBColorTable(memdc, 0, ncolors, &rgb[0]))
{
//success!
}
SelectObject(memdc, oldbmp);
DeleteDC(memdc);

回到您的问题:GetDIBits 期望 pbmi 包含全零(bmiHeader.biSize 成员除外)。所以 pbmi->bmiHeader.biBitCount 应该为零。

//pbmi->bmiHeader.biBitCount = 1; <<= comment out this line

这应该有效;但是,正如文档中所述,这只会填充信息标题,而不是颜色表。要获得颜色表,您必须再次调用 GetDIBits 并为 dib 位分配足够的空间。

此外,DIB_PAL_COLORS 将返回调色板索引数组(我不确定您可以用它做什么)。您可能想要使用 DIB_RGB_COLORS 标志,它会在存在颜色表时返回实际颜色。

用从文件加载的位图试试这个:

HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"8bit.bmp",
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm);

//don't continue for hi color bitmaps
if(bm.bmBitsPixel > 8) return;

int ncolors = 1 << bm.bmBitsPixel;
HDC memdc = CreateCompatibleDC(NULL);
int bmpinfo_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ncolors;
std::vector<BYTE> buf(bmpinfo_size);
BITMAPINFO* bmpinfo = (BITMAPINFO*)buf.data();
bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if(!GetDIBits(memdc, hbitmap, 0, bm.bmHeight, NULL, bmpinfo, DIB_RGB_COLORS))
{
DWORD err = GetLastError();
//...
}

int dibsize = ((bm.bmWidth * bm.bmBitsPixel + 31) / 32) * 4 * bm.bmHeight;
std::vector<BYTE> dib(dibsize);
if(!GetDIBits(memdc, hbitmap, 0, (UINT)bm.bmHeight, &dib[0], bmpinfo, DIB_RGB_COLORS))
{
DWORD err = GetLastError();
//...
}

现在 bmpinfo->bmiColors 应该包含与前面显示的 rgb 数组相同的值。


BITMAPINFOBITMAPINFOHEADER 之间可能存在的混淆:

以上结构声明如下:

typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

所以 BITMAPINFO 没有 biBitCount 成员。但它确实有 bmiHeader.biBitCount 成员。

当您声明一个BITMAPINFOHEADER 变量时,您必须设置biSize 成员(这是Windows 的版本控制理念)。当您声明一个 BITMAPINFO 变量时,您必须确保它的 BITMAPINFOHEADER 得到处理。

请注意,大多数时候您不必担心调色板。例如,LoadImage 将返回兼容的位图(如果您未指定 LR_CREATEDIBSECTION),您可以立即使用它。

关于c++ - WinAPI/GDI : How to use GetDIBits() to get color table synthesized for a bitmap?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46562369/

24 4 0