Click here to Skip to main content
15,867,765 members
Articles / Desktop Programming / MFC

Drawing Transparent Bitmap with ease with on the fly masks in MFC

Rate me:
Please Sign up or sign in to vote.
3.82/5 (31 votes)
24 Aug 2000CPOL 404.7K   81   67
A few routines that makes implementing the ideas in Chris Becke's GDI tutorial a snap

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 unknown
                          int iTransPixelX,      // = 0
                          int 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Malaysia Malaysia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalximaico.cpp bug.. Pin
yuandi7412-Aug-03 15:04
yuandi7412-Aug-03 15:04 
GeneralRe: ximaico.cpp bug.. Pin
Anonymous12-Aug-03 15:16
Anonymous12-Aug-03 15:16 
GeneralDefault clrpTransColor value must not be NULL Pin
Junho Ryu11-Aug-03 14:16
Junho Ryu11-Aug-03 14:16 
Generalrandom picture :-( Pin
didine9-May-03 15:52
didine9-May-03 15:52 
Generalrandom picture :-( Pin
didine9-May-03 15:51
didine9-May-03 15:51 
Generalrandom picture :-( Pin
didine9-May-03 15:50
didine9-May-03 15:50 
GeneralAny one know where to Download the utility which converty vc++ 7.0 project to vc++ 6.0 project Pin
Anthony Dass27-Apr-03 19:36
Anthony Dass27-Apr-03 19:36 
QuestionAny advice on adding this to a Control? Pin
IbanTheGreat13-Apr-03 14:54
IbanTheGreat13-Apr-03 14:54 
GeneralWorks fine Pin
garylyb18-Feb-03 17:15
garylyb18-Feb-03 17:15 
GeneralStretchBlt Pin
Kyudos18-Nov-02 23:54
Kyudos18-Nov-02 23:54 
GeneralRe: StretchBlt Pin
Kyudos19-Nov-02 1:01
Kyudos19-Nov-02 1:01 
GeneralRe: StretchBlt Pin
Kyudos19-Nov-02 1:32
Kyudos19-Nov-02 1:32 
GeneralDisplaying pixels on the screen Pin
mbandi30-Oct-02 1:19
mbandi30-Oct-02 1:19 
GeneralRe: Displaying pixels on the screen Pin
Christian Graus30-Oct-02 1:30
protectorChristian Graus30-Oct-02 1:30 
GeneralAvoid Flicker Pin
zahc21-Oct-02 17:35
zahc21-Oct-02 17:35 
GeneralRe: Avoid Flicker Pin
Christian Graus30-Oct-02 1:31
protectorChristian Graus30-Oct-02 1:31 
QuestionTransparent bitmaps on CStatics? Pin
Anonymous10-Oct-02 12:28
Anonymous10-Oct-02 12:28 
GeneralNeed ur Help in Wiz97 Pin
Anonymous11-Aug-02 20:15
Anonymous11-Aug-02 20:15 
GeneralSimple Animation of a bit map (Urgent) Pin
HBK25-Jul-02 21:27
HBK25-Jul-02 21:27 
GeneralRe: Simple Animation of a bit map (Urgent) Pin
Matthew R. Miller2-Sep-02 14:17
Matthew R. Miller2-Sep-02 14:17 
QuestionIs it possible to test your code? Pin
Anonymous18-Jul-02 12:39
Anonymous18-Jul-02 12:39 
QuestionAnyone knows where to download the mfc7.0 library and source code? Pin
Edd1-Jun-02 15:07
Edd1-Jun-02 15:07 
AnswerRe: Anyone knows where to download the mfc7.0 library and source code? Pin
9-Jun-02 20:50
suss9-Jun-02 20:50 
Generalhow... when maping mode is MM_LOENGLISH Pin
7-Feb-02 2:31
suss7-Feb-02 2:31 
GeneralWin32 API TransparentBlt() can do... Pin
13-Dec-01 23:04
suss13-Dec-01 23:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.