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

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds