如何为 32 位位图生成单色位掩码

发布于 2024-09-27 18:55:11 字数 932 浏览 4 评论 0原文

在 Win32 下,通过执行以下操作从位图生成单色位掩码以供透明度使用是一种常见技术:

SetBkColor(hdcSource, clrTransparency);
VERIFY(BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcSource, 0, 0, SRCCOPY));

这假设 hdcSource 是保存源图像的内存 DC,而 hdcMask 是保存相同源图像的单色位图的内存 DC大小(因此两者都是 32x32,但源是 4 位彩色,而目标是 1 位单色)。

然而,当源是 32 位颜色 + alpha 时,这对我来说似乎失败了。我没有在 hdcMask 中获得单色位图,而是获得全黑的蒙版。没有位设置为白色 (1)。而这适用于 4 位颜色源。

我的 search-foo 失败了,因为我似乎找不到任何对此特定问题的引用。

我发现这确实是我的代码中的问题:即,如果我使用 16 色(4 位)的源位图,它就可以工作;如果我使用 32 位图像,它会生成全黑蒙版。

对于 32 位彩色图像,我应该使用其他方法吗? Alpha 通道是否存在覆盖上述技术正常行为的问题?

感谢您提供的任何帮助!

附录:我仍然无法找到一种技术来为我的 GDI+ 生成的源位图创建有效的单色位图。

我通过根本不生成单色位掩码在一定程度上缓解了我的特殊问题,而是使用TransparentBlt(),这似乎是正确的(但我不知道他们在内部做了什么,这与允许他们正确地掩盖图像)。

拥有一个非常好的、有效的函数可能会很有用:

HBITMAP CreateTransparencyMask(HDC hdc, HBITMAP hSource, COLORREF crTransparency);

无论 hSource 的颜色深度如何,它总是创建一个有效的透明蒙版。

Under Win32, it is a common technique to generate a monochrome bitmask from a bitmap for transparency use by doing the following:

SetBkColor(hdcSource, clrTransparency);
VERIFY(BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcSource, 0, 0, SRCCOPY));

This assumes that hdcSource is a memory DC holding the source image, and hdcMask is a memory DC holding a monochrome bitmap of the same size (so both are 32x32, but the source is 4 bit color, while the target is 1bit monochrome).

However, this seems to fail for me when the source is 32 bit color + alpha. Instead of getting a monochrome bitmap in hdcMask, I get a mask that is all black. No bits get set to white (1). Whereas this works for the 4bit color source.

My search-foo is failing, as I cannot seem to find any references to this particular problem.

I have isolated that this is indeed the issue in my code: i.e. if I use a source bitmap that is 16 color (4bit), it works; if I use a 32 bit image, it produces the all-black mask.

Is there an alternate method I should be using in the case of 32 bit color images? Is there an issue with the alpha channel that overrides the normal behavior of the above technique?

Thanks for any help you may have to offer!

ADDENDUM: I am still unable to find a technique that creates a valid monochrome bitmap for my GDI+ produced source bitmap.

I have somewhat alleviated my particular issue by simply not generating a monochrome bitmask at all, and instead I'm using TransparentBlt(), which seems to get it right (but I don't know what they're doing internally that's any different that allows them to correctly mask the image).

It might be useful to have a really good, working function:

HBITMAP CreateTransparencyMask(HDC hdc, HBITMAP hSource, COLORREF crTransparency);

Where it always creates a valid transparency mask, regardless of the color depth of hSource.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

橘亓 2024-10-04 18:55:11

如果有 Alpha 通道就无法做到这一点。
COLORREF 将前 8 位用于多种目的,包括指定较低的 3 个字节是否是当前调色板的颜色表索引或 RGB 三元组。因此,您不能在 clrTransparency 的高字节中指定除 0x00 之外的任何内容。

如果您有一个 Alpha 位图,那么对于仍然“不知道”Alpha 通道的 GDI,没有明智的方法来实际比较 24 位 BkColor 与位图中的 32 位像素。

我希望 GDI 将 32bpp 位图中的 Alpha 通道视为“保留”,并且仅成功比较保留通道为零的像素。也就是说,无论如何,你的蒙版颜色必须完全透明才有机会成功。
(并且,如果您制作了合法的预乘位图,则意味着 RGV 值也将为零,而不是限制您对遮罩颜色的选择:P)

You can't do it if there is an alpha channel.
COLORREF's use the top 8 bits for a number of purposes, including specifying wether or not the lower 3 bytes are a color table index into the current palette, or a RGB triplet. As such you can't specify anything except 0x00 in the upper byte of clrTransparency.

If you have an alpha bitmap then, to GDI that remains "unaware" of the alpha channel, theres no sane way to actually compare a 24bit BkColor with 32bit pixels in the bitmap.

I would expect GDI to treat the alpha channel in 32bpp bitmaps as "Reserved", and only successfully compare pixels where the reserved channel is zero. i.e. your mask color must be fully transparent anyway to have a chance of succeeding.
(and, if youve made a legitimate premultiplied bitmap, that implies the RGV values would be zero too, rather constraining your choice of mask colors :P)

不交电费瞎发啥光 2024-10-04 18:55:11

可以做:)
正如上面“Chris Becke”所指出的,只有当保留的 Alpha 通道为零时,GDI 才能进行比较。
从 BITMAP::GetHBITMAP() 获取的 HBITMAP 返回一个 HBITMAP,其中 Alpha 通道全部设置为 0xFF。
这必须为 0x00 SetBkColor() 比较才能工作。
因此,Soln:循环遍历每个像素并将 Alpha 分量设置为零。

Bitmap img(L"X.bmp");
HBITMAP hBM;
img.GetHBITMAP(Color::White, &hBM);
BITMAP bm;
GetObject(g_hbmBall, sizeof(BITMAP), &bm);
for(UINT i = 0, n = -1; i < bm.bmHeight; i++)
    for(UINT j = 0; j < bm.bmWidth; j++)
    {
        n += 4; // Once per Pixel of 4 Bytes
        ((LPBYTE)bm.bmBits)[n] = 0;
    }
// Now SetBkColor and BitBlt will work as expected

Can do :)
As pointed out by 'Chris Becke' above, GDI can compare only if the reserved Alpha channel is zero.
The HBITMAP got from BITMAP::GetHBITMAP() returns an HBITMAP with Alpha Channel all set to 0xFF.
This must be 0x00 for SetBkColor() Comparison to work.
Hence, the Soln: Loop through each pixel and set the Alpha Component to Zero.

Bitmap img(L"X.bmp");
HBITMAP hBM;
img.GetHBITMAP(Color::White, &hBM);
BITMAP bm;
GetObject(g_hbmBall, sizeof(BITMAP), &bm);
for(UINT i = 0, n = -1; i < bm.bmHeight; i++)
    for(UINT j = 0; j < bm.bmWidth; j++)
    {
        n += 4; // Once per Pixel of 4 Bytes
        ((LPBYTE)bm.bmBits)[n] = 0;
    }
// Now SetBkColor and BitBlt will work as expected
摇划花蜜的午后 2024-10-04 18:55:11

对我有用的方法是首先将位图从 32 位转换为 24 位。

1. CreateCompatibleDC
2. CreateDIBSection with 24 as the biBitCount.
3. SelectObject
4. BitBlt from 32bit DC to 24 bit. This removes alpha.
5. BitBlt from 24 bit DC to the monochrome DC works as expected.

在我的机器上,这比 Ujjwal 答案中的双循环执行得更快。

The method that worked for me was to convert the bitmap from 32 bit to 24 bit first.

1. CreateCompatibleDC
2. CreateDIBSection with 24 as the biBitCount.
3. SelectObject
4. BitBlt from 32bit DC to 24 bit. This removes alpha.
5. BitBlt from 24 bit DC to the monochrome DC works as expected.

On my machine this executes faster than the double loop from Ujjwal's answer.

美煞众生 2024-10-04 18:55:11

另一种方法是自己扫描像素并根据源颜色(或源 Alpha 与阈值)生成单色位图。

请注意,如果您使用的是 GDI+,则根据操作的不同,像素可能已被抗锯齿,导致它们都无法与您的“透明”颜色完全匹配。

An alternate method would be to scan the pixels yourself and generate and monochrome bitmap based on the source color (or source alpha versus a threshold).

Note that if you're using GDI+, then, depending on the operation, the pixels may have been antialiased, resulting in none of them being an exact match for your "transparent" color.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文