Introduction
This article introduces WTLIPicture Viewer, an updated version of the WTL BmpView sample application. WTLIPicture Viewer uses a wrapper for the OLE Picture object and handles multiple image types, including bitmap, cursor, enhanced metafile, icon, gif, jpeg, and windows metafile. Image files can be opened and zoomed in or out, copied from or pasted to the clipboard, and previewed and printed.
The Picture object wrapper is contained in the source file WTLIPicture.h and provides all needed code for using a Picture object with an image viewer like the sample WTLIPicture Viewer. It contains a WTL port and extension of the CPictureHolder class from MFC and also contains classes that provide support for multiple clipboard image formats. In addition, it provides a set of semi-standardized structures, similar to BITMAPFILEHEADER and BITMAPINFOHEADER, for most of the supported image formats.
A Note About PNG
WTLIPicture Viewer does not support PNG images because IPicture predates PNG.
Picture Object
OLE Picture objects provide a language-neutral abstraction for bitmaps, icons, and metafiles. The primary interfaces are IPicture and IPictureDisp. The IPicture interface allows the caller to manage picture properties and to use the picture in graphical rendering. The IPictureDisp interface is derived from IDispatch to provide access to the picture's properties through automation.
The following subsections explain the various methods provided by the CPixT template to simplify use of a Picture Object. Member variable m_pPix is an IPicture pointer.
Create Methods
CreateEmpty() is the basic method provided by CPixT to initialize a Picture object. All other create methods call it, passing a pointer to a filled in PICTDESC structure containing information about the picture.
BOOL CreateEmpty(LPPICTDESC lpPictDesc = NULL, BOOL bOwn = FALSE)
{ if (lpPictDesc == NULL)
{
PICTDESC pdesc;
pdesc.cbSizeofstruct = sizeof(pdesc);
pdesc.picType = PICTYPE_NONE;
lpPictDesc = &pdesc;
}
return SUCCEEDED(::OleCreatePictureIndirect(lpPictDesc, IID_IPicture, bOwn,
(LPVOID*)&m_pPix)); }
CreateFromBitmap() is a set of three methods that allow initialization of a Picture object from a bitmap resource, a CBitmap pointer, or a bitmap handle. The following code shows the version that accepts a bitmap handle, an optional palette, and a flag indicating whether or not to transfer ownership of the bitmap to the Picture object.
BOOL CreateFromBitmap(HBITMAP hbm, HPALETTE hpal, BOOL bTransferOwnership)
{ PICTDESC pdesc;
pdesc.cbSizeofstruct = sizeof(pdesc);
pdesc.picType = PICTYPE_BITMAP;
pdesc.bmp.hbitmap = hbm;
pdesc.bmp.hpal = hpal;
return CreateEmpty(&pdesc, bTransferOwnership); }
CreateFromEnhancedMetafile() supports creation of a Picture object from an Enhanced Metafile.
CreateFromIcon() provides methods that create a Picture object from either an icon resource or an icon handle. It supports both icon and cursor images.
CreateFromMetafile() provides initialization of a Picture object from a Windows Metafile.
Load Methods
These methods provide mechanisms for loading a Picture object from various input sources such as files and streams.
LoadFromDispatch loads a Picture object from an image file and sets the IPictureDisp interface.
BOOL LoadFromDispatch(LPTSTR szFilePath)
{ VARIANT varFileName;
varFileName.vt = VT_BSTR;
varFileName.bstrVal = CComBSTR(szFilePath);
LPDISPATCH lpDisp = NULL;
BOOL bResult = SUCCEEDED(::OleLoadPictureFile(varFileName, &lpDisp));
if (bResult) lpDisp->QueryInterface(IID_IPicture, (LPVOID*)&m_pPix);
return bResult; }
LoadFromFile() loads a Picture object from an image file using standard file i/o.
LoadFromIStream() loads from an IStream.
LoadFromISequentialStream() loads the Picture object using an ISequentialStream pointer such as those from an OLE DB provider.
LoadFromPath() loads from a file name or URL. This is the simplest method of loading an image but it is rumored to leak resources.
BOOL LoadFromPath(LPCTSTR szFilePath)
{ return SUCCEEDED(::OleLoadPicturePath(CComBSTR(szFilePath), NULL, 0, 0,
IID_IPicture, (LPVOID *)&m_pPix)); }
Save Methods
These methods provide mechanisms for saving a Picture object to a file.
SaveToDispatch() saves a Picture object to an image file using the IPictureDisp interface.
BOOL SaveToDispatch(LPTSTR szFilePath)
{ BOOL bResult = FALSE;
LPPICTUREDISP pDisp = NULL;
if (SUCCEEDED(m_pPix->QueryInterface(IID_IPictureDisp, (LPVOID*)&pDisp)))
BOOL bResult = SUCCEEDED(::OleSavePictureFile((LPDISPATCH)pDisp,
CComBSTR(szFilePath)));
return bResult; }
SaveToFile() saves a Picture object to an image file using standard file I/O.
Render Method
Draws the image that was created or loaded into the IPicture onto a device context. You can pass in a rectangle with values less than the image size to scale down or with values greater than the image size to scale up.
void Render(CDCHandle dc, const CRect& rcRender)
{ long hmWidth;
long hmHeight;
m_pPix->get_Width(&hmWidth);
m_pPix->get_Height(&hmHeight);
m_pPix->Render(dc, rcRender.left, rcRender.top, rcRender.Width(),
rcRender.Height(), 0, hmHeight-1, hmWidth, -hmHeight, NULL); }
Properties
GetAttributes() - returns a DWORD containing transparency and scalability flags
GetDescription() - returns the textual description of the image type
GetHandle() - returns an OLE_HANDLE to the image
GetHandle() - takes a reference to an OLE_HANDLE and sets the value
GetPixInformation() - returns a structure with image information such as size, type, and the first 256 bytes of the image
GetSizeInHiMetric() - takes a SIZE reference and returns height and width in HiMetric
GetSizeInPixels() - as above, but in Pixels
GetType() - returns the numeric image type, such as PICTYPE_BITMAP
Tests
These methods return a BOOL value indicating what type of image the IPicture contains.
IsNull() - m_pPix is null
IsBitmap() - image is a bitmap, GIF, or JPEG
IsMetafile() - image is a windows metafile
IsIcon() - image is an icon or cursor
IsEnhMetafile() - image is an enhanced metafile
Clipboard Helper Classes
WTLIPicture.h contains two classes that help when getting or setting clipboard images. CClipboardFormatDlg is a small dialog to prompt image type selection when more than one type is available on the clipboard. It supports bitmap, enhanced metafile, and windows metafile. CWTLIPictureClipboard provides the copy function for bitmap, icon (converted to bitmap), and both metafile types. It also provides the paste function for bitmap and both types of metafiles.
Semi-standard Structures
WTLIPicture.h provides a set of semi-standardized structures, similar to BITMAPFILEHEADER and BITMAPINFOHEADER. Structures are provided for cursors and icons, jpegs, and enhanced and windows metafiles. The intent of these structures is to provide access to commonly referenced values contained in image file headers. For example, here is the definition of METAFILEHEADER for windows metafiles.
#include < pshpack2.h >
typedef struct tagMETAFILEHEADER {
DWORD mfKey; WORD mfHandle; WORD mfLeft; WORD mfTop; WORD mfRight; WORD mfBottom; WORD mfInch; DWORD mfReserved; WORD mfChecksum; } METAFILEHEADER, FAR *LPMETAFILEHEADER;
#include < poppack.h >
The include files pshpack2.h and poppack.h are required to byte align the structure because it does not end on a four byte boundary.
Known Issues
- PNG images are not supported as
IPicture doesn't support PNG
- EMF images that are copied to the clipboard and pasted back in WMF format are misaligned
SaveToDispatch() may cause a system crash with large images (> 5 MB)
- Slight flickering may occur when a zoomed image is scrolled
Acknowledgements
The CWTLIPictureT template class is a WTL port and extension of CPictureHolder from the Microsoft Foundation Class library. The WTLIPictureViewer application is based on the BmpView sample application distributed with the Windows Template Library.
Terms Of Use
The sample application available with this article is free but is subject to any restrictions placed on the original BmpView sample application and CPictureHolder. The source code provided in WTLIPicture.h is free to use for any purpose as long as CPOL requirements are observed.
THIS SOFTWARE IS DISTRIBUTED AS-IS, WITHOUT WARRANTIES OF ANY KIND.