在 Winapi 中创建 24 位位 BITMAP



我使用以下代码将我的ImageMagick图像转换为32位HBITMAP:

BITMAP bitmap;
std::memset(&bitmap, 0, sizeof(bitmap));
bitmap.bmType = 0;
bitmap.bmWidth = image->image()->columns;
bitmap.bmHeight = image->image()->rows;
bitmap.bmWidthBytes = 4 * bitmap.bmWidth;
bitmap.bmPlanes = 1;
bitmap.bmBitsPixel = 32;
bitmap.bmBits = NULL;
const size_t size = bitmap.bmWidthBytes * bitmap.bmHeight;
auto buffer = (HANDLE)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
RGBQUAD *bitmap_bits = (RGBQUAD *) GlobalLock((HGLOBAL) buffer);
register RGBQUAD *q = bitmap_bits;
for (size_t y = 0; y < image->image()->rows; y++)
{
    register auto p = GetVirtualPixels(image->image(), 0, y, image->image()->columns, 1, exception);
    if (!p) break;
    for (size_t x = 0; x < image->image()->columns; x++)
    {
        q->rgbRed = ScaleQuantumToChar(GetPixelRed(image->image(), p));
        q->rgbGreen = ScaleQuantumToChar(GetPixelGreen(image->image(), p));
        q->rgbBlue = ScaleQuantumToChar(GetPixelBlue(image->image(), p));
        q->rgbReserved = 0;
        p += GetPixelChannels(image->image());
        q++;
    }
}
bitmap.bmBits = bitmap_bits;
HBITMAP hbmp = CreateBitmapIndirect(&bitmap);

它运行良好,但我想通过使用较低深度的图像来节省一些内存。不幸的是,我什至无法使其适用于 24 位图像。我修改了我的代码,如下所示:

BITMAP bitmap;
std::memset(&bitmap, 0, sizeof(bitmap));
bitmap.bmType = 0;
bitmap.bmWidth = image->image()->columns;
bitmap.bmHeight = image->image()->rows;
bitmap.bmWidthBytes = ((bitmap.bmWidth * 24 + 31) / 32) * 4;
bitmap.bmPlanes = 1;
bitmap.bmBitsPixel = 24;
bitmap.bmBits = NULL;
const size_t length = bitmap.bmWidthBytes * bitmap.bmHeight;
auto buffer = (HANDLE)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, length);
RGBTRIPLE *bitmap_bits = (RGBTRIPLE *) GlobalLock((HGLOBAL) buffer);
register RGBTRIPLE *q = bitmap_bits;
for (size_t y = 0; y < image->image()->rows; y++)
{
    register auto p = GetVirtualPixels(image->image(), 0, y, image->image()->columns, 1, exception);
    if (!p) break;
    for (size_t x = 0; x < image->image()->columns; x++)
    {
        q->rgbtRed = ScaleQuantumToChar(GetPixelRed(image->image(), p));
        q->rgbtGreen = ScaleQuantumToChar(GetPixelGreen(image->image(), p));
        q->rgbtBlue = ScaleQuantumToChar(GetPixelBlue(image->image(), p));
        p += GetPixelChannels(image->image());
        q++;
    }
}
bitmap.bmBits = bitmap_bits;
HBITMAP hbmp = CreateBitmapIndirect(&bitmap);

但似乎此代码无法生成有效的位图。我做错了什么?

您没有考虑步幅/对齐方式。每一行都需要对齐 DWORD。

计算表面步幅

在未压缩的位图中,步幅是从一行像素的开头到下一行的开头所需的字节数。图像格式定义图像的最小步幅。此外,图形硬件可能需要为包含图像的图面提供更大的步幅。 对于未压缩的 RGB 格式,最小步幅始终是图像宽度(以字节为单位(,向上舍入到最接近的 DWORD。您可以使用以下公式计算步幅:

stride = ((((biWidth * biBitCount) + 31) & ~31) >> 3)

您需要修复在缓冲区中访问 RGBTRIPLE 的方式。

在"x 循环"之前,您应该执行以下操作q = (RGBTRIPLE*) (((char*)bitmap_bits) + (y * bitmap.bmWidthBytes));

CreateBitmapIndirect创建可能不是最佳选择的 DDB,请改为创建 DIB:

#define CalcStride(w, bpp) ( ((((w) * (bpp)) + 31) & ~31) >> 3 )
static void SetPixel24(UINT w, void*bits, UINT x, UINT y, COLORREF cr)
{
    RGBTRIPLE*p = ((RGBTRIPLE*) ( ((char*)bits) + (y * CalcStride(w, 24)) )) + x;
    p->rgbtRed = GetRValue(cr);
    p->rgbtGreen = GetGValue(cr);
    p->rgbtBlue = GetBValue(cr);
}
void Silly24BPPExample()
{
    HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, WC_STATIC, 0, WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_OVERLAPPEDWINDOW|SS_BITMAP|SS_REALSIZECONTROL, 0, 0, 99, 99, 0, 0, 0, 0);
    const INT w = 4, h = 4, bpp = 24;
    BITMAPINFO bi;
    ZeroMemory(&bi, sizeof(bi));
    BITMAPINFOHEADER&bih = bi.bmiHeader;
    bih.biSize = sizeof(BITMAPINFOHEADER);
    bih.biWidth = w, bih.biHeight = -h;
    bih.biPlanes = 1, bih.biBitCount = bpp;
    bih.biCompression = BI_RGB;
    void*bits;
    HBITMAP hBmp = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &bits, NULL, 0);
    for (UINT x = 0; x < w; ++x)
        for (UINT y = 0; y < h; ++y)
            SetPixel24(w, bits, x, y, RGB(255, 0, 0)); // All red
    SetPixel24(w, bits, 0, 0, RGB(0, 0, 255)); // except one blue
    SendMessage(hWnd, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hBmp);
    for (MSG msg; IsWindow(hWnd) && GetMessage(&msg, 0, 0, 0); ) DispatchMessage(&msg);
    // DeleteObject(...)
}

相关内容

  • 没有找到相关文章

最新更新