diff options
-rw-r--r-- | vcl/inc/vcl/bitmap.hxx | 9 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap4.cxx | 206 |
2 files changed, 213 insertions, 2 deletions
diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx index 7e6cf3aeb4c9..dc354cfb96c2 100644 --- a/vcl/inc/vcl/bitmap.hxx +++ b/vcl/inc/vcl/bitmap.hxx @@ -183,6 +183,7 @@ private: { sal_uInt16 mnSepiaPercent; sal_uInt8 mcSolarGreyThreshold; + double mnRadius; MosaicTileSize maMosaicTileSize; EmbossAngles maEmbossAngles; @@ -197,6 +198,10 @@ public: meFilter( BMP_FILTER_SOLARIZE ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd ), mcSolarGreyThreshold( cSolarGreyThreshold ) {} + BmpFilterParam( double nRadius, sal_uLong nProgressStart = 0, sal_uLong nProgressEnd = 0 ) : + meFilter( BMP_FILTER_SMOOTH ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd ), + mnRadius( cSolarGreyThreshold ) {} + BmpFilterParam( sal_uInt16 nSepiaPercent, sal_uLong nProgressStart = 0, sal_uLong nProgressEnd = 0 ) : meFilter( BMP_FILTER_SEPIA ), mnProgressStart( nProgressStart ), mnProgressEnd( nProgressEnd ), mnSepiaPercent( nSepiaPercent ) {} @@ -397,6 +402,10 @@ public: SAL_DLLPRIVATE sal_Bool ImplMosaic( const BmpFilterParam* pFilterParam, const Link* pProgress ); SAL_DLLPRIVATE sal_Bool ImplPopArt( const BmpFilterParam* pFilterParam, const Link* pProgress ); + SAL_DLLPRIVATE bool ImplSeparableBlurFilter( const double aRadius = 0.7 ); + SAL_DLLPRIVATE bool ImplSeparableUnsharpenFilter( const double aRadius = 0.7 ); + SAL_DLLPRIVATE void ImplBlurContributions( const int aSize, const int aNumberOfContributions, + double* pBlurVector, double*& pWeights, int*& pPixels, int*& pCount ); public: Bitmap(); diff --git a/vcl/source/gdi/bitmap4.cxx b/vcl/source/gdi/bitmap4.cxx index 331ac8b68603..2dc69487d914 100644 --- a/vcl/source/gdi/bitmap4.cxx +++ b/vcl/source/gdi/bitmap4.cxx @@ -55,8 +55,20 @@ sal_Bool Bitmap::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, { case( BMP_FILTER_SMOOTH ): { - const long pSmoothMatrix[] = { 1, 2, 1, 2, 5, 2, 1, 2, 1 }; - bRet = ImplConvolute3( &pSmoothMatrix[ 0 ], 17, pFilterParam, pProgress ); + // Blur for positive values of mnRadius + if (pFilterParam->mnRadius > 0.0) + { + bRet = ImplSeparableBlurFilter(pFilterParam->mnRadius); + } + // Unsharpen Mask for negative values of mnRadius + else if (pFilterParam->mnRadius < 0.0) + { + bRet = ImplSeparableUnsharpenFilter(pFilterParam->mnRadius); + } + else + { + bRet = sal_False; + } } break; @@ -1006,4 +1018,194 @@ sal_Bool Bitmap::ImplPopArt( const BmpFilterParam* /*pFilterParam*/, const Link* return bRet; } + +double* MakeBlurKernel(const double radius, int& rows) { + int intRadius = (int) radius + 1.0; + rows = intRadius * 2 + 1; + double* matrix = new double[rows]; + + double sigma = radius / 3; + double radius2 = radius * radius; + int index = 0; + for (int row = -intRadius; row <= intRadius; row++) + { + double distance = row*row; + if (distance > radius2) { + matrix[index] = 0.0; + }else { + matrix[index] = exp( -distance / (2.0 * sigma * sigma) ) / sqrt( 2.0 * M_PI * sigma ); + } + index++; + } + return matrix; +} + +void Bitmap::ImplBlurContributions( const int aSize, const int aNumberOfContributions, + double* pBlurVector, double*& pWeights, int*& pPixels, int*& pCount ) +{ + pWeights = new double[ aSize*aNumberOfContributions ]; + pPixels = new int[ aSize*aNumberOfContributions ]; + pCount = new int[ aSize ]; + + int aLeft, aRight, aCurrentCount, aPixelIndex; + double aWeight; + + for ( int i = 0; i < aSize; i++ ) + { + aLeft = (int) i - aNumberOfContributions / 2; + aRight = (int) i + aNumberOfContributions / 2; + aCurrentCount = 0; + for ( int j = aLeft; j <= aRight; j++ ) + { + aWeight = pBlurVector[aCurrentCount]; + + // Mirror edges + if (j < 0) + { + aPixelIndex = -j; + } + else if ( j >= aSize ) + { + aPixelIndex = (aSize - j) + aSize - 1; + } + else + { + aPixelIndex = j; + } + + // Edge case for small bitmaps + if ( aPixelIndex < 0 || aPixelIndex >= aSize ) + { + aWeight = 0.0; + } + + pWeights[ i*aNumberOfContributions + aCurrentCount ] = aWeight; + pPixels[ i*aNumberOfContributions + aCurrentCount ] = aPixelIndex; + + aCurrentCount++; + } + pCount[ i ] = aCurrentCount; + } +} + +// Separable Gaussian Blur +// +// Separable Gaussian Blur filter and accepts a blur radius +// as a parameter so the user can change the strength of the blur. +// Radius of 1.0 is 3 * standard deviation of gauss function. +// +// Separable Blur implementation uses 2x separable 1D convolution +// to process the image. +bool Bitmap::ImplSeparableBlurFilter(const double radius) +{ + const long nWidth = GetSizePixel().Width(); + const long nHeight = GetSizePixel().Height(); + + // Prepare Blur Vector + int aNumberOfContributions; + double* pBlurVector = MakeBlurKernel(radius, aNumberOfContributions); + + double* pWeights; + int* pPixels; + int* pCount; + + // Do horizontal filtering + ImplBlurContributions( nWidth, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount); + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + + // switch coordinates as convolution pass transposes result + Bitmap aNewBitmap( Size( nHeight, nWidth ), 24 ); + + bool bResult = ImplConvolutionPass( aNewBitmap, nWidth, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); + + // Cleanup + ReleaseAccess( pReadAcc ); + delete[] pWeights; + delete[] pPixels; + delete[] pCount; + + if ( !bResult ) + return bResult; + + // Swap current bitmap with new bitmap + ImplAssignWithSize( aNewBitmap ); + + // Do vertical filtering + ImplBlurContributions(nHeight, aNumberOfContributions, pBlurVector, pWeights, pPixels, pCount ); + + pReadAcc = AcquireReadAccess(); + aNewBitmap = Bitmap( Size( nWidth, nHeight ), 24 ); + bResult = ImplConvolutionPass( aNewBitmap, nHeight, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); + + // Cleanup + ReleaseAccess( pReadAcc ); + delete[] pWeights; + delete[] pCount; + delete[] pPixels; + delete[] pBlurVector; + + if ( !bResult ) + return bResult; + + // Swap current bitmap with new bitmap + ImplAssignWithSize( aNewBitmap ); + + return true; +} + +// Separable Unsharepn Mask filter is actually a substracted blured +// image from the original image. +bool Bitmap::ImplSeparableUnsharpenFilter(const double radius) { + const long nWidth = GetSizePixel().Width(); + const long nHeight = GetSizePixel().Height(); + + Bitmap aBlur( *this ); + aBlur.ImplSeparableBlurFilter(-radius); + + // Amount of unsharpening effect on image - currently set to a fixed value + double aAmount = 2.0; + + Bitmap aResultBitmap( Size( nWidth, nHeight ), 24); + + BitmapReadAccess* pReadAccBlur = aBlur.AcquireReadAccess(); + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + BitmapWriteAccess* pWriteAcc = aResultBitmap.AcquireWriteAccess(); + + BitmapColor aColor, aColorBlur; + + // For all pixels in original image substract pixels values from blured image. + for( int x = 0; x < nWidth; x++ ) + { + for( int y = 0; y < nHeight; y++ ) + { + aColorBlur = pReadAccBlur->GetPixel( y , x ); + if( pReadAccBlur->HasPalette() ) + { + pReadAccBlur->GetPaletteColor( aColorBlur ); + } + + aColor = pReadAcc->GetPixel( y , x ); + if( pReadAcc->HasPalette() ) + { + aColor = pReadAcc->GetPaletteColor( aColor ); + } + + BitmapColor aResultColor( + (sal_uInt8) MinMax( aColor.GetRed() + (aColor.GetRed() - aColorBlur.GetRed()) * aAmount, 0, 255 ), + (sal_uInt8) MinMax( aColor.GetGreen() + (aColor.GetGreen() - aColorBlur.GetGreen()) * aAmount, 0, 255 ), + (sal_uInt8) MinMax( aColor.GetBlue() + (aColor.GetBlue() - aColorBlur.GetBlue()) * aAmount, 0, 255 ) ); + + pWriteAcc->SetPixel( y, x, aResultColor ); + } + } + + ReleaseAccess( pWriteAcc ); + ReleaseAccess( pReadAcc ); + ReleaseAccess( pReadAccBlur ); + ImplAssignWithSize ( aResultBitmap ); + return true; +} + + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |