Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ WinAPI/GDI:如何使用GetDIBits()为位图合成颜色表?_C++_Winapi_Gdi - Fatal编程技术网

C++ WinAPI/GDI:如何使用GetDIBits()为位图合成颜色表?

C++ WinAPI/GDI:如何使用GetDIBits()为位图合成颜色表?,c++,winapi,gdi,C++,Winapi,Gdi,我发现很难理解以下摘自MSDN网站GetDIBits()函数的摘录: 如果lpvBits为NULL,并且BITMAPINFO的位计数成员为 初始化为零,GetDIBits填充BitMapInfo头 结构或不带颜色表的BITMAPCOREHEADER。这 该技术可用于查询位图属性 问题1:“BITMAPINFO的位计数成员”是什么意思?它是否意味着某些\u bmi.bmiHeader.biBitCount 问题2:“GetDIBits填充BitMapInfo标头结构或BITMAPCOREHEADE

我发现很难理解以下摘自MSDN网站
GetDIBits()
函数的摘录:

如果lpvBits为NULL,并且BITMAPINFO的位计数成员为 初始化为零,GetDIBits填充BitMapInfo头 结构或不带颜色表的BITMAPCOREHEADER。这 该技术可用于查询位图属性

问题1:“BITMAPINFO的位计数成员”是什么意思?它是否意味着
某些\u bmi.bmiHeader.biBitCount

问题2:“GetDIBits填充BitMapInfo标头结构或BITMAPCOREHEADER而不填充颜色表”是什么意思?有什么颜色的表格来填充这些结构?它们似乎都没有与颜色表相关的成员。这是关于数组
的一些\u bmi.bmiColors

问题3:是否有一种方法可以使用
GetDIBits()
来获取位图的颜色表(即数组映射索引到颜色)


编辑:

从目前为止的评论来看,把问题分成几个小部分似乎是无效的。我会用另一种方法试试

这是我从MSDN开头引用的部分中了解到的:

假设函数调用是
GetDIBits(hdc、hbmp、uStartScan、cscanline、lpvBits、lpbi、uUsage)
;如果lpvBits为NULL且
lpvBits->bmiHeader.bibibitCount
初始化为零,则GetDIBits()仅填写
lpbi->bmiHeader
,并且不修改
lpbi->bmiColor

这是正确的理解方式吗?如果是这样,是否有办法让GetDIBits()填充
lpbi->bmiColors
,例如将
lpvBits->bmiHeader.bibibitCount
初始化为位图的位深度


我尝试按如下方式测试问题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);
}
无效测试(HWND-HWND){
//获取内存DC
HDC HDC=GetDC(hWnd);
HDC hdcmem=CreateCompatibleDC(HDC);//是否已选择1x1单声道位图
//默认情况下,最初会将其导入
//选择一个16x16单声道bmp
常量int bmp_h=16,bmp_w=16;
常数int位每像素=1;
HBITMAP hbmp=CreateCompatibleBitmap(hdcmem,bmp_h,bmp_w);//16x16单声道位图
HGDIOBJ hOldBmp=SelectObject(hdcmem,hbmp);
//初始化BITMAPINFO ptr
//(确保分配一个足够容纳2个RGBquad的缓冲区
//如果颜色表由GetDIBits()调用返回)
康斯特国际bmi_buf_sz=
sizeof(位图信息)+sizeof(RGBQUAD)*(1种颜色)
BYTE*p_bmi_buf=新字节[bmi_buf_sz];
BITMAPINFO*pbmi=重新解释投射(p\u bmi\u buf);
零内存(pbmi、bmi_buf_sz);
//填充位图信息
pbmi->bmiHeader.biSize=sizeof(BitMapInfo头文件);
pbmi->bmiHeader.biBitCount=1;//设置为1只是为了查看GetDIBits()是否
//也填写pbmi->BMI颜色
//(设置为0时,仅填充pbmi->BMI标头)
如果(!GetDIBits(hdcmem,hbmp,
0,(UINT)bmp_h,
空、pbmi、DIB_PAL_颜色){
MessageBox(hWnd,L“GetDIBits()失败!”,NULL,MB_OK);
}
//清理
删除[]p_bmi_buf;
选择对象(hdcmem,hOldBmp);//将hbmp推出
删除对象(hbmp);
DeleteDC(hdcmem);
释放DC(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
,并为dib位分配足够的空间

此外,
DIB\u PAL\u COLORS
将返回调色板索引数组(我不确定您可以用它做什么)。您可能需要使用
DIB\u RGB\u 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();
    //...
}
因此,
BITMAPINFO
没有
bibitbitcount
成员。但它确实有
bmiHeader.bibibitcount
成员

当您声明
BITMAPINFO
变量时,必须设置
biSize
成员(这是Windows的版本控制思想)。当您声明
BITMAPINFO
变量时,必须确保它是
BITMAPINFO
变量


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

尽管公认的答案涵盖了细节,但这更直接地回答了OP中的问题

假设函数调用是
GetDIBits(hdc、hbmp、uStartScan、cscanline、lpvBits、lpbi、uUsage)

问题1:

没错。“BITMAPINFO的位计数成员”指的是
lpbi->bmiHeader.biBitCount

问题2:

当调用
GetDIBits()
以获取DIB位(即,使用非null的
lpvBits
和适当初始化的
lpbi->bmiHeader
)时,
lpbi->bmiColors
也会由函数用颜色表填充(如果位深度小于24 bpp)。 不幸的是,这在函数的文档中并不清楚。考虑到这一点,引用部分的意思是,当
lpvBits
为空且
lpbi->bmiHeader.bibibibitCount
为零时,函数只填充
lpbi->bmiHeader
,而不修改
lpbi->bimColor
(与调整函数以获取DIB位时相反)

问题3:

您可以在
lpbi->bmiColors
中通过使用
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();
    //...
}
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;