Click here to Skip to main content
15,867,594 members
Articles / Programming Languages / C++
Article

Image Viewer Utility

Rate me:
Please Sign up or sign in to vote.
4.94/5 (50 votes)
10 Mar 2007CPOL18 min read 405.1K   19.2K   200   84
A little utility program that allows you to view the contents of memory bitmaps and device contexts while you are stepping through your drawing code.

Image Viewer Application showing the contents of a memory DC

The Image Viewer application showing the contents of an image list

Contents

Introduction

Have you ever debugged a graphics routine where you would really like to see what the images you are working with in memory actually looked like while you are stepping through your code? Well, now you can!!!

The Image Viewer is a simple utility program that you can plug into your drawing code. It has a zoom feature so you can get a real close look at what you are drawing, or a good overview of a larger picture. Use it to peek at HDCs, HBITMAPs, HICONs, HCURSORs, HFONTs, HIMAGELISTs, HRGNs, and Gdiplus::Images.

The Image Viewer download contains just the compiled files and the ImageViewer.h header file. The demo application download contains all the source code.

The ImageViewer.h header file and the ImageViewer.dll library file were both written using only the Win32 APIs and some ATL. MFC was not used. Both the header and library files have been tested with Visual C++ 6.0 and Visual C++ 8.0, using both MBCS and Unicode builds.

System Requirements

Because the Image Viewer application is a 32 bit MFC 8.0 unicode application you will need the Visual C++ 8.0 runtimes installed on your machine in order to use it. The runtimes can by obtained from the Microsoft website. Follow the directions on that page to download and install the vcredist_x86.exe runtime installer. The Image Viewer application also makes use of GDI+. If you are running Windows 2000 you may have to download and install the GDI+ redistributable files available from the Microsoft website.

Installing the files

There is no installer provided, so the files have to be manually copied to the proper locations on your hard drive. All the neccessary files are contained in the Image Viewer utility download file.

FILEIN FOLDER
ImageViewer.hDev Studio\VC\Include
ImageViewer.dllWindows or WINNT
ImageViewer.libDev Studio\VC\Lib
ImageViewer.exeDev Studio\Common\Tools

How to use the Image Viewer

Using the utility is pretty painless. Simply include the ImageViewer.h header file in the source file you have your drawing code in. You turn the viewer on by defining the ACTIVATE_VIEWER macro.

C++
// viewer active
#define ACTIVATE_VIEWER
#include "ImageViewer.h"

or

C++
// viewer not active
// #define ACTIVATE_VIEWER
#include "ImageViewer.h"

If ACTIVATE_VIEWER is defined, and you are working in debug mode, the ImageViewer.h file will cause your program to link to the ImageViewer.lib file, and when your program executes, it will load the ImageViewer.dll file.

To actually view the images, you have to run the ImageViewer.exe program. The DLL will send the bitmap to be viewed to the Viewer application using a WM_COPYDATA message.

In your drawing code, place a call to one of the Show* functions whenever you want to take a peek at an image.

C++
CDC memDC;
memDC.CreateCompatibleDC(NULL);

// some drawing code

ShowDC(memDC); // take a peek at what is drawn so far

// some more code etc.

If the Image Viewer tool is active, the VIEWER_ACTIVE macro will be defined, so you can control extra code around the Show*() macros by checking for the VIEWER_ACTIVE macro.

C++
#ifdef VIEWER_ACTIVE

// Some code that requires the image viewer tool

#endif // VIEWER_ACTIVE

The API Macros

The API consists of the following macros:

  • ShowBitmap (HBITMAP bmp)
  • ShowBitmap2 (HBITMAP bmp, LPCTSTR Text)
  • ShowDC (HDC DC)
  • ShowDC2 (HDC DC, LPCTSTR Text)
  • ShowGDIPlusBitmap (Gdiplus::Image)
  • ShowGDIPlusBitmap2 (Gdiplus::Image, LPCTSTR Text)
  • ShowIcon (HICON icon)
  • ShowIcon2 (HICON icon, LPCTSTR Text)
  • ShowCursor (HCURSOR cursor)
  • ShowCursor2 (HCURSOR cursor, LPCTSTR Text)
  • ShowFont (HFONT Font)
  • ShowFont2 (HFONT Font, LPCTSTR Text)
  • ShowFont3 (LPCTSTR Sample, HFONT Font, LPCTSTR Text)
  • ShowImageList (HIMAGELIST List, int Index, UINT Flags)
  • ShowImageList2 (HIMAGELIST List, int Index, UINT Flags, LPCTSTR Text)
  • ShowRegion (HRGN Region)
  • ShowRegion2 (HRGN Region, LPCTSTR Text)
  • ShowRegion3 (HRGN Region, HBITMAP Bitmap, LPCTSTR Text)
  • ShowRegion4 (HRGN Region, HDC DC, LPCTSTR Text)

All these macros return a LRESULT value that represents a Win32 error code. The possible return codes are explained below.

The ShowBitmap(), ShowDC(), and ShowGDIPlusBitmap() functions will show the image "as-is".

To watch a Gdiplus::Graphics object that you may be working on, create it with an Image, and watch that Image.

Image bmp(width, height);
Graphics g(bmp);
g.DrawImage(Picture, 0, 0);
ShowGDIPlusBitmap(bmp); // take a peek at what is drawn.

The ShowIcon() and ShowCursor functions show the icon or cursor as a three part horizontal image. The left most part is the AND mask, the middle is the XOR mask, and the right most part is the actual icon or cursor as it will appear when drawn.

Image Viewer showing a cursor by using the ShowIcon() function

The Image Viewer application with a cursor

The ShowImageList() function, which was originally written by Jrgen Sigvardsson, works a little differently as it takes three parameters. They are the image list's handle, the index of the image in the list, and a custom ILD_* display flag. The index may be -1, or a legal index for the image list. Specifying -1 as the index will draw the entire image list. The image is drawn three times: ILD_NORMAL on top, ILD_TRANSPARENT in the middle, and the bottom is drawn using the custom ILD_* flags parameter.

With the ShowRegion functions, which are based on code supplied by WalderMort, it is possible to show the HRGN in black on the default background, or if a background image is supplied as either a HBITMAP or HDC the HRGN will be shown by inverting the pixels of the background image that are within the supplied HRGN.

Image Viewer showing an HRGN region by inverting the colours of a bitmap

Image Viewer showing an HRGN region by inverting the colours of a bitmap

The second version of the functions take a LPCTSTR pointer to a descriptive text that can be accessed later from the Image Viewer application when viewing the image. It will be seen in the child frames status bar and can also be seen in the properties dialog. The Properties dialog also shows the image size in pixels, the bit-depth of the image, and the source file and line number where the Show* macro was called.

Image properties dialog

The image properties dialog

ShowGraphic() API function

The ShowGraphic function is new in version 2.2. It is designed to replace all the previously listed Show* functions. The problem with it is that it uses the __noop keyword so it does not work in older versions Visual C++. The ShowGraphic function requires Visual C++ version 7.0 or later. The code for the ShowGraphic function is based on the Location Trace article by Paul Mclachlan that was originally adapted for this function by Mor FTP. One of the main advantages of ShowGraphic is that by using operator overloading one function can now show many different graphics object. The other main advantage is that the descriptive text can now be specified using printf style formatting.

The various overloads are listed here.

  • LRESULT ShowGraphic(HBITMAP hBitmap, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HDC hDC, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HICON hIcon, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HCURSOR hCursor, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HFONT hFont, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(LPCTSTR Sample, HFONT hFont, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HIMAGELIST hList, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HRGN hRgn, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HRGN hRgn, HBITMAP hBitmap, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(HRGN hRgn, HDC hDC, LPCTSTR Format = NULL, ...)
  • LRESULT ShowGraphic(Gdiplus::Image Image, LPCTSTR Format = NULL, ...)

API Return Values

All these error return codes are defined in the WinError.h header file. If the Image Viewer utility is not activated (see above) all the Show* functions will return zero. If the Image Viewer utility is active then these are the possible values returned by the Show* functions.

  • ERROR_SUCCESS
    • The graphic object has successfully been sent to the Image Viewer application.
  • ERROR_NOT_READY
    • The hidden windows used to communicate with the Image Viewer application are not ready. The most common reason is that the Image Viewer application is not running.
  • ERROR_INVALID_HANDLE
    • The graphic object handle is NULL.
  • ERROR_INVALID_DATA
    • HRGN objects only. The HRGN handle is valid but the region itself is empty.
  • ERROR_FUNCTION_FAILED
    • An unspecified error occured within the function so it was unable to send the graphic object to the Image Viewer application.
  • ERROR_TIMEOUT
    • The function tried to send the graphic object to the Image Viewer application but the Image Viewer application took too long to respond.
  • ERROR_SHARING_PAUSED
    • The Image Viewer application is in the paused state and is not recieving anything at this time
  • ERROR_NOT_ENOUGH_MEMORY
    • The Image Viewer application has used up all it's alloted memory

If you run the demo application provided, you will want to start up the ImageViewer.exe program, and then step through the ViewerDemoView::OnDraw() function.

I hope some of you find this as useful as I do.

Navigating the Image Viewer application

The viewer application has been greatly improved in version 2.0. The main features added are the history feature and the ability to save the session or individual images to disk for later browsing or sharing with others. With the history feature, it is possible to browse forward and backwards through the images generated so they can be viewed and reviewed without having to rerun the app being debugged. The Image Viewer application is built as an MFC MDI app. Each time a new instance of an app is being debugged, a new MDI document is created in the Image Viewer. This makes it easy to compare one run to another. It is also possible to create multiple views of the same document, so one can compare sequential images side by side.

It is also possible to save the generated images to disk. An entire history document can be saved into a *.ivd file (Image Viewer Data file) that can be reloaded into the Image Viewer for later viewing. Or individual images can be saved to a picture file on disc.

The supported picture file formats are:

  • Portable Network Graphics (*.png).
  • Windows Bitmap (*.bmp).
  • Tag Image File Format (*.tiff).
  • Graphics Interchange Format (*.gif).
  • Joint Photographic Experts Group (*.jpeg).

In addition, the Image Viewer can read from, but not write to, the following types of files:

  • Windows Icon (*.ico).
    • Reads the first image only. Does not support multi-image icons
  • Windows Meta Files (*.wmf).
  • Enhanced Meta Files (*.emf).

The toolbar

Every button on the toolbar has a menu equivalent and a keyboard shortcut to go with it.

Image reception control

Image 5Pause.

  • Menu: File/Pause.
  • Keyboard: <Pause>.

Pauses the image reception. The Image Viewer will not receive any images from any other apps while it is in the paused state.

Save and Open session data

Image 6Save session document.

  • Menu: File/Save As.
  • Keyboard: <CTRL>+'S'.

Saves the entire document to a *.ivd file. The file can get quite large if there are lots of images in it, as it is saved as a series of uncompressed DIBs.

Image 7Open session document.

  • Menu: File/Open.
  • Keyboard: <CTRL>+'O'.

Opens an *.ivd file that was previously saved.

General display options

Image 8Always on Top.

  • Menu: View/Always on Top.
  • Keyboard: 'T'.

Keeps the Image Viewer application on top of all other windows so it is never obscured by other processes.

Image 9Background Colour.

  • Menu: View/Background Colour.
  • Keyboard: 'B'.

Brings up the standard Choose Colour dialog to choose the background colour that is used to fill the transparent part of images and also to fill the parts of the views not covered by the images.

Image 10Hexadecimal Tooltips.

  • Menu: View/Hexadecimal Tooltips.
  • Keyboard: 'X'.

Toggles the colour values on the tooltip window between decimal and hexadecimal display.

Image 11Display Lock.

  • Menu: View/Display Lock.
  • Keyboard: 'D'.

Locks the display on the image currently being viewed. If this option is not set, the last image received by the Image Viewer is displayed as it is received.

Single image options

Image 12Save as Picture.

  • Menu: Image/Save as Picture.
  • Keyboard: 'S'.

Saves the image currently being viewed on disk as a picture file.

Image 13Properties.

  • Menu: Image/Properties.
  • Keyboard: 'P' to show, <ESC> to hide.

Toggles the Properties dialog. The data displayed on the Properties dialog is updated as the image currently being viewed changes.

Image 14Delete Images.

  • Menu: Image/Delete.
  • Keyboard: <DEL>.

Brings up a dialog where the choice can be made to remove an image or a series of images from the images in the session document. The default setting is to remove the image currently being viewed.

Image history selection options

Image 15Go to first image.

  • Menu: Image/First.
  • Keyboard: Shift + '<'.
  • Mouse: Press right mouse button, then move mouse up.

Image 16Go to previous image.

  • Menu: Image/Previous.
  • Keyboard: '<'.
  • Mouse: Press right mouse button, then move mouse left.

Image 17Select an image.

  • Menu: Image/Select.
  • Keyboard: '?'.

Image 18Go to next image.

  • Menu: Image/Next.
  • Keyboard: '>'.
  • Mouse: Press right mouse button, then move mouse right.

Image 19Go to last image.

  • Menu: Image/Last.
  • Keyboard: Shift + '>'.
  • Mouse: Press right mouse button, then move mouse down.

Image zoom options

Image 20Show Grid.

  • Menu: Zoom/Grid.
  • Keyboard: 'G'.

Draws a grid on the image that outlines each pixel. The image has to be magnified at least 200% for the grid to show.

Image 21Zoom In.

  • Menu: Zoom/Zoom In.
  • Keyboard: '+'.
  • Mouse: <CTRL>+Roll mouse wheel up.

Image 22Zoom Out.

  • Menu: Zoom/Zoom Out.
  • Keyboard: '-'.
  • Mouse: <CTRL>+Roll mouse wheel down.

The tooltip and scrolling

The coordinates and the RGB colour of the pixel under the mouse cursor is displayed on a tooltip that follows the mouse cursor around. The most obvious way of controlling the tooltip is to grab the mouse and move it. But for finer control, or for those who do not like using the mouse, the mouse cursor can be controlled with the arrow keys on the keyboard. The default behaviour of the arrow keys is to first scroll the image by one pixel, leaving the mouse cursor where it is on the screen, until the image can not be scrolled any farther. At that point, the mouse cursor will move until it hits the edge of the view. To disable the scrolling and have the mouse cursor move instead, simply hold down the SHIFT key while pressing the arrow keys, or toggle the Scroll Lock button on the keyboard. The mouse cursor has to be over the view in order for this to work, but simply pressing the 'C' key on the keyboard will center the mouse cursor over the view.

The view can also be scrolled using the Home, End, PageUp, or PageDown buttons, as well as by rolling the mouse wheel. The standard behaviour of these controls is to scroll the view vertically, but by holding down the SHIFT key at the same time as using these controls, the view will scroll horizontally. If the mouse is being used, the view can be scrolled by holding down the left mouse button and moving the mouse cursor against an edge of the view. Clicking the middle mouse button, or mouse wheel, will start the panning feature.

Memory management

There was some concern expressed in the forums below about the Image Viewer being a real memory hog. So as of version 2.1 it now possible to limit the maximum amount of memory that the viewer can use to store the images it receives. When there are no child view windows open the default menu will have an option "Setup/Memory...". If you select that option you will get a dialog that allows you to set the maximum amount of memory that the Image Viewer will use. You can set any amount in the range of 100000 KB through to 1750000 KB.

Another mechanism that was added to control memory usage was the addition of the "Pause" command and toolbar button. It is now possible to pause the Image Viewer application so it will not receive images from any other applications that may be trying to send them.

In order for the user to able to see how much memory that Image Viewer application is using at any given time a memory usage meter has been added to the status bar. The meter has a textual readout of the amount of memory being used, and it has a graphical "progress bar" that shows how much of the available memory is used and how much is still available

Image 23

Memory usage meter

To free up memory when you run low it is simply a matter of either closing a document window, or using the "Image/Delete" command to delete a bunch of the older images that you may not need anymore.

Status Bars

The status bars can be used to give information about the Image Viewer application and about the image currently being viewed. The main status bar has three panes. The first is the standard information pane that shows the current status of the application and also displays helpful hints about the toolbar buttons and menu items that are currently selected. The second is the memory usage meter mentioned previously. The third is the Scroll lock indicator.

The status bar that is attached to the child view windows shows information about the image currently being displayed in that view. It has six panes that can be optionally shown or hidden by selecting them in the View/Indicators menu. The first pane is the Text pane. It shows the first line of the text that is supplied with the image when the Show* functions are called. The next panes show the time the Show* function was called and the source file, line, and function where the Show* function is located. The last pane shows the size, in pixels, of the image.

Image 24

The Image Viewer's status bars

Wish list

There are several things I would like to add to this application. The main one is to expand the support for the GDI+ API. Currently only Gdiplus::Image is supported. I would also like to add support for the rest of the GDI objects, such as HPEN, HBRUSH, and others. I would also like to write an installer/uninstaller that will properly setup and register the files with the various versions of Visual Studio.

If you do decide to implement any additional features to/for this application feel free to post the code in the forum below, or send them to me via email. If I like them I may even include them in future versions.

Disclaimer

Copyright (c) 2001-2006, PJ Arends

This software is released as FREEWARE and is provided "AS-IS" without any express or implied warranties, including, without limitation, the implied warranties of merchantability and fitness for a particular purpose.

This code may be used in any way you desire. This code may be redistributed by any means as long as it is not sold for profit, and providing that this notice and the author's name are included. Any modifications not made by the original author should be clearly marked as such to remove any confusion between the original version and any other versions.

If any bugs are found and fixed, a note to the author explaining the problem and fix would be nice.

Thanks and Credits

Updates

  • January 31, 2002
    • Fixed W2K bug reported by Melwyn.
  • April 11, 2004
    • Added the ShowIcon() function.
  • August 31, 2004
    • Added the ShowGDIPlusBitmap() function.
    • Added the ShowImageList() function. (Thanks Jrgen)
  • September 12, 2006
    • Released version 2.0.
  • November 13, 2006 - Version 2.1
    • Added the ShowRegion functions. (Thanks WalderMort)
    • Added the memory management and pause features.
    • Various other code cleanups and enhancements.
  • December 16, 2006 - Version 2.2
    • Added the ShowFont function.
    • Added the ShowGraphic function. (Thanks Mor FTP.)
    • Updated the Image Viewer's child status bar. Now has the option to show more information about the current image.
    • Updated how the Image Viewer handles regions. The tooltip now shows the region's coordinates, and the coordinates of the region's bounding rectangle is now displayed on the status bar.
    • Added the error return codes to the Show* functions.
    • Changed the keyboard shortcuts for the "Goto First Image" and "Goto Last Image" commands.
    • Added the wish list and disclaimer to the article text.
  • December 23, 2006 - Version 2.2.1
    • Fixed bug reported by Owen Lawrence.
  • March 5, 2006 - version 2.3
    • Added support for directly loading certain graphics files. The Image Viewer Application can now be used a stand alone picture viewing application.
    • Rewrote the drawing code so we can now zoom in on large images without running out of system resources.
    • Added a table of contents to the article.
    • Various other minor fixes and tweaks

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
President
Canada Canada
Father of two, brother of two, child of two.
Spouse to one, uncle to many, friend to lots.
Farmer, carpenter, mechanic, electrician, but definitely not a plumber.
Likes walks with the wife, board games, card games, travel, and camping in the summer.
High school graduate, college drop-out.
Hobby programmer who knows C++ with MFC and the STL.
Has dabbled with BASIC, Pascal, Fortran, COBOL, C#, SQL, ASM, and HTML.
Realized long ago that programming is fun when there is nobody pressuring you with schedules and timelines.

Comments and Discussions

 
GeneralA doubt Pin
melwyn30-Jan-02 22:06
melwyn30-Jan-02 22:06 
GeneralRe: A doubt Pin
PJ Arends31-Jan-02 4:49
professionalPJ Arends31-Jan-02 4:49 
Generalooops Pin
melwyn31-Jan-02 23:13
melwyn31-Jan-02 23:13 
GeneralRe: ooops Pin
PJ Arends1-Feb-02 9:13
professionalPJ Arends1-Feb-02 9:13 
GeneralThanks Pin
melwyn4-Feb-02 21:41
melwyn4-Feb-02 21:41 
GeneralA link to another method Pin
PJ Arends27-Jan-02 7:00
professionalPJ Arends27-Jan-02 7:00 
GeneralRe: A link to another method Pin
Max Santos20-Apr-04 10:47
Max Santos20-Apr-04 10:47 
GeneralSome ideas for further development Pin
Igor Okulist2-Jan-02 7:45
Igor Okulist2-Jan-02 7:45 
GeneralThanks Pin
12-Dec-01 7:37
suss12-Dec-01 7:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.