Creating an effective image viewer in Windows CE

Published on November 19, 2009

There are some cases where we may need to develop a DLL or application to show the images on the devices. For example, an Image viewer will be needed to show the picture after taking a snap shot from the camera using a direct show camera application. Windows Mobile supports the image viewer for this purpose, However if you are developing a custom camera application in Windows CE/Windows Mobile, you have to show the captured image with a custom developed image viewer. There you may need additional image manipulation functionality like zooming, rotation and cropping etc. Unfortunately Windows CE 6.0 doesn’t have an image viewer application at all. But Windows CE supports Imaging APIs to handle the various file types like JPG, BMP, TIFF and GIF etc…

Effective way of handing the JPEG images on Image viewer

Imaging APIs are accessed through COM interfaces. To Load the image you have to use IImagingFactory Interface with the class ID CLSID_ImagingFactory. Following code snippet show the procedure to load the imaging COM interfaces.

CoCreateInstance (CLSID_ImagingFactory, NULL,CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void **)&m_pImgFactory). The m_pImgFactory is the pointer to the IImagingFactory.

Opening an image file

Use the IImagingFactory ::CreateImageFromFile(const WCHAR* filename, IImage** image) to open the file.

Simple way to draw the Image on the Screen

We can use the IImage :: Draw( HDC hdc, const RECT* dstRect,OPTIONAL const RECT* srcRect) to draw the image on the screen with the required dstRect size. But when our application Menu area may over write some part of the image, we may need to redraw the image in WM_PAINT on our window proc. IImage::Draw() function will decode the image and draw every time, while calling the function. This makes your application slow, while clicking the Menu.

To avoid this, we can use the Image::SetImageFlags(ImageFlagsCaching) to cache the bitmap area and to reuse it for the next time. The disadvantage is, IImage::Draw() may fail because of  insufficient memory to cache the higher Mega Pixel files. This will happen in Windows Mobile (virtual memory limitations for each process). So we need to find the alternate solution, that should be effectively handling the memory and to maintain the performance.

Effective way to draw the image on the screen

The Effective way is, creating the bitmap for the exact required screen size once and uses it for several times. Following are the steps to create and draw the bitmap.

  • Passing IImage interface to IImagingFactory::CreateBitmapFromImage(IImage* image, OPTIONAL UINT width, OPTIONAL UINT height, OPTIONAL PixelFormatID pixelFormat,  InterpolationHint hints, IBitmapImage** bitmap) will provide IBitmapImage. We can create the bitmap to the required size. (ie) your required screen size. It will consume memory only to the width, height and the required pixelFormat . Using this you can show higher Mega pixels images.
  • Using this IBitmapImage::LockBits(const RECT*rect,UINT  flags,  PixelFormatID pixelFormat, BitmapData*   lockedBitmapData) we can get the BitmapData class, containing the width, height, scan0 ( bitmap area starting address) and other necessary data. Release the bitmap area by calling IBitmapImage::UnlockBits function.
  • Using this BitmapData information, we can create the BITMAPINFO structure as follows:

m_pBitMapInfo =(BITMAPINFO*) new char[sizeof(BITMAPINFO)+ 4];


m_pBitMapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

m_pBitMapInfo->bmiHeader.biWidth = m_Bitmapdata.Width;

m_pBitMapInfo->bmiHeader.biHeight = -(LONG)m_Bitmapdata.Height;

m_pBitMapInfo->bmiHeader.biPlanes = 1;

m_pBitMapInfo->bmiHeader.biBitCount = 16;

m_pBitMapInfo->bmiHeader.biCompression = BI_BITFIELDS;

m_pBitMapInfo->bmiHeader.biSizeImage = m_Bitmapdata.Width*m_Bitmapdata.Height;

m_pBitMapInfo->bmiHeader.biClrImportant = 0;

m_pBitMapInfo->bmiHeader.biClrUsed = 1;

unsigned long *ptr = (unsigned long *)(m_pBitMapInfo->bmiColors);

ptr[0] = 0xf800;

ptr[1] = 0x07e0;

ptr[2] = 0x001f;

  • Passing the BITMAPINFO with BitmapData::scan0 to StretchDIBits function to draw the image. Since we have the bitmap data, we can simply redraw during the WM_PAINT without any image decoding process. It will avoid the unnecessary overhead of the application.
  • For zooming and panning process, we can simply create the bitmap for the necessary size and we can show the part of the image, also moving and showing the image seamlessly with above described APIs.

Recently Published