我正在使用以下代码将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);
但是看来这段代码无法产生有效的位图。我在做什么错了?
答案 0 :(得分:1)
您未考虑步幅/对齐方式。每行都需要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(...)
}