Por defecto podemos crear algún tipo de región: rectangular, elíptica o poligonal. Se echa en falta conseguir una región a partir de un bitmap con un dibujo personalizado. El truco que presento trata de realizar eso mismo usando la API.
La función CreateBitmapRgn crea un HRGN a partir de un HBITMAP usando un color es una versión mejorada de la que publiqué en el tema Manejo de imágenes Bitmap estilo Winamp, una prueba de concepto donde hago uso de regiones para personalizar un Skin para un formulario.
HRGN CreateBitmapRgn(HBITMAP hBmp, COLORREF Color, bool Tr);
function CreateBitmapRgn(hbmp: HBITMAP; Color: COLORREF; Tr: boolean): HRGN;
hbmp: Es el bitmap a partir del que vamos a obtener una región.
Color: Es el color que va a definir la región dependiendo del valor de Tr.
Tr: Modifica el funcionamiento. Si Tr es true, Color se considerará que será transparente, en caso contrario, Color será opaco y todo lo demás transparente.
La región creada deberá ser destruida cuando no siga haciendo falta su uso con la API DeleteObject.
Os dejo el código en C/C++
HRGN CreateBitmapRgn(HBITMAP hBmp, COLORREF Color, bool Tr) { DWORD DWColor = ((Color << 16) & 0x00FF0000) | (Color & 0x0000FF00) | ((Color >> 16) & 0x000000FF); HDC hDC = GetDC(0); int x, y; HRGN hrgn, hrgnTmp; PDWORD pBites = 0; BITMAPINFO bmpInfo = {0}; // Obtengo un mapa de bits de 32 BitCount bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); GetDIBits(hDC, hBmp, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); bmpInfo.bmiHeader.biSizeImage = (bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight) << 2; bmpInfo.bmiHeader.biPlanes = 1; bmpInfo.bmiHeader.biBitCount = 32; bmpInfo.bmiHeader.biCompression = BI_RGB; pBites = (PDWORD)VirtualAlloc(0, bmpInfo.bmiHeader.biSizeImage, MEM_COMMIT, PAGE_READWRITE); GetDIBits(hDC, hBmp, 0, bmpInfo.bmiHeader.biHeight, pBites, &bmpInfo, DIB_RGB_COLORS); // Creo la región hrgn = CreateRectRgn(0, 0, 0, 0); int w = 0; for(y = bmpInfo.bmiHeader.biHeight-1; y>=0; y--){ for(x = 0; x < bmpInfo.bmiHeader.biWidth; x++){ if(x < bmpInfo.bmiHeader.biWidth-1 && x != w && ((*pBites & 0xFFFFFF) == DWColor) ^ Tr) w++; else if(w > 0){ hrgnTmp = CreateRectRgn(x-w, y, x + 1, y + 1); CombineRgn(hrgn, hrgn, hrgnTmp, RGN_OR); DeleteObject(hrgnTmp); w = 0; } pBites++; } } VirtualFree(pBites, 0, MEM_RELEASE); ReleaseDC(0, hDC); return hrgn; }
Y en delphi:
function CreateBitmapRgn(hbmp: HBITMAP; Color: COLORREF; Tr: boolean): HRGN; var DWColor: DWORD; DC: HDC; x, y, w: integer; incRow: integer; hrgnTmp: HRGN; pBites: PDWORD; bmpInfo: BITMAPINFO; begin DWColor:= ((Color shl 16) and $00FF0000) or (Color and $0000FF00) or ((Color shr 16) and $000000FF); DC:= GetDC(0); // Obtengo un mapa de bits de 32 BitCount ZeroMemory(@bmpInfo, sizeof(BITMAPINFO)); bmpInfo.bmiHeader.biSize := sizeof(BITMAPINFOHEADER); GetDIBits(DC, hbmp, 0, 0, nil, bmpInfo, DIB_RGB_COLORS); bmpInfo.bmiHeader.biSizeImage:= (bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight) * 4; bmpInfo.bmiHeader.biPlanes:= 1; bmpInfo.bmiHeader.biBitCount:= 32; bmpInfo.bmiHeader.biCompression:= BI_RGB; pBites := VirtualAlloc(nil, bmpInfo.bmiHeader.biSizeImage, MEM_COMMIT, PAGE_READWRITE); GetDIBits(DC, hbmp, 0, bmpInfo.bmiHeader.biHeight, pBites, bmpInfo, DIB_RGB_COLORS); // Creo la región Result:= CreateRectRgn(0, 0, 0, 0); w:= 0; for y:= bmpInfo.bmiHeader.biHeight-1 downto 0 do begin for x:= 0 to bmpInfo.bmiHeader.biWidth-1 do begin if (x<bmpInfo.bmiHeader.biWidth-1) and (x <> w) and ((((pBites^ and $FFFFFF) = DWColor) xor Tr) = true) then inc(w) else if w > 0 then begin hrgnTmp:= CreateRectRgn(x-w, y, x, y+1); CombineRgn(Result, Result, hrgnTmp, RGN_OR); DeleteObject(hrgnTmp); w:= 0; end; inc(pBites); end; end; VirtualFree(pBites, 0, MEM_RELEASE); ReleaseDC(0, DC); end;
Espero que la información y el código os sea de utilidad.
Saludos.