diff options
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/vcl/bitmap.hxx | 105 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap3.cxx | 232 |
2 files changed, 166 insertions, 171 deletions
diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx index 3dbee5050613..7e6cf3aeb4c9 100644 --- a/vcl/inc/vcl/bitmap.hxx +++ b/vcl/inc/vcl/bitmap.hxx @@ -50,6 +50,9 @@ #define BMP_SCALE_FAST 0x00000001UL #define BMP_SCALE_INTERPOLATE 0x00000002UL #define BMP_SCALE_LANCZOS 0x00000003UL +#define BMP_SCALE_BICUBIC 0x00000004UL +#define BMP_SCALE_BILINEAR 0x00000005UL +#define BMP_SCALE_BOX 0x00000006UL // ----------------------------------------------------------------------------- @@ -158,7 +161,7 @@ class VCL_DLLPUBLIC BmpFilterParam friend class Animation; private: - BmpFilter meFilter; + BmpFilter meFilter; sal_uLong mnProgressStart; sal_uLong mnProgressEnd; @@ -213,6 +216,89 @@ public: } }; +// -------------------- +// Resample Kernels +// -------------------- + +class Kernel +{ + +public: + Kernel () {} + virtual ~Kernel() {} + + virtual double GetWidth() = 0; + virtual double Calculate( double x ) = 0; +}; + +class Lanczos3Kernel : public Kernel +{ + +public: + virtual double GetWidth() { return 3.0; } + virtual double Calculate (double x) + { + return (-3.0 <= x && x < 3.0) ? SincFilter(x) * SincFilter( x / 3.0 ) : 0.0; + } + + inline double SincFilter(double x) + { + if (x == 0.0) + { + return 1.0; + } + x = x * M_PI; + return sin(x) / x; + } +}; + +class BicubicKernel : public Kernel { + virtual double GetWidth() { return 2.0; } + virtual double Calculate (double x) + { + if (x < 0.0) + { + x = -x; + } + + if (x <= 1.0) + { + return (1.5 * x - 2.5) * x * x + 1.0; + } + else if (x < 2.0) + { + return ((-0.5 * x + 2.5) * x - 4) * x + 2; + } + return 0.0; + } +}; + +class BilinearKernel : public Kernel { + virtual double GetWidth() { return 1.0; } + virtual double Calculate (double x) + { + if (x < 0.0) + { + x = -x; + } + if (x < 1.0) + { + return 1.0-x; + } + return 0.0; + } +}; + +class BoxKernel : public Kernel { + virtual double GetWidth() { return 0.5; } + virtual double Calculate (double x) + { + if (-0.5 <= x && x < 0.5) + return 1.0; + return 0.0; + } +}; + // ---------- // - Bitmap - // ---------- @@ -277,17 +363,14 @@ 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 bool ImplScaleConvolution( const double& rScaleX, const double& rScaleY, Kernel& aKernel); - 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 void ImplCalculateContributions( const int aSourceSize, const int aDestinationSize, + int& aNumberOfContributions, double*& pWeights, int*& pPixels, int*& pCount, + Kernel& aKernel ); - SAL_DLLPRIVATE static double ImplLanczosKernel( const double aValue, const double aSupport ); + SAL_DLLPRIVATE bool ImplConvolutionPass( Bitmap& aNewBitmap, const int nNewSize, BitmapReadAccess* pReadAcc, + int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount ); SAL_DLLPRIVATE sal_Bool ImplMakeMono( sal_uInt8 cThreshold ); SAL_DLLPRIVATE sal_Bool ImplMakeMonoDither(); @@ -305,7 +388,7 @@ public: long nR1, long nR2, long nG1, long nG2, long nB1, long nB2, long nColors, long nPixels, long& rIndex ); SAL_DLLPRIVATE sal_Bool ImplConvolute3( const long* pMatrix, long nDivisor, - const BmpFilterParam* pFilterParam, const Link* pProgress ); + const BmpFilterParam* pFilterParam, const Link* pProgress ); SAL_DLLPRIVATE sal_Bool ImplMedianFilter( const BmpFilterParam* pFilterParam, const Link* pProgress ); SAL_DLLPRIVATE sal_Bool ImplSobelGrey( const BmpFilterParam* pFilterParam, const Link* pProgress ); SAL_DLLPRIVATE sal_Bool ImplEmbossGrey( const BmpFilterParam* pFilterParam, const Link* pProgress ); diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx index ec458d9ac260..a4696814ba76 100644 --- a/vcl/source/gdi/bitmap3.cxx +++ b/vcl/source/gdi/bitmap3.cxx @@ -912,13 +912,37 @@ sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) ) { if( BMP_SCALE_FAST == nScaleFlag ) + { bRet = ImplScaleFast( rScaleX, rScaleY ); + } else if( BMP_SCALE_INTERPOLATE == nScaleFlag ) + { bRet = ImplScaleInterpolate( rScaleX, rScaleY ); + } else if( BMP_SCALE_LANCZOS == nScaleFlag ) - bRet = ImplScaleLanczos( rScaleX, rScaleY ); + { + Lanczos3Kernel kernel; + bRet = ImplScaleConvolution( rScaleX, rScaleY, kernel); + } + else if( BMP_SCALE_BICUBIC == nScaleFlag ) + { + BicubicKernel kernel; + bRet = ImplScaleConvolution( rScaleX, rScaleY, kernel ); + } + else if( BMP_SCALE_BILINEAR == nScaleFlag ) + { + BilinearKernel kernel; + bRet = ImplScaleConvolution( rScaleX, rScaleY, kernel ); + } + else if( BMP_SCALE_BOX == nScaleFlag ) + { + BoxKernel kernel; + bRet = ImplScaleConvolution( rScaleX, rScaleY, kernel ); + } else - bRet = sal_False; + { + return false; + } } else bRet = sal_True; @@ -2208,33 +2232,28 @@ sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, return bRet; } -bool Bitmap::ImplScaleLanczos( const double& rScaleX, const double& rScaleY ) +bool Bitmap::ImplScaleConvolution( const double& rScaleX, const double& rScaleY, Kernel& aKernel ) { - const Size aSizePix( GetSizePixel() ); - const long nWidth = aSizePix.Width(); - const long nHeight = aSizePix.Height(); + const long nWidth = GetSizePixel().Width(); + const long nHeight = GetSizePixel().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 = (aScale <= 1.0) ? aSupport / aScale : aSupport; - - int aNumberOfContributions = (int) ( 2 * aScaledRadius + 1 ); + bool bResult; + BitmapReadAccess* pReadAcc; + Bitmap aNewBitmap; - double* pWeights = new double[ nNewWidth*aNumberOfContributions ]; - int* pPixels = new int[ nNewWidth*aNumberOfContributions ]; - int* pCount = new int[ nNewWidth ]; + int aNumberOfContributions; + double* pWeights; + int* pPixels; + int* pCount; - ImplCalculateContributions( nWidth, nNewWidth, aSupport, aNumberOfContributions, pWeights, pPixels, pCount ); - - BitmapReadAccess* pReadAcc = AcquireReadAccess(); - Bitmap aNewBitmap( Size( nNewWidth, nHeight ), 24); - bool bResult = ImplHorizontalConvolution( aNewBitmap, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); + // Do horizontal filtering + ImplCalculateContributions( nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel ); + pReadAcc = AcquireReadAccess(); + aNewBitmap = Bitmap( Size( nHeight, nNewWidth ), 24); + bResult = ImplConvolutionPass( aNewBitmap, nNewWidth, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); - // Cleanup ReleaseAccess( pReadAcc ); delete[] pWeights; delete[] pCount; @@ -2243,26 +2262,15 @@ bool Bitmap::ImplScaleLanczos( const double& rScaleX, const double& rScaleY ) if ( !bResult ) return bResult; - // Swap current bitmap with new bitmap + // Swap Bitmaps ImplAssignWithSize( aNewBitmap ); // Do vertical filtering - aScale = nNewHeight / (double) nHeight; - aScaledRadius = (aScale <= 1.0) ? aSupport / aScale : aSupport; - - 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 ); - + ImplCalculateContributions( nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel ); pReadAcc = AcquireReadAccess(); aNewBitmap = Bitmap( Size( nNewWidth, nNewHeight ), 24); - bResult = ImplVerticalConvolution( aNewBitmap, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); + bResult = ImplConvolutionPass( aNewBitmap, nNewHeight, pReadAcc, aNumberOfContributions, pWeights, pPixels, pCount ); - // Cleanup ReleaseAccess( pReadAcc ); delete[] pWeights; delete[] pCount; @@ -2271,19 +2279,24 @@ bool Bitmap::ImplScaleLanczos( const double& rScaleX, const double& rScaleY ) 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 ) +void Bitmap::ImplCalculateContributions( const int aSourceSize, const int aDestinationSize, int& aNumberOfContributions, + double*& pWeights, int*& pPixels, int*& pCount, Kernel& aKernel) { + const double aSamplingRadius = aKernel.GetWidth(); const double aScale = aDestinationSize / (double) aSourceSize; - const double aScaledRadius = (aScale <= 1.0) ? aSupport / aScale : aSupport; - const double aFilterFactor = (aScale <= 1.0) ? aScale : 1.0; + const double aScaledRadius = (aScale < 1.0) ? aSamplingRadius / aScale : aSamplingRadius; + const double aFilterFactor = (aScale < 1.0) ? aScale : 1.0; + + aNumberOfContributions = (int) ( 2 * ceil(aScaledRadius) + 1 ); + + pWeights = new double[ aDestinationSize*aNumberOfContributions ]; + pPixels = new int[ aDestinationSize*aNumberOfContributions ]; + pCount = new int[ aDestinationSize ]; double aWeight, aCenter; int aIndex, aLeft, aRight; @@ -2295,37 +2308,19 @@ void Bitmap::ImplCalculateContributions( const int aSourceSize, const int aDesti aCurrentCount = 0; aCenter = i / aScale; - aLeft = (int) ((aCenter + 0.5) - aScaledRadius ); - aRight = (int) ( aLeft + 2 * aScaledRadius ); + aLeft = (int) floor(aCenter - aScaledRadius); + aRight = (int) ceil (aCenter + aScaledRadius); for ( int j = aLeft; j <= aRight; j++ ) { - aWeight = ImplLanczosKernel( (aCenter - j) * aFilterFactor, aSupport ); + aWeight = aKernel.Calculate( aFilterFactor * ( aCenter - (double) j ) ); - if (aWeight == 0.0) - { + // Reduce calculations with ignoring weights of 0.0 + if (fabs(aWeight < 0.0001)) continue; - } - - // Mirror edges - if (j < 0) - { - aPixelIndex = -j; - } - else if ( j >= aSourceSize ) - { - aPixelIndex = (aSourceSize - j) + aSourceSize - 1; - } - else - { - aPixelIndex = j; - } - // Edge case for small bitmaps - if ( aPixelIndex < 0 || aPixelIndex >= aSourceSize ) - { - aWeight = 0.0; - } + // Handling on edges + aPixelIndex = MinMax( j, 0, aSourceSize - 1); pWeights[ aIndex + aCurrentCount ] = aWeight; pPixels[ aIndex + aCurrentCount ] = aPixelIndex; @@ -2336,17 +2331,14 @@ void Bitmap::ImplCalculateContributions( const int aSourceSize, const int aDesti } } -bool Bitmap::ImplHorizontalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount) +bool Bitmap::ImplConvolutionPass(Bitmap& aNewBitmap, const int nNewSize, 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; @@ -2355,79 +2347,20 @@ bool Bitmap::ImplHorizontalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pRe for ( int y = 0; y < nHeight; y++ ) { - for ( int i = 0; i < nNewWidth; i++ ) + for ( int x = 0; x < nNewSize; x++ ) { - aBaseIndex = i * aNumberOfContributions; - aValueRed = aValueGreen = aValueBlue = 0.0; - aSum = 0.0; + aBaseIndex = x * aNumberOfContributions; + aSum = aValueRed = aValueGreen = aValueBlue = 0.0; - for ( int j=0; j < pCount[i]; j++ ) + for ( int j=0; j < pCount[x]; 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 ] ); - } + aSum += aWeight = pWeights[ 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; + aColor = pReadAcc->GetPixel( y, pPixels[ aIndex ] ); if( pReadAcc->HasPalette() ) - { - aColor = pReadAcc->GetPaletteColor( pReadAcc->GetPixel( pPixels[ aIndex ] , x ) ); - } - else - { - aColor = pReadAcc->GetPixel( pPixels[ aIndex ] , x ); - } + aColor = pReadAcc->GetPaletteColor( aColor ); + aValueRed += aWeight * aColor.GetRed(); aValueGreen += aWeight * aColor.GetGreen(); aValueBlue += aWeight * aColor.GetBlue(); @@ -2437,32 +2370,11 @@ bool Bitmap::ImplVerticalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pRead (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 ); + pWriteAcc->SetPixel( x, y, 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: */ |