weidagang2046的专栏

物格而后知致
随笔 - 8, 文章 - 409, 评论 - 101, 引用 - 0
数据加载中……

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:

  • DFB vs. DIB
    The difference between DFB and DIB.
  • Really cool visual FX
    A set of classes for doing stunning visual effects, including water, plasma and fire.
  • CPJAImage - Yet another image drawing class
    A class that draws an image with various options - transparently, disabled or grayscale, centered on or stretched to fit a given rectangle.
  • 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.
from: http://www.codeproject.com/bitmap/transbitmapmask.asp

posted on 2006-06-19 00:01 weidagang2046 阅读(1967) 评论(0)  编辑  收藏 所属分类: Windows


只有注册用户登录后才能发表评论。


网站导航: