英文:
How do I show an image into a window's client area in Win32?
问题
Given an RGBA array (24 bpp) of an image that has the same width and height of a window's client area, how do I efficiently show that image on that client area, using the Win32 API?
如何使用Win32 API有效地在窗口客户区域上显示具有与窗口客户区域相同宽度和高度的RGBA图像数组(24 bpp)?
Can I use the same function(s) to efficiently update part of the window's client area with a changed sub-image? If not, which other functions should I use?
我可以使用相同的函数来有效地更新窗口客户区域的一部分以更改的子图像吗?如果不能,我应该使用哪些其他函数?
I own the window of which I'm trying to modify the client area.
我拥有我尝试修改客户区域的窗口。
I tried by using these functions:
我尝试使用以下这些函数:
- Creating a compatible device context (with
CreateCompatibleDC
) - Creating a compatible bitmap (with
CreateCompatibleBitmap
) - Selecting the bitmap (with
SelectObject
) - Getting the bitmap object info (with
GetObject
) - Setting the bitmap bits (with
SetDIBits
) because CreateCompatibleBitmap does not allow to specify bits as a function argument - Transferring the color data to the device context (with
BitBlt
)
我尝试使用以下这些函数:
- 创建兼容的设备上下文(使用
CreateCompatibleDC
) - 创建兼容的位图(使用
CreateCompatibleBitmap
) - 选择位图(使用
SelectObject
) - 获取位图对象信息(使用
GetObject
) - 设置位图位(使用
SetDIBits
)因为CreateCompatibleBitmap不允许将位指定为函数参数 - 将颜色数据传输到设备上下文(使用
BitBlt
)
But the result I got does not match my expectations at all.
但是我得到的结果与我的期望完全不符。
What I expected was the client area divided in 4 equal parts, each one with a different shade of gray (white, light gray, dark gray, black).
我期望的是客户区域分成4个相等的部分,每个部分具有不同的灰度(白色、浅灰色、深灰色、黑色)。
I also tried using SetDIBitsToDevice
and removing the alpha channel, but the result is the same.
我还尝试使用SetDIBitsToDevice
并移除了alpha通道,但结果仍然相同。
I suspect that the actual problem is the channel order, as if Win32 didn't use RGB but BGR or others.
我怀疑实际问题是通道顺序,好像Win32不是使用RGB而是BGR或其他方式。
英文:
Given an RGBA array (24 bpp) of an image that has the same width and height of a window's client area, how do I efficiently show that image on that client area, using the Win32 API?
Can I use the same function(s) to efficiently update part of the window's client area with a changed sub-image? If not, which other functions should I use?
I own the window of which I'm trying to modify the client area.
I tried by using these functions:
- Creating a compatible device context (with
CreateCompatibleDC
) - Creating a compatible bitmap (with
CreateCompatibleBitmap
) - Selecting the bitmap (with
SelectObject
) - Getting the bitmap object info (with
GetObject
) - Setting the bitmap bits (with
SetDIBits
) because CreateCompatibleBitmap does not allow to specify bits as a function argument - Transferring the color data to the device context (with
BitBlt
)
But the result I got does not match my expectations at all.
This is what I got:
What I expected was the client area divided in 4 equal parts, each one with a different shade of gray (white, light gray, dark gray, black).
I also tried using SetDIBitsToDevice
and removing the alpha channel, but the result is the same.
I suspect that the actual problem is the channel order, as if Win32 didn't use RGB but BGR or others.
答案1
得分: 1
我可能会使用 CreateDIBSection
。这会创建一个 DIB Section 对象,允许直接访问其内存以及用作设备无关位图,因此您可以创建它,将数据复制到其内存中,然后像任何其他设备无关位图一样使用它,例如使用 BitBlt
(以及类似的功能,如 StretchBlt
、PlgBlt
等)。
调用 CreateDIBSection
的典型示例如下:
BITMAPINFO info {};
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biWidth = width;
info.bmiHeader.biHeight = height;
DWORD *pixels;
HBITMAP section = CreateDIBSection(mem, &info, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
此时,您有一个 HBITMAP,您可以使用它执行所有正常的位图操作(例如,将它选择到 DC
中,然后进行 BitBlit
操作)。
但是,您还有一个名为 pixels
的指针,该指针直接指向包含该位图数据的内存。要注意的一点是,在尝试直接访问该内存之前,您需要调用 GdiFlush()
(以便在尝试访问之前给 GDI 完成的机会,如果它已经在使用它)。
现在不要误会我的意思:如果您正确设置格式,当然也完全可以使 SetDIBIts
也起作用。但至少就我个人而言,我发现 DIB Sections 更不烦人。
哦,还有一个小细节:我建议始终使用每像素 32 位而不是 24 位。这可以消除任何需要填充数据的需要(这可能有点烦人),通常也会更快(每像素一个 dword 容易操作、显示等)。
英文:
Personally, I'd probably use CreateDIBSection
.
This creates a DIB Section object, which allows both direct access to its memory and use as a device independent bitmap, so you can create it, copy your data into its memory, then use it with BitBlt
(and similar such as StretchBlt
, PlgBlt
, etc.) just like any other device independent bitmap supports.
A typical call to CreateDIBSection will look something like this:
BITMAPINFO info {};
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biWidth = width;
info.bmiHeader.biHeight = height;
DWORD *pixels;
HBITMAP section = CreateDIBSection(mem, &info, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
At this point you have an HBITMAP, which you can use to do all the normal bitmap stuff (e.g., select it into a DC
,then BitBlit
to/from it).
But you also have pixels
, which is a pointer directly to the memory that contains the data for that bitmap. The one thing to look out for here is that you need to call GdiFlush()
before trying to access that memory directly (to give GDI a chance to finish if it's already using it).
Now don't get me wrong: if you get the format correct, it's certainly entirely possible to make SetDIBIts
work as well. But at least personally, I find DIB Sections less annoying to deal with.
Oh, one other minor detail: I'd advise always using 32 bits per pixel instead of 24. This eliminates any need to pad the data (which can be mildly annoying), and usually blits faster as well (one dword per pixel is easy to manipulate, display, etc.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论