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 parlerons bien sûr que d'images de type Bitmap (celle dont les fichiers ont l'extention bmp).
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 mit à 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 terme de ressources systèmes, mais à l'avantage
que le contrôle peut gérer les messages de notifications.
Si l'on a pas besoin de gérer ces messages, il est préférable de dessiner
l'image sur un contexe de périférique.
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 sur le traitement
du message WM_CREATE et l'affichons
avec la fonction DrawState sur le traitement du message WM_PAINT.
Et destruction de l'objet quand on n'en a plus besoin avec la fonction DeleteObject.
Cette solution est moins gourmande en ressources système.
Le fichier ressources étant le même que précédement.
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP hBmp;
switch (uMsg)
{
case WM_CREATE :
hBmp=LoadBitmap(hinst,"MyPicture");
return 0;
case WM_PAINT :
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
DrawState(hdc,NULL,NULL,(long)hBmp,0,10,10,0,0,DST_BITMAP);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY :
DeleteObject(hBmp);
PostQuitMessage(0);
return 0;
default :
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
Sous les plateformes Windows 95 et Windows XP et suivante nous pouvons par la même methode
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.
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP hBmp;
switch (uMsg)
{
case WM_CREATE :
hBmp=LoadImage(NULL,"image.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
return 0;
case WM_PAINT :
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
DrawState(hdc,NULL,NULL,(long)hBmp,0,10,10,0,0,DST_BITMAP);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY :
DeleteObject(hBmp);
PostQuitMessage(0);
return 0;
default :
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
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.
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP hBmp;
static HBITMAP hbmTmp;
static BITMAP bmpi;
static HDC hdcMem;
switch ( uMsg ) {
case WM_CREATE:
{
hBmp=LoadBitmap(hinst,"MyPicture");
hdcMem = CreateCompatibleDC(NULL);
hbmTmp = SelectObject(hdcMem,hBmp);
GetObject(hBmp,sizeof(bmpi),&bmpi);
return 0;
}
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
BitBlt(hdc,10,10,bmpi.bmWidth,bmpi.bmHeight,hdcMem,0,0,SRCCOPY);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
SelectObject(hdcMem,hbmTmp);
DeleteDC(hdcMem);
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 fonction
GetObject qui les affectes à 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 6ème étant le handle du contexte de périphérique de la source.
le 7ème et le 8ème la position de départ (haut, gauche) sur la source. Le dernier étant une constante
déterminant le traitement à éffectuer.
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 traitement pouvant être appliqué.
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)
{
static HBITMAP hBmp;
switch (uMsg)
{
case WM_CREATE :
hBmp=LoadBitmap(hinst,"MyPicture");
case WM_PAINT :
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
DrawState(hdc,NULL,NULL,(long)hBmp,0,10,10,0,0,DST_BITMAP);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY :
DeleteObject(hBmp);
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, Visual C++, Code::Blocks avec MinGW et DevC++.
Sous Windows NT LoadImage ne permet pas de charger un bitmap depuis un fichier.
Je vous met un exemple qui permet de le faire.
A vos PC.
CGi
|