API Windows en C

Afficher des images sous windows NT

CGI

- Titre : API Windows en C

- Auteur : CGI

- Parution : 15 mai 2006

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2013 CGI. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Chargement du fichier

- III. Création de la palette de couleur

- IV. Affichage de l'image

- V. Code complet

I - Introduction

Nous avons vu comment afficher des images bitmap tout en les chargeant avec la fonction LoadImage, hélas cette fonction ne permet pas de charger une image depuis un fichier sous Windows NT. Nous allons devoir charger le fichier et le traiter avant affichage.

II - Chargement du fichier

L'ouverture du fichier se fait avec la fonction CreateFile. Nous extrayons tout d'abord l'entête du fichier BITMAPFILEHEADER à l'aide de la fonction ReadFile. Ensuite nous chargeons le bitmap dans un buffer.

static LPVOID buffer;

/* ... */

HANDLE hf;
DWORD FileSize,nbcharRead;
BITMAPFILEHEADER bfh;

hf = CreateFile("image.bmp", GENERIC_READ, 0,NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

FileSize = GetFileSize(hf, NULL);
ReadFile(hf, &bfh, sizeof(bfh), &nbcharRead, NULL) ;

buffer = GlobalAlloc(GMEM_FIXED, FileSize);
ReadFile(hf, buffer, FileSize - sizeof(BITMAPFILEHEADER),
&nbcharRead, NULL);

/* ... */
CloseHandle(hf);
/* ... */
GlobalFree(buffer);

III - Création de la palette de couleur

Si le bitmap à un nombre de couleurs inférieur ou égal à 256, il faut générer sa palette de couleur. Les bitmaps ayant plus de 256 couleurs n'ont pas de palette. Chaque pixel est représenté par la valeur réelle de sa couleur. Le bitmap contient un entête BITMAPINFO donnant ces informations nous y extrayons le nombre de couleurs et créons la palette si besoin. La palette sera ensuite accessible via son handle de palette hpal de type HPALETTE.

static LPVOID buffer;
static UINT nbColors;
static HPALETTE hpal;
static BITMAPINFO *bmInfo;

/* ... */

bmInfo = (BITMAPINFO*)buffer;
nbColors = bmInfo->bmiHeader.biClrUsed ?
bmInfo->bmiHeader.biClrUsed :
1 << bmInfo->bmiHeader.biBitCount;

if( nbColors <= 256 )
{
UINT i;
UINT nSize = sizeof(LOGPALETTE) +
(sizeof(PALETTEENTRY) * nbColors);

LOGPALETTE *pLPal = (LOGPALETTE*) GlobalAlloc(GMEM_FIXED,nSize);
pLPal->palVersion = 0x300;
pLPal->palNumEntries = nbColors;
for( i=0; i < nbColors; i++)
{
pLPal->palPalEntry[i].peRed = bmInfo->bmiColors[i].rgbRed;
pLPal->palPalEntry[i].peGreen = bmInfo->bmiColors[i].rgbGreen;
pLPal->palPalEntry[i].peBlue = bmInfo->bmiColors[i].rgbBlue;
pLPal->palPalEntry[i].peFlags = 0;
}
hpal = CreatePalette(pLPal);
GlobalFree(pLPal);
}

IV - Affichage de l'image

L'affichage de l'image se fait avec la fonction SetDIBitsToDevice. Cette fonction reçoit entre autres un pointeur sur l'entête du bitmap (bmInfo) mais aussi un pointeur sur les pixels (lpDIBBits) qu'il faut calculer en fonction des infos contenues dans l'entête du bitmap. Et s'il y a une palette, il faut la sélectionner.

static LPVOID buffer;
static UINT nbColors;
static HPALETTE hpal;
static BITMAPINFO *bmInfo;

/* ... */

case WM_PAINT :
{
HDC hdc;
PAINTSTRUCT ps;
LPVOID lpDIBBits;

if( bmInfo->bmiHeader.biBitCount > 8 )
lpDIBBits = (bmInfo->bmiColors +
bmInfo->bmiHeader.biClrUsed) +
((bmInfo->bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0);
else
lpDIBBits = bmInfo->bmiColors + nbColors;

hdc = BeginPaint(hwnd, &ps);

if( hpal && (GetDeviceCaps(hdc,RASTERCAPS) & RC_PALETTE) )
{
SelectPalette(hdc, hpal, FALSE);
RealizePalette(hdc);
}
SetDIBitsToDevice(hdc,10,10,bmInfo->bmiHeader.biWidth,
bmInfo->bmiHeader.biHeight, 0, 0, 0,
bmInfo->bmiHeader.biHeight, lpDIBBits, bmInfo,
DIB_RGB_COLORS);

EndPaint(hwnd, &ps);

return 0;
}

V - Code complet

L'exemple pour rester simple n'effectue aucun test de validité. Il va de soi que dans un cas réel il faudra effectuer ces tests.

winmain.c

#include <windows.h>

LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wc;

wc.style = 0;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(1 + COLOR_BTNFACE);
wc.lpszMenuName =  NULL;
wc.lpszClassName = "MaWinClass";

if(!RegisterClass(&wc)) return FALSE;

hwnd = CreateWindow("MaWinClass", "Dessiner", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 280, 240,
NULL, NULL, hinstance, NULL);
if (!hwnd) return FALSE;

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/******************************************************************************/

LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static LPVOID buffer;
static BITMAPINFO *bmInfo;
static UINT nbColors;
static HPALETTE hpal;

switch (uMsg)
{
case WM_CREATE :
{
HANDLE hf;
DWORD FileSize,nbcharRead;
BITMAPFILEHEADER bfh;

hf = CreateFile("image.bmp", GENERIC_READ, 0,NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

FileSize = GetFileSize(hf, NULL);
ReadFile(hf, &bfh, sizeof(bfh), &nbcharRead, NULL) ;

buffer = GlobalAlloc(GMEM_FIXED, FileSize);
ReadFile(hf, buffer, FileSize - sizeof(BITMAPFILEHEADER),
&nbcharRead, NULL);
bmInfo = (BITMAPINFO*)buffer;
nbColors = bmInfo->bmiHeader.biClrUsed ?
bmInfo->bmiHeader.biClrUsed :
1 << bmInfo->bmiHeader.biBitCount;

if( nbColors <= 256 )
{
UINT i;
UINT nSize = sizeof(LOGPALETTE) +
(sizeof(PALETTEENTRY) * nbColors);

LOGPALETTE *pLPal = (LOGPALETTE*) GlobalAlloc(GMEM_FIXED,nSize);
pLPal->palVersion = 0x300;
pLPal->palNumEntries = nbColors;
for( i=0; i < nbColors; i++)
{
pLPal->palPalEntry[i].peRed = bmInfo->bmiColors[i].rgbRed;
pLPal->palPalEntry[i].peGreen = bmInfo->bmiColors[i].rgbGreen;
pLPal->palPalEntry[i].peBlue = bmInfo->bmiColors[i].rgbBlue;
pLPal->palPalEntry[i].peFlags = 0;
}
hpal = CreatePalette(pLPal);
GlobalFree(pLPal);
}

CloseHandle(hf);
return 0;
}

case WM_PAINT :
{
HDC hdc;
PAINTSTRUCT ps;
LPVOID lpDIBBits;

if( bmInfo->bmiHeader.biBitCount > 8 )
lpDIBBits = (bmInfo->bmiColors +
bmInfo->bmiHeader.biClrUsed) +
((bmInfo->bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0);
else
lpDIBBits = bmInfo->bmiColors + nbColors;

hdc = BeginPaint(hwnd, &ps);

if( hpal && (GetDeviceCaps(hdc,RASTERCAPS) & RC_PALETTE) )
{
SelectPalette(hdc, hpal, FALSE);
RealizePalette(hdc);
}

SetDIBitsToDevice(hdc,10,10,bmInfo->bmiHeader.biWidth,
bmInfo->bmiHeader.biHeight, 0, 0, 0,
bmInfo->bmiHeader.biHeight, lpDIBBits, bmInfo,
DIB_RGB_COLORS);

EndPaint(hwnd, &ps);

return 0;
}

case WM_DESTROY :
GlobalFree(buffer);
PostQuitMessage(0);
return 0;

default :
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}

J'ai testé les compilations avec C++ Builder et DevC++.

À vos PC.

CGi

Sommaire