Dessiner un bitmap transparent (win32)

Description

Ce petit prog montre comment dessiner un bitmap comportant des zones qui doivent être transparente. Cela necessite un masque du bitmap à recopier que l'on fournit dans les ressources ou que l'on calcule à l'exécution à partir du couleur de transparence.

Source / Exemple :


//***************************************************************************************
// TestBmp.cpp :
//
//***************************************************************************************

#include <windows.h>

#include "Resource.h"

//=======================================================================================
// Variables globales.
//=======================================================================================
HINSTANCE	g_hAppInstance	= NULL;	// instance de l'application
HWND		g_hWndMainFrame	= NULL;	// fenêtre principale

//=======================================================================================
// Variables du module.
//=======================================================================================
static HBITMAP s_hBmpSprite			= NULL;	// bitmap à afficher
static HBITMAP s_hBmpSpriteMask		= NULL;	// masque du bitmap à afficher
static HBITMAP s_hBmpBackground		= NULL;	// bitmap du fond

static HDC	s_hDCSprite				= NULL;	// DC avec le bitmap à afficher
static HDC	s_hDCSpriteMask			= NULL;	// DC avec le masque du bitmap à afficher
static HDC	s_hDCBackground			= NULL;	// DC avec le bitmap du fond

static HBITMAP s_hOldBmpSprite		= NULL; // ancien bitmap de s_hDCSprite
static HBITMAP s_hOldBmpSpriteMask	= NULL; // ancien bitmap de s_hDCSpriteMask
static HBITMAP s_hOldBmpBackground	= NULL; // ancien bitmap de s_hDCBackground

static SIZE s_SizeBmpSprite			= {0, 0};	// taille de s_hBmpSprite
static SIZE s_SizeBmpBackground		= {0, 0};	// taille de s_hBmpBackground

static POINT s_PtSprite				= {0, 0};	// position où afficher le bitmap

//=======================================================================================
// Fonctions du module.
//=======================================================================================
static BOOL InitInstance(HINSTANCE hInstance, int nShowCmd);

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

static int  OnCreate	(HWND hWnd);
static void OnDestroy	();
static void OnPaint		();
static void OnMouseMove	(WPARAM wParam, LPARAM lParam);

static HBITMAP CreateBmpMask(HBITMAP hBmp, COLORREF clrTransparent);

//***************************************************************************************
// WinMain :
//***************************************************************************************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
				   int nShowCmd)
{
	// initialisation de l'application
	if(!InitInstance(hInstance, nShowCmd))
		return 0;

	// boucle de messages
	MSG msg;
	while(GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

//***************************************************************************************
// InitInstance :
//***************************************************************************************
BOOL InitInstance(HINSTANCE hInstance, int nShowCmd)
{
	// sauvegarde instance de l'application
	g_hAppInstance = hInstance;
	char szWndClass[] = "TestBmp_MainFrame";
	char szWndTitle[] = "TestBmp";

	// initialisation classe de fenêtre
	WNDCLASS wc;
	memset(&wc, 0, sizeof(WNDCLASS));
	wc.hInstance		= g_hAppInstance;
	wc.style			= CS_HREDRAW|CS_VREDRAW;
	wc.hIcon			= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.lpfnWndProc		= WndProc;
	wc.lpszClassName	= szWndClass;
	if(!RegisterClass(&wc)) return FALSE;

	// création de la fenêtre
	g_hWndMainFrame = CreateWindow(szWndClass, szWndTitle, WS_OVERLAPPEDWINDOW, 
									CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
									NULL, NULL, g_hAppInstance, NULL);

	// position initiale du sprite (à l'emplacement de la souris)
	GetCursorPos(&s_PtSprite);
	ScreenToClient(g_hWndMainFrame, &s_PtSprite);

	// affichage
	ShowWindow(g_hWndMainFrame, nShowCmd);
	UpdateWindow(g_hWndMainFrame);
	return TRUE;
}

//***************************************************************************************
// WndProc :
//***************************************************************************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
	case WM_CREATE		: return OnCreate(hWnd);
	case WM_DESTROY		: OnDestroy();					return 0;
	case WM_PAINT		: OnPaint();					return 0;
	case WM_MOUSEMOVE	: OnMouseMove(wParam, lParam);	return 0;
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

//***************************************************************************************
// OnCreate :
//***************************************************************************************
int OnCreate(HWND hWnd)
{
	// chargement des bitmaps
	s_hBmpSprite = LoadBitmap(g_hAppInstance, MAKEINTRESOURCE(IDB_SPRITE));
	s_hBmpBackground = LoadBitmap(g_hAppInstance, MAKEINTRESOURCE(IDB_BACKGROUND));

	// le masque peut être choit chargé depuis les ressources soit créé lors de
	// l'exécution en indiquant la couleur de transparence
//	s_hBmpSpriteMask = LoadBitmap(g_hAppInstance, MAKEINTRESOURCE(IDB_SPRITEMASK));
	s_hBmpSpriteMask=CreateBmpMask(s_hBmpSprite, RGB(0xFF, 0x00, 0xFF));

	// création de DCs pour ces bitmap
	HDC hdc = GetDC(hWnd);
	s_hDCSprite = CreateCompatibleDC(hdc);
	s_hDCSpriteMask = CreateCompatibleDC(hdc);
	s_hDCBackground = CreateCompatibleDC(hdc);
	ReleaseDC(hWnd, hdc);

	// sélection des bitmaps dans les DCs et savegarde des anciens
	s_hOldBmpSprite = (HBITMAP) SelectObject(s_hDCSprite, s_hBmpSprite);
	s_hOldBmpSpriteMask = (HBITMAP) SelectObject(s_hDCSpriteMask, s_hBmpSpriteMask);
	s_hOldBmpBackground = (HBITMAP) SelectObject(s_hDCBackground, s_hBmpBackground);

	// récupération de la taille des bitmaps
	BITMAP bmpInfo;
	GetObject(s_hBmpSprite, sizeof(BITMAP), &bmpInfo);
	s_SizeBmpSprite.cx = bmpInfo.bmWidth;
	s_SizeBmpSprite.cy = bmpInfo.bmHeight;
	GetObject(s_hBmpBackground, sizeof(BITMAP), &bmpInfo);
	s_SizeBmpBackground.cx = bmpInfo.bmWidth;
	s_SizeBmpBackground.cy = bmpInfo.bmHeight;

	// création réussie
	return 0;
}

//***************************************************************************************
// OnDestroy :
//***************************************************************************************
void OnDestroy()
{
	// sélection des anciens bitmaps dans les DCs
	SelectObject(s_hDCSprite, s_hOldBmpSprite);
	SelectObject(s_hDCSpriteMask, s_hOldBmpSpriteMask);
	SelectObject(s_hDCBackground, s_hOldBmpBackground);

	// destruction des DCs
	DeleteDC(s_hDCSprite);
	DeleteDC(s_hDCSpriteMask);
	DeleteDC(s_hDCBackground);

	// destruction des bitmaps
	DeleteObject(s_hBmpSprite);
	DeleteObject(s_hBmpSpriteMask);
	DeleteObject(s_hBmpBackground);

	// fin de l'application
	PostQuitMessage(0);
}

//***************************************************************************************
// OnPaint :
//***************************************************************************************
void OnPaint()
{
	// début du dessin
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(g_hWndMainFrame, &ps);

	// taille zone cliente
	RECT rcClient;
	GetClientRect(g_hWndMainFrame, &rcClient);
	int cxClient = rcClient.right-rcClient.left;
	int cyClient = rcClient.bottom-rcClient.top;

	// création de bitmaps et DCs pour l'affichage final et les opérations
	// intermédiaires
	HDC hDCFinal = CreateCompatibleDC(hdc);
	HDC hDCTemp = CreateCompatibleDC(hdc);
	HBITMAP hBmpFinal = CreateCompatibleBitmap(hdc, cxClient, cyClient);
	HBITMAP hBmpTemp = CreateCompatibleBitmap(hdc, s_SizeBmpSprite.cx, s_SizeBmpSprite.cy);
	HBITMAP hOldBmpFinal = (HBITMAP) SelectObject(hDCFinal, hBmpFinal);
	HBITMAP hOldBmpTemp = (HBITMAP) SelectObject(hDCTemp, hBmpTemp);

	// effacement du fond du DC final
	HBRUSH hWhiteBrush = CreateSolidBrush(RGB(0xFF, 0xFF, 0xFF));
	FillRect(hDCFinal, &rcClient, hWhiteBrush);
	DeleteObject(hWhiteBrush);

	// Les 2 opération suivantes peuvant être réalisée une seule fois lors de
	// l'initialisation de l'application

	// temp = NOT mask
	BitBlt(hDCTemp, 0, 0, s_SizeBmpSprite.cx, s_SizeBmpSprite.cy,
			s_hDCSpriteMask, 0, 0, NOTSRCCOPY);

	// temp = temp AND bitmap
	BitBlt(hDCTemp, 0, 0, s_SizeBmpSprite.cx, s_SizeBmpSprite.cy,
			s_hDCSprite, 0, 0, SRCAND);

	// final = background
	BitBlt(hDCFinal, 0, 0, s_SizeBmpBackground.cx, s_SizeBmpBackground.cy,
			s_hDCBackground, 0, 0, SRCCOPY);

	// final = final AND mask (à la position finale du sprite)
	BitBlt(hDCFinal, s_PtSprite.x, s_PtSprite.y, s_SizeBmpSprite.cx, s_SizeBmpSprite.cy,
			s_hDCSpriteMask, 0, 0, SRCAND);

	// final = final OR temp (à la position finale du sprite)
	BitBlt(hDCFinal, s_PtSprite.x, s_PtSprite.y, s_SizeBmpSprite.cx, s_SizeBmpSprite.cy,
			hDCTemp, 0, 0, SRCPAINT);

	// recopie à l'écran
	BitBlt(hdc, 0, 0, cxClient, cyClient, hDCFinal, 0, 0, SRCCOPY);

	// libération des ressources
	SelectObject(hDCFinal, hOldBmpFinal);
	SelectObject(hDCTemp, hOldBmpTemp);
	DeleteDC(hDCFinal);
	DeleteDC(hDCTemp);
	DeleteObject(hBmpFinal);
	DeleteObject(hBmpTemp);

	// fin du dessin
	EndPaint(g_hWndMainFrame, &ps);
}

//***************************************************************************************
// OnMouseMove :
//***************************************************************************************
void OnMouseMove(WPARAM wParam, LPARAM lParam)
{
	// on dessine le bitmap à la position de la souris
	s_PtSprite.x = (short)LOWORD(lParam);
	s_PtSprite.y = (short)HIWORD(lParam);
	InvalidateRect(g_hWndMainFrame, NULL, FALSE);
	UpdateWindow(g_hWndMainFrame);
}

//***************************************************************************************
// CreateBmpMask :
//***************************************************************************************
HBITMAP CreateBmpMask(HBITMAP hBmp, COLORREF clrTransparent)
{
	// information sur le bitmap (taille)
	BITMAP bmpInfo;
	GetObject(hBmp, sizeof(BITMAP), &bmpInfo);

	// création bitmap monochrome pour le masque
	HBITMAP hBmpMask = CreateBitmap(bmpInfo.bmWidth, bmpInfo.bmHeight, 1, 1, NULL);

	// création de DCs pour y mettre les bitmaps
	HDC hdc = GetDC(NULL);
	HDC hDCBmp = CreateCompatibleDC(hdc);
	HDC hDCBmpMask = CreateCompatibleDC(hdc);
	ReleaseDC(NULL, hdc);
	HBITMAP hOldBmp = (HBITMAP)SelectObject(hDCBmp, hBmp);
	HBITMAP hOldBmpMask = (HBITMAP)SelectObject(hDCBmpMask, hBmpMask);

	// on mettant la couleur de fond du DC avec le bitmap initial à la couleur de
	// tranparence et en le recopiant dans le DC avec le bitmap monochrome, on crée le
	// masque voulu : les pixels de la couleur transparente seront mis au noir et les
	// autres au blanc.
	SetBkColor(hDCBmp, clrTransparent);
	BitBlt(hDCBmpMask, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, hDCBmp, 0, 0, SRCCOPY);
	
	// libération des ressources er retour
	SelectObject(hDCBmp, hOldBmp);
	SelectObject(hDCBmpMask, hOldBmpMask);
	DeleteDC(hDCBmp);
	DeleteDC(hDCBmpMask);
	return hBmpMask;
}

Conclusion :


Outre les commentaires, un fichier .doc qui explique plus en détail les opérations intermédiaires et leur résultat.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.