Draw bitmap with grayed 3D effect

I have tried the DrawState function before writing one of my own. However, what I have got disappointed me because I found that often, some colors are badly converted from the original image and disapear into the result. I have attached to this message a sample bitmap which shows very well the difference between DrawState() and DitherBlt() when they are used on the same bitmap. It's true that the difference is not always so visible. In fact, it depends on the original bitmap. More it has pale colors or adjacent pixels with near color, more ugly the result is with DrawState(). DitherBlt() has not this problem and the result looks always perfect. In addition, it works under Win32s. I agree that in most cases, DrawState() is good enough. But if your application must run on Windows 3.1 and/or you have bitmaps with a lot of pale colors to draw, its better using DitherBlt(). I tested it under NT3.51, NT4.0 and Windows95.
//
//      DitherBlt :     Draw a bitmap dithered (3D grayed effect like disabled buttons in toolbars) into a destination DC
//      Author :        Jean-Edouard Lachand-Robert (iamwired@geocities.com), June 1997.
//
//      hdcDest :       destination DC
//      nXDest :        x coordinate of the upper left corner of the destination rectangle into the DC
//      nYDest :        y coordinate of the upper left corner of the destination rectangle into the DC
//      nWidth :        width of the destination rectangle into the DC
//      nHeight :       height of the destination rectangle into the DC
//      hbm :           the bitmap to draw (as a part or as a whole)
//      nXSrc :         x coordinates of the upper left corner of the source rectangle into the bitmap
//      nYSrc :         y coordinates of the upper left corner of the source rectangle into the bitmap
//
void DitherBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth, 
				int nHeight, HBITMAP hbm, int nXSrc, int nYSrc)
{
	ASSERT(hdcDest && hbm);
	ASSERT(nWidth > 0 && nHeight > 0);
	
	// Create a generic DC for all BitBlts
	HDC hDC = CreateCompatibleDC(hdcDest);
	ASSERT(hDC);
	
	if (hDC)
	{
		// Create a DC for the monochrome DIB section
		HDC bwDC = CreateCompatibleDC(hDC);
		ASSERT(bwDC);
		
		if (bwDC)
		{
			// Create the monochrome DIB section with a black and white palette
			struct {
				BITMAPINFOHEADER bmiHeader; 
				RGBQUAD 		 bmiColors[2]; 
			} RGBBWBITMAPINFO = {
				
				{		// a BITMAPINFOHEADER
					sizeof(BITMAPINFOHEADER),	// biSize 
						nWidth, 				// biWidth; 
						nHeight,				// biHeight; 
						1,						// biPlanes; 
						1,						// biBitCount 
						BI_RGB, 				// biCompression; 
						0,						// biSizeImage; 
						0,						// biXPelsPerMeter; 
						0,						// biYPelsPerMeter; 
						0,						// biClrUsed; 
						0						// biClrImportant; 
				},
				
				{
					{ 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
					} 
			};
			VOID *pbitsBW;
			HBITMAP hbmBW = CreateDIBSection(bwDC,
				(LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
			ASSERT(hbmBW);
			
			if (hbmBW)
			{
				// Attach the monochrome DIB section and the bitmap to the DCs
				SelectObject(bwDC, hbmBW);
				SelectObject(hDC, hbm);
				
				// BitBlt the bitmap into the monochrome DIB section
				BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);
				
				// Paint the destination rectangle in gray
				FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest +
					nHeight), GetSysColorBrush(COLOR_3DFACE));
				
				// BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT bits in the destination DC
				// The magic ROP comes from the Charles Petzold's book
				HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
				HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb);
				BitBlt(hdcDest, nXDest + 1, nYDest + 1, nWidth, nHeight, bwDC, 0, 0, 0xB8074A);
				
				// BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW bits in the destination DC
				hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
				DeleteObject(SelectObject(hdcDest, hb));
				BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, 0xB8074A);
				DeleteObject(SelectObject(hdcDest, oldBrush));
			}
			
			VERIFY(DeleteDC(bwDC));
		}
		
		VERIFY(DeleteDC(hDC));
	}
}



Comments

  • MFC code here - method taking CBitmap&

    Posted by inbugable on 01/04/2006 11:16pm

    void GTMainFrame::MakeDisabled(CBitmap &ioBM)
    {
    	// For MFC - Adapted by Koen Zagers from Zundert
    
    	CDC dc;
    	CDC dcBW;
    
    	// Create memory DCs
    	dc.CreateCompatibleDC(NULL);
    	dcBW.CreateCompatibleDC(NULL);
    
    	// Get bitmap dimensions
    	BITMAP bm;
    	ioBM.GetBitmap(&bm);
    	int nWidth = bm.bmWidth;
    	int nHeight = bm.bmHeight;
    
    	// Create a monochrome DIB section with a black and white palette
    	struct
    	{
    		BITMAPINFOHEADER	bmiHeader;
    		RGBQUAD				bmiColors[2];
    	} RGBBWBITMAPINFO =
    	{
    
    		{	// a BITMAPINFOHEADER
    			sizeof(BITMAPINFOHEADER),	// biSize 
    			nWidth, 					// biWidth; 
    			nHeight,					// biHeight; 
    			1,							// biPlanes; 
    			1,							// biBitCount 
    			BI_RGB, 					// biCompression; 
    			0,							// biSizeImage; 
    			0,							// biXPelsPerMeter; 
    			0,							// biYPelsPerMeter; 
    			0,							// biClrUsed; 
    			0							// biClrImportant; 
    		},
    
    		{
    			{ 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
    		}
    	};
    
    	VOID *pbitsBW;
    	HBITMAP hbmBW = CreateDIBSection(dcBW.m_hDC, (LPBITMAPINFO) &RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
    
    	ASSERT(hbmBW);
    
    	if (hbmBW)
    	{
    		// Attach the monochrome DIB section and the bitmap to the DCs
    		SelectObject(dcBW.m_hDC, hbmBW);
    		SelectObject(dc.m_hDC, ioBM.m_hObject);
    		CBrush brush;
    
    		// BitBlt the bitmap into the monochrome DIB section
    		dcBW.BitBlt(0, 0, nWidth, nHeight, &dc, 0, 0, SRCCOPY);
    
    		// Paint the destination bitmap in gray
    		brush.CreateSysColorBrush(COLOR_3DFACE);
    		dc.FillRect(CRect(0, 0, nWidth, nHeight), &brush);
    
    		// BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT bits in the destination DC
    		// The magic ROP comes from the Charles Petzold's book
    		brush.DeleteObject();
    		brush.CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
    		dc.SelectObject(&brush);
    		dc.BitBlt(1, 1, nWidth, nHeight, &dcBW, 0, 0, 0xB8074A);
    
    		// BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW bits in the destination DC
    		brush.DeleteObject();
    		brush.CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
    		dc.SelectObject(&brush);
    		dc.BitBlt(0, 0, nWidth, nHeight, &dcBW, 0, 0, 0xB8074A);
    
    		brush.DeleteObject();
    		DeleteObject(hbmBW);
    	}
    }

    Reply
  • Code stolen !

    Posted by Legacy on 11/25/2003 12:00am

    Originally posted by: Jeff

    Like many code samples from this site, the code has been copyed from elsewhere : in this case : WTL source code !
    Shame on the "author"...

    • Prove that it is a stollen code

      Posted by TheCric on 09/07/2005 04:13pm

      1st) Prove what you are saying . Why shouldn't the author be the original one! 2nd) This source doesn't use use the WTL anyway so it is useful like that!!

      Reply
    Reply
  • To correct the bug in C++

    Posted by Legacy on 01/29/2003 12:00am

    Originally posted by: Leandro Gustavo Biss Becker

    Hi

    To correct the bug, after the last delete object inside the if, put DeleteObject(hbmBW);

    Reply
  • Can you tell me how to draw it transparently?

    Posted by Legacy on 08/14/2001 12:00am

    Originally posted by: niry

    How to draw 3D-gray effect transparently?

    Reply
  • This code don't work properly. It 'eats' memory

    Posted by Legacy on 03/23/2000 12:00am

    Originally posted by: Javier Santisteban

    I don't speak english very well, so I'll speak spanish.
    
    He generado el siguiente c�digo en Visual Basic, y este soluciona el problema de memoria del original. La modificaci�n del c�digo en C es bastante f�cil a partir de �ste.

    Public Sub DitherBlt(ByVal hdcDest As Long, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hbm As Long, ByVal nXSrc As Integer, ByVal nYSrc As Integer)
    Dim hdc As Long, bwDC As Long
    Dim hbmBW As Long, pbitsBW As Long
    Dim RGBBWBitmapInfo As BitmapInfo
    Dim rectangulo As RECT
    Dim hb As Long, oldBrush As Long
    Dim OldbwDC, OldHdc As Long

    hdc = CreateCompatibleDC(hdcDest)
    If hdc > 0 Then
    bwDC = CreateCompatibleDC(hdc)
    If bwDC > 0 Then
    With RGBBWBitmapInfo
    With .bmiHeader
    .biSize = Len(RGBBWBitmapInfo.bmiHeader)
    .biWidth = nWidth
    .biHeight = nHeight
    .biPlanes = 1
    .biBitCount = 1
    .biCompression = BI_RGB
    .biSizeImage = 0
    .biXPelsPerMeter = 0
    .biYPelsPerMeter = 0
    .biClrUsed = 0
    .biClrImportant = 0
    End With
    With .bmiColors(0)
    .rgbBlue = 0
    .rgbGreen = 0
    .rgbRed = 0
    .rgbReserved = 0
    End With
    With .bmiColors(1)
    .rgbBlue = 255
    .rgbGreen = 255
    .rgbRed = 255
    .rgbReserved = 0
    End With
    End With
    hbmBW = CreateDIBSection(bwDC, RGBBWBitmapInfo, DIB_RGB_COLORS, pbitsBW, 0, 0)
    If hbmBW > 0 Then
    ' Esta es la 1� modificaci�n ***********
    OldbwDC = SelectObject(bwDC, hbmBW)
    OldHdc = SelectObject(hdc, hbm)
    ' **************************************
    BitBlt bwDC, 0, 0, nWidth, nHeight, hdc, nXSrc, nYSrc, SRCCOPY
    With rectangulo
    .Left = nXDest
    .Top = nYDest
    .Right = nXDest + nWidth
    .Bottom = nYDest + nHeight
    End With
    hb = CreateSolidBrush(QBColor(15))
    oldBrush = SelectObject(hdcDest, hb)
    BitBlt hdcDest, nXDest + 1, nYDest + 1, nWidth, nHeight, bwDC, 0, 0, &HB8074A
    hb = CreateSolidBrush(QBColor(8))
    SelectObject hdcDest, hb
    BitBlt hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, &HB8074A
    DeleteObject SelectObject(hdcDest, oldBrush)
    ' Esta es la 2� modificaci�n ***********
    SelectObject hdc, OldHdc
    SelectObject bwDC, OldbwDC
    ' **************************************
    End If
    DeleteObject hbmBW
    DeleteObject bwDC
    End If
    DeleteObject hdc
    End If
    End Sub

    Reply
  • This code don't work properly. It 'eats' memory

    Posted by Legacy on 03/23/2000 12:00am

    Originally posted by: Javier Santisteban

    I don't speak english very well, so I'll speak spanish.
    
    He generado el siguiente c�digo en Visual Basic, y este soluciona el problema de memoria del original. La modificaci�n del c�digo en C es bastante f�cil a partir de �ste.
    Public Sub DitherBlt(ByVal hdcDest As Long, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hbm As Long, ByVal nXSrc As Integer, ByVal nYSrc As Integer)
    Dim hdc As Long, bwDC As Long
    Dim hbmBW As Long, pbitsBW As Long
    Dim RGBBWBitmapInfo As BitmapInfo
    Dim rectangulo As RECT
    Dim hb As Long, oldBrush As Long
    Dim OldbwDC, OldHdc As Long

    hdc = CreateCompatibleDC(hdcDest)
    If hdc > 0 Then
    bwDC = CreateCompatibleDC(hdc)
    If bwDC > 0 Then
    With RGBBWBitmapInfo
    With .bmiHeader
    .biSize = Len(RGBBWBitmapInfo.bmiHeader)
    .biWidth = nWidth
    .biHeight = nHeight
    .biPlanes = 1
    .biBitCount = 1
    .biCompression = BI_RGB
    .biSizeImage = 0
    .biXPelsPerMeter = 0
    .biYPelsPerMeter = 0
    .biClrUsed = 0
    .biClrImportant = 0
    End With
    With .bmiColors(0)
    .rgbBlue = 0
    .rgbGreen = 0
    .rgbRed = 0
    .rgbReserved = 0
    End With
    With .bmiColors(1)
    .rgbBlue = 255
    .rgbGreen = 255
    .rgbRed = 255
    .rgbReserved = 0
    End With
    End With
    hbmBW = CreateDIBSection(bwDC, RGBBWBitmapInfo, DIB_RGB_COLORS, pbitsBW, 0, 0)
    If hbmBW > 0 Then
    ' Esta es la 1� modificaci�n ***********
    OldbwDC = SelectObject(bwDC, hbmBW)
    OldHdc = SelectObject(hdc, hbm)
    ' **************************************
    BitBlt bwDC, 0, 0, nWidth, nHeight, hdc, nXSrc, nYSrc, SRCCOPY
    With rectangulo
    .Left = nXDest
    .Top = nYDest
    .Right = nXDest + nWidth
    .Bottom = nYDest + nHeight
    End With
    hb = CreateSolidBrush(QBColor(15))
    oldBrush = SelectObject(hdcDest, hb)
    BitBlt hdcDest, nXDest + 1, nYDest + 1, nWidth, nHeight, bwDC, 0, 0, &HB8074A
    hb = CreateSolidBrush(QBColor(8))
    SelectObject hdcDest, hb
    BitBlt hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, &HB8074A
    DeleteObject SelectObject(hdcDest, oldBrush)
    ' Esta es la 2� modificaci�n ***********
    SelectObject hdc, OldHdc
    SelectObject bwDC, OldbwDC
    ' **************************************
    End If
    DeleteObject hbmBW
    DeleteObject bwDC
    End If
    DeleteObject hdc
    End If
    End Sub

    Reply
  • Not working

    Posted by Legacy on 10/29/1999 12:00am

    Originally posted by: satish ks

    It is not working in 24 bit bitmap.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • With 81% of employees using their phones at work, companies have stopped asking: "Is corporate data leaking from personal devices?" and started asking: "How do we effectively prevent corporate data from leaking from personal devices?" The answer has not been simple. ZixOne raises the bar on BYOD security by not allowing email data to reside on the device. In addition, Zix allows employees to maintain complete control of their personal device, therefore satisfying privacy demands of valued employees and the …

  • Managing your company's financials is the backbone of your business and is vital to the long-term health and viability of your company. To continue applying the necessary financial rigor to support rapid growth, the accounting department needs the right tools to most efficiently do their job. Read this white paper to understand the 10 essentials of a complete financial management system and how the right solution can help you keep up with the rapidly changing business world.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds