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

Thread: MFC : Make a bitmap with a transparant color

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

  7. #7
    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

    Quote Originally Posted by FireJocker
    Must I declare transparent color I want ?
    Yes....

    Quote Originally Posted by FireJocker
    Isn't it possible getting the transparent of a pixel given ? (by it's X, Y position) ?
    Not as far as I know - though someone might correct me about that.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

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

    Talking Re: MFC : Make a bitmap with a transparant color

    lol !

    I'm really bad ! I don't see how using your code

    Code:
    void CTransparentBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
    {
    	CBitmapButton::DrawItem(lpDIS);
    	DrawTransparentBitmap(
    
    }
    what are these parameters :
    HDC hdc, HBITMAP hBitmap, short xStart, short yStart, bool bAssume100Green ?

    Sorry being so bad !

  9. #9
    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

    Okay, sorry - here's how to call the function....

    Code:
    // From 'OnPaint()
    void CTransparentBitmapButton::OnPaint() 
    {
    	if ((GetParent()) && (GetParent()->IsIconic()))
    	{
    		CBitmapButton::OnPaint();
    	}
    	else
    	{
    		CPaintDC dc(this); // device context for painting
    		
    		// At least onw bitmap must be loaded before calling 'Paint()'
    		ASSERT(m_bitmap.m_hObject != NULL);
    
    		// and we'll assume until we find otherwise, that
    		// the button is being drawn in its normal state.
    		CBitmap* pBitmap = &m_bitmap;
    
    		if ((!(IsWindowEnabled())) && (NULL != m_bitmapDisabled.m_hObject))
    			pBitmap = &m_bitmapDisabled;
    
    		DrawTransparentBitmap(dc.m_hDC, *pBitmap, 0, 0, m_kTransparentColour, true);
    	}
    }
    
    
    // From 'DrawItem()'
    void CTransparentBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
    	ASSERT(lpDrawItemStruct != NULL);
    
    	// At least onw bitmap must be loaded before calling 'DrawItem()'
    	ASSERT(m_bitmap.m_hObject != NULL);
    
    	CBitmap* pBitmap = &m_bitmap;
    	UINT state = lpDrawItemStruct->itemState;
    
    	if ((state & ODS_SELECTED) && (NULL != m_bitmapSel.m_hObject))
    		pBitmap = &m_bitmapSel;
    	else if ((state & ODS_FOCUS) && (NULL != m_bitmapFocus.m_hObject))
    		pBitmap = &m_bitmapFocus;
    	else if ((state & ODS_DISABLED) && (NULL != m_bitmapDisabled.m_hObject))
    		pBitmap = &m_bitmapDisabled;
    
    	DrawTransparentBitmap(lpDrawItemStruct->hDC, *pBitmap, 0, 0, m_kTransparentColour, true);
    }
    I'll be out for the next couple of hours - but leave a message saying how you got on.
    "A problem well stated is a problem half solved.” - Charles F. Kettering

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

    Re: MFC : Make a bitmap with a transparant color

    ok, thanks

    I was near your code !

    Looking the code of CBitmapButton in afxext.h then in winbtn.cpp, my code was .....
    Code:
    void CTransparentBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
    {
    	CBitmapButton::DrawItem(lpDIS);
    	
    	HBITMAP pBitmap = m_bitmap;
    	UINT state = lpDIS->itemState;
    	if ((state & ODS_SELECTED) && m_bitmapSel.m_hObject != NULL)
    		pBitmap = &m_bitmapSel;
    	else if ((state & ODS_FOCUS) && m_bitmapFocus.m_hObject != NULL)
    		pBitmap = &m_bitmapFocus;   // third image for focused
    	else if ((state & ODS_DISABLED) && m_bitmapDisabled.m_hObject != NULL)
    		pBitmap = &m_bitmapDisabled;   // last image for disabled
    
    	DrawTransparentBitmap(lpDIS->hDC, pBitmap, 
    
    }
    I'll use yours then I'll answers you.

    thanks a lot for your help !

  11. #11
    Join Date
    May 2005
    Location
    Oregon
    Posts
    3,716

    Re: MFC : Make a bitmap with a transparant color

    First Set your Button Style OwnerDraw.Then use CBitMapButton Class and Create Object of your CBitmap Class Associate them with your Dialog Control and now do what ever u want
    some few lines will helps you
    Code:
    CBitmapButton m_btnAdd;
    DDX_Control(pDX, IDC_BUTTON_UPDATE, m_btnAdd);
    //now load the state of your button 
    m_btnAdd.LoadBitmaps(IDB_ADD_NORMAL, IDB_ADD_PRESSED, IDB_ADD_FOCUSED, IDB_ADD_DISABLED);
     m_btnAdd.SizeToContent();
    that is enough for your code.
    Thanx.
    Last edited by humptydumpty; February 7th, 2006 at 03:41 AM.

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

    Re: MFC : Make a bitmap with a transparant color

    Quote Originally Posted by humptydumpty
    First Set your Button Style OwnerDraw.Then use CBitMapButton Class and Create Object of your CBitmap Class Associate them with your Dialog Control and now do what ever u want
    some few lines will helps you
    Code:
    CBitmapButton m_btnAdd;
    DDX_Control(pDX, IDC_BUTTON_UPDATE, m_btnAdd);
    //now load the state of your button 
    m_btnAdd.LoadBitmaps(IDB_ADD_NORMAL, IDB_ADD_PRESSED, IDB_ADD_FOCUSED, IDB_ADD_DISABLED);
     m_btnAdd.SizeToContent();
    that is enough for your code.
    Thanx.
    I don't see how your code help me making a CBitmapButton transparent
    Could you explain ... ?

    thx

  13. #13
    Join Date
    May 2005
    Location
    Oregon
    Posts
    3,716

    Re: MFC : Make a bitmap with a transparant color

    Just Tryied That Once and let me know.Don't Forget to use CBitmapClass

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

    Re: MFC : Make a bitmap with a transparant color

    @ John E
    ------------


    Ok, If I understand a little, your code allow some threshold to make the transparency, I'm simply using one colour to make transparency, I think I'll remove this possibility,

    but, when I modify by calling your function with the parameter bAssume100Green to "false" transparency seems working

    I successfully get the Dialog Background, the originally but not the one I put with this code :
    Code:
    BOOL CMyDialog::OnEraseBkgnd(CDC* pDC)
    {	
    
    	CBitmap Bitmap;
        CDC MemDC;
      
    	Bitmap.LoadBitmap(p_iIDD_Background); // lecture bitmap dans les ressources
        BITMAP InfosBmp;				// structure d'informations.
        Bitmap.GetBitmap(&InfosBmp);
        MemDC.CreateCompatibleDC(pDC);	// creation d'un DC en memoire
        MemDC.SelectObject(&Bitmap);	// selection du bitmap dans le DC en memoire
        // transfert final du bitmap dans le dc de la view.
        pDC->BitBlt( 0,0,InfosBmp.bmWidth, InfosBmp.bmHeight,
                         &MemDC,
                         0,0,
                         SRCCOPY); 
    
    	return TRUE;
    }
    How merge the tranparency with this background ?

  15. #15
    Join Date
    Nov 2005
    Location
    India, Kerala, Trivandrum
    Posts
    37

    Re: MFC : Make a bitmap with a transparant color

    There is already a TransparentBlt function.

Page 1 of 3 123 LastLast

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