5,542,300 members and growing! (17,812 online)
Email Password   helpLost your password?
Multimedia » General Graphics » Bitmaps     Intermediate

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

By Raja Segar

A few routines that makes implementing the ideas in Chris Becke's GDI tutorial a snap
VC6, C++Windows, NT4, Win2K, Visual Studio, MFC, Dev

Posted: 24 Aug 2000
Updated: 24 Aug 2000
Views: 207,964
Bookmarked: 50 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
36 votes for this Article.
Popularity: 5.58 Rating: 3.58 out of 5
5 votes, 20.0%
1
0 votes, 0.0%
2
3 votes, 12.0%
3
0 votes, 0.0%
4
17 votes, 68.0%
5

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Raja Segar



Location: Malaysia Malaysia

Other popular General Graphics articles:

  • A flexible charting library for .NET
    Looking for a way to draw 2D line graphs with C#? Here's yet another charting class library with a high degree of configurability, that is also easy to use.
  • CxImage
    CxImage is a C++ class to load, save, display, transform BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, J2K images.
  • 3D Pie Chart
    A class library for drawing 3D pie charts.
  • Really cool visual FX
    A set of classes for doing stunning visual effects, including water, plasma and fire.
  • ImageStone
    An article on a library for image manipulation.
Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 63 (Total in Forum: 63) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralResizing+transprencymembercharfeddine_ahmed0:23 2 Oct '07  
GeneralRe: Resizing+transprencymembercharfeddine_ahmed0:28 2 Oct '07  
QuestionBitBlt() to CBitmap or HBITMAPmemberManni Singh22:34 7 Dec '06  
Answer[Message Removed]memberimmetoz10:40 1 Oct '08  
GeneralCheck your posted code.membershreejan16:30 19 Jan '06  
GeneralIs this possible ?sussAnonymous3:57 3 Oct '05  
GeneralHelp for eVC++ 4.0...memberjbdeuce229:14 15 Nov '04  
Generalthis is horrible complicated waymembernaristov18:20 1 Sep '04  
GeneralRe: this is horrible complicated waymembermvuong13:40 14 Sep '04  
GeneralRe: this is horrible complicated waymemberdinsh13:53 21 Jan '06  
GeneralRe: this is horrible complicated waymemberJason Tost12:41 17 Aug '06  
GeneralShould test code before releasememberLee Bamford5:34 5 May '04  
GeneralRe: Should test code before releasesussAnonymous10:35 20 May '04  
GeneralSolution to this problemsussSergio Del Valle8:19 2 Aug '04  
GeneralproblemmemberDavid St. Hilaire11:23 1 Mar '04  
GeneralRe: problemmemberSteve Wolf6:15 22 May '07  
GeneralSyntax error in VC++ 7membernamsaray12:16 10 Feb '04  
GeneralAnother Transparent Drawing Function using BitBltsussTim @ Fit18:04 26 Oct '03  
GeneralRe: Another Transparent Drawing Function using BitBltmembertjcufpc18:12 26 Oct '03  
GeneralRe: Another Transparent Drawing Function using BitBltmemberLate2:27 6 Feb '06  
GeneralRe: Another Transparent Drawing Function using BitBltmemberjbandi8015:37 22 Sep '08  
Generalximaico.cpp bug..sussjihun, cheong16:04 12 Aug '03  
GeneralRe: ximaico.cpp bug..sussAnonymous16:16 12 Aug '03  
GeneralDefault clrpTransColor value must not be NULLmemberJoon-ho Ryu15:16 11 Aug '03  
Generalrandom picture :-(memberdidine16:52 9 May '03  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 24 Aug 2000
Editor: Chris Maunder
Copyright 2000 by Raja Segar
Everything else Copyright © CodeProject, 1999-2008
Web16 | Advertise on the Code Project