API Windows en C

Afficher des images

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. Image sur contrôle static

- III. Dessiner une image avec DrawState

- IV. Dessiner une image avec BitBlt

- V. Code complet

I - Introduction

Le traitement d'images dans Windows est un sujet très vaste. Dans ce petit article nous allons voir comment afficher simplement une image dans une fenêtre. Nous avons déjà vu l'affichage d'une image dans une boîte de dialogue à l'aide du contrôle static. Nous allons faire de même, mais dans une fenêtre standard. Nous ne parlerons bien sûr que d'images de type Bitmap (celles dont les fichiers ont l'extension BMP).

II - Image sur contrôle static

Nous le créons comme tout contrôle à l'aide de la fonction CreateWindow avec comme nom de classe de fenêtre "STATIC" suivi du nom de la ressource image (le contrôle static ne peut afficher que des images provenant des ressources du programme). Il devra bien sûr avoir le style SS_BITMAP. Les paramètres de dimensions n'ont aucun effet en ce cas, ils peuvent donc être mis à zéro.

case WM_CREATE :
{
HWND hstatic = CreateWindow("STATIC", "MyPicture",
WS_CHILD | WS_VISIBLE| SS_BITMAP,
10, 10, 0, 0, hwnd, NULL, hinst, NULL);
return 0;
}

Le fichier ressource :

MyPicture BITMAP "image.bmp"

Cette façon de faire et plus lourde en termes de ressources système, mais a l'avantage que le contrôle peut gérer les messages de notification. Si l'on n'a pas besoin de gérer ces messages, il est préférable de dessiner l'image sur un contexte de périphérique.

III - Dessiner une image avec DrawState

Une seconde solution est de dessiner l'image dans la fenêtre en utilisant un contexte de périphérique. Nous chargerons l'image depuis les ressources avec la fonction LoadBitmap et l'afficherons avec la fonction DrawState. Cette solution est moins gourmande en ressources système. Le fichier ressources étant le même que précédemment.

case WM_PAINT:
{
HBITMAP hBmp;
HDC hdc;
PAINTSTRUCT ps;

hBmp=LoadBitmap(hinst,"MyPicture");

hdc = BeginPaint(hwnd, &ps);

DrawState(hdc,NULL,NULL,(long)hBmp,NULL,10,10,0,0,DST_BITMAP);

EndPaint(hwnd, &ps);

DeleteObject(hBmp);

return 0;
}

Sous les plateformes Windows 95 et Windows XP, nous pouvons par la même méthode afficher une image provenant d'un fichier (voir note en bas de page pour Windows NT). Pour cela nous chargeons l'image avec la fonction LoadImage.

case WM_PAINT :
{
HBITMAP hBmp;
HDC hdc;
PAINTSTRUCT ps;

hBmp=LoadImage(NULL,"image.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

hdc = BeginPaint(hwnd, &ps);

DrawState(hdc,NULL,NULL,(long)hBmp,NULL,10,10,0,0,DST_BITMAP);

EndPaint(hwnd, &ps);

DeleteObject(hBmp);

return 0;
}

IV - Dessiner une image avec BitBlt

Une troisième solution est de sélectionner l'image sur un contexte de périphérique en mémoire, puis d'en faire la copie sur le contexte de périphérique d'affichage à l'aide de la fonction BitBlt. Cette solution permet de n'afficher qu'une partie du bitmap d'origine.

LONG APIENTRY WndProc(HWND hwnd, UINT uMsg, UINT wParam, LONG lParam)
{
static HBITMAP hBmp;

switch ( uMsg ) {

case WM_CREATE:
{
hBmp=LoadBitmap(hInst,"MyPicture");
return 0;
}

case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
HBITMAP hbmTmp;
BITMAP bmpi;
HDC hdcMem;

hdcMem = CreateCompatibleDC(NULL);
hbmTmp = SelectObject(hdcMem,hBmp);
GetObject(hBmp,sizeof(bmpi),&bmpi);

hdc = BeginPaint(hwnd, &ps);
BitBlt(hdc,10,10,bmpi.bmWidth,bmpi.bmHeight,hdcMem,0,0,SRCCOPY);
EndPaint(hwnd, &ps);

SelectObject(hdcMem,hbmTmp);
DeleteDC(hdcMem);
return 0;
}

case WM_DESTROY:
DeleteObject(hBmp);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);

}

Dans cet exemple on a chargé l'image dès la création de l'application. Le contexte de périphérique en mémoire est obtenu avec la fonction CreateCompatibleDC. Son unique paramètre est un contexte de périphérique compatible avec celui avec lequel on travaille. Dans l'exemple il est à NULL, ce qui le rend compatible avec l'écran. On sélectionne le bitmap sur ce contexte de périphérique avec la fonction SelectObject. La fonction BitBlt ayant besoin des dimensions de l'image, nous les obtenons à l'aide de la fonctionGetObject qui les affecte à une structure BITMAP.
La fonction BitBlt reçoit en son premier paramètre le handle du contexte de périphérique de destination. Les deux paramètres suivants sont la position sur la destination. Les deux suivants sont la largeur et la hauteur de la copie. Le 6e étant le handle du contexte de périphérique de la source. Le 7e et le 8e la position de départ (haut, gauche) sur la source. Le dernier étant une constante déterminant le traitement à effectuer. Dans l'exemple c'est une simple copie de la source vers la destination (SRCCOPY). Voir l'aide sur API Win32 pour les différents traitements pouvant être appliqués.

V - Code complet

Code complet de la deuxième méthode.
winmain.c :

#include <windows.h>

HINSTANCE hinst;

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

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

hinst = hinstance;

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)
{
switch (uMsg)
{
case WM_PAINT:
{
HBITMAP hBmp;
HDC hdc;
PAINTSTRUCT ps;

hBmp=LoadBitmap(hinst,"MyPicture");

hdc = BeginPaint(hwnd, &ps);

DrawState(hdc,NULL,NULL,(long)hBmp,NULL,10,10,0,0,DST_BITMAP);

EndPaint(hwnd, &ps);

DeleteObject(hBmp);

return 0;
}

case WM_DESTROY:
PostQuitMessage(0);
return 0;

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

resources.rc :

#include <windows.h>

MyPicture BITMAP "image.bmp"

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

CGi

Sommaire