Bugzilla – Attachment 62428 Details for
Bug 46378
Poor Resampling Image quality
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Lanczos3 resampling of images added to Bitmap and enabled in PDF export
0001-Lanczos3-resampling-of-images-added-to-Bitmap-and-en.patch (text/plain), 12.52 KB, created by
Tomaz Vajngerl
on 2012-06-02 11:47:25 UTC
(
hide
)
Description:
Lanczos3 resampling of images added to Bitmap and enabled in PDF export
Filename:
MIME Type:
Creator:
Tomaz Vajngerl
Created:
2012-06-02 11:47:25 UTC
Size:
12.52 KB
patch
obsolete
>From a7cec31da61a783b84eced77e75f9df0ba6af14d Mon Sep 17 00:00:00 2001 >From: quikee <quikee@gmail.com> >Date: Sat, 2 Jun 2012 20:16:36 +0200 >Subject: [PATCH] Lanczos3 resampling of images added to Bitmap and enabled in > PDF export. > >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 >--- > vcl/inc/vcl/bitmap.hxx | 13 ++ > vcl/source/gdi/bitmap3.cxx | 238 ++++++++++++++++++++++++++++++++++++ > vcl/source/gdi/pdfwriter_impl2.cxx | 4 +- > 3 files changed, 254 insertions(+), 1 deletion(-) > >diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx >index 17041d8..28fff13 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 sal_Bool ImplScaleLanczos( const double& rScaleX, const double& rScaleY ); >+ >+ SAL_DLLPRIVATE sal_Bool ImplCalculateContributions( const int aSourceSize, const int aDestinationSize, >+ const double aSupport, const int aNumberOfContributions, >+ double* pWeights, int* pPixels, int* pCount ); >+ SAL_DLLPRIVATE sal_Bool ImplHorizontalConvolution( Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, >+ int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount ); >+ SAL_DLLPRIVATE sal_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..5e60b97 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,239 @@ sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, > return bRet; > } > >+//----------------------------------------------------------------------------------- >+sal_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() ); >+ sal_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 sal_True; >+} >+ >+sal_Bool 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 ]++; >+ } >+ } >+ return sal_True; >+} >+ >+sal_Bool Bitmap::ImplHorizontalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount) >+{ >+ BitmapWriteAccess* pWriteAcc = aNewBitmap.AcquireWriteAccess(); >+ >+ if (!pReadAcc || !pWriteAcc) >+ { >+ return sal_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 sal_True; >+} >+ >+sal_Bool Bitmap::ImplVerticalConvolution(Bitmap& aNewBitmap, BitmapReadAccess* pReadAcc, int aNumberOfContributions, double* pWeights, int* pPixels, int* pCount) >+{ >+ BitmapWriteAccess* pWriteAcc = aNewBitmap.AcquireWriteAccess(); >+ >+ if (!pReadAcc || !pWriteAcc) >+ { >+ return sal_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 sal_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: */ >diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx >index 4ba5e2c..12af40e 100644 >--- a/vcl/source/gdi/pdfwriter_impl2.cxx >+++ b/vcl/source/gdi/pdfwriter_impl2.cxx >@@ -137,7 +137,9 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz > aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH); > } > if( aNewBmpSize.Width() && aNewBmpSize.Height() ) >- aBitmapEx.Scale( aNewBmpSize ); >+ { >+ aBitmapEx.Scale( aNewBmpSize, BMP_SCALE_LANCZOS ); >+ } > else > aBitmapEx.SetEmpty(); > } >-- >1.7.9.5 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 46378
:
57380
|
57381
|
62054
|
62196
| 62428