Code: Select all | Expand
HB_FUNC( GETBMPPIXEL ) // GetBmpPixel( hBitmap,nY,nX )
{
HBITMAP hBmp = ( HBITMAP ) hb_parnl( 1 ) ;
BITMAP bmp ;
int nY = hb_parni( 2 ) ; // nTop
int nX = hb_parni( 3 ) ; // nLeft
GetObject( ( HBITMAP ) hBmp, sizeof( BITMAP ), ( LPSTR ) &bmp ) ;
if ( bmp.bmBits == 0 || bmp.bmBitsPixel < 24 )
{
hb_retnl( ( LONG ) 0 ) ;
}
else
{
BYTE * lpDib = ( BYTE * ) bmp.bmBits ;
if ( bmp.bmBitsPixel == 24 )
{
nY = (bmp.bmHeight-1-nY) * ( ( ( ( ( bmp.bmWidth*3 ) - 1 ) / 4 ) + 1 ) * 4 ) ;
nX = (nX*3)+nY ;
}
else // bmp.bmBitsPixel == 32
{
nY = (bmp.bmHeight-1-nY) * ( bmp.bmWidth * 4 ) ;
nX = (nX*4)+nY ;
}
hb_retnl( ( LONG ) ( lpDib[nX+2] + (lpDib[nX+1] << 8) + (lpDib[nX+0] << 16) ) ) ;
}
}
HB_FUNC( GETBMPALPHA ) // GetBmpAlpha( hBitmap,nY,nX )
{
HBITMAP hBmp = ( HBITMAP ) hb_parnl( 1 ) ;
BITMAP bmp ;
int nY = hb_parni( 2 ) ; // nTop
int nX = hb_parni( 3 ) ; // nLeft
GetObject( ( HBITMAP ) hBmp, sizeof( BITMAP ), ( LPSTR ) &bmp ) ;
if ( bmp.bmBitsPixel == 32 )
{
BYTE * lpDib = ( BYTE * ) bmp.bmBits ;
nY = (bmp.bmHeight-1-nY) * ( bmp.bmWidth * 4 ) ;
nX = (nX*4)+nY ;
hb_retnl( ( LONG ) lpDib[nX+3] ) ;
}
else hb_retnl( ( LONG ) 0 ) ;
}
La primera función nos dice de qué color es el pixel (nX,nY) del bitmap 'hBitmap'. La segunda, qué nivel de opacidad/transparencia tiene ese pixel en el canal alpha. La primera utilidad es parecida a GetPixel(), pero muuucho más rápido, cientos de veces más rápido, la segunda no tiene equivalencia. La diferencia es que trabajan con bitmaps (o DIB's) de 24 o 32 bits de profundidad de color. Ventaja? bueno en mi aplicación "Selector de color":
viewtopic.php?f=6&t=30195
Intenté capturar los colores con GetPixel() y fue totalmente imposible, demasiado lento, el programa se atrancaba y no progresaba, con GetBmpPixel() el resultado es inmediato.
La pega que no conseguía resolver desde hace años es la siguiente: Me gusta dibujar botones, de hecho he modificado la clase TBITMAP para utilizarla como un botón sensible al ratón, es decir que cuando el cursor pasa por encima del control pasa de CursorArrow() a CursorHand() y cambio el bitmap, cuando dejo de estar sobre el control, el cursor vuelve a CursorArrow() y recupero el bitmap original. Hasta aquí ningún misterio. Lo malo es cuando el bitmap que utilizo como botón no es rectángular, por ejemplo un círculo, un libro, un coche etc, entonces mejor será que lo explique con un gráfico:
Imagen 1º: El cursor aun no ha llegado al botón representado por una circunferencia de colores, y tiene forma CursorArrow().
Imagen 2º: El cursor está sobre el control TBITMAP, y el cursor pasa a CursorHand(), pero aún está sobre la parte transparente del botón. Al cambiar ahí, es como si pasara a CursorHand() antes de llegar al botón. Al abandonar el control ocurre el efecto contrario, el cursor continúa como CursorHand() cuando ya no está sobre el dibujo, porque sigue estando sobre la parte transparente y aún no ha salido del control. Ese el efecto desagradable que qería suprimir con mi función.
Imagen 3º: El cursor está sobre el control pero sigue como CursorArrow() porque con GetBmpPixel() detecto que el pixel es de color transparente.
Imagen 4º: El cursor se encuentra sobre la parte opaca del botón y cambia a CursorHand(), se mantendrá así mientras detecte que no está sobre color transparente.
En mi clase modificada, también puedo representar bitmaps de 32 bits con canal de transparencia. Gracias a GetBmpAlpha() puedo saber si el cursor está sobre una parte transparente o traslucida, por ejemplo una sombra, o sobre una parte más opaca. Por ejemplo puedo ordenar que cambie a CursorHand() solo cunado el nivel de opacidad sea mayor de 200.
Por último, precisar que estás funciones solo trabajan con mapas de bits (o DIB's) de 24 o 32 bits de profundidad de color. Con bitmaps de 8 bits, 256 colores o monocromos, no lo he investigado. Y con lo poco que he visto, ahora mismo sería incapaz de implementarlo. Si a alguien le interesa y sabe hacerlo, si no le importa, estaría bien que lo expusiera en este post.
Espero que os sea de utilidad.
Un saludo.