Ir al contenido


Foto

[MULTILENGUAJE] Crear una región personalizada a partir de un hBitmap


  • Por favor identifícate para responder
6 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 abril 2011 - 03:37

Las regiones en Windows nos permiten realizar cosas interesantes. Quizás una de las mas llamativas sea definir contornos personalizados para nuestras ventanas. También permiten aislar zonas sobre las que vanos a dibujar.

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.
 

cpp
  1. HRGN CreateBitmapRgn(HBITMAP hBmp, COLORREF Color, bool Tr);


delphi
  1. 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++
 

cpp
  1. HRGN CreateBitmapRgn(HBITMAP hBmp, COLORREF Color, bool Tr)
  2. {
  3.   DWORD DWColor = ((Color << 16) & 0x00FF0000) | (Color & 0x0000FF00) | ((Color >> 16) & 0x000000FF);
  4.   HDC hDC = GetDC(0);
  5.   int    x, y;
  6.   HRGN  hrgn,  hrgnTmp;
  7.   PDWORD pBites = 0;
  8.   BITMAPINFO bmpInfo = {0};
  9.  
  10.   // Obtengo un mapa de bits de 32 BitCount
  11.   bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  12.   GetDIBits(hDC, hBmp, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
  13.   bmpInfo.bmiHeader.biSizeImage = (bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight) << 2;
  14.   bmpInfo.bmiHeader.biPlanes = 1;
  15.   bmpInfo.bmiHeader.biBitCount = 32;
  16.   bmpInfo.bmiHeader.biCompression = BI_RGB;
  17.   pBites = (PDWORD)VirtualAlloc(0, bmpInfo.bmiHeader.biSizeImage, MEM_COMMIT, PAGE_READWRITE);
  18.   GetDIBits(hDC, hBmp, 0, bmpInfo.bmiHeader.biHeight, pBites, &bmpInfo, DIB_RGB_COLORS);
  19.  
  20.   // Creo la región
  21.   hrgn = CreateRectRgn(0, 0, 0, 0);
  22.   int w = 0;
  23.   for(y = bmpInfo.bmiHeader.biHeight-1; y>=0; y--){
  24.     for(x = 0; x < bmpInfo.bmiHeader.biWidth; x++){
  25.       if(x < bmpInfo.bmiHeader.biWidth-1 && x != w && ((*pBites & 0xFFFFFF) == DWColor) ^ Tr)
  26.         w++;
  27.       else  if(w > 0){
  28.         hrgnTmp = CreateRectRgn(x-w, y, x + 1, y + 1);
  29.         CombineRgn(hrgn, hrgn, hrgnTmp, RGN_OR);
  30.         DeleteObject(hrgnTmp);
  31.         w = 0;
  32.       }
  33.       pBites++;
  34.     }
  35.   }
  36.  
  37.   VirtualFree(pBites, 0, MEM_RELEASE);
  38.   ReleaseDC(0, hDC);
  39.   return hrgn;
  40. }

Y en delphi:

delphi
  1. function CreateBitmapRgn(hbmp: HBITMAP; Color: COLORREF; Tr: boolean): HRGN;
  2. var
  3.   DWColor: DWORD;
  4.   DC: HDC;
  5.   x, y, w: integer;
  6.   incRow: integer;
  7.   hrgnTmp: HRGN;
  8.   pBites: PDWORD;
  9.   bmpInfo: BITMAPINFO;
  10. begin
  11.   DWColor:= ((Color shl 16) and $00FF0000) or (Color and $0000FF00) or ((Color shr 16) and $000000FF);
  12.   DC:= GetDC(0);
  13.  
  14.   // Obtengo un mapa de bits de 32 BitCount
  15.   ZeroMemory(@bmpInfo, sizeof(BITMAPINFO));
  16.   bmpInfo.bmiHeader.biSize := sizeof(BITMAPINFOHEADER);
  17.   GetDIBits(DC, hbmp, 0, 0, nil, bmpInfo, DIB_RGB_COLORS);
  18.   bmpInfo.bmiHeader.biSizeImage:= (bmpInfo.bmiHeader.biWidth * bmpInfo.bmiHeader.biHeight) * 4;
  19.   bmpInfo.bmiHeader.biPlanes:= 1;
  20.   bmpInfo.bmiHeader.biBitCount:= 32;
  21.   bmpInfo.bmiHeader.biCompression:= BI_RGB;
  22.   pBites := VirtualAlloc(nil, bmpInfo.bmiHeader.biSizeImage, MEM_COMMIT, PAGE_READWRITE);
  23.   GetDIBits(DC, hbmp, 0, bmpInfo.bmiHeader.biHeight, pBites, bmpInfo, DIB_RGB_COLORS);
  24.  
  25.   // Creo la región
  26.   Result:= CreateRectRgn(0, 0, 0, 0);
  27.   w:= 0;
  28.   for y:= bmpInfo.bmiHeader.biHeight-1 downto 0 do
  29.   begin
  30.     for x:= 0 to bmpInfo.bmiHeader.biWidth-1 do
  31.     begin
  32.       if (x<bmpInfo.bmiHeader.biWidth-1) and (x <> w) and ((((pBites^ and $FFFFFF) = DWColor) xor Tr) = true) then
  33.         inc(w)
  34.       else  if w > 0 then
  35.       begin
  36.         hrgnTmp:= CreateRectRgn(x-w, y, x, y+1);
  37.         CombineRgn(Result, Result, hrgnTmp, RGN_OR);
  38.         DeleteObject(hrgnTmp);
  39.         w:= 0;
  40.       end;
  41.       inc(pBites);
  42.     end;
  43.   end;
  44.   VirtualFree(pBites, 0, MEM_RELEASE);
  45.   ReleaseDC(0, DC);
  46. end;


Espero que la información y el código os sea de utilidad.

Saludos.
  • 0

#2 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 07 abril 2011 - 08:45

Excelente amigo escafandra, ¿que color usas en el ejemplo?


Saludos!
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 abril 2011 - 09:03

Excelente amigo escafandra, ¿que color usas en el ejemplo?



Se puede usar cualquier color del hBitmap en cuestión. Puedes considerarlo como el transparente, en cuyo caso se elimina de la región, o como opaco, siendo todos los demás los que se eliminarán.


En el ejemplo del tema "Manejo de imágenes Bitmap estilo Winamp" uso el blanco, como transparente, para la región que marcará el borde de la ventana porque así lo elegí. En los botones, el color de cada botón como opaco.


Se deme tener cuidado con bitmaps true color (24 y 32 bits) porque podemos encontrar el color deseado en zonas no deseadas y pequeñas diferencias de color que no son el color elegido con lo que el resultado puede no ser exactamente el esperado. En estos casos es mejor realizar una máscara con un editor gráfico, es decir un nueva capa del bitmap con los colores bien diferenciados para usarlo al crear la región.


Saludos.
  • 0

#4 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 07 abril 2011 - 09:09

Ok, porque en el ejemplo del otro hilo usas un Bitmap que maneja diferentes colores dependiendo de la región (imagino que para diferenciarlos), ¿esto es importante o simplemente todos vienen siendo el "opaco"?


Saludos!
  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 07 abril 2011 - 09:16

Si es importante la diferenciación de los colores, porque esas regiones serán las sensibles al ratón y cada color identifica un botón real del formulario, digamos que representan tanto la correspondencia Form1.Button --> dibujo Skin del botón correspondiente, como la zona del Skin que se redibuja al pulsar u soltar el botón izquierdo del ratón.


En esos colores la consideración es "opaco", así se crea una región por cada botón del Skin que se guarda en la propiedad Tag de cada botón real.


Quizás el código sea mas explícito que mis comentarios, no se si son un poco liosos.




Saludos.
  • 0

#6 felipe

felipe

    Advanced Member

  • Administrador
  • 3.283 mensajes
  • LocationColombia

Escrito 07 abril 2011 - 09:19

Si es importante la diferenciación de los colores, porque esas regiones serán las sensibles al ratón y cada color identifica un botón real del formulario, digamos que representan tanto la correspondencia Form1.Button --> dibujo Skin del botón correspondiente, como la zona del Skin que se redibuja al pulsar u soltar el botón izquierdo del ratón.


En esos colores la consideración es "opaco", así se crea una región por cada botón del Skin que se guarda en la propiedad Tag de cada botón real.


Quizás el código sea mas explícito que mis comentarios, no se si son un poco liosos.




Saludos.



Es claro el asunto amigo, era más como por saber la lógica del mismo en primera mano :)


Saludos!
  • 0

#7 Caral

Caral

    Advanced Member

  • Moderador
  • PipPipPip
  • 4.266 mensajes
  • LocationCosta Rica

Escrito 07 abril 2011 - 09:45

Hola
Muy interesante, como siempre.
Cosas asi son las que motivan a investigar mas.
Gracias escafandra.
Saludos
  • 0




IP.Board spam blocked by CleanTalk.