Simple BMP Viewer

Environment: Developed with VC 5.

This is a sample simple BMP viewer. It only shows
the minimum code for loading a BMP from a file
and showing it in a window. It does not do everything;
I get frustrated trying to figure out how to do something simple
using a sample that does everything. In particular, it does not
do palettes, which is something that seems to be important, but
also seems to be relatively complicated. I am not a graphics
expert so I invite an expert to create another article
documenting correspondingly simple palette processing and/or
printing and print preview processing.

Consistent with the theme of keeping things
simple, I will simply describe how to create a sample program and
supply relevant code here. You can use this code as a sample for
use in your project or use this code and instructions to create a
complete working sample.

To create a complete working sample, start by
generating an MDI application with a CScrollView view. You might
want to de-select the option for printing and print preview. Then:

  1. Use ClassWizard to add processing for ID_FILE_NEW
    in your application class, but do nothing more with it,
    since we do not support bitmap creation.

  2. Use ClassWizard to add processing for
    DeleteContents in your document class and add the
    following to it:

    if (m_Bitmap.m_hObject != NULL)
    	m_Bitmap.DeleteObject();
  3. Use ClassWizard to add processing for
    OnOpenDocument in your document class and replace
    all
    the generated code with the following:

    if (IsModified())
    	TRACE0("Warning: OnOpenDocument replaces an unsaved documentn");
    DeleteContents();
    BeginWaitCursor();
    HBITMAP hImage = (HBITMAP)LoadImage(NULL, lpszPathName, IMAGE_BITMAP,
    	0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION|LR_DEFAULTSIZE);
    EndWaitCursor();
    if (!hImage) {
    	DWORD LastError = GetLastError();
    	// Error message should be fomatted with LastError included
    	AfxMessageBox("LoadImage failed");
    	return FALSE;
    	}
    if (!m_Bitmap.Attach(hImage)) {
    	AfxMessageBox("Bitmap could not be attached");
    	return FALSE;
    	}
    SetModifiedFlag(FALSE);
    UpdateAllViews(NULL);
    return TRUE;
  4. Add the following to the header for the
    document:

    public:
    	HBITMAP GetHandle() const {return (HBITMAP)m_Bitmap.m_hObject;};
    	void SelectOldBitmap(CDC *pDCMem) {pDCMem->SelectObject(m_pOldBitmap);};
    	void SelectBitmap(CDC *pDCMem)
    		{m_pOldBitmap=pDCMem->SelectObject(&m_Bitmap);};
    	int GetBitmap(BITMAP* pBitMap) {return m_Bitmap.GetBitmap(pBitMap);};
    
    protected:
    	CBitmap m_Bitmap;
    	CBitmap* m_pOldBitmap;
  5. Use ClassWizard to remove
    processing for OnInitialUpdate in your view class and delete
    the function from the code

  6. Add to the view constructor:

    SetScrollSizes(MM_TEXT, CSize(0, 0));
  7. Use ClassWizard to add processing for
    OnUpdate in your view class and add the following to it:

    	CBMPLookDoc* pDoc = GetDocument();
    	CFrameWnd* pParentFrame = GetParentFrame();
    	BITMAP BitMap;
    if (!pDoc->GetHandle())
    	return;
    pDoc->GetBitmap(&BitMap);
    SetScrollSizes(MM_TEXT, CSize(BitMap.bmWidth, BitMap.bmHeight));
    pParentFrame->RecalcLayout();
    ResizeParentToFit();
  8. Finally, replace the OnDraw processing
    with the following:

    	CBMPLookDoc* pDoc = GetDocument();
    	BITMAP BitMap;
    	CDC DCMem;
    // Do not call CWnd::OnPaint() for painting messages
    ASSERT_VALID(pDoc);
    if (!pDoc->GetHandle())
    	return;
    if (!DCMem.CreateCompatibleDC(pDC))
    	TRACE0("DCMem.CreateCompatibleDC failedn");
    pDoc->SelectBitmap(&DCMem);
    pDoc->GetBitmap(&BitMap);
    if (!pDC->BitBlt(0, 0, BitMap.bmWidth, BitMap.bmHeight, &DCMem, 0, 0, SRCCOPY))
    	TRACE0("BitBlt failedn");
    pDoc->SelectOldBitmap(&DCMem);
    DCMem.DeleteDC();

You should also modify the "<filterName>"
and "<filterExt>" in the Document Template String
to use appropriate file extensions and ".bmp" for the
file extension. See CDocTemplate::GetDocString and Microsoft
Knowledge Base article "INFO: Format of the Document
Template String" (Article ID: Q129095) for information on
Document Template Strings. The string resource id for the string
is usually 129.

The LR_CREATEDIBSECTION flag in the LoadImage
function can probably be removed to improve performance, but the
documentaion for this and many, many other things need to be
studied because bitmaps and graphics are quite complex.

References

To go beyond this very simple sample, the MFC
DIBLook sample is an example of the type of sample that is too
complicated to get just the basics from but does show most of the
fancier stuff that should be done.

There is an abundance of documentation to wade
through in the section on Bitmaps in the GDI portion of Graphics
and Multimedia Services
in the Platform SDK
documentation. For Windows 9X, in the Windows Base Services
chapter of the Platform SDK there is a Windows 95
Graphics Device Interface
topic in Windows 95 System
Limitations
in About Windows 95 in Windows 95
Feature
s.

The Multimedia Technical Article DIBs and
Their Use
might be helpful.

In the Microsoft Systems Journal Volume
12 Number 1 is the article More Fun with MFC: DIBs, Palettes,
Subclassing, and a Gamut of Reusable Goodies
.

The following are Microsoft Knowledge Base
articles (the last two are from the Win16 knowledge base):

Q94326 SAMPLE: 16 and 32 Bits-Per-Pel Bitmap Formats
Q158898 How To Use LoadImage() to Read a BMP File
Q124947 Retrieving Palette Information from a Bitmap
Resource
Q159649 PARSEBIT.EXE Directly Accesses the Bits of a DIB
Section
Q67883 How to Use a DIB Stored as a Windows Resource
Q83034 SAMPLE: Reading and Converting Between the Three
GDI Resources
Q81498 SAMPLE: DIBs and Their Uses

History

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read