Click here to Skip to main content
Click here to Skip to main content

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

By , 1 Dec 2002
 

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));
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Jacob Navia
Web Developer
France France
I am the author of the lcc-win32 C compiler system. http://www.cs.virginia.edu/~lcc-win32

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membermanoj kumar choubey26-Feb-12 20:56 
GeneralMy vote of 5memberRaghavan145-Jan-12 6:27 
GeneralMy vote of 3memberMarcus Elliott13-Oct-10 0:45 
GeneralI need helpmemberGbenbam6-Aug-10 2:43 
I am new to windows programming and I am developing, at the moment my first windows application and I have the following concerns.
-how does one link a library to a project using microsoft VCC++ compiler.
-I tried using the display image example program shown below ,but it did not work at all.
What does the writer mean by coinnitialize().
The program has thee function CloseImage(), why the reference to CloseGraphic(),
 
The compiler complained that render() is not a member of IPicture.It also did not recognise lpVtbl. I really and urgently need assistance.
 
Is there some other simpler method of rendering images.
 
I hope to hear from someone soon.
 

 

 

 
#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));
}
GeneralLooks like a little bugmembermouseparty17-Feb-06 1:24 
GeneralRe: Looks like a little bugmembervictoryli14-Apr-08 10:12 
GeneralRelease VSsussAnonymous6-Feb-05 17:20 
GeneralRotating the imagememberAlex Evans4-Jan-05 9:24 
GeneralBinary sizememberMr.Prakash2-Mar-04 4:37 
General28 Kbmemberessersr11-Feb-04 9:31 
GeneralRe: 28 Kbmembervictoryli14-Apr-08 8:25 
GeneralPlease help me !sussAnonymous18-Oct-03 1:39 
QuestionRender ?memberlibrazone20-Jun-03 16:29 
AnswerRe: Render ?sussAnonymous24-Jun-03 21:55 
GeneralRe: Render ?memberkubicle7-Jan-05 20:21 
GeneralCode SizesussAnonymous8-Mar-03 23:39 
GeneralRe: Code SizememberKvasi30-Mar-03 5:37 
GeneralRe: Code SizesussAnonymous5-May-03 20:16 
GeneralRe: Code SizesussAnonymous19-Mar-05 4:35 
Generalneither simple nor powerfulsussAnonymous3-Dec-02 13:16 
GeneralRe: neither simple nor powerfulmemberJacob Navia5-Dec-02 3:11 
GeneralRe: neither simple nor powerfulmemberRufus V. Smith5-Aug-03 6:45 
General170K? no waysussAnonymous2-Dec-02 20:55 
GeneralBad newssussAnonymous2-Dec-02 19:09 
GeneralRe: Bad newsmemberTarmo2-Dec-02 20:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130617.1 | Last Updated 2 Dec 2002
Article Copyright 2002 by Jacob Navia
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid