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.
Chargement du fichier :
L'ouverture du fichier ce 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);
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éel de sa couleur.
Le bitmap contient un entête BITMAPINFO donnant ces informations nous y extayons le
nombre de couleurs et créons la palette si besoin.
La palette sera ensuite accéssible 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);
}
Affichage de l'image :
L'affichage de l'image ce fait avec la fonction SetDIBitsToDevice.
Cette fonction reçois entre autre un pointeur sur l'entête du bitmap (bmInfo) mais aussi
un pointeur sur les pixels (lpDIBBits) qu'il faut caluler en fonction des infos
contenu 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;
}
Code complet :
L'exemple pour rester simple n'éffectue aucun test de validité.
Il va de soit que dans un cas réel il faudra éffectuer 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++.
A vos PC.
CGi
|