The Image Viewer application showing the contents of an image list
Contents
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 HDC
s, HBITMAP
s, HICON
s, HCURSOR
s, HFONT
s, HIMAGELIST
s, HRGN
s, and Gdiplus::Image
s.
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.
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.
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.
FILE |
IN FOLDER |
ImageViewer.h |
Dev Studio\VC\Include |
ImageViewer.dll |
Windows or WINNT |
ImageViewer.lib |
Dev Studio\VC\Lib |
ImageViewer.exe |
Dev Studio\Common\Tools |
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.
#define ACTIVATE_VIEWER
#include "ImageViewer.h"
or
#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.
CDC memDC;
memDC.CreateCompatibleDC(NULL);
ShowDC(memDC);
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.
#ifdef VIEWER_ACTIVE
#endif
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);
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.
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
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.
The image properties dialog
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, ...)
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.
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).
Every button on the toolbar has a menu equivalent and a keyboard shortcut to go with it.
Pause.
- 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 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.
Open session document.
- Menu: File/Open.
- Keyboard: <CTRL>+'O'.
Opens an *.ivd file that was previously saved.
Always 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.
Background 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.
Hexadecimal Tooltips.
- Menu: View/Hexadecimal Tooltips.
- Keyboard: 'X'.
Toggles the colour values on the tooltip window between decimal and hexadecimal display.
Display 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.
Save as Picture.
- Menu: Image/Save as Picture.
- Keyboard: 'S'.
Saves the image currently being viewed on disk as a picture file.
Properties.
- 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.
Delete 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.
Go to first image.
- Menu: Image/First.
- Keyboard: Shift + '<'.
- Mouse: Press right mouse button, then move mouse up.
Go to previous image.
- Menu: Image/Previous.
- Keyboard: '<'.
- Mouse: Press right mouse button, then move mouse left.
Select an image.
- Menu: Image/Select.
- Keyboard: '?'.
Go to next image.
- Menu: Image/Next.
- Keyboard: '>'.
- Mouse: Press right mouse button, then move mouse right.
Go to last image.
- Menu: Image/Last.
- Keyboard: Shift + '>'.
- Mouse: Press right mouse button, then move mouse down.
Show 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.
Zoom In.
- Menu: Zoom/Zoom In.
- Keyboard: '+'.
- Mouse: <CTRL>+Roll mouse wheel up.
Zoom Out.
- Menu: Zoom/Zoom Out.
- Keyboard: '-'.
- Mouse: <CTRL>+Roll mouse wheel down.
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.
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
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.
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.
The Image Viewer's status bars
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.
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.
- 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
- 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