diff options
-rw-r--r-- | vcl/inc/vcl/bitmap.hxx | 13 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap3.cxx | 237 |
2 files changed, 250 insertions, 0 deletions
diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx index 17041d809e74..14aae27f1b62 100644 --- a/vcl/inc/vcl/bitmap.hxx +++ b/vcl/inc/vcl/bitmap.hxx @@ -49,6 +49,7 @@ #define BMP_SCALE_NONE 0x00000000UL #define BMP_SCALE_FAST 0x00000001UL #define BMP_SCALE_INTERPOLATE 0x00000002UL +#define BMP_SCALE_LANCZOS 0x00000003UL // ----------------------------------------------------------------------------- @@ -276,6 +277,18 @@ public: SAL_DLLPRIVATE sal_Bool ImplScaleFast( const double& rScaleX, const double& rScaleY ); SAL_DLLPRIVATE sal_Bool ImplScaleInterpolate( const double& rScaleX, const double& rScaleY ); + SAL_DLLPRIVATE bool ImplScaleLanczos( const double& rScaleX, const double& rScaleY ); + + SAL_DLLPRIVATE void ImplCalculateContributions( const int aSourceSize, const int aDestinationSize, + const double aSupport, const int aNumberOfContributions, + double* pWeights, int* pPixels, int* pCount ); + SAL_DLLPRIVATE bool ImplHorizontalConvolution( Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, + int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount ); + SAL_DLLPRIVATE bool ImplVerticalConvolution( Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, + int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount ); + + SAL_DLLPRIVATE static double ImplLanczosKernel( const double aValue, const double aSupport ); + SAL_DLLPRIVATE sal_Bool ImplMakeMono( sal_uInt8 cThreshold ); SAL_DLLPRIVATE sal_Bool ImplMakeMonoDither(); SAL_DLLPRIVATE sal_Bool ImplMakeGreyscales( sal_uInt16 nGreyscales ); diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx index a2b8587087e2..2d35c6a4d805 100644 --- a/vcl/source/gdi/bitmap3.cxx +++ b/vcl/source/gdi/bitmap3.cxx @@ -36,6 +36,7 @@ #include <impoct.hxx> #include <impvect.hxx> +#include <math.h> // ----------- // - Defines - @@ -914,6 +915,8 @@ sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong bRet = ImplScaleFast( rScaleX, rScaleY ); else if( BMP_SCALE_INTERPOLATE == nScaleFlag ) bRet = ImplScaleInterpolate( rScaleX, rScaleY ); + else if( BMP_SCALE_LANCZOS == nScaleFlag ) + bRet = ImplScaleLanczos( rScaleX, rScaleY ); else bRet = sal_False; } @@ -2205,4 +2208,238 @@ sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, return bRet; } +//----------------------------------------------------------------------------------- +bool Bitmap::ImplScaleLanczos( const double& rScaleX, const double& rScaleY ) +{ + const Size aSizePix( GetSizePixel() ); + const long nWidth = aSizePix.Width(); + const long nHeight = aSizePix.Height(); + const long nNewWidth = FRound( nWidth * rScaleX ); + const long nNewHeight = FRound( nHeight * rScaleY ); + + double aSupport = 3.0; // Sampling radius + + // Do horizontal filtering + double aScale = nNewWidth / (double) nWidth; + double aScaledRadius = aSupport / aScale; + int aNumberOfContributions = (int) ( 2 * aScaledRadius + 1 ); + + double* pWeights = new double[ nNewWidth*aNumberOfContributions ]; + int* pPixels = new int[ nNewWidth*aNumberOfContributions ]; + int* pCount = new int[ nNewWidth ]; + + ImplCalculateContributions( nWidth, nNewWidth, aSupport, aNumberOfContributions, pWeights, pPixels, pCount ); + + BitmapReadAccess* pReadAcc = AcquireReadAccess(); + Bitmap aNewBitmap( Size( nNewWidth, nHeight ), GetBitCount(), &pReadAcc->GetPalette() ); + bool bResult = ImplHorizontalConvolution( aNewBitmap, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); + + // Cleanup + ReleaseAccess( pReadAcc ); + delete[] pWeights; + delete[] pCount; + delete[] pPixels; + + if ( !bResult ) + return bResult; + + // Swap current bitmap with new bitmap + ImplAssignWithSize( aNewBitmap ); + + // Do vertical filtering + aScale = nNewHeight / (double) nHeight; + aScaledRadius = aSupport / aScale; + aNumberOfContributions = (int) ( 2 * aScaledRadius + 1 ); + + pWeights = new double[ nNewHeight*aNumberOfContributions ]; + pPixels = new int[ nNewHeight*aNumberOfContributions ]; + pCount = new int[ nNewHeight ]; + + ImplCalculateContributions(nHeight, nNewHeight, aSupport, aNumberOfContributions, pWeights, pPixels, pCount ); + + pReadAcc = AcquireReadAccess(); + aNewBitmap = Bitmap( Size( nNewWidth, nNewHeight ), GetBitCount(), &pReadAcc->GetPalette() ); + bResult = ImplVerticalConvolution( aNewBitmap, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); + + // Cleanup + ReleaseAccess( pReadAcc ); + delete[] pWeights; + delete[] pCount; + delete[] pPixels; + + if ( !bResult ) + return bResult; + + // Swap current bitmap with new bitmap + ImplAssignWithSize( aNewBitmap ); + + return true; +} + +void Bitmap::ImplCalculateContributions( const int aSourceSize, const int aDestinationSize, const double aSupport, + const int aNumberOfContributions, double* pWeights, int* pPixels, + int* pCount ) +{ + const double aScale = aDestinationSize / (double) aSourceSize; + const double aScaledRadius = aSupport / aScale; + const double aFilterFactor = aScale; + + double aWeight, aCenter; + int aIndex, aLeft, aRight; + + for ( int i = 0; i < aDestinationSize; i++ ) { + aIndex = i * aNumberOfContributions; + pCount[i] = 0; + aCenter = ((double)i) / aScale; + + aLeft = (int)((aCenter + 0.5) - aScaledRadius); + aRight = (int)(aLeft + 2 * aScaledRadius); + + for ( int j = aLeft; j<= aRight; j++ ) { + if ( j < 0 || j >= aSourceSize ) { + continue; + } + + aWeight = ImplLanczosKernel( (aCenter - j) * aFilterFactor, aSupport ); + if (aWeight == 0.0) { + continue; + } + + int currentCount = pCount[ i ]; + pWeights[ aIndex + currentCount ] = aWeight; + pPixels[ aIndex + currentCount ] = j; + pCount[ i ]++; + } + } +} + +bool Bitmap::ImplHorizontalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount) +{ + BitmapWriteAccess* pWriteAcc = aNewBitmap.AcquireWriteAccess(); + + if (!pReadAcc || !pWriteAcc) + { + return false; + } + + const int nHeight = GetSizePixel().Height(); + const int nNewWidth = aNewBitmap.GetSizePixel().Width(); + + BitmapColor aColor; + double aValueRed, aValueGreen, aValueBlue; + double aSum, aWeight; + int aBaseIndex, aIndex; + + for ( int y = 0; y < nHeight; y++ ) + { + for ( int i = 0; i < nNewWidth; i++ ) + { + aBaseIndex = i * aNumberOfContributions; + aValueRed = aValueGreen = aValueBlue = 0.0; + aSum = 0.0; + + for ( int j=0; j < pCount[i]; j++ ) + { + aIndex = aBaseIndex + j; + aWeight = pWeights[ aIndex ]; + aSum += aWeight; + if( pReadAcc->HasPalette() ) + { + aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( y , pPixels[ aIndex ] ) ); + } + else + { + aColor = pReadAcc->GetPixel( y , pPixels[ aIndex ] ); + } + + aValueRed += aWeight * aColor.GetRed(); + aValueGreen += aWeight * aColor.GetGreen(); + aValueBlue += aWeight * aColor.GetBlue(); + } + + BitmapColor aResultColor( + (sal_uInt8) MinMax( aValueRed / aSum, 0, 255 ), + (sal_uInt8) MinMax( aValueGreen / aSum, 0, 255 ), + (sal_uInt8) MinMax( aValueBlue / aSum, 0, 255 ) ); + pWriteAcc->SetPixel( y, i, aResultColor ); + } + } + aNewBitmap.ReleaseAccess( pWriteAcc ); + return true; +} + +bool Bitmap::ImplVerticalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount) +{ + BitmapWriteAccess* pWriteAcc = aNewBitmap.AcquireWriteAccess(); + + if (!pReadAcc || !pWriteAcc) + { + return false; + } + + const int nWidth = GetSizePixel().Width(); + const int nNewHeight = aNewBitmap.GetSizePixel().Height(); + + BitmapColor aColor; + double aValueRed, aValueGreen, aValueBlue; + double aSum, aWeight; + int aBaseIndex, aIndex; + for (int x = 0; x < nWidth; x++) + { + for (int i = 0; i < nNewHeight; i++) + { + aBaseIndex = i * aNumberOfContributions; + aSum = 0.0; + aValueRed = aValueGreen = aValueBlue = 0.0; + + for (int j=0; j < pCount[i]; j++) + { + aIndex = aBaseIndex + j; + aWeight = pWeights[ aIndex ]; + aSum += aWeight; + if( pReadAcc->HasPalette() ) + { + aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( pPixels[ aIndex ] , x ) ); + } + else + { + aColor = pReadAcc->GetPixel( pPixels[ aIndex ] , x ); + } + aValueRed += aWeight * aColor.GetRed(); + aValueGreen += aWeight * aColor.GetGreen(); + aValueBlue += aWeight * aColor.GetBlue(); + } + + BitmapColor aResultColor( + (sal_uInt8) MinMax( aValueRed / aSum, 0, 255 ), + (sal_uInt8) MinMax( aValueGreen / aSum, 0, 255 ), + (sal_uInt8) MinMax( aValueBlue / aSum, 0, 255 ) ); + pWriteAcc->SetPixel( i, x, aResultColor ); + } + } + + aNewBitmap.ReleaseAccess( pWriteAcc ); + return true; +} + +double Bitmap::ImplLanczosKernel( const double aValue, const double aSupport ) { + double x = aValue; + if (x == 0.0) + { + return 1.0; + } + if (x < 0.0) + { + x = -x; + } + + x *= M_PI; + if (x < aSupport) + { + double x3 = x / 3.0; + return (sin(x) / x) * sin(x3) / x3; + } + return 0.0; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |