[Libreoffice-commits] .: vcl/inc vcl/source

Jan Holesovsky kendy at kemper.freedesktop.org
Mon Jun 4 07:12:53 PDT 2012


 vcl/inc/vcl/bitmap.hxx     |   13 ++
 vcl/source/gdi/bitmap3.cxx |  237 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 250 insertions(+)

New commits:
commit 47e0df5cebc05576e55210c5dd408a6f3eb91700
Author: Tomaz Vajngerl <quikee at gmail.com>
Date:   Sat Jun 2 20:16:36 2012 +0200

    fdo#46378: Lanczos3 resampling of images added to Bitmap.
    
    Current resampling methods for images are FAST and INTERPOLATE.
    FAST is used where speed of resampling is required, on the other
    hand INTERPOLATE resampling is used when we need quality. For
    example INTERPOLATE resampling method is used at PDF export.
    INTERPOLATE resampling uses bilinear interpolation which is known
    to be lower quality as other modern (and slower) resampling
    algorithms such as Lanczos, Mitchell or BiCubic resampling.
    This change adds Lanczos resampling to the Bitmap class and
    enables Lanczos resampling in PDF export.
    
    Lanczos3 resampling is implmented using separable convolution
    with which it is also possible to easily add other resampling
    methods like BiCubic just by changing the kernel function.
    
    Change-Id: I8dff5b65753b09dffd5bc34f2343d9818efb3e58

diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx
index 17041d8..14aae27 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 a2b8587..2d35c6a 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: */


More information about the Libreoffice-commits mailing list