Transparent Image Static Class


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

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


  • It works great!

    Posted by SeninAndrew on 10/13/2005 10:22am

    Thank you!

  • It works for screen DC, but fails while using printer DC

    Posted by gopuanil on 03/28/2005 04:24pm

    Your logic of MaskBlt resolve the problem of displaying transparent images but fails in the print, Is this a limitation or any way out to get it resolved?

  • Thanks!

    Posted by Legacy on 09/07/2002 07:00am

    Originally posted by: Daniel

    Thank you very much for this code - it helped me quite a bit in my application!

  • If CImageList is used...

    Posted by Legacy on 09/04/2001 07:00am

    Originally posted by: Mizan Rahman

    If CImageList is used, would it require the bulky MFC Libraies?

  • ROP4 & SRCMASK constants with different transparent color

    Posted by Legacy on 09/04/2001 07:00am

    Originally posted by: Krotow

    Thank you! You done a good job and save a big problem for me - you may guess, what it is :) Ok, this is done, but I have a question about transparent color. Now you use light magenta (0xFF00FF). This will be best in most situations, because this color is a very rarely used on GUI elements. But sometimes I need different color as transparent color, and I have some elements (about 3) in one application, where with light magenta I get an elements with some extra holes and without color, when it is needed :(

    So maybe you may tell me, what constants for ROP4 and SRCMASK will be needed in this case and in which way I may get those? I will appreciate it :)

  • Can be done using CBitmap and CImageList too

    Posted by Legacy on 11/18/1999 08:00am

    Originally posted by: Wim Wouters

    Why not using a CImageList objet? You can fill it using a LoadMappedBitmap:

    // Read the bitmap
    COLORMAP ColorMap[3] = {
    { RGB(128,128,128), ::GetSysColor(COLOR_BTNSHADOW) },
    { RGB(192,192,192), ::GetSysColor(COLOR_BTNFACE) },
    { RGB(255,255,255), ::GetSysColor(COLOR_BTNHILIGHT)}
    CImageList ImageList
    CBitmap Bitmap;
    Bitmap.LoadMappedBitmap(IDB_BITMAP, 0, ColorMap, 3);
    ImageList.Create(19, 19, ILC_COLOR16|ILC_MASK, 1, 0);
    ImageList.Add(&Bitmap, ::GetSysColor(COLOR_3DFACE));

    Then you just use the Draw member function of CImageList to blit.

  • Why so many BitBlts?

    Posted by Legacy on 11/17/1999 08:00am

    Originally posted by: Brad Wilson

    You can cut down from 5 BitBlts to 3, using SRCINVERT (source), SRCAND (mask), and then SRCINVERT (source) again.

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date