A DIBSection wrapper for Win32
CDIBSectionLite is a subset of CDIBSection which is used in Dundas Software's Ultimate Paint for MFC component. CDIBSection adds in functionality for transparancy, clipboard functions and image manipulation routines.
Environment: VC 6.0, NT4, Win9x
Introduction
Device Independant Bitmaps (DIBs) offer a means to manipulate and display bitmaps in a form that is independant of the current display setting of your computer. They are also the format of the standard windows .BMP file, and so having a means to load, display and modify DIBs is very handy. DIBs, are created by allocating memory for a bitmap header and for the actual bitmap bits, then calling functions such as SetDIBits to fill in those bits. To actually display the DIB you need to use SetDIBitsToDevice or the DrawDib functions. To modify the bits in a DIB you need to access the individual bits of the bitmap yourself. There are no shortcuts.
Device Dependant Bitmaps (DDBs), on the other hand, only allow the manipulation of bitmaps that are in the same format as your current display device. DIBs can be created in many ways, including via the CBitmap class, via the functions CreateDIBitmap and Createbitmap, or through the LoadImage function. The only option in displaying and manipulating bitmaps is to use the GDI functions BitBlt etc. While DDBs are not able to maintain device independance, they do allow bitmaps to be selected into Device Contexts and manipululated using the GDI functions such as Rectangle and TextOut.
DIBSections are a combination of these two approaches. A DIBSection is created using either the CreateDIBSection function, or by calling LoadImage with the flag LR_CREATEDIBSECTION. DIBSections are DIBs, and so they can be used to manipulate bitmaps that were created for a device other than the display device, yet they can also be manipulated using the usual GDI functions becuase of their associated HBITMAP. In effect you have the independance and power of a DIB, with the ease of use of a DDB. When displaying DIBSection you can use BitBlt, SetDIBitsToDevice or the DrawDib functions.
The only problem with DIBsections, from an MFC programmers point of view, is that there is no DIBSection wrapper. Jeff Prosise, in his book Programming Windows 95 with MFC discusses DIBSections and how great they are, but states that becuase the next version of MFC will have a DIBSection wrapper class, there is no point in him supplying one in his book. Oops! Many updates to MFC have come and gone since that boook was written and still there is no sign of a DIBSection wrapper class.
With the advent of CE, DIBSections have become even more important. Since CE is an abridged version of the Windows operating system, many of the usual APIs we know and love have been left out. If you wish to use DIBs in CE, then your only option is to use DIBSections. In a subsequent article I will extend the class presented here in order to show how to use DIBsections in CE.
Using DIBSections
To create a DIBSection you simply fill in a BITMAPINFOHEADER structure and call CreateDIBSection(). The main things you need to supply are a handle to a DC, a pointer to the BITMAPINFOHEADER structure and the address of a pointer that will point to the image bits. See Zafir's articles on creating DIBs for more information on the BITMAPINFOHEADER - the basic idea is exactly the same. CreateDIBSection will then return a HBITMAP. Hang on to this - it will be very useful.
To display DIBSections you can use
- SetDIBitsToDevice or SetDIBits. For this you will need the BITMAPINFOHEADER structure that created the image, plus the pointer to the image bits
- BitBlt. Use the HBITMAP returned by CreateDIBSection
- DrawDibDraw. Again using the BITMAPINFOHEADER struct and the bits pointer.
The first two options have been dealt with many times. To use the DrawDib functions you need to create a DrawDib DC and then call DrawDibDraw:
CPalette Palette; // palette to use
CDC* pDC; // Device context on which to draw image
CPoint ptSrc, ptDest; // Source and destination point of image
CSize sizeSrc, sizeDest; // Source and Dest. sizees of the image
BITMAPINFOHEADER* pBitmapInfoHeader; // bitmap info header info
LPVOID pBitmapBits; // Pointer to bitmap bits
HDRAWDIB hDrawDib = DrawDibOpen();
DrawDibSetPalette( hDrawDib, (HPALETTE) Palette);
DrawDibRealize( hDrawDib, pDC->GetSafeHdc(), FALSE);
DrawDibDraw(hDrawDib, pDC->GetSafeHdc(),
ptDest.x, ptDest.y, sizeDest.cx, sizeDest.cy,
pBitmapInfoHeader, pBitmapBits,
ptSrc.x, ptSrc.y, sizeSrc.cx, sizeSrc.cy,
0);
DrawDibClose(hDrawDib);
Usually you would create a HDRAWDIB at the start of your program (using DrawDibOpen),
and destroy it at the end (using DrawDibClose)
CDIBSectionLite
CDIBSectionLite is a stripped down version of the CDIBSection DIBSection wrapper class used in Ultimate Paint, an image editing library by Dundas Software that replicates the functionality of MS Paint. DIBSections were chosen for this application due to their DIB nature, and becuase of the ease in which they allowed the bitmap bits to be manipulated.This class provides a simple interface to DIBSections including loading, saving and displaying DIBsections. Full palette support is provided, as well as the options of using the DrawDib routines to provide lightning fast drawing and full dithering. Note that the DrawDib functions are only available for images with at least 8 bits per pixel.
Using CDIBSectionLite
This class is very simple to use. The bitmap can be set using either SetBitmap() (which accepts either a Device dependant or device independant bitmap, or a resource ID) or by using Load(), which allows an image to be loaded from disk. To display the bitmap simply use Draw or Stretch.
eg.
CDIBSectionLite dibsection;
dibsection.Load(_T("image.bmp"));
dibsection.Draw(pDC, CPoint(0,0)); // pDC is of type CDC*
or
CDIBSectionLite dibsection;
dibsection.SetBitmap(IDB_BITMAP);
dibsection.Draw(pDC, CPoint(0,0)); // pDC is of type CDC*
Note that CDIBsectionLite::Draw() takes an optional third parameter that allows you
to specify background drawing. This is useful in a palettized environment when
you application is not in the foreground, as it selects the current palette in
background, leaving the foreground app looking normal, and you app looking somewhat
more respectable than otherwise. See OnQueryNewPalette and OnPaletteChanged functions
for more info on foreground and background palette handling.
CDIBsectionLite API
The CDIBsectionLite API includes methods for loading and displaying images, methods to extract information about the image, as well as palette options for getting and setting the current palette. or later.
void DeleteObject() // Deletes the image and frees all memory
HBITMAP GetSafeHandle() const // Gets a HBITMAP handle to the image
CSize GetSize() const // Gets the size of the image in pixels
int GetHeight() const // Gets the height of the image in pixels
int GetWidth() const // Gets the width of the image in pixels
int GetPlanes() const // Gets the number of colour planes in the image
int GetBitCount() const // Gets the bits per pixel for the image
LPVOID GetDIBits() // Returns a pointer to the image bits
LPBITMAPINFO GetBitmapInfo() // Returns a pointer a BITMAPINFO structure for the image
DWORD GetImageSize() const // Returns the size of the image (in bytes)
LPBITMAPINFOHEADER GetBitmapInfoHeader() // Returns a pointer to a BITMAPINFOHEADER structure
BOOL SetBitmap(UINT nIDResource); // Loads an image into the object.
BOOL SetBitmap(LPCTSTR lpszResourceName); // nIDResource - Bitmap resource ID
BOOL SetBitmap(HBITMAP hBitmap, // lpszResourceName - Bitmap resource ID
CPalette* pPalette = NULL); // hBitmap - existing image handle
BOOL SetBitmap(LPBITMAPINFO lpBitmapInfo, // palette - palette to be used for image construction
LPVOID lpBits); // lpBitmapInfo - pointer to BITMAPINFO structure
// lpBits - pointer to image bits
CPalette *GetPalette() // Return current palette
BOOL SetPalette(CPalette* pPalette) // Set current palette
BOOL SetLogPalette(LOGPALETTE* pLogPalette) // Set current palette
BOOL SetDither(BOOL bDither); // Use DrawDib to dither?
BOOL GetDither(); // Is DrawDib being used to dither?
BOOL Load(LPCTSTR lpszFileName); // Load form disk
BOOL Save(LPCTSTR lpszFileName); // Save to disk
BOOL Draw(CDC* pDC, CPoint ptDest, // Draw image
BOOL bForceBackground = FALSE);
BOOL Stretch(CDC* pDC, CPoint ptDest, CSize size, // Stretch draw image
BOOL bForceBackground = FALSE);

Comments
memory leaking problem when using CreateDibSection
Posted by Legacy on 03/27/2003 12:00amOriginally posted by: test
do you have the same problem like this situation?
it seems that inner implementation within CreateDibSection are some problem to release the memory allcated. so resource be occupied after repeat CreatDIBSection several times. what can i do?
ReplyI have questions so
Posted by Legacy on 02/08/2003 12:00amOriginally posted by: Payam Govahi
ReplyPrinting the DIB?
Posted by Legacy on 01/19/2003 12:00amOriginally posted by: Kyle Brown
Hi there, I am using your code, and it works great. I have a slight problem, when I use the stretch function in my print function, it seems to work differently on different printers? Do you know if there is something special I have to do to get a consistent print? Thanks.
Kyle.
ReplyHow to use it ?
Posted by Legacy on 10/16/2002 12:00amOriginally posted by: Alex Chung
I am just a VC++ beginner. But I have to work on an imaging project. Could anyone tell me how to make use of the DIBsectionLite functions to read an Bitmap file? I look fwd to receiving your valuable advice. Thanks very much !
Replydrawdibdraw virus
Posted by Legacy on 08/27/2002 12:00amOriginally posted by: Simon
My computer is displaying a window saying 'DrawDibDraw refused to cooperate' which will not delete, I assume its a virus. Any ideas how to get rid of it?
Replygreat stuff
Posted by Legacy on 03/13/2002 12:00amOriginally posted by: philip cunningham
Replygreat stuff
Posted by Legacy on 03/13/2002 12:00amOriginally posted by: philip cunningham
ReplyHow can I print out a screenshot?
Posted by Legacy on 10/30/2001 12:00amOriginally posted by: Karsten Brinkmann
I want to make a screenshot and print it out.
I use the following code:
void CPrintScreenDlg::OnButtonDrucken()
{
HWND hWnd = ::GetDesktopWindow();
CWnd* pWnd = new CWnd;
pWnd->Attach(hWnd);
CClientDC dc(pWnd);
CDC memDC;
CRect rect;
memDC.CreateCompatibleDC(&dc);
pWnd->GetWindowRect(rect);
m_bitmap.CreateCompatibleBitmap( &dc, rect.Width(), rect.Height() );
CBitmap* pOldBitmap = memDC.SelectObject(&m_bitmap);
memDC.BitBlt(0, 0, rect.Width(),rect.Height(), &dc, 0, 0, SRCCOPY);
m_dibSection.SetBitmap( (HBITMAP) m_bitmap.GetSafeHandle() );
Drucken();
memDC.SelectObject(pOldBitmap);
m_bitmap.Detach();
pWnd->Detach();
delete pWnd;
}
void CPrintScreenDlg::Drucken()
{
DOCINFO DocInfo; // DOCINFO
CDC dc; // Device Context
// Druckereinstellung ermitteln
CPrintDialog PrintDlg( true, PD_RETURNDC );
// PrintDlg anzeigen ja / nein
if( PrintDlg.DoModal() != IDOK )
return;
DocInfo.cbSize = sizeof(DocInfo);
DocInfo.lpszDocName = _T("Screenshot");
DocInfo.lpszOutput = NULL;
// Drucker DC holen
dc.Attach( PrintDlg.GetPrinterDC() );
//dc.ResetDC( mod );
// nicht ben�tigte Resourcen freigeben
if( PrintDlg.m_pd.hDevMode )
::GlobalFree( PrintDlg.m_pd.hDevMode );
if( PrintDlg.m_pd.hDevNames )
::GlobalFree( PrintDlg.m_pd.hDevNames );
// Dokumentanfang
dc.StartDoc( &DocInfo );
m_dibSection.Draw( &dc, CPoint(0,0) );
// Dokumentende
dc.EndPage();
dc.EndDoc();
}
But the printer allways prints a BLACK box.
What do I wrong?
thank you
ReplySerializing CDIBsectionLite
Posted by Legacy on 08/27/1999 12:00amOriginally posted by: Rupert
Thanks for this code, it is really useful. Just a couple of questions; what would I need to do to support serialization in CDIBsectionLite (any code appreciated). Is there a way to get CDIBsection without buying the entire Ultimate paint application ($899 seems a bit much for one class).
ReplyRupert
Small "LoadImage" bug fixed
Posted by Legacy on 06/04/1999 12:00amOriginally posted by: Chris Maunder
There was a small "LoadImage" bug that has been fixed as of 4 june 1999.
ReplySorry for any inconvenience! This was causing bitmaps with less than 256 colours to appear black (they were not getting loaded properly)
Loading, Please Wait ...