我发现很难理解GetDIBits()函数的MSDN站点下面的摘录:
如果BITMAPINFOHEADER为空,并且BITMAPINFO的位计数成员初始化为零,则GetDIBits将填充不带颜色表的结构或。此技术可用于查询位图属性。
问题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->bmiHeader,而lpbi->bmiColors不被修改。
这是理解它的正确方法吗?如果是这样的话,是否有一种方法可以让GetDIBits()填充lpbi->bmiColors,例如将lpvBits->bmiHeader.biBitCount初始化为位图的位深度?
我尝试测试问题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);
}发布于 2017-10-05 01:47:00
获取颜色表的最简单方法是使用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数组相同的值。
BITMAPINFO和BITMAPINFOHEADER之间的可能混淆
上述结构声明如下:
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成员(这就是biSize的版本控制思想)。当您声明一个BITMAPINFO变量时,您必须确保它是BITMAPINFOHEADER。
请注意,大多数情况下,您不必担心调色板。例如,LoadImage将返回一个兼容的位图(如果没有指定LR_CREATEDIBSECTION),您可以立即使用该位图。
发布于 2017-10-06 09:03:49
虽然接受的答案涵盖了细节,但这更多的是对执行部分中的问题的直接回答。
假设函数调用为GetDIBits(hdc, hbmp, uStartScan, cScanLines, lpvBits, lpbi, uUsage);
问题-1:
这是正确的。“BITMAPINFO的位计数成员”指的是lpbi->bmiHeader.biBitCount。
问题2:
当调用GetDIBits()以获取DIB位(即使用非空lpvBits和适当初始化的lpbi->bmiHeader)时,lpbi->bmiColors也会被颜色表填充(如果位深度小于24 bpp)。不幸的是,这一点在该职能的文档中并不清楚。考虑到这一点,引用的部分的意思是,当lpvBits为NULL而lpbi->bmiHeader.biBitCount为零时,函数只填充lpbi->bmiHeader only,不修改lpbi->bimColor(与调用函数以获取DIB位时不同)。
问题3:
您可以在lpbi->bmiColors中获得返回颜色表的函数(对于具有8-bbp或更少的位图),方法是使用非空lpvBits和适当初始化的lpbi->bmiHeader调用它。IOW,当您像往常一样调用函数获取DIB位时,它也会填充lpbi->bmiColors。
编辑部分的问题:
如果lpvBits为NULL,而
lpvBits->bmiHeader.biBitCount被初始化为零,则GetDIBits()只填充lpbi->bmiHeader,而lpbi->bmiColors不被修改。 这是理解它的正确方法吗?
是的,这是正确的。
如果是这样的话,是否有一种方法可以让GetDIBits()填充
lpbi->bmiColors,例如将lpvBits->bmiHeader.biBitCount初始化为位图的位深度?
是的,有一种方法可以让函数返回颜色表,但正如在答复Q2中所解释的,仅将lpvBits->bmiHeader.biBitCount初始化为位图的位深度是不够的。必须对lpvBits->bmiHeader的所有成员进行适当的初始化,lpvBits必须为非空。这基本上与调用函数获取DIB位相同。
https://stackoverflow.com/questions/46562369
复制相似问题