Windows 在Winapi中创建24位位图

Windows 在Winapi中创建24位位图,windows,winapi,bitmap,imagemagick,hbitmap,Windows,Winapi,Bitmap,Imagemagick,Hbitmap,我使用以下代码将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

我使用以下代码将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);
位图;
std::memset(&bitmap,0,sizeof(bitmap));
bitmap.bmType=0;
bitmap.bmWidth=image->image()->columns;
bitmap.bmHeight=图像->图像()->行;
bitmap.bmWidthBytes=4*bitmap.bmWidth;
位图.bmPlanes=1;
bitmap.bmBitsPixel=32;
bitmap.bmBits=NULL;
常量大小\u t size=bitmap.bmWidthBytes*bitmap.bmHeight;
自动缓冲=(句柄)全局分配(GMEM_可移动| GMEM_数据共享,大小);
RGBQUAD*位图_位=(RGBQUAD*)全局块((HGLOBAL)缓冲区);
寄存器RGBQUAD*q=位图_位;
对于(大小y=0;yimage()->行;y++)
{
register auto p=GetVirtualPixels(image->image(),0,y,image->image()->列,1,异常);
如果(!p)断裂;
对于(大小x=0;ximage()->columns;x++)
{
q->rgbreed=scalequaltumtochar(GetPixelRed(image->image(),p));
q->rgbGreen=scalequaltumtochar(GetPixelGreen(image->image(),p));
q->rgbBlue=scalequaltumtochar(GetPixelBlue(image->image(),p));
q->rgb=0;
p+=GetPixelChannel(图像->图像());
q++;
}
}
bitmap.bmBits=位图_位;
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);
位图;
std::memset(&bitmap,0,sizeof(bitmap));
bitmap.bmType=0;
bitmap.bmWidth=image->image()->columns;
bitmap.bmHeight=图像->图像()->行;
bitmap.bmWidthBytes=((bitmap.bmWidth*24+31)/32)*4;
位图.bmPlanes=1;
bitmap.bmBitsPixel=24;
bitmap.bmBits=NULL;
const size\u t length=bitmap.bmWidthBytes*bitmap.bmHeight;
自动缓冲=(句柄)全局分配(GMEM_可移动| GMEM_数据共享,长度);
RGBTRIPLE*位图_位=(RGBTRIPLE*)全局块((HGLOBAL)缓冲区);
寄存器RGBTRIPLE*q=位图_位;
对于(大小y=0;yimage()->行;y++)
{
register auto p=GetVirtualPixels(image->image(),0,y,image->image()->列,1,异常);
如果(!p)断裂;
对于(大小x=0;ximage()->columns;x++)
{
q->rgbtRed=scalequaltumtochar(GetPixelRed(image->image(),p));
q->rgbtGreen=scalequaltumtochar(GetPixelGreen(image->image(),p));
q->rgbtBlue=scalequaltumtochar(GetPixelBlue(image->image(),p));
p+=GetPixelChannel(图像->图像());
q++;
}
}
bitmap.bmBits=位图_位;
HBITMAP hbmp=CreateBitmapIndirect(&bitmap);

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

您没有考虑步幅/路线。每行都需要DWORD对齐

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

stride=(((biWidth*bibibit计数)+31)和~31)>>3)

您需要修复访问缓冲区中RGB字符串的方式

在“x循环”之前,您应该执行类似于
q=(RGBTRIPLE*)(((char*)位图_位)+(y*位图.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(...)
}
#定义CalcStride(w,bpp)(((w)*(bpp))+31)和~31)>>3)
静态无效设置像素24(UINT w,无效*位,UINT x,UINT y,COLORREF cr)
{
RGBTRIPLE*p=((RGBTRIPLE*)((char*)位)+(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|U位图| SS|U REALSIZECONTROL,0,0,99,0,0,0,0);
常数INT w=4,h=4,bpp=24;
BITMAPINFO-bi;
零内存(&bi,sizeof(bi));
BitMapInfo头&bih=bi.bmiHeader;
bih.biSize=sizeof(BitMapInfo头);
白车身宽度=w,白车身高度=h;
波黑双翼飞机=1,波黑双翼飞机计数=bpp;
bih.biCompression=biu RGB;
空*位;
HBITMAP hBmp=CreateDIBSection(NULL,和bi,DIB_RGB_颜色和位,NULL,0);
对于(UINT x=0;x
谢谢!如果(!p)中断,我在这行下面添加了代码
但恐怕这没用。代码的其余部分在您看来是否正常?CreateBitmapIndirect是否返回NULL或像素不正确的位图?您应该验证bmWidthBytes是否正确,并可能从MSDN切换到算法。它返回像素不正确的位图(当我将它们加载到wxWidgets提供的画布上时,我看不到任何内容,当我将其保存为位图时,它在图像查看器中显示为黑色表面)。HBITMAP本身似乎有适当的结构,我可以从中获得正确的bmi.bmiHeader.biBitCount。@请尝试将每个像素设置为已知颜色(例如
q->rgbtRed=255;q->rgbtGreen=0;q->rgbtBlue=255;对于粉色,请查看生成的位图是否为该颜色。如果你知道问题出在输入数据上,而不是输出转换。@JonathanPotter对不起,我忘了说我已经试过了。这似乎与转换无关