如何在Win32中将图像显示在窗口的客户区域?

huangapple go评论83阅读模式
英文:

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:

我尝试使用以下这些函数:

  1. Creating a compatible device context (with CreateCompatibleDC)
  2. Creating a compatible bitmap (with CreateCompatibleBitmap)
  3. Selecting the bitmap (with SelectObject)
  4. Getting the bitmap object info (with GetObject)
  5. Setting the bitmap bits (with SetDIBits) because CreateCompatibleBitmap does not allow to specify bits as a function argument
  6. Transferring the color data to the device context (with BitBlt)

我尝试使用以下这些函数:

  1. 创建兼容的设备上下文(使用CreateCompatibleDC
  2. 创建兼容的位图(使用CreateCompatibleBitmap
  3. 选择位图(使用SelectObject
  4. 获取位图对象信息(使用GetObject
  5. 设置位图位(使用SetDIBits)因为CreateCompatibleBitmap不允许将位指定为函数参数
  6. 将颜色数据传输到设备上下文(使用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:

  1. Creating a compatible device context (with CreateCompatibleDC)
  2. Creating a compatible bitmap (with CreateCompatibleBitmap)
  3. Selecting the bitmap (with SelectObject)
  4. Getting the bitmap object info (with GetObject)
  5. Setting the bitmap bits (with SetDIBits) because CreateCompatibleBitmap does not allow to specify bits as a function argument
  6. 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:

如何在Win32中将图像显示在窗口的客户区域?

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(以及类似的功能,如 StretchBltPlgBlt 等)。

调用 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.)

huangapple
  • 本文由 发表于 2023年6月8日 08:13:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427832.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定