MFC : Make a bitmap with a transparant color
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 31

Thread: MFC : Make a bitmap with a transparant color

Hybrid View

  1. #1
    Join Date
    Jan 2006
    Location
    Marseille, France
    Posts
    94

    Question MFC : CBitmapButton with a transparant color

    Hi,

    I use pictures instead of CButton with this component : http://www.codeguru.com/Cpp/controls...cle.php/c5163/


    But I need to add a transparant color, I wanted to use this code : http://www.codeguru.com/forum/showthread.php?p=1025767

    But it's not to MFC,

    Does someone have a solution to modify the component I gave above ?

    Thanks all.
    Last edited by FireJocker; February 7th, 2006 at 02:27 AM.

  2. #2
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,242

    Re: MFC : Make a bitmap with a transparant color

    I've just been working on this myself. You need to nominate a particular colour in the bitmap to be the "transparency colour". In my case, I chose 100% green and I used this code which I modified from some code I found on MSDN....

    In your class - or header file...
    Code:
    const COLORREF RGB_BLACK	  = 0x00000000L;
    const COLORREF RGB_WHITE	  = 0x00FFFFFFL;
    const COLORREF RGB_RED		  = 0x000000FFL;
    const COLORREF RGB_GREEN	  = 0x0000FF00L;
    const COLORREF RGB_BLUE		  = 0x00FF0000L;
    const COLORREF RGB_LIGHTGRAY = 0x00C0C0C0L;
    // Define any others you need.
    
    // The colour inside this button's bitmap(s) that should be regarded as transparent
    COLORREF m_kTransparentColour;
    
    // The thresholds for red, green & blue 
    short		m_RedThreshold, m_GreenThreshold , m_BlueThreshold;

    In your CPP file...
    Code:
    // Initialise the transparency colour
    // and thresholds for this button.
    m_kTransparentColour = RGB_GREEN;
    m_RedThreshold			= 100; // Adjust to your own requirements
    m_GreenThreshold		= 132; // Adjust to your own requirements
    m_BlueThreshold		= 80; // Adjust to your own requirements
    The actual code....
    Code:
    void YourClass::DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart, short yStart, COLORREF kTransparentColour, bool bAssume100Green)
    {
    BITMAP	bm;
    COLORREF cColour;
    HBITMAP	bmAndBack, bmAndObject, bmAndMem, bmSave;
    HBITMAP	bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
    HDC		hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
    POINT		ptSize;
    int x, y;
    
    	hdcTemp = CreateCompatibleDC(hdc);
    	if (HGDIOBJ hOldObj = SelectObject(hdcTemp, hBitmap)) // Select the bitmap
    		DeleteObject(hOldObj);
    
    	GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
    	ptSize.x = bm.bmWidth;		  // Get width of bitmap
    	ptSize.y = bm.bmHeight;		  // Get height of bitmap
    	DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
    										  // to logical points
    
    	// Create some DCs to hold temporary data.
    	hdcBack	 = CreateCompatibleDC(hdc);
    	hdcObject = CreateCompatibleDC(hdc);
    	hdcMem	 = CreateCompatibleDC(hdc);
    	hdcSave	 = CreateCompatibleDC(hdc);
    
    	// Create a bitmap for each DC. DCs are required for a number of GDI functions.
    
    	// Monochrome DC
    	bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
    
    	// Monochrome DC
    	bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
    
    	bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
    	bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
    
    
    	// Each DC must select a bitmap object to store pixel data.
    	bmBackOld	= (HBITMAP)SelectObject(hdcBack, bmAndBack);
    	bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject);
    	bmMemOld		= (HBITMAP)SelectObject(hdcMem, bmAndMem);
    	bmSaveOld	= (HBITMAP)SelectObject(hdcSave, bmSave);
    
    	// Set proper mapping mode.
    	SetMapMode(hdcTemp, GetMapMode(hdc));
    
    	// Save the bitmap sent here, because it will be overwritten.
    	BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
    
    	// If we're assuming a 100% green background (the normal case) set all
    	// pixels that are green or "very nearly green" to be exactly 100% green.
    	if (bAssume100Green)
    	{
    		for (x = 0; x < ptSize.x; x++)
    			for (y = 0; y < ptSize.y; y++)
    			{
    				COLORREF pixel = GetPixel(hdcTemp, x, y);
    				if (pixel)
    				{
    					DWORD dwRedContent, dwGreenContent, dwBlueContent;
    
    					dwRedContent   = ((pixel & 0x000000FF) % 0xFFFFFF); 
    					dwGreenContent = (((pixel & 0x0000FF00) >>  8) % 0xFFFFFF); 
    					dwBlueContent  = (((pixel & 0x00FF0000) >> 16) % 0xFFFFFF);
    					
    					// Does the pixel have a high content of green?
    					if ((short)dwGreenContent > m_GreenThreshold)
    					{
    						// If so, and it has a low content of both
    						// red and blue, set it to be 100% green.
    						if (((short)dwRedContent < m_RedThreshold) &&
    							 ((short)dwBlueContent < m_BlueThreshold))
    							SetPixel(hdcTemp, x, y, RGB_GREEN);
    					}
    				}
    			}
    	}
    	else
    		cColour = SetBkColor(hdcTemp, kTransparentColour);
    
    	// Create the object mask for the bitmap by performing a BitBlt
    	// from the source bitmap to a monochrome bitmap.
    	BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
    
    	// Now, if we're assuming a 100% green background, make
    	// absolutely sure that any 100% green pixels are converted
    	// to white in the mask - and all other pixels are black.
    	if (bAssume100Green)
    	{
    		for (x = 0; x < ptSize.x; x++)
    			for (y = 0; y < ptSize.y; y++)
    			{
    				COLORREF pixel = GetPixel(hdcTemp, x, y);
    				if (pixel == RGB_GREEN)
    					SetPixel(hdcObject, x, y, RGB_WHITE);
    				else
    					SetPixel(hdcObject, x, y, RGB_BLACK);
    			}
    
    		// Now change the green background colour for the supplied
    		// bitmap to be the colour that we want for transparency.
    		for (x = 0; x < ptSize.x; x++)
    			for (y = 0; y < ptSize.y; y++)
    			{
    				COLORREF pixel = GetPixel(hdcTemp, x, y);
    				if (pixel)
    					if (pixel == RGB_GREEN)
    						SetPixel(hdcTemp, x, y, kTransparentColour);
    			}
    	}
    	else
    		SetBkColor(hdcTemp, cColour);
    
    	// Create the inverse of the object mask.
    	BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
    
    	// Copy the background of the main DC to the destination.
    	BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart, SRCCOPY);
    
    	// Mask out the places where the bitmap will be placed.
    	BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
    
    	// Mask out the transparent coloured pixels on the bitmap.
    	BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
    
    	// XOR the bitmap with the background on the destination DC.
    	BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
    
    	// Copy the destination to the screen.
    	BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
    
    	// Place the original bitmap back into the bitmap sent here.
    	BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
    
    	// Delete the memory bitmaps.
    	DeleteObject(SelectObject(hdcBack, bmBackOld));
    	DeleteObject(SelectObject(hdcObject, bmObjectOld));
    	DeleteObject(SelectObject(hdcMem, bmMemOld));
    	DeleteObject(SelectObject(hdcSave, bmSaveOld));
    
    	// Delete the memory DCs.
    	DeleteDC(hdcMem);
    	DeleteDC(hdcBack);
    	DeleteDC(hdcObject);
    	DeleteDC(hdcSave);
    	DeleteDC(hdcTemp);
    }
    The main bit I added was support for "assume 100% green". All this does is to look at colours that are "almost 100% green" and turn them into precisely 100% green. If you use a different colour, you'll need to adjust m_kTransparentColour (and the RGB thresholds) to suit your own requirements. It takes quite a long time to get this right BTW – so be prepared to experiment…!


    [Edit...] Incidentally, the parameters xStart and yStart will both be 0 in most cases.
    Last edited by John E; February 6th, 2006 at 11:50 AM.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  3. #3
    Join Date
    Apr 1999
    Posts
    3,585

    Re: MFC : Make a bitmap with a transparant color

    As an alternative, take a look at CDC::TransparentBlt().
    Gort...Klaatu, Barada Nikto!

  4. #4
    Join Date
    Jan 2006
    Location
    Marseille, France
    Posts
    94

    Re: MFC : Make a bitmap with a transparant color

    And what about CBitmapButton ?

    I finally choose using this component, it really easier to use !

    Is it possible making it transparent ?

  5. #5
    John E is offline Elite Member Power Poster
    Join Date
    Apr 2001
    Location
    Manchester, England
    Posts
    4,242

    Re: MFC : Make a bitmap with a transparant color

    Yes - use the code that I gave you above. That's exactly what I was doing... You need to call it in DrawItem() and OnPaint() - selecting the appropriate bitmap to pass to the DrawTransparentBitmap() function.

    The main problem is that you have to nominate a particular colour as the transparency colour. This sounds very easy in theory - but in practice, most graphics packages (DrawPlus / Paint / PhotoShop etc) don't export the exact colours that you define. In my case, 100% green would come out as "not quite" 100% green - so I needed to correct this in the source bitmap. However, it is possible. I managed to make it work extremely well.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

  6. #6
    Join Date
    Jan 2006
    Location
    Marseille, France
    Posts
    94

    Re: MFC : Make a bitmap with a transparant color

    Must I declare transparent color I want ?

    Isn't it possible getting the transparent of a pixel given ? (by it's X, Y position) ?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center