Page 1 of 1

Alphablend Platform Independent Working !!!

Posted: Thu Apr 16, 2009 1:39 pm
by toninhofwi
Hi friends,

This is my first try of an AlphaBlend funtion that works on all windows version, and can be changed to work on linux too:

It is working but need be optmized for speed:

Code: Select all

#pragma BEGINDUMP

#include "windows.h"
#include "hbapi.h"

WORD DibNumColors( void * pv );

HANDLE DibFromBitmap( HBITMAP, DWORD, WORD, HPALETTE );

static WORD PaletteSize( void * pv )
{
    LPBITMAPINFOHEADER lpbi = ( LPBITMAPINFOHEADER ) pv;

    WORD NumColors = DibNumColors( lpbi );

    if( lpbi->biSize == sizeof( BITMAPCOREHEADER ) )
    {
       return ( WORD )( NumColors * sizeof( RGBTRIPLE ) );
    }
    else
    {
       return ( WORD )( NumColors * sizeof( RGBQUAD ) );
    }
}

void DrawNewAlpha( HDC hdc, HBITMAP hbm, int iRow, int iCol )
{
   HANDLE hDib = DibFromBitmap( hbm, 0, 0, ( HPALETTE ) 0 );

   COLORREF clr;

   int i, j;

   BYTE r, g, b;

   if( hDib )
   {
      LPBITMAPINFO lpbmi = ( LPBITMAPINFO ) GlobalLock( hDib );

      unsigned char * uc = ( LPBYTE ) lpbmi + ( WORD ) lpbmi->bmiHeader.biSize + PaletteSize( lpbmi );

      unsigned long ul = 3, a1, a2;

      for( j = 0; j < lpbmi->bmiHeader.biHeight; j++ )
      {
         for( i = 0; i < lpbmi->bmiHeader.biWidth; i++ )
         {
              a1 = uc[ ul ];

              if( a1 != 0 )
              {
                  if( a1 == 255 )
                  {
                      clr = RGB( uc[ ul - 1 ], uc[ ul - 2 ], uc[ ul - 3 ] );

                      SetPixelV( hdc, i + iCol, lpbmi->bmiHeader.biHeight - j + iRow, clr );
                  }
                  else
                  {
                      a2 = 255 - a1;

                      clr = GetPixel( hdc, i + iCol, lpbmi->bmiHeader.biHeight - j + iRow );

                      b = clr / 65536;
                      g = clr / 256;
                      r = ( clr - ( b * 65536 ) - ( g * 256 ) );

                      SetPixelV( hdc, i + iCol, lpbmi->bmiHeader.biHeight - j + iRow, RGB( ( ( ( a1 * uc[ ul - 1 ] ) + ( a2 * r ) ) / 255 ), ( ( ( a1 * uc[ ul - 2 ] ) + ( a2 * g ) ) / 255 ), ( ( ( a1 * uc[ ul - 3 ] ) + ( a2 * b ) ) / 255 ) ) );
                  }
              }

              ul += 4;
         }
      }

      GlobalUnlock( hDib );
   }

   hb_retl( 1 );
}

//------------------------------------------------------------------------------------------------------------------//

HB_FUNC( NEWALPHABLEND )
{
   DrawNewAlpha( ( HDC )  hb_parnl( 1 ), ( HBITMAP ) hb_parnl( 2 ), hb_parni( 3 ), hb_parni( 4 ) );
}

#pragma ENDDUMP

To test:

Code: Select all

   local hBmp := LoadBitmap(GetResources(), 7777 )
   NewAlphaBlend( oDlg:GetDC(), hBmp, 40, 40 )
   oDlg:ReleaseDC()

Regards,

Toninho.

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 1:46 pm
by Antonio Linares
Toninho,

GetPixel() and SetPixel() are quite slow, you should avoid them.

To improve the speed, you have to directly access the array of bytes of the bitmap.

Please review this DrDobbs article :-) AlphaBlendU()
http://www.ddj.com/windows/184416353?pgno=21

The Alpha Channel is not used in such code. It has to be modified to use it.

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 2:37 pm
by toninhofwi
Antonio Linares wrote:Toninho,

GetPixel() and SetPixel() are quite slow, you should avoid them.

To improve the speed, you have to directly access the array of bytes of the bitmap.
Hi Antonio. Thanks. I know it. As I say, it is my first try.
Antonio Linares wrote: Please review this DrDobbs article :-) AlphaBlendU()
http://www.ddj.com/windows/184416353?pgno=21

The Alpha Channel is not used in such code. It has to be modified to use it.
Thanks for the hint. I´ll try implement Alpha Channel in its code.

Regards,

Toninho.

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 2:49 pm
by Antonio Linares
Toninho,

> I´ll try implement Alpha Channel in its code.

I have tried it and I have it partially working.

If you want to I can share my changes so we can work together to get it properly working :-)

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 2:54 pm
by Antonio Linares
Toninho,

The fourth byte keeps the alpha channel amount. These are my changes. They are working but the alpha level is not taken into account. We need to improve it :-)

Code: Select all

...
for ( i = 0; i < cx; ++i)
        {
            if( pbSrcRGB[3] )  // Alpha value
            {
               pbSrcRGB[0]=(pbDestRGB[0] * ( alpha - pbSrcRGB[3] ) + // (255-alpha) +
                            pbSrcRGB[0] * ( pbSrcRGB[3] ) ) >>8; // alpha
               pbSrcRGB[1]=(pbDestRGB[1] * ( alpha - pbSrcRGB[3] ) + // (255-alpha) +
                            pbSrcRGB[1] * ( pbSrcRGB[3] ) ) >>8;
               pbSrcRGB[2]=(pbDestRGB[2] * ( alpha - pbSrcRGB[3] ) + // (255-alpha) +
                            pbSrcRGB[2] * ( pbSrcRGB[3] ) ) >>8;
            }   
            else
            {
               pbSrcRGB[0] = pbDestRGB[0];
               pbSrcRGB[1] = pbDestRGB[1];
               pbSrcRGB[2] = pbDestRGB[2];
            }                
            pbSrcRGB += 4;
            pbDestRGB += 4;
        }
...
 

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 4:56 pm
by toninhofwi
Hi Antonio.

Done !!!!!!!!!!!!! In another way:

Code: Select all

#pragma BEGINDUMP

#include "windows.h"
#include "hbapi.h"

//------------------------------------------------------------------------------------------------------------------//

WORD DibNumColors( void * pv );

HPALETTE CreateDIBPalette( HGLOBAL hDIB );

HANDLE DibFromBitmap( HBITMAP, DWORD, WORD, HPALETTE );

BOOL DibDraw( HDC hDC, HGLOBAL hDib, WORD wCol, WORD wRow, HPALETTE hPalette, WORD wWidth, WORD wHeight, DWORD dwRop );

static WORD PaletteSize( void * pv )
{
    LPBITMAPINFOHEADER lpbi = ( LPBITMAPINFOHEADER ) pv;

    WORD NumColors = DibNumColors( lpbi );

    if( lpbi->biSize == sizeof( BITMAPCOREHEADER ) )
    {
       return ( WORD )( NumColors * sizeof( RGBTRIPLE ) );
    }
    else
    {
       return ( WORD )( NumColors * sizeof( RGBQUAD ) );
    }
}

//------------------------------------------------------------------------------------------------------------------//

void DrawNewAlpha( HDC hDC1, HBITMAP hBitmap1, int iRow, int iCol )
{
   HDC hDC2;

   HANDLE hDib1, hDib2;

   unsigned char * uc1;
   unsigned char * uc2;

   unsigned long a1, a2;

   unsigned int i1;

   LPBITMAPINFO lpbmi1, lpbmi2;

   HBITMAP hBitmap2, hBmpOld;

   BITMAP bm;

   hDC2 = CreateCompatibleDC( hDC1 );

   GetObject( ( HGDIOBJ ) hBitmap1, sizeof( BITMAP ), ( LPSTR ) &bm );

   hBitmap2 = CreateCompatibleBitmap( hDC1, bm.bmWidth, bm.bmHeight );

   hBmpOld = ( HBITMAP ) SelectObject( hDC2, hBitmap2 );

   BitBlt( hDC2, 0, 0, bm.bmWidth, bm.bmHeight, hDC1, iCol, iRow, SRCCOPY );

   //---------------------------------------------------------------------------------------------------------------//

   hDib1 = DibFromBitmap( hBitmap1, 0, 32, ( HPALETTE ) 0 );
   hDib2 = DibFromBitmap( hBitmap2, 0, 32, ( HPALETTE ) 0 );

   lpbmi1 = ( LPBITMAPINFO ) GlobalLock( hDib1 );
   lpbmi2 = ( LPBITMAPINFO ) GlobalLock( hDib2 );

   uc1 = ( LPBYTE ) lpbmi1 + ( WORD ) lpbmi1->bmiHeader.biSize + PaletteSize( lpbmi1 );
   uc2 = ( LPBYTE ) lpbmi2 + ( WORD ) lpbmi2->bmiHeader.biSize + PaletteSize( lpbmi2 );

   //---------------------------------------------------------------------------------------------------------------//

   for( i1 = 3; i1 <= lpbmi1->bmiHeader.biSizeImage; i1 += 4 )
   {
        a1 = uc1[ i1 ];

        if( a1 != 0 )
        {
            if( a1 == 255 )
            {
                uc2[ i1 - 3 ] = uc1[ i1 - 3 ];
                uc2[ i1 - 2 ] = uc1[ i1 - 2 ];
                uc2[ i1 - 1 ] = uc1[ i1 - 1 ];
            }
            else
            {
                a2 = 255 - a1;

                uc2[ i1 - 3 ] = ( a1 * uc1[ i1 - 3 ] + a2 * uc2[ i1 - 3 ] ) / 255;
                uc2[ i1 - 2 ] = ( a1 * uc1[ i1 - 2 ] + a2 * uc2[ i1 - 2 ] ) / 255;
                uc2[ i1 - 1 ] = ( a1 * uc1[ i1 - 1 ] + a2 * uc2[ i1 - 1 ] ) / 255;
            }
        }
   }

   DibDraw( hDC1, hDib2, iCol, iRow, 0, 0, 0, 0 );

   //---------------------------------------------------------------------------------------------------------------//

   GlobalUnlock( hDib1 );
   GlobalUnlock( hDib2 );

   SelectObject( hDC2, hBmpOld );

   DeleteObject( hBitmap2 );

   DeleteDC( hDC2 );
}

//------------------------------------------------------------------------------------------------------------------//

HB_FUNC( NEWALPHABLEND )
{
   DrawNewAlpha( ( HDC )  hb_parnl( 1 ), ( HBITMAP ) hb_parnl( 2 ), hb_parni( 3 ), hb_parni( 4 ) );
}

//------------------------------------------------------------------------------------------------------------------//

#pragma ENDDUMP

Regards,

Toninho.

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 5:58 pm
by Antonio Linares
Toninho,

You have to free the hDibs memory:

Code: Select all

   GlobalUnlock( hDib1 );
   GlobalUnlock( hDib2 );
   GlobalFree( hDib1 );  // new
   GlobalFree( hDib2 );  // new
 
Your code works fine but it does not uses an AlphaBlend transparency level. i.e.:

NEWALPHABLEND( hDC, hBitmap, nRow, nCol, nSourceConstantAlpha )
where nSourceConstantAlpha is in the range 0, 255.

From Microsoft docs:
SourceConstantAlpha
Specifies an alpha transparency value to be used on the entire source bitmap. The SourceConstantAlpha value is combined with any per-pixel alpha values in the source bitmap. If you set SourceConstantAlpha to 0, it is assumed that your image is transparent. When you only want to use per-pixel alpha values, set the SourceConstantAlpha value to 255 (opaque) .

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 6:31 pm
by toninhofwi
Hey Antonio, you are fast ! :D

Here is the code:

Code: Select all

#pragma BEGINDUMP

#include "windows.h"
#include "hbapi.h"

//------------------------------------------------------------------------------------------------------------------//

WORD DibNumColors( void * pv );

HPALETTE CreateDIBPalette( HGLOBAL hDIB );

HANDLE DibFromBitmap( HBITMAP, DWORD, WORD, HPALETTE );

BOOL DibDraw( HDC hDC, HGLOBAL hDib, WORD wCol, WORD wRow, HPALETTE hPalette, WORD wWidth, WORD wHeight, DWORD dwRop );

static WORD PaletteSize( void * pv )
{
    LPBITMAPINFOHEADER lpbi = ( LPBITMAPINFOHEADER ) pv;

    WORD NumColors = DibNumColors( lpbi );

    if( lpbi->biSize == sizeof( BITMAPCOREHEADER ) )
    {
       return ( WORD )( NumColors * sizeof( RGBTRIPLE ) );
    }
    else
    {
       return ( WORD )( NumColors * sizeof( RGBQUAD ) );
    }
}

//------------------------------------------------------------------------------------------------------------------//

void DrawNewAlpha( HDC hDC1, HBITMAP hBitmap1, int iRow, int iCol, int alpha )
{
   HDC hDC2;

   HANDLE hDib1, hDib2;

   unsigned char * uc1;
   unsigned char * uc2;

   unsigned long a1, a2;

   unsigned int i1;

   LPBITMAPINFO lpbmi1, lpbmi2;

   HBITMAP hBitmap2, hBmpOld;

   BITMAP bm;

   hDC2 = CreateCompatibleDC( hDC1 );

   GetObject( ( HGDIOBJ ) hBitmap1, sizeof( BITMAP ), ( LPSTR ) &bm );

   hBitmap2 = CreateCompatibleBitmap( hDC1, bm.bmWidth, bm.bmHeight );

   hBmpOld = ( HBITMAP ) SelectObject( hDC2, hBitmap2 );

   BitBlt( hDC2, 0, 0, bm.bmWidth, bm.bmHeight, hDC1, iCol, iRow, SRCCOPY );

   //---------------------------------------------------------------------------------------------------------------//

   hDib1 = DibFromBitmap( hBitmap1, 0, 32, ( HPALETTE ) 0 );
   hDib2 = DibFromBitmap( hBitmap2, 0, 32, ( HPALETTE ) 0 );

   lpbmi1 = ( LPBITMAPINFO ) GlobalLock( hDib1 );
   lpbmi2 = ( LPBITMAPINFO ) GlobalLock( hDib2 );

   uc1 = ( LPBYTE ) lpbmi1 + ( WORD ) lpbmi1->bmiHeader.biSize + PaletteSize( lpbmi1 );
   uc2 = ( LPBYTE ) lpbmi2 + ( WORD ) lpbmi2->bmiHeader.biSize + PaletteSize( lpbmi2 );

   //---------------------------------------------------------------------------------------------------------------//

   alpha = 255 - alpha;

   for( i1 = 3; i1 <= lpbmi1->bmiHeader.biSizeImage; i1 += 4 )
   {
        a1 = uc1[ i1 ];

        if( a1 != 0 )
        {
            a2 = 255 + alpha - uc1[ i1 ];

            uc2[ i1 - 3 ] = ( a1 * uc1[ i1 - 3 ] + a2 * uc2[ i1 - 3 ] ) / ( 255 + alpha );
            uc2[ i1 - 2 ] = ( a1 * uc1[ i1 - 2 ] + a2 * uc2[ i1 - 2 ] ) / ( 255 + alpha );
            uc2[ i1 - 1 ] = ( a1 * uc1[ i1 - 1 ] + a2 * uc2[ i1 - 1 ] ) / ( 255 + alpha );
        }
   }

   DibDraw( hDC1, hDib2, iCol, iRow, 0, 0, 0, 0 );

   //---------------------------------------------------------------------------------------------------------------//

   GlobalUnlock( hDib1 );
   GlobalUnlock( hDib2 );

   GlobalFree( hDib1 );
   GlobalFree( hDib2 );

   SelectObject( hDC2, hBmpOld );

   DeleteObject( hBitmap2 );

   DeleteDC( hDC2 );
}

//------------------------------------------------------------------------------------------------------------------//

HB_FUNC( NEWALPHABLEND )
{
   DrawNewAlpha( ( HDC )  hb_parnl( 1 ), ( HBITMAP ) hb_parnl( 2 ), hb_parni( 3 ), hb_parni( 4 ), 55 );
}

//------------------------------------------------------------------------------------------------------------------//

#pragma ENDDUMP
The last param of DrawNewAlpha() accept valus from 0 to 255. 255 is full and 0 is transparent.

Regards,

Toninho.

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 7:16 pm
by Antonio Linares
Toninho,

It is getting better :-)

I would use:

Code: Select all

HB_FUNC( NEWALPHABLEND )
{
   DrawNewAlpha( ( HDC )  hb_parnl( 1 ), ( HBITMAP ) hb_parnl( 2 ), hb_parni( 3 ), hb_parni( 4 ), hb_parnl( 5 ) );
}
 
Anyhow if you use a zero alpha value, the bitmap should not be seen. With your code, still it is seen.

I think that you are quite close to have it :-)

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 7:30 pm
by toninhofwi
Antonio Linares wrote:Toninho,

It is getting better :-)

Anyhow if you use a zero alpha value, the bitmap should not be seen. With your code, still it is seen.

I think that you are quite close to have it :-)
Antonio, Thanks.

I´ll see it tonight and post here.

But I´m trying to use crestostr() without success, can you please review this FWH function? I´m trying in this way:

? Len( cResToStr( 7777, 2 ) ) // 7777 is my resource, 2 is RT_BITMAP

Regards,

Toninho.

Re: Alphablend Platform Independent !!!

Posted: Thu Apr 16, 2009 7:44 pm
by Antonio Linares
Toninho,

> ? Len( cResToStr( 7777, 2 ) ) // 7777 is my resource, 2 is RT_BITMAP

Actually cResToStr() expects a string as the second parameter:

? Len( cResToStr( 7777, "BITMAP" ) )

We have to modify cResToStr() to accept numbers also.

Re: Alphablend Platform Independent !!!

Posted: Fri Apr 17, 2009 12:56 am
by toninhofwi
Antonio Linares wrote:Toninho,
It is getting better :-)
Anyhow if you use a zero alpha value, the bitmap should not be seen. With your code, still it is seen.
I think that you are quite close to have it :-)
DONE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Code: Select all

// Alphablend platform independent
// works in all windows versions
// Toninho@fwi.com.br
// Ver 1.05 - Apr 2009

#pragma BEGINDUMP

#include "windows.h"
#include "hbapi.h"

//------------------------------------------------------------------------------------------------------------------//

WORD DibNumColors( void * pv );

HPALETTE CreateDIBPalette( HGLOBAL hDIB );

HANDLE DibFromBitmap( HBITMAP, DWORD, WORD, HPALETTE );

BOOL DibDraw( HDC hDC, HGLOBAL hDib, WORD wCol, WORD wRow, HPALETTE hPalette, WORD wWidth, WORD wHeight, DWORD dwRop );

static WORD PaletteSize( void * pv )
{
    LPBITMAPINFOHEADER lpbi = ( LPBITMAPINFOHEADER ) pv;

    WORD NumColors = DibNumColors( lpbi );

    if( lpbi->biSize == sizeof( BITMAPCOREHEADER ) )
    {
       return ( WORD )( NumColors * sizeof( RGBTRIPLE ) );
    }
    else
    {
       return ( WORD )( NumColors * sizeof( RGBQUAD ) );
    }
}

//------------------------------------------------------------------------------------------------------------------//

void DrawNewAlpha( HDC hDC1, HBITMAP hBitmap1, int iRow, int iCol, int alpha )
{
   HDC hDC2;

   HANDLE hDib1, hDib2;

   unsigned char * uc1;
   unsigned char * uc2;

   unsigned long a1, a2;

   unsigned int i1;

   LPBITMAPINFO lpbmi1, lpbmi2;

   HBITMAP hBitmap2, hBmpOld;

   BITMAP bm;

   hDC2 = CreateCompatibleDC( hDC1 );

   GetObject( ( HGDIOBJ ) hBitmap1, sizeof( BITMAP ), ( LPSTR ) &bm );

   hBitmap2 = CreateCompatibleBitmap( hDC1, bm.bmWidth, bm.bmHeight );

   hBmpOld = ( HBITMAP ) SelectObject( hDC2, hBitmap2 );

   BitBlt( hDC2, 0, 0, bm.bmWidth, bm.bmHeight, hDC1, iCol, iRow, SRCCOPY );

   //---------------------------------------------------------------------------------------------------------------//

   hDib1 = DibFromBitmap( hBitmap1, 0, 32, ( HPALETTE ) 0 );
   hDib2 = DibFromBitmap( hBitmap2, 0, 32, ( HPALETTE ) 0 );

   lpbmi1 = ( LPBITMAPINFO ) GlobalLock( hDib1 );
   lpbmi2 = ( LPBITMAPINFO ) GlobalLock( hDib2 );

   uc1 = ( LPBYTE ) lpbmi1 + ( WORD ) lpbmi1->bmiHeader.biSize + PaletteSize( lpbmi1 );
   uc2 = ( LPBYTE ) lpbmi2 + ( WORD ) lpbmi2->bmiHeader.biSize + PaletteSize( lpbmi2 );

   //---------------------------------------------------------------------------------------------------------------//

   for( i1 = 3; i1 <= lpbmi1->bmiHeader.biSizeImage; i1 += 4 )
   {
        a1 = uc1[ i1 ];

        if( a1 != 0 )
        {
            a1 = alpha * ( ( uc1[ i1 ] * 100 ) / 255 ) / 100;

            a2 = 255 - a1;

            uc2[ i1 - 3 ] = ( uc1[ i1 - 3 ] * a1 ) + ( uc2[ i1 - 3 ] * a2 ) >> 8;
            uc2[ i1 - 2 ] = ( uc1[ i1 - 2 ] * a1 ) + ( uc2[ i1 - 2 ] * a2 ) >> 8;
            uc2[ i1 - 1 ] = ( uc1[ i1 - 1 ] * a1 ) + ( uc2[ i1 - 1 ] * a2 ) >> 8;

        }
   }

   DibDraw( hDC1, hDib2, iCol, iRow, 0, 0, 0, 0 );

   //---------------------------------------------------------------------------------------------------------------//

   GlobalUnlock( hDib1 );
   GlobalUnlock( hDib2 );

   GlobalFree( hDib1 );
   GlobalFree( hDib2 );

   SelectObject( hDC2, hBmpOld );

   DeleteObject( hBitmap2 );

   DeleteDC( hDC2 );
}

//------------------------------------------------------------------------------------------------------------------//

HB_FUNC( NEWALPHABLEND )
{
   DrawNewAlpha( ( HDC )  hb_parnl( 1 ), ( HBITMAP ) hb_parnl( 2 ), hb_parni( 3 ), hb_parni( 4 ), hb_parni( 5 ) );
}

//------------------------------------------------------------------------------------------------------------------//

#pragma ENDDUMP

Regards,

Toninho.

Re: Alphablend Platform Independent Working !!!

Posted: Fri Apr 17, 2009 8:22 am
by Antonio Linares
Toninho,

Very good! :-)

Congratulations!

Re: Alphablend Platform Independent Working !!!

Posted: Fri Apr 17, 2009 1:43 pm
by Adolfo
Toninho...

Great... thanks for your efforts...

I'll try it right away..


From Chile
Adolfo