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

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

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

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

但是,当源为32位颜色+ alpha时,这对我来说似乎失败了。 我得到的是一个全黑的面具,而不是在hdcMask中获得单色位图。 没有位设置为白色(1)。 而这适用于4位彩色光源。

我的搜索foo失败了,因为我似乎找不到任何对这个特定问题的引用。

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

在32位彩色图像的情况下,我应该使用另一种方法吗? alpha通道是否存在覆盖上述技术正常行为的问题?

感谢您提供的任何帮助!

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

我有点缓解了我的特殊问题,根本就是根本不生成单色位掩码,而是我正在使用TransparentBlt(),这似乎是正确的(但我不知道他们在内部做了什么,这是任何不同的允许他们正确掩盖图像)。

拥有一个非常好的,有效的function可能是有用的:

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

无论hSource的颜色深度如何,它始终会创建有效的透明蒙版。

想法?

如果存在Alpha通道,则无法执行此操作。 COLORREF使用前8位用于多种用途,包括指定是否较低3个字节是当前调色板的颜色表索引,或RGB三元组。 因此,您无法在clrTransparency的高位字节中指定除0x00之外的任何内容。

如果你有一个alpha位图然后,对于仍然“不知道”alpha通道的GDI,没有理智的方法来实际比较位图中的24位BkColor和32位像素。

我希望GDI将32bpp位图中的alpha通道视为“保留”,并且只能成功比较保留通道为零的像素。 即你的面具颜色必须完全透明,才有可能成功。 (并且,如果您制作了合法的预乘位图,则意味着RGV值也将为零,而是限制您选择的蒙版颜色:P)

可以做 :)
正如上面的“Chris Becke”所指出的,GDI只能在保留的Alpha通道为零时进行比较。
从BITMAP :: GetHBITMAP()获得的HBITMAP返回一个HBITMAP,Alpha Channel全部设置为0xFF。
对于SetBkColor(),必须为0x00才能进行比较。
因此,Soln:遍历每个像素并将Alpha Component设置为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

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

请注意,如果您正在使用GDI +,那么根据操作,像素可能已被抗锯齿,导致它们都不是“透明”颜色的精确匹配。

对我有用的方法是首先将位图从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的答案的双循环执行得更快。