Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 1 Dec 2002
Rate this:
Please Sign up or sign in to vote.
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));
}

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

Share

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

Comments and Discussions

 
GeneralMy vote of 5 - demonstrates use of non-Microsoft tools PinmemberEdCaputo19-Jun-14 23:10 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 20:56 
GeneralMy vote of 5 PinmemberRaghavan145-Jan-12 6:27 
GeneralMy vote of 3 PinmemberMarcus Elliott13-Oct-10 0:45 
GeneralI need help PinmemberGbenbam6-Aug-10 2:43 
GeneralLooks like a little bug Pinmembermouseparty17-Feb-06 1:24 
GeneralRe: Looks like a little bug Pinmembervictoryli14-Apr-08 10:12 
GeneralRelease VS PinsussAnonymous6-Feb-05 17:20 
GeneralRotating the image PinmemberAlex Evans4-Jan-05 9:24 
GeneralBinary size PinmemberMr.Prakash2-Mar-04 4:37 
General28 Kb Pinmemberessersr11-Feb-04 9:31 
GeneralRe: 28 Kb Pinmembervictoryli14-Apr-08 8:25 
GeneralPlease help me ! PinsussAnonymous18-Oct-03 1:39 
QuestionRender ? Pinmemberlibrazone20-Jun-03 16:29 
AnswerRe: Render ? PinsussAnonymous24-Jun-03 21:55 
GeneralRe: Render ? Pinmemberkubicle7-Jan-05 20:21 
GeneralCode Size PinsussAnonymous8-Mar-03 23:39 
GeneralRe: Code Size PinmemberKvasi30-Mar-03 5:37 
GeneralRe: Code Size PinsussAnonymous5-May-03 20:16 
GeneralRe: Code Size PinsussAnonymous19-Mar-05 4:35 
really to hell with VC and .NET architecture,
 
LCC, and GCC rock, who the hell needs the stupid additional dozzens of code generated by dumb head VC. Every developer tries to have minimal binaries so that they are easily distributable.
 
You write what you think, but do not care about the effort of the person who is giving you a free source, if it is not useful to you and you cant write two words of appreciation, then goto hell and dont join the discussion thread.
 
Author has done a great job, and was tryign to differentiate between the minimum possible output of the final executable. Did he force you to download and/or discuss his resources ?Mad | :mad:
 
Quoting everything comes to your stupid brain, and then saying "I hope you will use this message constructively to improve your programming skills." does not heal up the wounds Mad | :mad: . What do yo uknow abotu the strfucture of VC compiler, tell me streight, I would like to have debate on it 'WITH YOU'.
 
Now, when directX has also been made embedable with c++ applciations and made available opensource in the form of libraries and headers [so that developers dont have to ship the shared DLLs], you will come to say, this is not workign properly as Microsoft directX Dynamic Linked Libraries.
 

Few questions for you,
 
1.how many technologies you know, especially compilers ?
2.can you compile pure windows API source on Linux ??????I CAN.
3.Did you ever create a compiler or even an interpreter or IDE ?
 
I am sure all will be
1. No
2. No
3. No
 
Then why the heck you are criticizing a person who comes with a very good source? although he forgot to mention the platform compatibility.
 

btw nice job Mr.Author.
Generalneither simple nor powerful PinsussAnonymous3-Dec-02 13:16 
GeneralRe: neither simple nor powerful PinmemberJacob Navia5-Dec-02 3:11 
GeneralRe: neither simple nor powerful PinmemberRufus V. Smith5-Aug-03 6:45 
General170K? no way PinsussAnonymous2-Dec-02 20:55 
GeneralBad news PinsussAnonymous2-Dec-02 19:09 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 2 Dec 2002
Article Copyright 2002 by Jacob Navia
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid