begin process at 2012 02 10 07:59:01
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Graphique

 > REGION À PARTIR D'UN BITMAP

REGION À PARTIR D'UN BITMAP


 Information sur la source

Note :
9,5 / 10 - par 4 personnes
9,50 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Graphique Niveau :Initié Date de création :02/05/2003 Date de mise à jour :02/05/2003 19:46:31 Vu :5 182

Auteur : anthraxx

Ecrire un message privé
Commentaire sur cette source (13)
Ajouter un commentaire et/ou une note

 Description

Cette fonction permet d'avoir une region (de type HRGN) composée des pixels non noirs d'un bitmap (HBITMAP), afin de faire une fenetre avec une forme non rectangulaire.

On trouve pas mal de codes-sources comme celui-ci sur Internet, mais soit ils sont trop lents, soit ils ne marchent pas! Je l'ai appris à mes dépens!
Déçu, j'en ai fait un moi-même (en m'inspirant d'un source que j'avais trouvé sur le net qui ne marchait pas).
Celui-ci est très rapide (une dizaine de millisecondes, meme pour une grosse image)

Vous pouvez, pour tester la fonction:
-dessiner une image non recangulaire sur fond en teinte unie.
-dans le code, créer une fenetre sans bordure, sinon ça aura des conséquences étranges
-charger le bitmap dans une variable HBITMAP (grâce à LoadImage par exemple)
-Utiliser la fonction BmpToRgn avec en parametre le bitmap et la couleur de fond de l'image
-Utiliser SetWindowRgn pour affecter la region ainsi créee à la fenêtre
-utiliser BitBlt pour copier le bitmap sur la fenetre chaque fois qu'elle à besoin d'être redessinée

Source

  • HRGN BmpToRgn (HBITMAP hBmp, COLORREF cTransparentColor = 0)
  • {
  • #define ALLOC_UNIT 100
  • HRGN hRgn = NULL;
  • if (!hBmp) return 0; // si bitmap invalide retourne
  • BITMAP bm;
  • GetObject(hBmp, sizeof(bm), &bm); // met les infos d'en tete du bitmap dans bm
  • UINT siz=bm.bmWidth*bm.bmHeight*4; // enregistre la taille des donnes de l'image
  • char *lpBmpBits=(char*)LocalAlloc(LMEM_FIXED,siz); // fait de la place pour les bits du bitmap
  • GetBitmapBits(hBmp,siz,lpBmpBits); // obtient les bits de l'image dans l'espace qu'on a reservé
  • bm.bmBits=lpBmpBits; // complete la strucutre bm avec les bits
  • while (bm.bmWidthBytes % 4) bm.bmWidthBytes++; // bmWidthBytes doit être divisible par 4
  • DWORD maxRects = ALLOC_UNIT;
  • HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
  • RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
  • pData->rdh.dwSize = sizeof(RGNDATAHEADER);
  • pData->rdh.iType = RDH_RECTANGLES;
  • pData->rdh.nCount = pData->rdh.nRgnSize = 0;
  • SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  • BYTE *p32 = (BYTE *)bm.bmBits;
  • for (int y = 0; y < bm.bmHeight; y++) // parcourt toutes les lignes de l'image, de haut en bas
  • {
  • for (int x = 0; x < bm.bmWidth; x++) // parcourt tous les pixels de la ligne, de gauche à droite
  • {
  • // Recherche une suite continue de pixels non transparents
  • int x0 = x;
  • LONG *p = (LONG *)(p32 + 4*x);
  • while (x < bm.bmWidth)
  • {
  • if ((unsigned)*p==cTransparentColor)
  • break; // ce pixel est transparent
  • p++;
  • x++;
  • }
  • if (x > x0)
  • {
  • // ajoute les pixels (de (x0, y) à (x, y+1)) à la region en tant que rectangle
  • if (pData->rdh.nCount >= maxRects)
  • {
  • GlobalUnlock(hData);
  • maxRects += ALLOC_UNIT;
  • hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) +
  • (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
  • pData = (RGNDATA *)GlobalLock(hData);
  • }
  • RECT *pr = (RECT *)&pData->Buffer;
  • SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);
  • if (x0 < pData->rdh.rcBound.left)
  • pData->rdh.rcBound.left = x0;
  • if (y < pData->rdh.rcBound.top)
  • pData->rdh.rcBound.top = y;
  • if (x > pData->rdh.rcBound.right)
  • pData->rdh.rcBound.right = x;
  • if (y+1 > pData->rdh.rcBound.bottom)
  • pData->rdh.rcBound.bottom = y+1;
  • pData->rdh.nCount++;
  • // Il parait que sous Windows 98, ExtCreateRegion() ne marche pas s'il y a trop de rectangles
  • // Pas de panique: on construit la region en deux fois
  • if (pData->rdh.nCount == 2000)
  • {
  • HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
  • if (hRgn)
  • {
  • CombineRgn(hRgn, hRgn, h, RGN_OR);
  • DeleteObject(h);
  • }
  • else
  • hRgn = h;
  • pData->rdh.nCount = 0;
  • SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  • }
  • }
  • }
  • // On passe à la ligne suivante
  • p32 += bm.bmWidthBytes;
  • }
  • // On cree la region
  • // (et, s'il y avait plus de 2000 rectangles, on la combine avec celle créee precedemment)
  • HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
  • if (hRgn)
  • {
  • CombineRgn(hRgn, hRgn, h, RGN_OR);
  • DeleteObject(h);
  • }
  • else hRgn = h;
  • LocalFree((HLOCAL)lpBmpBits);
  • return hRgn;
  • }
HRGN BmpToRgn (HBITMAP hBmp, COLORREF cTransparentColor = 0)
{
#define ALLOC_UNIT 100
	HRGN hRgn = NULL;
	if (!hBmp) return 0; // si bitmap invalide retourne
	BITMAP bm;
	GetObject(hBmp, sizeof(bm), &bm); // met les infos d'en tete du bitmap dans bm
	UINT siz=bm.bmWidth*bm.bmHeight*4; // enregistre la taille des donnes de l'image
	char *lpBmpBits=(char*)LocalAlloc(LMEM_FIXED,siz); // fait de la place pour les bits du bitmap
	GetBitmapBits(hBmp,siz,lpBmpBits); // obtient les bits de l'image dans l'espace qu'on a reservé
	bm.bmBits=lpBmpBits; // complete la strucutre bm avec les bits
	while (bm.bmWidthBytes % 4) bm.bmWidthBytes++; // bmWidthBytes doit être divisible par 4

	DWORD maxRects = ALLOC_UNIT;
	HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
	RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
	pData->rdh.dwSize = sizeof(RGNDATAHEADER);
	pData->rdh.iType = RDH_RECTANGLES;
	pData->rdh.nCount = pData->rdh.nRgnSize = 0;
	SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);

	BYTE *p32 = (BYTE *)bm.bmBits;
	for (int y = 0; y < bm.bmHeight; y++) // parcourt toutes les lignes de l'image, de haut en bas
	{
		for (int x = 0; x < bm.bmWidth; x++) // parcourt tous les pixels de la ligne, de gauche à droite
		{
			// Recherche une suite continue de pixels non transparents
			int x0 = x;
			LONG *p = (LONG *)(p32 + 4*x);
			while (x < bm.bmWidth)
			{
				if ((unsigned)*p==cTransparentColor)
					break; // ce pixel est transparent
				p++;
				x++;
			}
			if (x > x0)
			{
				// ajoute les pixels (de (x0, y) à (x, y+1)) à la region en tant que rectangle
				if (pData->rdh.nCount >= maxRects)
				{
					GlobalUnlock(hData);
					maxRects += ALLOC_UNIT;
					hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + 
						(sizeof(RECT) * maxRects), GMEM_MOVEABLE);
					pData = (RGNDATA *)GlobalLock(hData);
				}
				RECT *pr = (RECT *)&pData->Buffer;
				SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);
				if (x0 < pData->rdh.rcBound.left)
					pData->rdh.rcBound.left = x0;
				if (y < pData->rdh.rcBound.top)
					pData->rdh.rcBound.top = y;
				if (x > pData->rdh.rcBound.right)
					pData->rdh.rcBound.right = x;
				if (y+1 > pData->rdh.rcBound.bottom)
					pData->rdh.rcBound.bottom = y+1;
				pData->rdh.nCount++;

				// Il parait que sous Windows 98, ExtCreateRegion() ne marche pas s'il y a trop de rectangles
				// Pas de panique: on construit la region en deux fois
				if (pData->rdh.nCount == 2000)
				{
					HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
					if (hRgn)
					{
						CombineRgn(hRgn, hRgn, h, RGN_OR);
						DeleteObject(h);
					}
					else
						hRgn = h;
					pData->rdh.nCount = 0;
					SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
				}
			}
		}
		// On passe à la ligne suivante
		p32 += bm.bmWidthBytes;
	}
	// On cree la region
	// (et, s'il y avait plus de 2000 rectangles, on la combine avec celle  créee precedemment)
	HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
	if (hRgn)
	{
		CombineRgn(hRgn, hRgn, h, RGN_OR);
		DeleteObject(h);
	}
	else hRgn = h;
	LocalFree((HLOCAL)lpBmpBits);
	return hRgn;
}



 Sources de la même categorie

Source avec Zip APPLICATION DE DESSIN DE QUELQUES FIGURES par laguchori
Source avec Zip Source avec une capture HDR EXPOSURE FUSION par mecrosoft
Source avec Zip Source avec une capture IRC CLIENT MULTISERVEUR EN MFC (TXIRC) par TeniX
Source avec Zip ENTETE DU FICHIER BMP (BIPMAP) par k.Lutchi
Source avec Zip Source avec une capture XCOUPE : COUPE 2D par pop70

Commentaires et avis

Commentaire de MangaII le 03/05/2003 09:17:52

Pas mal le principe !!!
Mais le fait de passer toute l'image point par point ? c pas un peu long ?
Y'a auncune fonction de l'API qui fé ca automatiquement ?

Commentaire de langedechu le 03/05/2003 11:57:29

Super Ca marche tres bien.
Perso Ca fait un moment que je cherchais comment faire mais comme tu la dit ce que j'ai trouvé sur le net étais trops long en temps
d'execution.

Concernant le Message de MangaII : c peut etre long de passer l image poit par point au niveaux code ( en taille ) mais ca permet d avoir un temps d'execution le plus petit possible au niveau du traitement de l'image.

Commentaire de langedechu le 03/05/2003 13:16:33

j ai plein de bug graphique avec windows quand je fais une fenetre non carré.
par exemple si j ai une fenetre dejas ouverte ( style exploreur ou meme un autre programme ) et que je clic dessus (l ancienne fenetre)
je ma fenetre non carré qui s'efface et la partie efface reste dessiner sur l autre fenetre

Commentaire de langedechu le 03/05/2003 13:34:30

pour resoudre le bug si utilisation de mfc :
bouton droit sur la boite de dialogue en lever l option transparent.

puis sur définir :
OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hBrush = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

   switch (nCtlColor)
   {

      case CTLCOLOR_DLG : // pour le fond
hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); // transparent
            break ;

         } ;
   return hBrush ;

}

Commentaire de anthraxx le 03/05/2003 20:24:52

en reponse aux commentaires sur la vitesse d'execution:
il faut savoir que en effet la fonction utilise des instructions "for" imbriquées qui peuvent paraitre longues; cepandant, l'interieur de ces boucles n'est constitué que de code C++ et de manipulations basiques avec des pointeurs, ce qui est tres rapide, c++ etant connu pour cela.

Les autres codes sont plus lents, car s'il utilisent aussi des boucles imbriquées, celles-ci contiennent des appels aux API, comme GetPixel, CreateRectRgn et CombineRgn, et ces fonctions, elles, sont beaucoup plus lentes que des courtes operations entre pointeurs.

Commentaire de Iwin le 12/08/2003 23:49:17

C'est vrai qu'elle est vraiment cool ta fonction, paske les CombineRgn, on peut pas en mettre plusieurs pour avoir une fenêtre composé de plus de 2 figures géométriques, alors pas mal ton truc !

Commentaire de Iwin le 29/09/2003 22:34:15

heu rectification, ta fonction me renvoie pas la même forme que l'image mais plutôt la forme dédoublé, j'ai réécrit une fonction qui marche bien mais qui est assez lente (elle enlève tout les pixels de la même couleur que le pixel en haut à gauche). La voila :
void AddRectToRgn( HRGN & hrgn, int left, int top, int right, int bottom )
{
if( hrgn == NULL )
        hrgn = CreateRectRgn( left, top, right + 1, bottom + 1 );
    else
    {
HRGN hrgn2 = CreateRectRgn( left, top, right + 1, bottom + 1 );
        CombineRgn( hrgn, hrgn, hrgn2, RGN_OR );
        DeleteObject( hrgn2 );
    }
}

HRGN BmpToRgn (HBITMAP hBmp,int xi, int yi)
{
HDC hdc = NULL;
HRGN hrgnCurrent = NULL;
hdc = CreateCompatibleDC(NULL);
SelectObject(hdc, hBmp);
COLORREF c0 = GetPixel(hdc,0,0);

for(int y=0;y&lt;yi;y++){
for(int x=0;x&lt;xi;x++){
if(GetPixel(hdc,x,y) != c0 ) AddRectToRgn( hrgnCurrent, x, y, x, y );
}
}
DeleteObject(hdc);
    return hrgnCurrent;
}

Commentaire de basted le 31/10/2003 12:10:22

tres interessante ta fonction, je n'est pas remarque de difference notable entre l'utilsation de ExtCreateRegion et CreateRgn et CombineRgm, l'interet de ton code est plutot l'optimisation des boucles, et la non utilisation de GetPxiel !!

Cf mon code:

HRGN hRgnBase = CreateRectRgn(0,0,0,0);

// algo brutale: chaque point noire arrete la delimitation d'une ligne qui devien region
for (int y=0;y&lt;deltaYwin;y++)
for (int x=0;x&lt;=deltaXwin;x++)
{
int x0=x;
int pos = (x+(deltaYwin-1-y)*deltaXwin)*3;
float *ptr = pixels+pos;

while (x&lt;deltaXwin)
{
if ((ptr[0]==0)&&(ptr[1]==0)&&(ptr[2]==0)) break;
x++;
ptr+=3;
}
if (x&gt;x0)
{
HRGN hRgnCur = CreateRectRgn(x0,y,x,y+1);
CombineRgn(hRgnBase,hRgnBase,hRgnCur,RGN_OR);
DeleteObject(hRgnCur);
}
}

J'ai cependant une question: pour un tres grand nombres de region (&gt;100) la fenetre est bien delimité, mais le contenu de la partie basse n'est pas valide (ancienne image)

Y a t'il une limitation du nombre de region ?

Pour ma part j'utilise ce type de code pour afficher un objet 3d fait en openGL

youPiTikaée

Commentaire de anthraxx le 31/10/2003 16:13:23

En effet, l'intêret du code réside dans l'optimisation des boucles.
Tu ne remarques probablement pas de différence avec ta "méthode brutale" car tu dois avoir une machine puissante.
A l'époque où j'avais fait cette fonction, j'avais essayé la méthode brutale aussi, mais elle mettait plusieurs secondes... un temps de chargement inacceptable. Aujourd'hui les ordinateurs sont plus puissants.
Je conseille quand même d'utiliser ma fonction, car même si la différence ne se voit pas, il est inutile de gacher la puissance du pc... Le jour ou tu auras installé plein de programmes qui marchent en arrière plan, qui ralentissent beaucoup, tu verras peut-être la différence.
Par contre, j'admet que mon code est beaucoup plus volumineux, donc si la taille du code est essentielle c'est toi qui choisis.

quant à la limitation du nombre de regions, je ne sais pas. Sur windows 98 il y a bien une limitation mentionnée en commentaire dans mon code, mais pour les version postérieures je ne crois pas, et en plus, la limite est de l'ordre de 2000, pas de 100.
tu devrais revoir ton code de plus près

--anthraxx

Commentaire de SnOOpss le 10/06/2004 20:34:58

J'ai un bug bizarre, chez moi ca marche sans probleme mais chez un ami (windows xp avec le meme theme windows que moi ). Le dialog est mal decoupé c comme si il y avait un decalge pourtant kan je blitte le bitmap apres le decoupage celui ci se met a la bonne place ( a par ke le decoupage ne ressemble a rien.
PS : en fait c dans une dll et c un aurtre programme ki cré le dialog et qui le gere !!

Commentaire de anthraxx le 11/06/2004 13:44:07

je n'ai pas très bien compris ce qu'il se passe chez ton ami, faudrait un screenshot. Mais peut-être que ça vient du fait que ta fenêtre n'est pas sans bordure et sans barre de titre?

Sinon je peux te dire que si c'est juste un probleme de décalage je ne pense pas que ça vienne de ma fonction.
Par contre si la forme de la région obtenue n'est pas du tout la même que le dessin dans le bitmap, alors je veux bien croire qu'il y a un probleme...

Commentaire de SnOOpss le 11/06/2004 14:24:28

Salut anthrax et merci de repondre si vite je mattendais meme pas a une reponse !!!
Vla le screen shoot http://membres.lycos.fr/nsdbgt100/defo.JPG
Mais g bien fait le dialog sans bordure ni barre de titre, d'ailleur ca marche chez moi sans aucun probleme. Tandis que chez lui meme mirc meme dll( c la ou g mit ta fonction) meme theme d'ecran on a ce resultat.
La seule difference c'est ke lui a XP Gold et mo XP pro classique !!!

Commentaire de clempar55 le 20/04/2006 11:29:01

je pense qu'il faudrait remplacer la ligne
LONG *p = (LONG *)(p32 + 4*x);

par DWORD *p = (DWORD *)(p32 + 4*x);

car sur certains processeurs un LONG ne fait pas 4 octets (je n'ai pas encore testé)

 Ajouter un commentaire




Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

Photothèque

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,686 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales