#include "FiveWin.ch"
#include "Slider.ch"
STATIC oWnd, oBmp
FUNCTION Main()
local n
local oSlide1
local nVar1 := 0
local cFile := cGetFile( "*.bmp", "Select a BMP file" )
local hBmp
local hBlur
local oSay, cSay := Space( 11 )
DEFINE WINDOW oWnd TITLE "Test Blur Effect"
if !Empty( cFile )
hBmp = PalBmpRead( 0, cFile )
hBlur = PalBmpRead( 0, cFile )[ 1 ]
else
return nil
endif
@ 0, nBmpWidth( hBmp[ 1 ] ) + 15 SLIDER oSlide1 VAR nVar1 OF oWnd ;
VERTICAL ;
TOP DIRECTION ;
RANGE 0, 100;
MARKS 10;
SIZE 33, nBmpHeight( hBmp[ 1 ] ) PIXEL ;
ON CHANGE( cSay:= AllTrim( STR( nVar1 ) ), ;
oSay:Refresh(), ;
DeleteObject( hBlur ),;
hBlur := Blur( hBmp[ 1 ], nVar1 ),;
oWnd:Refresh() )
@ 0, oSlide1:nLeft + oSlide1:nWidth + 10 SAY oSay VAR cSay PIXEL OF oWnd
ACTIVATE WINDOW oWnd ;
ON PAINT( PalBmpDraw( hDC, 0, 0, If( nVar1 == 0, hBmp[ 1 ], hBlur ) ) )
RETURN ( nil )
#pragma BEGINDUMP
#include <windows.h>
#include <hbapi.h>
void DoHBlur( INT iStart, INT iEnd, INT iRadio, BYTE *pbDestRGB, BYTE *pbSrcRGB, LONG *lTotalClrs, INT iBPP );
void DoHorizontalBlur( BITMAP SrcBmp, BYTE *pBmpDes, BYTE *pBmpBytes, INT iRadio );
void DoVBlur( INT iStart, INT iEnd, INT iRadio, BYTE *pBmpDes, BYTE *pBmpBytes, LONG *lTotalClrs, DWORD dwWidth, INT iCol, INT iBPP );
void DoVerticalBlur( BITMAP SrcBmp, BYTE *pBmpDes, BYTE *pBmpBytes, INT iRadio );
HBITMAP Blur( HBITMAP hSrcBmp, INT iRadio )
{
BITMAP SrcBmp;
BITMAPINFO sBmpInfo;
BYTE *pBmpBytes, *pBmpDes, *pBmpHBlur;
HBITMAP hbmDest, hbmSrc, hbmOldFrom, hbmOldDes, hbmOld, hbmOldBlur, hbmHBlur;
LONG i, j, lOffset;
HDC dcSrc, dcDest, dcFrom, dcHBlur;
if( iRadio == 0 )
return 0;
GetObject(hSrcBmp, sizeof( BITMAP ), &SrcBmp);
#ifdef UNICODE
if( (SrcBmp.bmBitsPixel != 32) )
return 0;
#else
if( (SrcBmp.bmBitsPixel != 24) && (SrcBmp.bmBitsPixel != 32) )
return 0;
#endif
sBmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
sBmpInfo.bmiHeader.biWidth = SrcBmp.bmWidth;
sBmpInfo.bmiHeader.biHeight = SrcBmp.bmHeight;
sBmpInfo.bmiHeader.biBitCount = SrcBmp.bmBitsPixel;
sBmpInfo.bmiHeader.biPlanes = 1;
sBmpInfo.bmiHeader.biCompression = BI_RGB;
sBmpInfo.bmiHeader.biSizeImage = SrcBmp.bmBitsPixel * SrcBmp.bmWidth * SrcBmp.bmHeight / 8;
// Select HBITMAP Source ( hSrcBmp ) to Mem DC ( dcFrom )
dcFrom = CreateCompatibleDC( NULL );
hbmOldFrom = SelectObject( dcFrom, hSrcBmp );
hbmSrc = CreateDIBSection( dcFrom, ( LPBITMAPINFO )&sBmpInfo,
DIB_RGB_COLORS, ( void ** )&pBmpBytes, 0, 0);
dcSrc = CreateCompatibleDC( NULL );
hbmOld = (HBITMAP) SelectObject( dcSrc, hbmSrc );
// Fill the buffer with a copy of the bitmap's bits
BitBlt( dcSrc, 0, 0, SrcBmp.bmWidth, SrcBmp.bmHeight, dcFrom, 0, 0, SRCCOPY );
SelectObject( dcFrom, hbmOldFrom );
DeleteDC( dcFrom );
//Prepare Horizontal Bitmap Blur
dcHBlur = CreateCompatibleDC( NULL );
hbmHBlur = CreateDIBSection( dcHBlur, ( LPBITMAPINFO )&sBmpInfo,
DIB_RGB_COLORS, ( void ** )&pBmpHBlur, 0, 0);
hbmOldBlur = SelectObject( dcHBlur, hbmHBlur );
//Prepare Destination Bitmap
dcDest = CreateCompatibleDC( NULL );
hbmDest = CreateDIBSection( dcDest, ( LPBITMAPINFO )&sBmpInfo,
DIB_RGB_COLORS, ( void ** )&pBmpDes, 0, 0);
hbmOldDes = SelectObject( dcDest, hbmDest );
// Gaussian Horzintal blur bitmap
DoHorizontalBlur( SrcBmp, pBmpHBlur, pBmpBytes, iRadio );
BitBlt( dcDest, 0, 0, SrcBmp.bmWidth, SrcBmp.bmHeight, dcHBlur, 0, 0, SRCCOPY );
DoVerticalBlur( SrcBmp, pBmpDes, pBmpHBlur, iRadio );
SelectObject( dcSrc, hbmOld );
DeleteDC( dcSrc );
DeleteObject( hbmSrc );
SelectObject( dcHBlur, hbmOldBlur );
DeleteDC( dcHBlur );
DeleteObject( hbmHBlur );
SelectObject( dcDest, hbmOldDes );
DeleteDC( dcDest );
return hbmDest;
}
//-------------------------------------------------------------------------------//
void DoHorizontalBlur( BITMAP SrcBmp, BYTE *pBmpDes, BYTE *pBmpBytes, INT iRadio )
{
INT j;
INT iBPP = SrcBmp.bmBitsPixel >> 3;
for( j = 0; j < SrcBmp.bmHeight; j++ )
{
LPBYTE pbDestRGB = ( LPBYTE )&( ( DWORD * ) pBmpDes )[ j * SrcBmp.bmWidth ];
LPBYTE pbSrcRGB = ( LPBYTE )&( ( DWORD * ) pBmpBytes )[ j * SrcBmp.bmWidth ];
INT ky;
LONG lTotalClrs[ 3 ];
lTotalClrs[ 0 ] = 0;
lTotalClrs[ 1 ] = 0;
lTotalClrs[ 2 ] = 0;
//First pixel
for( ky = 0; ky <= iRadio; ky++ )
{
lTotalClrs[ 0 ] += pbSrcRGB[ ky * iBPP + 0 ];
lTotalClrs[ 1 ] += pbSrcRGB[ ky * iBPP + 1 ];
lTotalClrs[ 2 ] += pbSrcRGB[ ky * iBPP + 2 ];
}
pbDestRGB[ 0 ] = ( BYTE )( lTotalClrs[ 0 ] / ( iRadio + 1 ) );
pbDestRGB[ 1 ] = ( BYTE )( lTotalClrs[ 1 ] / ( iRadio + 1 ) );
pbDestRGB[ 2 ] = ( BYTE )( lTotalClrs[ 2 ] / ( iRadio + 1 ) );
pbSrcRGB += iBPP;
pbDestRGB += iBPP;
DoHBlur( 1, SrcBmp.bmWidth, iRadio, pbDestRGB, pbSrcRGB, lTotalClrs, iBPP );
}
}
//-------------------------------------------------------------------------------//
void DoHBlur( INT iStart, INT iEnd, INT iRadio, BYTE *pbDestRGB, BYTE *pbSrcRGB, LONG *lTotalClrs, INT iBPP )
{
INT i, ky;
INT iAverage;
for( i = iStart; i < iEnd; i++ )
{
iAverage = iRadio * 2 + 1;
//Subtract pixel leave
if( ( i - iRadio ) > 0 )
{
lTotalClrs[ 0 ] -= pbSrcRGB[ -iRadio * iBPP + 0 ];
lTotalClrs[ 1 ] -= pbSrcRGB[ -iRadio * iBPP + 1 ];
lTotalClrs[ 2 ] -= pbSrcRGB[ -iRadio * iBPP + 2 ];
}
else
{
iAverage += i - iRadio;
}
//Add pixel entering
if( i + iRadio < iEnd )
{
lTotalClrs[ 0 ] += pbSrcRGB[ iRadio * iBPP + 0 ];
lTotalClrs[ 1 ] += pbSrcRGB[ iRadio * iBPP + 1 ];
lTotalClrs[ 2 ] += pbSrcRGB[ iRadio * iBPP + 2 ];
}
else
{
iAverage -= ( iRadio - iEnd + i ) + 1;
}
pbDestRGB[ 0 ] = ( BYTE )( lTotalClrs[ 0 ] / iAverage );
pbDestRGB[ 1 ] = ( BYTE )( lTotalClrs[ 1 ] / iAverage );
pbDestRGB[ 2 ] = ( BYTE )( lTotalClrs[ 2 ] / iAverage );
pbSrcRGB += iBPP;
pbDestRGB += iBPP;
}
}
//-------------------------------------------------------------------------------//
void DoVerticalBlur( BITMAP SrcBmp, BYTE *pBmpDes, BYTE *pBmpBytes, INT iRadio )
{
INT j;
INT iBPP = SrcBmp.bmBitsPixel >> 3;
for( j = 0; j < SrcBmp.bmWidth; j++ )
{
INT ky;
LONG lTotalClrs[ 3 ];
lTotalClrs[ 0 ] = 0;
lTotalClrs[ 1 ] = 0;
lTotalClrs[ 2 ] = 0;
//First pixel
for( ky = 0; ky <= iRadio; ky++ )
{
lTotalClrs[ 0 ] += pBmpBytes[ j * iBPP + ky * SrcBmp.bmWidth * iBPP + 0 ];
lTotalClrs[ 1 ] += pBmpBytes[ j * iBPP + ky * SrcBmp.bmWidth * iBPP + 1 ];
lTotalClrs[ 2 ] += pBmpBytes[ j * iBPP + ky * SrcBmp.bmWidth * iBPP + 2 ];
}
pBmpDes[ j * iBPP + 0 ] = ( BYTE )( lTotalClrs[ 0 ] / ( iRadio + 1 ) );
pBmpDes[ j * iBPP + 1 ] = ( BYTE )( lTotalClrs[ 1 ] / ( iRadio + 1 ) );
pBmpDes[ j * iBPP + 2 ] = ( BYTE )( lTotalClrs[ 2 ] / ( iRadio + 1 ) );
DoVBlur( 1, SrcBmp.bmHeight, iRadio, pBmpDes, pBmpBytes, lTotalClrs, SrcBmp.bmWidth, j , iBPP);
}
}
//-------------------------------------------------------------------------------//
void DoVBlur( INT iStart, INT iEnd, INT iRadio,
BYTE *pBmpDes, BYTE *pBmpBytes,
LONG *lTotalClrs, DWORD dwWidth, INT iCol, INT iBPP )
{
INT i;
INT iAverage;
for( i = iStart; i < iEnd; i++ )
{
iAverage = iRadio * 2 + 1;
//Subtract pixel leave
if( ( i - iRadio ) > 0 )
{
lTotalClrs[ 0 ] -= pBmpBytes[ iCol * iBPP + ( i - iRadio ) * dwWidth * iBPP + 0 ];
lTotalClrs[ 1 ] -= pBmpBytes[ iCol * iBPP + ( i - iRadio ) * dwWidth * iBPP + 1 ];
lTotalClrs[ 2 ] -= pBmpBytes[ iCol * iBPP + ( i - iRadio ) * dwWidth * iBPP + 2 ];
}
else
{
iAverage += i - iRadio;
}
//Add pixel entering
if( i + iRadio < iEnd )
{
lTotalClrs[ 0 ] += pBmpBytes[ iCol * iBPP + ( i + iRadio ) * dwWidth * iBPP + 0 ];
lTotalClrs[ 1 ] += pBmpBytes[ iCol * iBPP + ( i + iRadio ) * dwWidth * iBPP + 1 ];
lTotalClrs[ 2 ] += pBmpBytes[ iCol * iBPP + ( i + iRadio ) * dwWidth * iBPP + 2 ];
}
else
{
iAverage -= ( iRadio - iEnd + i ) + 1;
}
pBmpDes[ iCol * iBPP + i * dwWidth * iBPP + 0 ] = ( BYTE )( lTotalClrs[ 0 ] / iAverage );
pBmpDes[ iCol * iBPP + i * dwWidth * iBPP + 1 ] = ( BYTE )( lTotalClrs[ 1 ] / iAverage );
pBmpDes[ iCol * iBPP + i * dwWidth * iBPP + 2 ] = ( BYTE )( lTotalClrs[ 2 ] / iAverage );
}
}
HB_FUNC( BLUR )
{
hb_retnl( ( LONG ) Blur( ( HBITMAP ) hb_parnl( 1 ), hb_parni( 2 ) ) );
}
#pragma ENDDUMP