CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 36

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 03:27 AM.

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

    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 12:50 PM.
    "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,835

    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) ?

  7. #7
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: MFC : Make a bitmap with a transparant color

    sorry if you think my question is improper because I am new to mfc.
    It's not that the question is improper - its that this thread is over 8 years old and it would have been more appropriate to start a new thread asking your specific question.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

Posting Permissions

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





Click Here to Expand Forum to Full Width

Featured