Environment: Windows 98/NT
Introduction
This article grew out of my dissatisfaction with the "Copy a DIB to a JPEG File" article I wrote a few years ago. The code presented in that article had a few errors, and was not well formatted on the web page, due to my inexperience in posting articles.
(continued)
The main problem with the article was that it required users to download and build the libJPEG project from the Independent JPEG Group. This project is very tricky to build and use, and has led to a steady stream of "Help me!" e-mails.
The obvious solution was to build a component. This component would allow a generalized way to create a JPEG file from the contents of a view window. Once built, users would not have to worry about building their own copy of jpeg.lib.
Thus ImageHandler was born.
Acknowledgements
Imagehandler could not have been written without much existing code from other sources:
- Zafir Anjum and other CodeGuru adminiatrators and contributors
- The Independent JPEG Group for creating libJPEG and making it available for use
- Jeff Prosise's excellent book Programming Windows 95 with MFC.
- Jeff Prosise and his excellent book Programming Windows 95 with MFC.
- Jonathan Bates's very instructive book Creating Lightweight Components with ATL*
(*Although, since ImageHandler shamelessly uses MFC, it might not be what Bates would consider "lightweight".)
Paintlib (libJPEG)
ImageHandler uses the 6b of 27-Mar-1998 version of libJPEG.
This article does not include libJPEG or the jpeg.lib library file. If you wish to modify the ImageHandler project to create more interfaces, you will need to get the latest version of libJPEG from the paintlib web site and build it to create your own jpeg.lib.
Building jpeg.lib is not a trivial process (which is what led to me creating this component in the first place). However, many other developers have done so successfully. If you have questions about paintlib itself or problems building it, please direct your inquiries to the paintlib authors.
When I built jpeg.lib I followed this process:
- I downloaded libJPEG and de-compressed it
- I read the Windows sections of the build instructions
- I tried to build the project and watched the build fail
- I re-read the build instructions carefully
- I made corrections, rebuilt the libJPEG project, and it has worked ever since
The ImageHandler Component
ImageHandler was built as an ATL in-process server. It uses MFC as a static library; you will not need MFC on your machine to run ImageHandler. It is about 164 KB in size (abbout 100 KB of this is due to static linkage of MFC).
ImageHandler has one interface class, IRectToJpeg. IRectToJpeg exposes one one interface, HdcToJpeg. The picture below shows the interface class as it appears
in the project workspace:
Click here for larger image
Registering the Component
To register the component, first download and unzip the "executables" self-extracting archive below. This file contains a copy of regsvr32.exe, and a bat file (RegTheDll.bat) which executes regsvr32.exe against ImageHandler.dll to register it.
Imagehandler will not be useable until you run the bat file and register it on your machine.
The HdcToJpg() Interface
HdcToJpg() is defined as follows:
virtual HRESULT STDMETHODCALLTYPE HdcToJpeg(
long lngHDC,
int nTLX,
int nTLY,
int nBRX,
int nBRY,
int nQuality,
BSTR bstrPath,
BSTR __RPC_FAR *pbstrMsg,
long __RPC_FAR *lngResult) = 0;
|
The coordinates may be positive or negative. They should be in Logical units appropriate to the mapping mode of the HDC.
The quality factor must be in the range 1-100.
HdcToJpg() will return a message to the caller, unless pbstrMsg is set to NULL.
HdcToJpg() may return these messages:
- HDC is invalid:
The HDC parameter was NULL.
- nQuality value is invalid (must be 1-100):
The quality value was out of range.
- JPEG file path is empty:
The path value was empty.
- Could not create CBitmap from rectangle:
Additional string at end of one of the other error messages.
- Could not create JPEG from CBitmap:
Additional string at end of one of the other error messages.
- <file> created OK:
The JPEG file was created, no errors detected.
- Could not get internal bitmap data:
HdcToJpg() was unable to create
internal bitmap information. This could be because the HDC is invalid, or because
there was not enough memory available.
- Could not create internal bitmap data:
Same meaning as above.
- Could not create DIB from DDB:
HdcToJpg() probably could not get enough memory
to turn its internal DDB into a DIB.
- Failed to create compatible dc:
CreateCompatibleDC() failed when creating the required memory DC.
This is probably due to the rectangle being too large.
- Failed to create compatible bitmap:
CreateCompatibleBitmap() failed when creating the required memory DC.
This is probably because the rectangle is too big.
- Failed to do bitblt into memory DC:
The StretchBlt() call to copy into the memory DC failed.
Return Values:
HdcToJpg() returns a result of either S_OK (0) or S_FALSE (1).
Sanity Checking:
HdcToJpg() does some basic sanity checks on the input parameters, such as making sure pointers are not NULL.
However, it does not check the rectangle coordinates. It is the caller's responsibility to make sure they make sense for the Device Context in question.
It does not check the path, other than to make sure that it is not empty. It is the callers's responsibility to make sure the pathname and file name are correct, and that the correct file extension is present (usually .jpg).
Creating the ImageHandler Interface using the Type Library
When I created the client project (the C++ driver whose snippet code appears below) I decided to do it the easy (lazy) way, and use the Imagehandler type library. This file is included in the executables download as Imagehandler.tlb.
To create the automation class IRectToJpeg:
- Open Class Wizard
- Click on the "Automation" tab.
- Click on the "Add Class..." button and pick the "From a type library..." option.
- In the "Import from Type Library" dialog,
navigate to the ImageHandler.tlb file and choose it.
- In the "Confirm Classes" dialog, just keep the defaults given.