检索位图图像的调色板

Retrieving the palette of a bitmap image

我正在通过 GDI 函数 LoadImage 从文件(BMP 类型)加载位图图像,returns 一个 BITMAP 句柄。

我知道如何访问位图位。但是图像的格式是 8BPP,因此被调色了。如何获取调色板条目?

Select 将位图转为 dc 并调用 GetDIBColorTable。这里可以使用临时内存dc:

RGBQUAD rgb[256] = { 0 };
HDC memdc = CreateCompatibleDC(hdc);
auto oldbmp = SelectObject(memdc, hbitmap);
GetDIBColorTable(memdc, 0, 256, rgb);
SelectObject(memdc, oldbmp);
DeleteDC(memdc);

或者使用GetDIBits阅读BITMAPINFO。您必须预留足够的内存来读取颜色 table + 所有字节 + sizeof(BITMAPINFO).

颜色 table 将被复制到 BITMAPINFO -> bmiColors

Gdi+ 是另一种选择。这是 GDI 示例:

int main()
{
    HBITMAP hbitmap = (HBITMAP)LoadImage(0, L"source.bmp", 
            IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE);
    if (!hbitmap)
        return 0;

    BITMAP bm;
    GetObject(hbitmap, sizeof(bm), &bm);
    int width = bm.bmWidth;
    int height = bm.bmHeight;

    WORD clrbits = (WORD)(bm.bmPlanes * bm.bmBitsPixel);
    if (clrbits == 8)       clrbits = 1;
    else if (clrbits <= 4)  clrbits = 4;
    else if (clrbits <= 8)  clrbits = 8;
    else if (clrbits <= 16) clrbits = 16;
    else if (clrbits <= 24) clrbits = 24;
    else clrbits = 32;

    HDC hdc = GetDC(0);

    if(clrbits == 8)
    {
        RGBQUAD rgb[256] = { 0 };
        HDC memdc = CreateCompatibleDC(hdc);
        auto oldbmp = SelectObject(memdc, hbitmap);
        GetDIBColorTable(memdc, 0, 256, rgb);
        SelectObject(memdc, oldbmp);
        DeleteDC(memdc);
    }

    int palette_size = (clrbits < 24) ? sizeof(RGBQUAD) * (1 << clrbits) : 0;
    BITMAPINFO* bmpinfo = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFO) + palette_size];
    int width_in_bytes = ((width * clrbits + 31) & ~31) / 8;
    DWORD size = width_in_bytes * height;
    bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmpinfo->bmiHeader.biWidth = width;
    bmpinfo->bmiHeader.biHeight = height;
    bmpinfo->bmiHeader.biPlanes = bm.bmPlanes;
    bmpinfo->bmiHeader.biBitCount = bm.bmBitsPixel;
    bmpinfo->bmiHeader.biClrUsed = (clrbits < 24) ? (1 << clrbits) : 0;
    bmpinfo->bmiHeader.biCompression = BI_RGB;
    bmpinfo->bmiHeader.biSizeImage = size;

    BYTE* bits = new BYTE[size];
    GetDIBits(hdc, hbitmap, 0, height, bits, bmpinfo, 0);
   
    //palette size should be 1024 for 256 color
    //it should be stored in `bmpinfo->bmiColors`

    delete[]bits;
    delete[](BYTE*)bmpinfo;
    DeleteObject(hbitmap);
    ReleaseDC(0, hdc);

    return 0;
}