Drawing a bitmap transparently
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 );
maskDC.CreateCompatibleDC(&dc);
CBitmap maskBitmap;
//add these to store return of SelectObject() calls
CBitmap* pOldMemBmp = NULL;
CBitmap* pOldMaskBmp = NULL;
HBITMAP hOldTempBmp = NULL;
memDC.CreateCompatibleDC(&dc);
tempDC.CreateCompatibleDC(&dc);
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 );
dc.RealizePalette();
::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.SetBkColor(RGB(0,0,0));
memDC.SetTextColor(RGB(255,255,255));
memDC.BitBlt(0, 0, nWidth, nHeight, &maskDC, 0, 0, SRCAND);
// Set the foreground to black. See comment above.
dc.SetBkColor(RGB(255,255,255));
dc.SetTextColor(RGB(0,0,0));
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 );
dc.Detach();
}

Comments
How do I set background colund white where foreground has a line of definite width and length
Posted by Legacy on 07/16/2003 12:00amOriginally posted by: deepthi
How do I set background colour black and foreground colour towhite where foreground has a line of definite width and length
ReplySerializing the bitmap
Posted by Legacy on 11/21/2002 12:00amOriginally posted by: srinivasan
ReplyWhere is the article:TransparentBlt using only two BLT operations - m.chung (1998/12/18)?
Posted by Legacy on 08/09/2002 12:00amOriginally posted by: Hector
Where is the article: TransparentBlt using only two BLT operations - m.chung (1998/12/18)?
I need it. Thanks
ReplyExcellent! Works great.
Posted by Legacy on 06/14/2002 12:00amOriginally posted by: J.Reichard
Thanks a million!
Reply
How to add transparent bitmap into header control for list view
Posted by Legacy on 04/18/2002 12:00amOriginally posted by: Tao Zhou
Thanks
ReplyEasier with image-list
Posted by Legacy on 05/16/2001 12:00amOriginally 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;
pBitmap->GetBitmap(&bmpInfo);
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));
}
Reply
This function does no work with resource(system color) bitmaps.
Posted by Legacy on 12/04/2000 12:00amOriginally 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) );
m_ImgLst.Draw(pDC,0,CPoint(x0,y0),ILD_TRANSPARENT);
This method works perfectly to all images.
ReplyAll black output ?
Posted by Legacy on 05/17/2000 12:00amOriginally 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
ReplyHelp me in drawing a bitmap in Dialog based Projects.
Posted by Legacy on 04/12/2000 12:00amOriginally posted by: Ren
ReplyBe careful...
Posted by Legacy on 02/22/2000 12:00amOriginally posted by: Greg Heck
Be careful using this one in Windows 2000 and Windows 98. The Windows API has added the function TransparentBlt.
Reply
Loading, Please Wait ...