How to use IMGDECMP.DLL in WindowsCE.
Disclaimer:
This information is provided as is. This API may change at some future date. This API is
not officially documented by Microsoft at this time. However, current indications are it will not be
changing soon.
The sample applications are restricted in as much as you may not distribute them as
commercial applications. You may create 'significant' derivations as distribute them. No warranty
is given or implied.
What is it?
IMGDECMP.DLL is a WindowsCE specific DLL which enables CE applications, such as
PIE, to read graphics file of several types. It supports the reading of Bitmaps (.BMP and .2BP),
GIF, JPEG, and XBM image types. [ Note: I have not verified its use on .XBM files ]
It does this using a single API call in the DLL. This API then uses two (2) user defined Callback
functions to do the work of:
1. Reading the data from a stream
2. Indicating what is to be done with the data when done reading.
The advantage to using this DLL is size and speed of your native application, since the
DLL is already in ROM. The DLL does not provide any custom palette options or unique dithering
API's however. What you get is what you get. Another advantage of the DLL is that it has
provisions to know about 'Cookie's' that are used by HTMLview.DLL for use in rendering Images
in the HTMLview control.
Where is it?
It is located in the /Windows directory of WindowsCE devices and the emulator's.
How to setup to use it?
It is assumed that you have a working development environment for WindowCE installed
already. Then to use the DLL you must have the include files (.h) and the library files (.lib),
installed in the correct directories. The following files should be in the *.zip file that included this
README file.
Include.zip - This is a zip file, which contains
Imgdecmp.h - This is the include file for IMGDECMP.DLL
Imgrendr.h - This is the render interface file. Imgdecmp.h includes it
Lib.zip - This is a zip file that contains
Imgdecmp.lib 's - These are the .lib files for MIPS, sh, and emulation. These will need to
be copied to the correct lib directories of you WindowsCE SDK folder. They have the extensions
MIPS and SHx for their respective processor types.
Sample1.zip - This is a very simple sample that demonstrates how to read an image and paint it
in a window
Sample2.zip - This is a slightly more complex example that demonstrates the use of the
IMGDECMP.DLL in a WebBrowser setting. This browser only reads the top level URL's and does
not respond to hotspot messages. Parts of this sample were derived from the INETALL sample
on MSDN.
Detailed explanations of the samples are provided at the end of this document.
Quick Steps:
The simple and quick steps to get this working in your own application are:
1. Copy the files to the appropriate locations
2. Include the correct .lib file in your project settings
3. Include the .h files in your .c/.cpp files
4. Fill in the 'DecompressImageInfo' structure
5. Create two callback functions
6. Call DecompressImageIndirect
Detailed Steps:
1. Copy the files to the appropriate locations
You need to copy the files (imgdecmp.h and imgrendr.h) to the general include directory for
your WindowsCE application development environment. For example, the location of this
might be:
/Windows CE SDK/wce/include/{Device}
These two include files are used by all WindowsCE platforms which support
IMGDECMP.DLL. The first file 'imgdecmp.h' is the include file to include in your application.
It will by default include the 'imgrendr.h' file.
Next you need to copy the library files (imgdecmp.lib) to the general library directory for your
WindowsCE application development environment. This must be done for each processor
type. For example, the location of this might be:
/Windows CE SDK/wce/lib/wce200/{Device}/{wcemips or wcesh or x86em}
The 'lib' files are named with a MIPS or SH appended, to indicate which lib directory to place
them in. The 'lib' file that does not have an appended name is used in the x86 emulator.
Once you have copied them to the correct directories, remember to rename them to
imgdecmp.lib. This is so you won't need to have multiple differing names in your project
settings/ link lib's field.
2. Include the correct .lib file in your project settings
In your project you will need to go to the Project/Settings/Link {TAB}/Object Library Modules
field and type in the 'imgdecmp.lib' name for your project.
3. Include the .h files in your .c/.cpp files
Include the .h files in your project, like this.
#include <imgdecmp.h>
4. Fill in the 'DecompressImageInfo' structure which is found in the imgdecmp.h file.
typedef struct tagDecompressImageInfo {
DWORD dwSize; // Size of this structure
LPBYTE pbBuffer; // Pointer to the buffer to use for data
DWORD dwBufferMax; // Size of the buffer
DWORD dwBufferCurrent; // The amount of data which is current in the buffer
HBITMAP * phBM; // Pointer to the bitmap returned (can be NULL)
IImageRender ** ppImageRender; // Pointer to an IImageRender object (can be NULL)
int iBitDepth; // Bit depth of the output image
LPARAM lParam; // User parameter for callback functions
HDC hdc; // HDC to use for retrieving palettes
int iScale; // Scale factor (1 - 100)
int iMaxWidth; // Maximum width of the output image
int iMaxHeight; // Maxumum height of the output image
GETDATAFUNC pfnGetData; // Callback function to get more data
PROGRESSFUNC pfnImageProgress; // Callback function to notify caller
//of progress decoding the image
COLORREF crTransparentOverride; // If this color is not (UINT)-1, it will override the
// transparent color in the image with this color.
//(GIF ONLY)
} DecompressImageInfo;
The important elements of this structure are:
LPBYTE pbBuffer; // Pointer to the buffer to use for data
DWORD dwBufferMax; // Size of the buffer
This is a pointer to a Buffer that you have allocated. This buffer is used to hold the data stream
as it is being read. It is important to note that if this buffer is to small it will not decode the
graphics correctly. I have found it to work best with a 4K buffer or better, if I am reading graphics
from a URL or the Web.
HBITMAP * phBM; // Pointer to the bitmap returned (can be NULL)
This will contain a pointer to the resultant bitmap that is created when the image decompression
is complete. This is quite handy if you are just reading from a file. You can set it to NULL if you
don't want to use this pointer.
IImageRender ** ppImageRender; // Pointer to an IImageRender object (can be NULL)
I haven't done enough work with this to comment on it. Just set it to NULL.
int iBitDepth; // Bit depth of the output image
This is a setting indicating the bit depth of the device or the image you want returned. For
example, if you are on a 4-bit screen, set it to 4. However, you are probably better off just setting
it with a call to GetDeviceCaps with the BITSPIXEL flag as demonstrated in the first sample.
LPARAM lParam; // User parameter for callback functions
This parameter allows you to pass any type of information to the callback functions. Use it to
pass in an Image structure as shown in sample 2 or a simple HANDLE to a file as shown in
sample 1.
HDC hdc; // HDC to use for retrieving palettes
This device context is used to determine the palette of the device it is decoding for. Remember
to release the HDC when you are done with it.
int iScale; // Scale factor (1 - 100)
This is a scale factor for decoding the image. Use something between 1 (representing 1 percent)
to 100 (representing 100 percent). The IMGDECMP.DLL will read the bit data of the image and
decimate (i.e. it appears to really just skip intervening bits) the image and reduce in size. The
resultant image is then returned at this reduced size. It is open to debate about which will return
a better-looking image IMGDECMP with a scale factor or StretchBlt.
int iMaxWidth; // Maximum width of the output image
int iMaxHeight; // Maxumum height of the output image
This is the maximum width and height of an image that you want returned. The image will be
chopped at these values if it is bigger that them.
GETDATAFUNC pfnGetData; // Callback function to get more data
PROGRESSFUNC pfnImageProgress; // Callback function to notify caller
//of progress decoding the image
These are two call back functions that do the meat of the work. The first call back to define is the
pfnGetData function. The function reads data from a stream and provides the data back to the
IMGDECMP function. You can read data from just about anywhere that you have a semi-
continuous stream. Files, the net, IR, Serial, etc?
The second function, pfnImageProgress is called to provide your application with a status about
the progress in reading and decoding the data stream. A flag (bComplete) which is passed in this
function indicates the completion of the decoding process.
COLORREF crTransparentOverride; // If this color is not (UINT)-1, it will override the
// transparent color in the image with this color.
(GIF ONLY)
This value allows you to change the transparency color on a GIF image. If you don't indicate a
transparency color the color of the top left pixel is used. Using this technique you could get a
solid square image with a circular transparent hole in it, by using the color of the circle as the
transparency color.
5. Create the two callback functions
These callback functions are pfnGetData and pfnImageProgress.
The pfnGetData function has the form:
static DWORD CALLBACK GetImageData( LPSTR szBuffer, DWORD dwBufferMax, LPARAM lParam )
Basically you want to read bytes of data into the szBuffer in this function and return the number
of bytes read. Refer to the samples for more details.
The pfnImageProgress function has the form:
static void CALLBACK ImageProgress( IImageRender *pRender, BOOL bComplete, LPARAM lParam )
This function will pass in information about the ImageRender interface status (refer to the file
imgrendr.h if you want more information), whether the decoding is complete, and any other data
in the lparam.
Looking at the samples is the easiest way to explain these two functions.
6. Call DecompressImageIndirect
Decide where you want to call the DecompressImageIndirect() API to read the file data and then
call it.
If you want to know the size of the resulting BITMAP before you have completely decoded it and
you are implementing progressive download supplying data to the decoder (i.e. you are
supplying a pfnGetData function and a pfnImageProgress callback) You can do a GetObject on
the HBITMAP in the first call to pfnImageProgress. This will give you a BITMAP structure with
the bitmap characteristics. Then, if you decide that you don't want to continue, return 0 from the
next call to pfnGetData from IMGDECMP.
Summary:
In conclusion, the IMGDECMP.DLL library is a powerful API for use in reading raster images and
displaying them in WindowsCE applications.
Sample Code:
1. SAMPLE1.zip - Getting the graphic from a file
This sample illustrates how to read an image from a file and display it. The items of interest are
indicated with the word 'Step' in the comment line.
///*-------------------------------------------------------------------*/
Module: PalmImgDecmp1.cpp
Abstract: The PalmImgDecmp1 sample
/*-------------------------------------------------------------------*/
?
//Step 1. Copy the files to the appropriate locations
//Step 2. Include the correct .lib file in your project settings
//Step 3. Include the .h files in your .c/.cpp files (such as 'imgdecmp.h')
#include <imgdecmp.h>
?
HBITMAP g_hDestBitmap = NULL; //Has the global Bitmap handle
HDC g_hdcMem = NULL; //A global compatible HDC
?
BOOL GetPictureFromFile(HWND ); //Uses the OpenFile dialog to get filename
BOOL ReadPictureFile(HWND , LPTSTR ); //Does the work
?
static DWORD CALLBACK GetImageData( LPSTR , DWORD , LPARAM ); //Callback for reading data
static void CALLBACK ImageProgress( IImageRender *, BOOL , LPARAM ); //Callback for
completion
//------------------------------------------------------
// Local Functions
//------------------------------------------------------
BOOL GetPictureFromFile(HWND hwnd)
{
?
//Read the file
if (!ReadPictureFile( hwnd, szFilenameW))
return FALSE;
//Select the bitmap into the memory device context
SelectObject(g_hdcMem,g_hDestBitmap);
//Invalidate the window to update it
InvalidateRect(hwnd, NULL, TRUE);
return TRUE;
}
// === ReadPictureFile ==============================================
BOOL ReadPictureFile(HWND hwnd, LPTSTR szFilenameW)
{
HRESULT hr;
BYTE szBuffer[1024] = {0};
HANDLE hFile = INVALID_HANDLE_VALUE;
DecompressImageInfo dii;
HDC hdc;
//Open the file for reading
hFile = CreateFile(szFilenameW , GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
hdc = GetDC(hwnd); //Get the device context
//Step 4: Fill in the 'DecompressImageInfo' structure
dii.dwSize = sizeof( DecompressImageInfo ); // Size of this structure
dii.pbBuffer = szBuffer; // Pointer to the buffer to use for data
dii.dwBufferMax = 1024;// Size of the buffer
dii.dwBufferCurrent = 0; // The amount of data which is current in the buffer
dii.phBM = &g_hDestBitmap; // Pointer to the bitmap returned (can be NULL)
dii.ppImageRender = NULL; // Pointer to an IImageRender object (can be NULL)
dii.iBitDepth = GetDeviceCaps(hdc,BITSPIXEL);// Bit depth of the output image
dii.lParam = ( LPARAM ) hFile; // User parameter for callback functions
dii.hdc = hdc; // HDC to use for retrieving palettes
dii.iScale = g_iScale; // Scale factor (1 - 100)
dii.iMaxWidth = g_iMaxWidth; // Maximum width of the output image
dii.iMaxHeight = g_iMaxHeight; // Maxumum height of the output image
dii.pfnGetData = GetImageData; // Callback function to get image data
dii.pfnImageProgress = ImageProgress; // Callback function to notify caller of
progress decoding the image
dii.crTransparentOverride = ( UINT ) -1; // If this color is not (UINT)-1, it
will override the
// transparent color in the image with this color. (GIF ONLY)
//Step 6: Call DecompressImageIndirect
hr = DecompressImageIndirect( &dii );
// Clean up
CloseHandle( hFile );
ReleaseDC(hwnd, hdc);
return TRUE;
}
//Step 5: Create the Callback functions
//---------------------------------------------------------------------
// GetImageData
//---------------------------------------------------------------------
static DWORD CALLBACK GetImageData( LPSTR szBuffer, DWORD dwBufferMax, LPARAM lParam )
{
DWORD dwNumberOfBytesRead;
if ( (HANDLE)lParam != INVALID_HANDLE_VALUE )
{
//graphics file
ReadFile( (HANDLE)lParam, szBuffer, dwBufferMax, &dwNumberOfBytesRead, NULL );
}
else
{
return 0;
}
return dwNumberOfBytesRead;
// return amount read
}
//---------------------------------------------------------------------
// ImageProgress
//---------------------------------------------------------------------
static void CALLBACK ImageProgress( IImageRender *pRender, BOOL bComplete, LPARAM lParam )
{
if( bComplete )
{
;//Do whatever when done processing the image
}
}
?
2. Using the graphic in HTMLview
This sample illustrates how to read an image from the Internet and display it in the HTMLview
control. The items of interest are indicated with the word 'Step' in the comment line. The
HTMLview control is created on a dialog using a dialog template in the project. This sample is
not a complete Web Browser. Another interesting item in this sample is the use of the Proxy
setting in WindowsCE, which are not in the same location in the registry as the proxy settings in
Windows 95/98/NT.
Remember WindowsCE does not do CERN type proxies. [Note: This example does work with my
MSProxyServer, WinGate, WinProxy, and others however. Provided the 'host' information is
correct in the registry of the device. Refer to the HostNameEdit application for more information.]
?
//------------------------------------------------------
// Local Functions
//------------------------------------------------------
static DWORD CALLBACK GetImageData( LPSTR szBuffer, DWORD dwBufferMax, LPARAM lParam )
{
DWORD dwNumberOfBytesRead;
ImageDataHandler *ImageHandler = (ImageDataHandler *)lParam;
This opens the connection to the internet and reads the data stream from the internet. This
should only be done once. It could also be done before calling the API. [Note: The sample does
not show the correct behaviour. ]
if (ImageHandler->hInternetFile == INVALID_HANDLE_VALUE )
{
ImageHandler->hInternetFile = (HINTERNET)InternetOpenUrl(hHTTPInternetSession,
(LPTSTR)ImageHandler->lpFileName,NULL, 0, INTERNET_FLAG_RELOAD |
INTERNET_FLAG_DONT_CACHE, 0);
}
if (ImageHandler->hInternetFile == INVALID_HANDLE_VALUE )
return 0;
if ( ImageHandler->hInternetFile != INVALID_HANDLE_VALUE )
{
//graphics file
InternetReadFile((HINTERNET)ImageHandler->hInternetFile, szBuffer, dwBufferMax,
&dwNumberOfBytesRead);
} else {
If it couldn't read the file from the net it tells the HTMLview control to put up the broken image
bitmap.
SendMessage(g_InetHTTP.hwndHTML, DTM_IMAGEFAIL, 0, (LPARAM) ImageHandler-
>pdwCookie);
if ( ImageHandler->hInternetFile != INVALID_HANDLE_VALUE ) InternetCloseHandle(
(HINTERNET)ImageHandler->hInternetFile );
ImageHandler->hInternetFile = INVALID_HANDLE_VALUE;
return 0;
}
// return amount read
return dwNumberOfBytesRead;
}
When it has finished reading the file send it to the htmlview control.
static void CALLBACK ImageProgress( IImageRender *pRender, BOOL bComplete, LPARAM lParam )
{
INLINEIMAGEINFO iii;
ImageDataHandler *ImageHandler = ( ImageDataHandler * )lParam;
If the decoding is complete then take ownership of the Bitmap. This tells the IMGDECMP.DLL
that you are going to keep the bitmap and send the handle on to the HTMLview control.
if( bComplete )
{
iii.dwCookie = ( WPARAM )ImageHandler->pdwCookie;
pRender->GetBitmap(&iii.hbm, TRUE);
pRender->GetOrigHeight(&iii.iOrigHeight);
pRender->GetOrigWidth(&iii.iOrigWidth);
// Take ownership of the hBitmap
iii.bOwnBitmap = TRUE;
if ( iii.hbm )
{
SendMessage(g_InetHTTP.hwndHTML, DTM_SETIMAGE, 0, LPARAM( &iii ));
}
InternetCloseHandle((HINTERNET)ImageHandler->hInternetFile);
}
}
?
//------------------------------------------------------
// SCR1DlgProc(HWND, WORD, WORD, LONG)
// IDD_SCR1
//------------------------------------------------------
LRESULT CALLBACK SCR1DlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
LRESULT lResult = TRUE;
switch(msg)
{
?
case WM_NOTIFY:
These are the notification for the HTMLview control.
if (wp == IDD_DISPLAY_HTML)
{
NM_HTMLVIEW * pnmHTML = (NM_HTMLVIEW *) lp;
LPNMHDR pnmh = (LPNMHDR) &(pnmHTML->hdr);
switch(pnmh->code)
{
// User tapped on a link or submitted a form
case NM_HOTSPOT:
;//Code goes here to react to hotspots
break;
This notification show the HTMLview control that you have an image for it to display. Remember
that if the cookie value is incorrect the image will not get displayed. The cookie value is used by
the HTMLview control as a placeholder in the rendering plane for the image. The image is then
added with the WM_ADDIMAGE message.
case NM_INLINE_IMAGE:
LPSTR lpImageFile;
lpImageFile = (LPSTR)MyAllocMem(strlen(pnmHTML->szTarget) + 1);
if ( lpImageFile )
{
strcpy(lpImageFile, pnmHTML->szTarget);
PostMessage(hwnd, WM_ADDIMAGE, pnmHTML->dwCookie , (LPARAM) lpImageFile);
} else {
SendMessage(g_InetHTTP.hwndHTML, DTM_IMAGEFAIL, 0, (LPARAM) pnmHTML->dwCookie);
}
break;
case WM_ADDIMAGE:
//Add Gif and Jpeg recognizer here
{
LPTSTR lpTarget = NULL;
LPSTR lpImageFile = (LPSTR) lp;
LPSTR lpTemp = NULL;
HDC hdc;
if ( lp )
{
?
This sets up the data structure to get the image data, given a image URL.
imgData = (ImageDataHandler *)MyAllocMem(sizeof(ImageDataHandler));
imgData->lpFileName = MyAllocMem(sizeof( TCHAR ) * ( lstrlen(( LPTSTR ) lpTarget )
+ 1 ));
wsprintf(( LPTSTR ) imgData->lpFileName, TEXT( "%s" ), ( LPTSTR )lpTarget );
MyFreeMem(lpTarget);
// Save DecompressImageInfo for passing around
imgData->pdwCookie = ( LPVOID )wp;
hdc = GetDC(hwnd);
dii.dwSize = sizeof( DecompressImageInfo );
dii.pbBuffer = pszBuffer;
dii.dwBufferMax = 8192;
dii.dwBufferCurrent = 0;
dii.phBM = NULL;
dii.ppImageRender = NULL;
dii.iBitDepth = 2;
This BitDepth is for the Palm-size PC. Change it for your needs.
dii.lParam = ( LPARAM ) imgData;
dii.hdc = hdc;
dii.iScale = 100;
dii.iMaxWidth = 1024;
dii.iMaxHeight = 1024;
dii.pfnGetData = GetImageData;
dii.pfnImageProgress = ImageProgress;
dii.crTransparentOverride = ( UINT ) -1;
hr = DecompressImageIndirect( &dii );