65.9K
CodeProject is changing. Read more.
Home

Library to display an image (JPG/GIF/BMP) in 300 lines/8K of code

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.22/5 (40 votes)

Dec 2, 2002

1 min read

viewsIcon

202424

downloadIcon

9

A simple yet powerful library to display an image in a window.

Introduction

Here is a sample of what is possible to do with just plain C. This code will display in a window an image that can be in JPG, GIF, BMP, or Windows metafile format.

Compiled with the lcc-Win32 compiler, the code is just 8K. No other language gives you this kind of efficiency. A similar piece of code in C++ weights more than 170K!

The interface is like this:

  1. You tell it the name of the graphic file
    HANDLE h = OpenGraphic(char *filename);

    That handle is used for closing the image.

  2. When painting your window, you pass it the hwnd and the hDC you get from BeginPaint.
    DisplayGraphic(HWND hwnd,HDC hdc);
  3. When finished, you close it with.
    void CloseGraphic(HANDLE h);

Note that CoInitialize() must be called before using these functions.

I did not add "bells and whistles" to keep the code simple to understand. You may add scrollbars, redimensioning whatever.

This code was developed with the lcc-win32 C compiler. You can download it at no charge from here.

P.S.: This contribution was critized because I did not use Microsoft tools. I know I am biased, but I tried to correct my evil ways. I took the dust out of MSVC 6.0 and OK, here is it, complete with .dsw file in a standard Microsoft Project.

Other critics pointed out to a bug in the transcription, where I added a "*" too much. I fixed that, and I thank the people who pointed me that bug.

It is interesting to note that the code size of the program as compiled with MSVC is 32K, with lcc-win32 is just 8K.

Nobody is perfect...

#include "windows.h"
#include "ocidl.h"
#include "olectl.h"

typedef struct tagImgInfo {
  IPicture *Ipic;
  SIZE sizeInHiMetric;
  SIZE sizeInPix;
  char *Path;
} IMG_INFO;

static IMG_INFO ImageInfo;

void *OpenGraphic(char *name)
{
  IPicture *Ipic = NULL;
  SIZE sizeInHiMetric,sizeInPix;
  const int HIMETRIC_PER_INCH = 2540;
  HDC hDCScreen = GetDC(NULL);
  HRESULT hr;
  int nPixelsPerInchX = GetDeviceCaps(hDCScreen, LOGPIXELSX);
  int nPixelsPerInchY = GetDeviceCaps(hDCScreen, LOGPIXELSY);
  unsigned short OlePathName[512];

  ReleaseDC(NULL,hDCScreen);
  mbstowcs(OlePathName,name,strlen(name)+1);
  hr = OleLoadPicturePath(OlePathName,
        NULL,
        0,
        0,
        &IID_IPicture,
        (void *)(&Ipic));
  if (hr)
    return 0;
  if (Ipic) {
    // get width and height of picture
    hr = Ipic->lpVtbl->get_Width(Ipic,&sizeInHiMetric.cx);
    if (!SUCCEEDED(hr))
      goto err;
    Ipic->lpVtbl->get_Height(Ipic,&sizeInHiMetric.cy);
    if (!SUCCEEDED(hr))
      goto err;

    // convert himetric to pixels
    sizeInPix.cx = (nPixelsPerInchX * sizeInHiMetric.cx +
              HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH;
    sizeInPix.cy = (nPixelsPerInchY * sizeInHiMetric.cy +
              HIMETRIC_PER_INCH / 2) / HIMETRIC_PER_INCH;
    ImageInfo.sizeInPix = sizeInPix;
    ImageInfo.sizeInHiMetric = sizeInHiMetric;
    ImageInfo.Ipic = Ipic;
    ImageInfo.Path = name;
    return Ipic;

  }
err:
  return 0;
}
void DisplayGraphic(HWND hwnd,HDC pDC)
{
  IPicture *Ipic = ImageInfo.Ipic;
  DWORD dwAttr = 0;
  HBITMAP Bmp,BmpOld;
  RECT rc;
  HRESULT hr;
  HPALETTE pPalMemOld;

  if (Ipic != NULL)
  {
    // get palette
    OLE_HANDLE hPal = 0;
    HPALETTE hPalOld=NULL,hPalMemOld=NULL;
    hr = Ipic->lpVtbl->get_hPal(Ipic,&hPal);

    if (!SUCCEEDED(hr))
      return;
    if (hPal != 0)
    {
      hPalOld = SelectPalette(pDC,(HPALETTE)hPal,FALSE);
      RealizePalette(pDC);
    }

    // Fit the image to the size of the client area. Change this
    // For more sophisticated scaling
    GetClientRect(hwnd,&rc);
    // transparent?
    if (SUCCEEDED(Ipic->lpVtbl->get_Attributes(Ipic,&dwAttr)) ||
      (dwAttr & PICTURE_TRANSPARENT))
    {
      // use an off-screen DC to prevent flickering
      HDC MemDC = CreateCompatibleDC(pDC);
      Bmp = 
       CreateCompatibleBitmap(pDC,ImageInfo.sizeInPix.cx,ImageInfo.sizeInPix.cy);

      BmpOld = SelectObject(MemDC,Bmp);
      pPalMemOld = NULL;
      if (hPal != 0)
      {
        hPalMemOld = SelectPalette(MemDC,(HPALETTE)hPal, FALSE);
        RealizePalette(MemDC);
      }
/* Use this to show the left corner
      rc.left = rc.top = 0;
      rc.right = ImageInfo.sizeInPix.cx;
        rc.bottom = ImageInfo.sizeInPix.cy;
*/
      // display picture using IPicture::Render
      hr = Ipic->lpVtbl->Render(Ipic,MemDC,
      0,
      0,
      rc.right,
      rc.bottom,
      0,
      ImageInfo.sizeInHiMetric.cy,
      ImageInfo.sizeInHiMetric.cx,
      -ImageInfo.sizeInHiMetric.cy,
      &rc);

      BitBlt(pDC,0, 0, ImageInfo.sizeInPix.cx, 
                               ImageInfo.sizeInPix.cy,
        MemDC, 0, 0, SRCCOPY);

      SelectObject(MemDC,BmpOld);

      if (pPalMemOld)  SelectPalette(MemDC,pPalMemOld, FALSE);
      DeleteObject(Bmp);
      DeleteDC(MemDC);

    }
    else
    {
      // display picture using IPicture::Render
      Ipic->lpVtbl->Render(Ipic,pDC,
       0,
       0,
       rc.right,
       rc.bottom,
       0,
       ImageInfo.sizeInHiMetric.cy,
       ImageInfo.sizeInHiMetric.cx,
       -ImageInfo.sizeInHiMetric.cy,
       &rc);
    }

    if (hPalOld != NULL) SelectPalette(pDC,hPalOld, FALSE);
    if (hPal)  DeleteObject((HPALETTE)hPal);
  }
}

void CloseImage(void *Ipict)
{
  IPicture *ip = (IPicture *)Ipict;

  if (ip == NULL)
    ip = ImageInfo.Ipic;
  if (ip == NULL)
    return;
  ip->lpVtbl->Release(ip);
  memset(&ImageInfo,0,sizeof(ImageInfo));
}