Drawing Transparent Bitmap with ease with on the fly masks in MFC
Introduction
I finally managed to get transparent drawing working and made a few routines that makes it a snap. I adapted this code from an example Chris Becke's Bitmap Basics - A GDI tutorial.
The situation
I have a master picture with lots of images in it, the transparent areas are all in purple. At runtime I pick parts of this picture and BitBlt
it on the screen while preserving the transparency.
Or maybe you have a bitmap that you wish to show transparently, just set the transparent areas to a unique color and use the routines below.
First the routines, at the end an example that puts it all together.
//**----------------------------------------------------------
//** STEP 1: Load the bitmap into a CBitmap Object
//**----------------------------------------------------------
BOOL CMyDlg::LoadFileBitmap(CBitmap* pBmp, LPCTSTR szFilename)
{
?? pBmp->DeleteObject();
?? return pBmp->Attach(LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0,
????????????????????? LR_LOADFROMFILE | LR_DEFAULTSIZE));
}
//**----------------------------------------------------------
//**STEP 2: Create the Mask and dump it into a CBitmap Object
//**----------------------------------------------------------
void CMyDlg::PrepareMask( CBitmap* pBmpSource,
????????????????????????? CBitmap* pBmpMask,
????????????????????????? COLORREF clrpTransColor, // Pass null if unknownint iTransPixelX,????? // = 0int iTransPixelY?????? // = 0
??????????????????????? )
{
?? BITMAP bm;
?? // Get the dimensions of the source bitmap
?? pBmpSource->GetObject(sizeof(BITMAP), &bm);
?? // Create the mask bitmap
?? pBmpMask->DeleteObject();
?? pBmpMask->CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL);
?? // We will need two DCs to work with. One to hold the Image
???// (the source), and one to hold the mask (destination).
???// When blitting onto a monochrome bitmap from a color, pixels
???// in the source color bitmap that are equal to the background
???// color are blitted as white. All the remaining pixels are
???// blitted as black.
?? CDC hdcSrc, hdcDst;
?? hdcSrc.CreateCompatibleDC(NULL);
?? hdcDst.CreateCompatibleDC(NULL);
?? // Load the bitmaps into memory DC
?? CBitmap* hbmSrcT = (CBitmap*) hdcSrc.SelectObject(pBmpSource);
?? CBitmap* hbmDstT = (CBitmap*) hdcDst.SelectObject(pBmpMask);
?? // Dynamically get the transparent color
?? COLORREF clrTrans;
?? if (clrpTransColor == NULL)
?? {
????? // User did not specify trans color so get it from bmp
????? clrTrans = hdcSrc.GetPixel(iTransPixelX, iTransPixelY);
?? }
?? else
?? {
????? clrTrans = clrpTransColor;
?? }
?? // Change the background to trans color
?? COLORREF clrSaveBk? = hdcSrc.SetBkColor(clrTrans);
?? // This call sets up the mask bitmap.
?? hdcDst.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &hdcSrc,0,0,SRCCOPY);
?? // Now, we need to paint onto the original image, making
???// sure that the "transparent" area is set to black. What
???// we do is AND the monochrome image onto the color Image
???// first. When blitting from mono to color, the monochrome
???// pixel is first transformed as follows:
???// if? 1 (black) it is mapped to the color set by SetTextColor().
???// if? 0 (white) is is mapped to the color set by SetBkColor().
???// Only then is the raster operation performed.
?? COLORREF clrSaveDstText = hdcSrc.SetTextColor(RGB(255,255,255));
?? hdcSrc.SetBkColor(RGB(0,0,0));
?? hdcSrc.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &hdcDst,0,0,SRCAND);
?? // Clean up by deselecting any objects, and delete the
???// DC's.
?? hdcDst.SetTextColor(clrSaveDstText);
?? hdcSrc.SetBkColor(clrSaveBk);
?? hdcSrc.SelectObject(hbmSrcT);
?? hdcDst.SelectObject(hbmDstT);
?? hdcSrc.DeleteDC();
?? hdcDst.DeleteDC();
}
//**----------------------------------------------------------
//** STEP 3: Drawing with Transparency. Call from OnPaint
//**----------------------------------------------------------
void CMyDlg::DrawTransparentBitmap(CMemDC* pDC,
?????????????????????????????????? int xStart,? int yStart,
?????????????????????????????????? int wWidth,? int wHeight,
?????????????????????????????????? CDC* pTmpDC,
?????????????????????????????????? int xSource, // = 0
????????????????????????????????????int ySource? // = 0)
{
?? // We are going to paint the two DDB's in sequence to the destination.
???// 1st the monochrome bitmap will be blitted using an AND operation to
???// cut a hole in the destination. The color image will then be ORed
???// with the destination, filling it into the hole, but leaving the
???// surrounding area untouched.
?? CDC hdcMem;
?? hdcMem.CreateCompatibleDC(NULL);
?? CBitmap* hbmT = hdcMem.SelectObject(&m_bmpMask);
?? pDC->BitBlt( xStart, yStart, wWidth, wHeight, &hdcMem,
??????????????? xSource, ySource, SRCAND);
?? // Also note the use of SRCPAINT rather than SRCCOPY.
?? pDC->BitBlt(xStart, yStart, wWidth, wHeight, pTmpDC,
?????????????? xSource, ySource,SRCPAINT);
?? // Now, clean up.
?? hdcMem.SelectObject(hbmT);
?? hdcMem.DeleteDC();
}
It is that simple. MSDN examples are very confusing. Chris Becke's examples are a lot better but in Win32. :)
So here is a example on how to put it together in a real life situation.
//**------------------------------------ //** EXAMPLE: Drawing with Transparency //**------------------------------------ //**------------------------------------------ //** EXP STEP 1: Declarations & variables //**------------------------------------------ In YourDlg.h, add the following CBitmap m_bmpPlmain; CBitmap m_bmpMask; BOOL LoadFileBitmap(CBitmap* pBmp, LPCTSTR szFilename); void PrepareMask( CBitmap* pBmpSource, CBitmap* pBmpMask, COLORREF clrpTransColor, int iTransPixelX = 0, int iTransPixelY = 0 ); void DrawTransparentBitmap (CMemDC* pDC, int xStart, int yStart, int wWidth, int wHeight, CDC* pTmpDC, int xSource = 0, int ySource = 0); //**------------------------------------------
//** EXP STEP 2: Load and Prepare the bitmaps
//**------------------------------------------ CYourDlg::OnInitDialog() { ... ... ... // I'm loading from a bitmap file but this can come from resource as well
??if (!LoadFileBitmap(&m_bmpPLMain, "BmpWithHoles.bmp")) { // Opps ... where did the picture go ?? } // Third param is NULL because I don't know the transparent color
??// but I know the trans color is at pixel 200, 50// or is you know the trans color(RED) then do the following// PrepareMask( &m_bmpPLMain, &m_bmpMask, RGB(255, 0, 0)); PrepareMask( &m_bmpPLMain, &m_bmpMask, NULL, 200, 50); } //**---------------------------------
//** EXP STEP 3: Drawing the bitmaps
//**--------------------------------- CYourDlg::OnPaint() { CPaintDC dc(this); // device context for painting CDC dcMem; // memory device context dcMem.CreateCompatibleDC(&dc); // Select the bmp into the tmp memory DC CBitmap* pOldBmp = (CBitmap*) dcMem.SelectObject(&m_bmpPLMain); DrawTransparentBitmap( &dc, // The destination DC. POP_X, // Where to draw POP_Y, POP_WIDTH, // Width & Height POP_HEIGHT, &dcMem, // the DC holding the bmp POP_BMP_X_OFF, // x & y pos in master bmp POP_BMP_Y_OFF); .... .... // Do whatever you want to do ... dcMem->SelectObject(pOldBmp); } //**-----------------------------
//** EXP STEP 4: Cleaning Up ..
//**----------------------------- CYourDlg::OnDestroy() { // Dont forget to delete the bmp's m_bmpPLMain.DeleteObject(); m_bmpMask.DeleteObject(); }
That's about it ...
Any mistakes, additions or optimizations, please feel free to point them out. Just send the comments to windev and/or raja@gelife.com.my
Raja Segar
|
Click here to view Raja Segar's online profile. |
Other popular articles:
|
posted on 2006-06-19 00:01 weidagang2046 閱讀(1984) 評論(0) 編輯 收藏 所屬分類: Windows