summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/inc/vcl/bitmap.hxx105
-rw-r--r--vcl/source/gdi/bitmap3.cxx232
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: */