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






3.22/5 (40 votes)
Dec 2, 2002
1 min read

202424

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:
- You tell it the name of the graphic file
HANDLE h = OpenGraphic(char *filename);
That handle is used for closing the image.
- When painting your window, you pass it the
hwnd
and thehDC
you get fromBeginPaint
.DisplayGraphic(HWND hwnd,HDC hdc);
- 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)); }