Click here to Skip to main content
15,886,513 members
Articles / Desktop Programming / MFC

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

Rate me:
Please Sign up or sign in to vote.
3.22/5 (40 votes)
1 Dec 20021 min read 198.1K   9   53  
A simple yet powerful library to display an image in a window.
#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
		HPALETTE hPal = NULL,hPalOld=NULL,hPalMemOld=NULL;
		hr = Ipic->lpVtbl->get_hPal(Ipic,&hPal);

		if (!SUCCEEDED(hr))
			return;
		if (hPal != NULL)
		{
			hPalOld = SelectPalette(pDC,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 != NULL)
			{
				hPalMemOld = SelectPalette(MemDC,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(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));
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

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


Written By
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