Transparent Image Static Class

While writing an about box recently, I added a image using a static.  I used the standard gray for the background in the image.  Looked great!  Alright, run over to the client and install the application on his system.  Run the program and while testing the menus, open the about box - puke.  Why?  The background was the standard gray but the computer in question had a darker, redder gray.

Back to the drawing board.  Search through the documentation and find MaskBlt().  Great!  Implement it and test it on my machine (Windows NT - see where this is going?).  Looked great!  Alright run over to the client and try again - worse, no image at all.

Scratch head for a while then see on the bottom of the documentation.  MaskBlt() only works on Windows NT, not Windows 98 - duh Microsoft?  Alright, this sucks, what now?  Read more documentation and see that MaskBlt() is not done by the driver, but by GDI in NT...hmmm...can I do it for GDI if GDI can't?  Sure can.  Recode, test it on Windows 95, Windows 98, Windows NT and Windows 2000 - woohoo!

One note - DO NOT USE THIS FOR ANIMATION OR OTHER TIME-CRITICAL USES.  This code uses three Blt's under NT (and remember, MaskBlt() does some internal) and if the MaskBlt() fails (like under Windows98), this code uses 7 (!!!) Blt's.  One way to increase performance if needed is to cache the buffer and mask and use these cached bitmaps.

How to use it?

The control itself is just a derived class from CStatic with an OnPaint() handler.  So to use it in your code, just make the background (transparent area) of the picture to light magenta (0xFF00FF) and add a CStatic member to the dialog class.  Then change the definition from CStatic to CTransparentImage.  Done!

Now, how does it work?

To draw transparently with NT, take the bitmap, blt it to a off-screen DC.  Next create a mask using a monochrome DC with the background color set to the transparent color by blt'ing from the off-screen DC.  Lastly, use MaskBlt() to blt the off-screen to the paint DC using the mask bitmap using the ROP4 code 0xCCAA0020 (mask is white where image does NOT paint).  If MaskBlt() fails, then we need to do a bunch more work.  First, grab a copy of the screen into a second off-screen (copy) DC.  'And' the mask with this copy DC to create black where the image will go.  Next, use the special ROP3 code 0x00220326 to 'and' the inverse of the mask with the buffer DC to create black around the image.  Now 'or' the copy and the buffer together to make a complete picture.  Last, blt the whole mess to the screen.

To see the code for this, see the OnPaint() message handler in the TranparentImage.cpp file.

One other note - this code does not handle stretching.  If you need to stretch, create the buffer DC to the client size of the static, then the first blt in the function which copies the bitmap to the buffer should use StretchBlt instead.

Download demo project - 53.1KB