views:

62

answers:

2

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.

Ideas?

+2  A: 

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)

Chris Becke
In this particular case, the issue is that I'm starting with a 4bit color bitmap. Then, in order to display it in a nice way when disabled, I'd like to make a gray scale rendering of it, and then use that as the button face (using the masked transparency technique as before). But the code that I'm using to produce the gray scale is GDI+ based, which I suspect creates a 32 bit color image rather than a 24 bit color image.
Mordachai
@Mordachai: Given what you just described, can you make the mask from the original 4-bit image and use it with the GDI-created one?
Adrian McCarthy
I like the idea for my purposes. But I'd still be interested in a generic "how to create a monochrome bit mask for *ANY* source HBITMAP".
Mordachai
I think the only way to do it for _any_ HBITMAP is to write your own. Many of these color-mapping techniques in plain GDI are specific to palette-based images and aren't applicable to non-palette images.
Adrian McCarthy
A: 

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.

Adrian McCarthy
I saved out the GDI+ generated gray scale image as a 32bit depth PNG, then sampled the pixels in Paint. They're okay. However, I did double check the resulting HBITMAP that GDI+ produces (via Bitmap::GetHBitmap()) and it is indeed always 32bit depth, despite the underlying Bitmap instance being PixelFormat24bppRGB).
Mordachai