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.
#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