Drawing a bitmap transparently


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

Drawing a bitmap transparently means that only those pixels that are not the designated transparent color are drawn onto the target device context. The pixels on the target device context that correspond to a transparent pixel in the source is left unchanged. Any color may be designated as being transparent. If you are drawing the bitmap from scratch you want to choose a background color that will not be used in the foreground. This background color can then be treated as the transparent color.

Here's what happens in the function. Besides getting the handle to the destination device context, the function creates three more device context. The tempDC is used to select the source bitmap into. This is used to copy the image into the second device context - the memDC. The third device context is the maskDC. The maskDC contains a monochrome bitmap. The maskDC is instrumental in allowing us to copy the foreground pixels only.

If the palette handle passed into the function is not null and if the destination device context supports palettes, we select the palette into the destination DC. Note that the last argument to the SelectPalette() function is FALSE. This indicates that the palette should be a foreground palette. That is, the exact colors in the palette should be displayed. If this argument were TRUE, then the colors in the logical palette would be mapped to the closest colors already in the physical palette. The call to RealizePalette() maps the palette entries to the system palette. We also select the palette into the memDC so that when the bitmap is copied into it, the colors are mapped properly.

We next create the mask bitmap from the source bitmap image. When we use BitBlt() to copy a color bitmap to a monochrome bitmap then all the pixels that are of the background color are copied as white pixels. All the remaining pixels (that is pixels that are not of the background color) are copied as black pixels. You will note that we call the SetBkColor() for the memDC with the transparent color.

Once we have the mask bitmap, we modify both the source image and the destination image so that we can then combine them to get the final image. Imagine that we have two sheets of paper, one with the image that is to be drawn over and the other with the bitmap image that is to be drawn transparently over the first image. What we do is take the second sheet with the bitmap image and cut out all the parts that contain the background color. We then take the first sheet and cut out all parts of it that correspond to the foreground of the bitmap image. We can now combine the two sheets to get a complete sheet without any overlap and get the final image.

This is what we do with the images in the device contexts. We take the memDC and copy the image in maskDC in such a way that all the background pixels are turned into black pixels - the equivalent of cutting these pixels away. Let's analyze how we do this. We first set the background color in memDC to black and we set the foreground (text color) to white. We then use the BitBlt() function to combine each pixel in the mask to the corresponding pixel in the image in memDC using the raster AND operation. Whenever the BitBlt() function encounters a background pixel (white) in maskDC, it uses the background color in memDC (black) and does a raster AND operation with the corresponding pixel in memDC. The result of a raster AND operation involving the black color is always black. Similarly, whenever the BitBlt() function encounters a foreground color (black) in the maskDC, is uses the text color in memDC (white) and combines it with the raster AND operation with the corresponding pixel in memDC. The result of a raster AND operation involving white and any other color is always the other color. That is, the destination pixel remains unchanged.

We execute a similar operation on the image in the destination device context. Only, this time we change all the pixels corresponding to the foreground color in the mask to white. We can now combine the two images using the raster operation SRCPAINT. The result of the SRCPAINT operation is such that any colored pixel combined with a black pixel results in the same colored pixel.

// TransparentBlt	- Copies a bitmap transparently onto the destination DC
// hdcDest		- Handle to destination device context 
// nXDest		- x-coordinate of destination rectangle's upper-left corner 
// nYDest		- y-coordinate of destination rectangle's upper-left corner 
// nWidth		- Width of destination rectangle 
// nHeight		- height of destination rectangle 
// hBitmap		- Handle of the source bitmap
// nXSrc		- x-coordinate of source rectangle's upper-left corner 
// nYSrc		- y-coordinate of source rectangle's upper-left corner 
// colorTransparent	- The transparent color
// hPal			- Logical palette to be used with bitmap. Can be NULL

void TransparentBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth, 
			int nHeight, HBITMAP hBitmap, int nXSrc, int nYSrc,
			COLORREF colorTransparent, HPALETTE hPal )
	CDC dc, memDC, maskDC, tempDC;
	dc.Attach( hdcDest );
	CBitmap maskBitmap;
	//add these to store return of SelectObject() calls
	CBitmap* pOldMemBmp = NULL;
	CBitmap* pOldMaskBmp = NULL;
	HBITMAP hOldTempBmp = NULL;
	CBitmap bmpImage;
	bmpImage.CreateCompatibleBitmap( &dc, nWidth, nHeight );
	pOldMemBmp = memDC.SelectObject( &bmpImage );
	// Select and realize the palette
	if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && hPal )
		::SelectPalette( dc, hPal, FALSE );
		::SelectPalette( memDC, hPal, FALSE );
	hOldTempBmp = (HBITMAP) ::SelectObject( tempDC.m_hDC, hBitmap );
	memDC.BitBlt( 0,0,nWidth, nHeight, &tempDC, nXSrc, nYSrc, SRCCOPY );
	// Create monochrome bitmap for the mask
	maskBitmap.CreateBitmap( nWidth, nHeight, 1, 1, NULL );
	pOldMaskBmp = maskDC.SelectObject( &maskBitmap );
	memDC.SetBkColor( colorTransparent );
	// Create the mask from the memory DC
	maskDC.BitBlt( 0, 0, nWidth, nHeight, &memDC, 
		0, 0, SRCCOPY );
	// Set the background in memDC to black. Using SRCPAINT with black 
	// and any other color results in the other color, thus making 
	// black the transparent color
	memDC.BitBlt(0, 0, nWidth, nHeight, &maskDC, 0, 0, SRCAND);
	// Set the foreground to black. See comment above.
	dc.BitBlt(nXDest, nYDest, nWidth, nHeight, &maskDC, 0, 0, SRCAND);
	// Combine the foreground with the background
	dc.BitBlt(nXDest, nYDest, nWidth, nHeight, &memDC, 
		0, 0, SRCPAINT);
	if (hOldTempBmp)
		::SelectObject( tempDC.m_hDC, hOldTempBmp);
	if (pOldMaskBmp)
		maskDC.SelectObject( pOldMaskBmp );
	if (pOldMemBmp)
		memDC.SelectObject( pOldMemBmp );


  • How do I set background colund white where foreground has a line of definite width and length

    Posted by Legacy on 07/16/2003 07:00am

    Originally posted by: deepthi

    How do I set background colour black and foreground colour towhite where foreground has a line of definite width and length

  • Serializing the bitmap

    Posted by Legacy on 11/21/2002 08:00am

    Originally posted by: srinivasan

    How to reload the bitmap using serialization.

  • Where is the article:TransparentBlt using only two BLT operations - m.chung (1998/12/18)?

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

    Originally posted by: Hector

    Where is the article: TransparentBlt using only two BLT operations - m.chung (1998/12/18)?

    I need it. Thanks

  • Excellent! Works great.

    Posted by Legacy on 06/14/2002 07:00am

    Originally posted by: J.Reichard

    Thanks a million!

  • How to add transparent bitmap into header control for list view

    Posted by Legacy on 04/18/2002 07:00am

    Originally posted by: Tao Zhou


  • Easier with image-list

    Posted by Legacy on 05/16/2001 07:00am

    Originally posted by: Stephan Brenner

    First I tried your function, but I had problems when printing. So I wrote my own short function using an image-list for drawing the bitmap transparently.

    void TransparentBlt(CDC* pDC, HBITMAP hBitmap, CPoint ptLocation)
    CBitmap* pBitmap = CBitmap::FromHandle(hBitmap);

    // Get size of bitmap
    BITMAP bmpInfo;
    CSize bitSize;
    bitSize = CSize(bmpInfo.bmWidth, bmpInfo.bmHeight);

    // Prepare ImageList
    CImageList imageList;
    imageList.Create(bitSize.cx, bitSize.cy, ILC_COLOR24|ILC_MASK, 1, 1);
    imageList.Add(pBitmap, 0xFFFFFF); // Transparent color: WHITE

    // Draw imagelist transparently
    imageList.DrawIndirect(pDC, 0, ptLocation, bitSize, CPoint(0, 0));

  • This function does no work with resource(system color) bitmaps.

    Posted by Legacy on 12/04/2000 08:00am

    Originally posted by: Andrey Zwyagilskii

    I spent many time trying to force this function work. But have no result. I use CImageList for this purpose. It is 2 lines of code need to draw system color bitmap transparently:
    m_ImgLst.Create( IDB_BITMAP, 16, 1, RGB(0,255,255) );

    This method works perfectly to all images.

  • All black output ?

    Posted by Legacy on 05/17/2000 07:00am

    Originally posted by: Morten Andersen

    I tried your routine, but instead of getting a transparent blit, I got an all black output. The bitmap I'm copying from is 256 colors, and the bitmap I'm blitting to is 16M colors. Can that have anything to do with it ?

    Please tell me what went wrong, and how I can fix it.

    - Morten Andersen

  • Help me in drawing a bitmap in Dialog based Projects.

    Posted by Legacy on 04/12/2000 07:00am

    Originally posted by: Ren


    I am trying to place a bitmap on my dialog based MFC project. I have used double buffering in OnInitDialog() and OnPaint(), but It didn't work to draw, bitmaps, even to SetBkColor(). Any help is appriciated.


  • Be careful...

    Posted by Legacy on 02/22/2000 08:00am

    Originally posted by: Greg Heck

    Be careful using this one in Windows 2000 and Windows 98. The Windows API has added the function TransparentBlt.

  • Loading, Please Wait ...

  • 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