I was looking for a simple way to do simple things, that is to display an image when processing a WM_PAINT message.
Immediateley I found it was not simple. The best (or the less bad) solution I found is GDI+ and the contribution of John Findlay helped a lot.
I implemented an image load function directly fom a file or from a resource file (setion RCDATA) and made it as simple as possible (sgi.c is 151 lines and sgi.h is 13 lines - no zip needed).
I tested successfully JPG and PNG files.
For BMP, EMF and TIF, it works only after loading from a resource file, I really wonder why.
Some idea, do anybody have?
sgi.h
typedef void* GP_GPIMAGE ;
/*-------- RETURN VALUES -------*/
int SGIinit(void) ; /* 0 if OK, <0 if error */
void SGIexit(void) ;
GP_GPIMAGE SGIimageLoad(char *filename) ; /* image handle, <0 if error */
void SGIimageUnload(GP_GPIMAGE image) ;
int SGIimageWidth(GP_GPIMAGE image) ; /* image's width, <0 if error */
int SGIimageHeight(GP_GPIMAGE image) ; /* image's height, <0 if error */
int SGIimageDraw(HDC hdc, RECT *rect, GP_GPIMAGE image) ; /* 0 if OK, <0 if error */
sgi.c
/*===================================================================================== sgi.c ==*/
/* Minimum implementation of GdiPlus that allows the loading and rendering of images */
/* cf. Microsoft GDI+ Flat API; J.Findlay http://www.johnfindlay.plus.com/pellesc/GdiPlus */
/* PNG and JPEG images can be loaded directly from a file or from a resource (RCDATA) */
/* BMP and EMF images can be loaded only from a resource (RCDATA) */
#include <windows.h>
#include <math.h>
#include "sgi.h"
/*========================================================================== INIT & EXIT GDI+ ==*/
typedef struct
{
UINT32 GdiplusVersion ;
void* DebugEventCallback ;
BOOL SuppressBackgroundThread ;
BOOL SuppressExternalCodecs ;
} GDIPLUSSTARTUPINPUT ;
typedef int _stdcall (*NotificationHookProc)(ULONG_PTR *token);
typedef VOID _stdcall (*NotificationUnhookProc)(ULONG_PTR token);
typedef struct
{
NotificationHookProc NotificationHook ;
NotificationUnhookProc NotificationUnhook ;
} GDIPLUSSTARTUPOUTPUT ;
int _stdcall GdiplusStartup(ULONG_PTR*, const GDIPLUSSTARTUPINPUT*, GDIPLUSSTARTUPOUTPUT*) ;
VOID _stdcall GdiplusShutdown(ULONG_PTR) ;
static ULONG_PTR gdiplusToken ;
/*----------------------------------------------------------------------------------------------*/
int SGIinit(void)
{
GDIPLUSSTARTUPINPUT gdiplusStartupInput = { 1, NULL, FALSE, FALSE } ; /* no option! */
int st = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
return - st ; /* resturn value is < 0 in case of error */
}
/*----------------------------------------------------------------------------------------------*/
void SGIexit(void)
{
GdiplusShutdown(gdiplusToken) ;
}
/*============================================================================== PAINT IMAGES ==*/
/* Minimum implementation of GdiPlus that allows the loading and rendering of image files */
/* cf. Microsoft GDI+ Flat API; J.Findlay http://www.johnfindlay.plus.com/pellesc/GdiPlus */
/* PNG and JPEG images can be loaded directly from a file or from a resource (RCDATA) */
/* BMP, EMF and TIFF images can be loaded only from a resource (RCDATA) */
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "gdiplus.lib")
/*----------------------------------------------------------------------------- GDI+ flat API --*/
typedef void* GP_GPGRAPHICS ;
int _stdcall GdipLoadImageFromStreamICM(IStream* stream, GP_GPIMAGE *image);
int _stdcall GdipLoadImageFromFileICM(const wchar_t*, GP_GPIMAGE *image) ;
int _stdcall GdipCreateFromHDC(HDC, GP_GPGRAPHICS**) ;
int _stdcall GdipDrawImageRectI(GP_GPGRAPHICS, GP_GPIMAGE, INT, INT, INT, INT) ;
int _stdcall GdipGetImageWidth(GP_GPIMAGE, UINT*) ;
int _stdcall GdipGetImageHeight(GP_GPIMAGE, UINT*) ;
int _stdcall GdipDisposeImage(GP_GPIMAGE) ;
int _stdcall GdipDeleteGraphics(GP_GPGRAPHICS*) ;
/*----------------------------------------------------------------------- Load & unload image --*/
GP_GPIMAGE SGIimageLoad(char *fName)
/*
fName is either the name of an image file (ie. "beach.png") or a resource name (ie. "#8009").
*/
{
GP_GPIMAGE image = NULL ;
int l = strlen(fName) ;
if (fName[0] == '#') /* case resource ID */
{
HMODULE hModule = GetModuleHandle(NULL) ;
HRSRC resrc = FindResource(hModule, fName, RT_RCDATA) ;
int size = SizeofResource(hModule, resrc) ;
LPVOID fByte = LockResource(LoadResource(hModule, resrc)) ;
LPSTREAM lpstr = SHCreateMemStream(fByte, size) ;
GdipLoadImageFromStreamICM(lpstr, &image) ;
}
else
{
wchar_t wname[2 * l + 4] ; /* convert fName to wide characters' */
if (mbstowcs(wname, fName, l) < 1)
return NULL ;
GdipLoadImageFromFileICM(wname, &image) ;
}
return image ;
}
void SGIimageUnload(GP_GPIMAGE image)
{
GdipDisposeImage(image) ;
}
/*-------------------------------------------------------------------------------- Image Size --*/
int SGIimageWidth(GP_GPIMAGE image)
{
UINT width = 0 ;
int e = GdipGetImageWidth(image, &width) ;
if (e) return - e ; /* If the function fails, it result is <0 */
return width ;
}
int SGIimageHeight(GP_GPIMAGE image)
{
UINT height = 0 ;
int e = GdipGetImageHeight(image, &height) ;
if (e) return - e ;
return height ;
}
/*-------------------------------------------------------------------------------- Draw image --*/
int SGIimageDraw(HDC hdc, RECT *rect, GP_GPIMAGE image)
/*
This function is typically called in the windows's message loop (case WM_PAINT).
The image is aligned top - left in the rectangle.
*/
{
int iw = SGIimageWidth(image) ; /* image size */
int ih = SGIimageHeight(image) ;
if ((double) iw * ih == 0.0) return - 99 ; /* one dimension is null */
GP_GPGRAPHICS *graphx ;
int e = GdipCreateFromHDC(hdc, &graphx) ;
if (e)
return - 98 ;
e = GdipDrawImageRectI(graphx, image, rect->left, rect->top, iw, ih) ;
GdipDeleteGraphics(graphx) ;
return - e ;
}