diff options
author | Armin Le Grand <alg@apache.org> | 2012-10-29 16:20:25 +0000 |
---|---|---|
committer | Armin Le Grand <alg@apache.org> | 2012-10-29 16:20:25 +0000 |
commit | bf734a151dc5169b65cf5d2a127e4142b765326c (patch) | |
tree | cd918614f76bc8f987eb21233fb355298a7e4a3e /vcl | |
parent | cb01e556e94b0d5bc96c4ff6183a3dc3cff934c8 (diff) |
#121233# Added bitmap scaling methods BMP_SCALE_SUPER (from symphony), BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and BMP_SCALE_BOX. changed defaults for internal scalings, enhanced PDF export when reduched DPI is used, added BMP_SCALE_BESTQUALITY and BMP_SCALE_FASTESTINTERPOLATE as new default for Bitmap::Scale
Notes
Notes:
merged as: 44fb0ceeb98f45bc301d021c11af2c13f051bd4b
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/vcl/alpha.hxx | 4 | ||||
-rw-r--r-- | vcl/inc/vcl/bitmap.hxx | 137 | ||||
-rw-r--r-- | vcl/inc/vcl/bitmapex.hxx | 4 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap3.cxx | 1330 | ||||
-rw-r--r-- | vcl/source/gdi/bitmapex.cxx | 4 | ||||
-rw-r--r-- | vcl/source/gdi/impgraph.cxx | 2 | ||||
-rw-r--r-- | vcl/source/gdi/pdfwriter_impl2.cxx | 8 | ||||
-rw-r--r-- | vcl/source/helper/canvasbitmap.cxx | 2 |
8 files changed, 1465 insertions, 26 deletions
diff --git a/vcl/inc/vcl/alpha.hxx b/vcl/inc/vcl/alpha.hxx index d76aef98d0d6..6d9c077ebbe8 100644 --- a/vcl/inc/vcl/alpha.hxx +++ b/vcl/inc/vcl/alpha.hxx @@ -81,8 +81,8 @@ public: sal_Bool Erase( sal_uInt8 cTransparency ); sal_Bool Invert(); sal_Bool Mirror( sal_uLong nMirrorFlags ); - sal_Bool Scale( const Size& rNewSize, sal_uLong nScaleFlag = BMP_SCALE_FAST ); - sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_FAST ); + sal_Bool Scale( const Size& rNewSize, sal_uLong nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE ); + sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE ); sal_Bool Rotate( long nAngle10, sal_uInt8 cFillTransparency ); sal_Bool Replace( const Bitmap& rMask, sal_uInt8 rReplaceTransparency ); sal_Bool Replace( sal_uInt8 cSearchTransparency, sal_uInt8 cReplaceTransparency, sal_uLong nTol = 0UL ); diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx index 9c51465bdc67..be57468ff32c 100644 --- a/vcl/inc/vcl/bitmap.hxx +++ b/vcl/inc/vcl/bitmap.hxx @@ -40,9 +40,21 @@ // ----------------------------------------------------------------------------- -#define BMP_SCALE_NONE 0x00000000UL -#define BMP_SCALE_FAST 0x00000001UL -#define BMP_SCALE_INTERPOLATE 0x00000002UL +#define BMP_SCALE_NONE 0x00000000UL +#define BMP_SCALE_FAST 0x00000001UL +#define BMP_SCALE_INTERPOLATE 0x00000002UL +#define BMP_SCALE_SUPER 0x00000003UL +#define BMP_SCALE_LANCZOS 0x00000004UL +#define BMP_SCALE_BICUBIC 0x00000005UL +#define BMP_SCALE_BILINEAR 0x00000006UL +#define BMP_SCALE_BOX 0x00000007UL + +// new default assigns for having slots for best quality and +// an alternative with a good compromize between speed and quality. +// Currently BMP_SCALE_BESTQUALITY maps to BMP_SCALE_LANCZOS and +// BMP_SCALE_FASTESTINTERPOLATE to BMP_SCALE_SUPER +#define BMP_SCALE_BESTQUALITY 0x000000feUL +#define BMP_SCALE_FASTESTINTERPOLATE 0x000000ffUL // ----------------------------------------------------------------------------- @@ -159,7 +171,7 @@ class VCL_DLLPUBLIC BmpFilterParam friend class Animation; private: - BmpFilter meFilter; + BmpFilter meFilter; sal_uLong mnProgressStart; sal_uLong mnProgressEnd; @@ -214,6 +226,114 @@ public: } }; +// -------------------- +// Resample Kernels +// -------------------- + +class Kernel +{ +public: + Kernel() {} + virtual ~Kernel() {} + + virtual double GetWidth() const = 0; + virtual double Calculate(double x) const = 0; +}; + +class Lanczos3Kernel : public Kernel +{ +public: + virtual double GetWidth() const + { + return 3.0; + } + + virtual double Calculate(double x) const + { + return (-3.0 <= x && 3.0 > x) ? SincFilter(x) * SincFilter( x / 3.0 ) : 0.0; + } + + inline double SincFilter(double x) const + { + if(0.0 == x) + { + return 1.0; + } + + x *= M_PI; + + return sin(x) / x; + } +}; + +class BicubicKernel : public Kernel +{ + virtual double GetWidth() const + { + return 2.0; + } + + virtual double Calculate(double x) const + { + if(0.0 > x) + { + x = -x; + } + + if(1.0 >= x) + { + return (1.5 * x - 2.5) * x * x + 1.0; + } + else if(2.0 > x) + { + return ((-0.5 * x + 2.5) * x - 4.0) * x + 2.0; + } + + return 0.0; + } +}; + +class BilinearKernel : public Kernel +{ + virtual double GetWidth() const + { + return 1.0; + } + + virtual double Calculate(double x) const + { + if(0.0 > x) + { + x = -x; + } + + if(1.0 > x) + { + return 1.0 - x; + } + + return 0.0; + } +}; + +class BoxKernel : public Kernel +{ + virtual double GetWidth() const + { + return 0.5; + } + + virtual double Calculate(double x) const + { + if(-0.5 <= x && 0.5 > x) + { + return 1.0; + } + + return 0.0; + } +}; + // ---------- // - Bitmap - // ---------- @@ -277,8 +397,11 @@ public: BitmapWriteAccess& rAcc, sal_Bool bRLE4 ); SAL_DLLPRIVATE static sal_Bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bRLE4 ); + SAL_DLLPRIVATE void ImplAdaptBitCount(Bitmap& rNew); 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 ImplScaleSuper( const double& rScaleX, const double& rScaleY ); + SAL_DLLPRIVATE sal_Bool ImplScaleConvolution( const double& rScaleX, const double& rScaleY, const Kernel& aKernel); SAL_DLLPRIVATE sal_Bool ImplMakeMono( sal_uInt8 cThreshold ); SAL_DLLPRIVATE sal_Bool ImplMakeMonoDither(); SAL_DLLPRIVATE sal_Bool ImplMakeGreyscales( sal_uInt16 nGreyscales ); @@ -531,8 +654,7 @@ public: @return sal_True, if the operation was completed successfully. */ - sal_Bool Scale( const Size& rNewSize, - sal_uLong nScaleFlag = BMP_SCALE_FAST ); + sal_Bool Scale( const Size& rNewSize, sal_uLong nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE ); /** Scale the bitmap @@ -544,8 +666,7 @@ public: @return sal_True, if the operation was completed successfully. */ - sal_Bool Scale( const double& rScaleX, const double& rScaleY, - sal_uLong nScaleFlag = BMP_SCALE_FAST ); + sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE ); /** Rotate bitmap by the specified angle diff --git a/vcl/inc/vcl/bitmapex.hxx b/vcl/inc/vcl/bitmapex.hxx index cc7cd1ea3789..fa6439778eb0 100644 --- a/vcl/inc/vcl/bitmapex.hxx +++ b/vcl/inc/vcl/bitmapex.hxx @@ -255,7 +255,7 @@ public: @return sal_True, if the operation was completed successfully. */ - sal_Bool Scale( const Size& rNewSize, sal_uLong nScaleFlag = BMP_SCALE_FAST ); + sal_Bool Scale( const Size& rNewSize, sal_uLong nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE ); /** Scale the bitmap @@ -267,7 +267,7 @@ public: @return sal_True, if the operation was completed successfully. */ - sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_FAST ); + sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE ); /** Rotate bitmap by the specified angle diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx index 2f91cb5e073f..c6f87e774310 100644 --- a/vcl/source/gdi/bitmap3.cxx +++ b/vcl/source/gdi/bitmap3.cxx @@ -40,6 +40,7 @@ #define RGB15( _def_cR, _def_cG, _def_cB ) (((sal_uLong)(_def_cR)<<10UL)|((sal_uLong)(_def_cG)<<5UL)|(sal_uLong)(_def_cB)) #define GAMMA( _def_cVal, _def_InvGamma ) ((sal_uInt8)MinMax(FRound(pow( _def_cVal/255.0,_def_InvGamma)*255.0),0L,255L)) +#define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<7L)+nFrac*((long)(cVal1)-(cVal0)))>>7L)) #define CALC_ERRORS \ nTemp = p1T[nX++] >> 12; \ @@ -905,21 +906,109 @@ sal_Bool Bitmap::ImplConvertGhosted() sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag ) { - sal_Bool bRet; +#ifdef DBG_UTIL + // #121233# allow to test the different scalers in debug build with source + // level debugger (change nNumber to desired action) + static sal_uInt16 nNumber(0); - if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) ) + switch(nNumber) { - if( BMP_SCALE_FAST == nScaleFlag ) - bRet = ImplScaleFast( rScaleX, rScaleY ); - else if( BMP_SCALE_INTERPOLATE == nScaleFlag ) - bRet = ImplScaleInterpolate( rScaleX, rScaleY ); - else - bRet = sal_False; + case 0 : break; + case 1: nScaleFlag = BMP_SCALE_FAST; break; + case 2: nScaleFlag = BMP_SCALE_INTERPOLATE; break; + case 3: nScaleFlag = BMP_SCALE_SUPER; break; + case 4: nScaleFlag = BMP_SCALE_LANCZOS; break; + case 5: nScaleFlag = BMP_SCALE_BICUBIC; break; + case 6: nScaleFlag = BMP_SCALE_BILINEAR; break; + case 7: nScaleFlag = BMP_SCALE_BOX; break; + case 8: nScaleFlag = BMP_SCALE_BESTQUALITY; break; + case 9: nScaleFlag = BMP_SCALE_FASTESTINTERPOLATE; break; + } +#endif // DBG_UTIL + + if(basegfx::fTools::equalZero(rScaleX) && basegfx::fTools::equalZero(rScaleY)) + { + // no scale + return true; } else - bRet = sal_True; + { + if(BMP_SCALE_BESTQUALITY == nScaleFlag) + { + // Use LANCZOS when best quality is requested + nScaleFlag = BMP_SCALE_LANCZOS; + } + else if(BMP_SCALE_FASTESTINTERPOLATE == nScaleFlag) + { + // Use BMP_SCALE_SUPER when speed is requested, but not worst quality + nScaleFlag = BMP_SCALE_SUPER; + } - return bRet; + switch(nScaleFlag) + { + default: + case BMP_SCALE_NONE : + { + return false; + break; + } + case BMP_SCALE_FAST : + { + return ImplScaleFast( rScaleX, rScaleY ); + break; + } + case BMP_SCALE_INTERPOLATE : + { + return ImplScaleInterpolate( rScaleX, rScaleY ); + break; + } + case BMP_SCALE_SUPER : + { + if(GetSizePixel().Width() < 2 || GetSizePixel().Height() < 2) + { + // fallback to ImplScaleFast + return ImplScaleFast( rScaleX, rScaleY ); + } + else + { + // #121233# use method from symphony + return ImplScaleSuper( rScaleX, rScaleY ); + } + break; + } + case BMP_SCALE_LANCZOS : + { + const Lanczos3Kernel kernel; + + return ImplScaleConvolution( rScaleX, rScaleY, kernel); + break; + } + case BMP_SCALE_BICUBIC : + { + const BicubicKernel kernel; + + return ImplScaleConvolution( rScaleX, rScaleY, kernel ); + break; + } + case BMP_SCALE_BILINEAR : + { + const BilinearKernel kernel; + + return ImplScaleConvolution( rScaleX, rScaleY, kernel ); + break; + } + case BMP_SCALE_BOX : + { + const BoxKernel kernel; + + return ImplScaleConvolution( rScaleX, rScaleY, kernel ); + break; + } + } + } + + // should not happen + return false; } // ------------------------------------------------------------------------ @@ -943,6 +1032,58 @@ sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag ) // ------------------------------------------------------------------------ +void Bitmap::ImplAdaptBitCount(Bitmap& rNew) +{ + // aNew is the result of some operation; adapt it's BitCount to the original (this) + if(GetBitCount() != rNew.GetBitCount()) + { + switch(GetBitCount()) + { + case 1: + { + rNew.Convert(BMP_CONVERSION_1BIT_THRESHOLD); + break; + } + case 4: + { + if(HasGreyPalette()) + { + rNew.Convert(BMP_CONVERSION_4BIT_GREYS); + } + else + { + rNew.Convert(BMP_CONVERSION_4BIT_COLORS); + } + break; + } + case 8: + { + if(HasGreyPalette()) + { + rNew.Convert(BMP_CONVERSION_8BIT_GREYS); + } + else + { + rNew.Convert(BMP_CONVERSION_8BIT_COLORS); + } + break; + } + case 24: + { + rNew.Convert(BMP_CONVERSION_24BIT); + break; + } + default: + { + OSL_ENSURE(false, "BitDepth adaption failed (!)"); + break; + } + } + } +} + +// ------------------------------------------------------------------------ + sal_Bool Bitmap::ImplScaleFast( const double& rScaleX, const double& rScaleY ) { const Size aSizePix( GetSizePixel() ); @@ -1136,6 +1277,7 @@ sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rSca if( bRet ) { bRet = sal_False; + ImplAdaptBitCount(aNewBmp); ImplAssignWithSize( aNewBmp ); pReadAcc = AcquireReadAccess(); aNewBmp = Bitmap( Size( nNewWidth, nNewHeight ), 24 ); @@ -1238,7 +1380,10 @@ sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rSca aNewBmp.ReleaseAccess( pWriteAcc ); if( bRet ) + { + ImplAdaptBitCount(aNewBmp); ImplAssignWithSize( aNewBmp ); + } } } @@ -1249,6 +1394,1171 @@ sal_Bool Bitmap::ImplScaleInterpolate( const double& rScaleX, const double& rSca } // ------------------------------------------------------------------------ +// #121233# Added BMP_SCALE_SUPER from symphony code + +sal_Bool Bitmap::ImplScaleSuper( + const double& rScaleX, + const double& rScaleY ) +{ + const Size aSizePix( GetSizePixel() ); + bool bHMirr = ( rScaleX < 0 ); + bool bVMirr = ( rScaleY < 0 ); + double scaleX = bHMirr ? -rScaleX : rScaleX; + double scaleY = bVMirr ? -rScaleY : rScaleY; + const long nDstW = FRound( aSizePix.Width() * scaleX ); + const long nDstH = FRound( aSizePix.Height() * scaleY ); + const double fScaleThresh = 0.6; + bool bRet = false; + + if( ( nDstW > 1L ) && ( nDstH > 1L ) ) + { + BitmapColor aCol0, aCol1, aColRes; + BitmapReadAccess* pAcc = AcquireReadAccess(); + long nW = pAcc->Width() ; + long nH = pAcc->Height() ; + Bitmap aOutBmp( Size( nDstW, nDstH ), 24 ); + BitmapWriteAccess* pWAcc = aOutBmp.AcquireWriteAccess(); + long* pMapIX = new long[ nDstW ]; + long* pMapIY = new long[ nDstH ]; + long* pMapFX = new long[ nDstW ]; + long* pMapFY = new long[ nDstH ]; + long nX, nY, nXDst, nYDst;; + double fTemp; + long nTemp , nTempX, nTempY, nTempFX, nTempFY; + sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1; + long nStartX = 0 , nStartY = 0; + long nEndX = nDstW - 1L; + long nEndY = nDstH - 1L; + long nMax = 1 << 7L; + + if( pAcc && pWAcc ) + { + const double fRevScaleX = ( nDstW > 1L ) ? ( (double) ( nW - 1 ) / ( nDstW - 1 ) ) : 0.0; + const double fRevScaleY = ( nDstH > 1L ) ? ( (double) ( nH - 1 ) / ( nDstH - 1 ) ) : 0.0; + + // create horizontal mapping table + for( nX = 0L, nTempX = nW - 1L, nTemp = nW - 2L; nX < nDstW; nX++ ) + { + fTemp = nX * fRevScaleX; + + if( bHMirr ) + fTemp = nTempX - fTemp; + + pMapFX[ nX ] = (long) ( ( fTemp - ( pMapIX[ nX ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. ); + } + + // create vertical mapping table + for( nY = 0L, nTempY = nH - 1L, nTemp = nH - 2L; nY < nDstH; nY++ ) + { + fTemp = nY * fRevScaleY; + + if( bVMirr ) + fTemp = nTempY - fTemp; + + pMapFY[ nY ] = (long) ( ( fTemp - ( pMapIY[ nY ] = MinMax( (long) fTemp, 0, nTemp ) ) ) * 128. ); + } + + if( pAcc->HasPalette() ) + { + if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL ) + { + if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) + { + Scanline pLine0, pLine1; + + for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; + pLine0 = pAcc->GetScanline( nTempY ); + pLine1 = pAcc->GetScanline( ++nTempY ); + + for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) + { + nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; + + const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTempX ] ); + const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTempX ] ); + const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTempX ] ); + const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTempX ] ); + + cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTempFX ); + cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTempFX ); + cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTempFX ); + + cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTempFX ); + cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTempFX ); + cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTempFX ); + + aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); + aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); + aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + } + } + } + else + { + Scanline pTmpY; + long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; + long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; + long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; + + for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTop = bVMirr ? ( nY + 1 ) : nY; + nBottom = bVMirr ? nY : ( nY + 1 ) ; + + if( nY ==nEndY ) + { + nLineStart = pMapIY[ nY ]; + nLineRange = 0; + } + else + { + nLineStart = pMapIY[ nTop ] ; + nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); + } + + for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) + { + nLeft = bHMirr ? ( nX + 1 ) : nX; + nRight = bHMirr ? nX : ( nX + 1 ) ; + + if( nX == nEndX ) + { + nRowStart = pMapIX[ nX ]; + nRowRange = 0; + } + else + { + nRowStart = pMapIX[ nLeft ]; + nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); + } + + nSumR = nSumG = nSumB = 0; + nTotalWeightY = 0; + + for(int i = 0; i<= nLineRange; i++) + { + pTmpY = pAcc->GetScanline( nLineStart + i ); + nSumRowR = nSumRowG = nSumRowB = 0; + nTotalWeightX = 0; + + for(int j = 0; j <= nRowRange; j++) + { + const BitmapColor& rCol = pAcc->GetPaletteColor( pTmpY[ nRowStart + j ] ); + + if(nX == nEndX ) + { + nSumRowB += rCol.GetBlue() << 7L; + nSumRowG += rCol.GetGreen() << 7L; + nSumRowR += rCol.GetRed() << 7L; + nTotalWeightX += 1 << 7L; + } + else if( j == 0 ) + { + nWeightX = (nMax- pMapFX[ nLeft ]) ; + nSumRowB += ( nWeightX *rCol.GetBlue()) ; + nSumRowG += ( nWeightX *rCol.GetGreen()) ; + nSumRowR += ( nWeightX *rCol.GetRed()) ; + nTotalWeightX += nWeightX; + } + else if ( nRowRange == j ) + { + nWeightX = pMapFX[ nRight ] ; + nSumRowB += ( nWeightX *rCol.GetBlue() ); + nSumRowG += ( nWeightX *rCol.GetGreen() ); + nSumRowR += ( nWeightX *rCol.GetRed() ); + nTotalWeightX += nWeightX; + } + else + { + nSumRowB += rCol.GetBlue() << 7L; + nSumRowG += rCol.GetGreen() << 7L; + nSumRowR += rCol.GetRed() << 7L; + nTotalWeightX += 1 << 7L; + } + } + + if( nY == nEndY ) + nWeightY = nMax; + else if( i == 0 ) + nWeightY = nMax - pMapFY[ nTop ]; + else if( nLineRange == 1 ) + nWeightY = pMapFY[ nTop ]; + else if ( nLineRange == i ) + nWeightY = pMapFY[ nBottom ]; + else + nWeightY = nMax; + + nWeightY = nWeightY ; + nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); + nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); + nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); + nTotalWeightY += nWeightY; + } + + aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); + aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); + aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + + } + } + } +} + else + { + if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) + { + for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTempY = pMapIY[ nY ], nTempFY = pMapFY[ nY ]; + + for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) + { + nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; + + aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, nTempX ) ); + aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY, ++nTempX ) ); + cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); + cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); + cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); + + aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTempY, nTempX ) ); + aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTempY--, --nTempX ) ); + cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); + cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); + cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); + + aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); + aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); + aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + } + } + + } + else + { + long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; + long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; + long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; + + for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTop = bVMirr ? ( nY + 1 ) : nY; + nBottom = bVMirr ? nY : ( nY + 1 ) ; + + if( nY ==nEndY ) + { + nLineStart = pMapIY[ nY ]; + nLineRange = 0; + } + else + { + nLineStart = pMapIY[ nTop ] ; + nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); + } + + for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) + { + nLeft = bHMirr ? ( nX + 1 ) : nX; + nRight = bHMirr ? nX : ( nX + 1 ) ; + + if( nX == nEndX ) + { + nRowStart = pMapIX[ nX ]; + nRowRange = 0; + } + else + { + nRowStart = pMapIX[ nLeft ]; + nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); + } + + nSumR = nSumG = nSumB = 0; + nTotalWeightY = 0; + + for(int i = 0; i<= nLineRange; i++) + { + nSumRowR = nSumRowG = nSumRowB = 0; + nTotalWeightX = 0; + + for(int j = 0; j <= nRowRange; j++) + { + aCol0 = pAcc->GetPaletteColor ( pAcc->GetPixelIndex( nLineStart + i, nRowStart + j ) ); + + if(nX == nEndX ) + { + + nSumRowB += aCol0.GetBlue() << 7L; + nSumRowG += aCol0.GetGreen() << 7L; + nSumRowR += aCol0.GetRed() << 7L; + nTotalWeightX += 1 << 7L; + } + else if( j == 0 ) + { + + nWeightX = (nMax- pMapFX[ nLeft ]) ; + nSumRowB += ( nWeightX *aCol0.GetBlue()) ; + nSumRowG += ( nWeightX *aCol0.GetGreen()) ; + nSumRowR += ( nWeightX *aCol0.GetRed()) ; + nTotalWeightX += nWeightX; + } + else if ( nRowRange == j ) + { + + nWeightX = pMapFX[ nRight ] ; + nSumRowB += ( nWeightX *aCol0.GetBlue() ); + nSumRowG += ( nWeightX *aCol0.GetGreen() ); + nSumRowR += ( nWeightX *aCol0.GetRed() ); + nTotalWeightX += nWeightX; + } + else + { + + nSumRowB += aCol0.GetBlue() << 7L; + nSumRowG += aCol0.GetGreen() << 7L; + nSumRowR += aCol0.GetRed() << 7L; + nTotalWeightX += 1 << 7L; + } + } + + if( nY == nEndY ) + nWeightY = nMax; + else if( i == 0 ) + nWeightY = nMax - pMapFY[ nTop ]; + else if( nLineRange == 1 ) + nWeightY = pMapFY[ nTop ]; + else if ( nLineRange == i ) + nWeightY = pMapFY[ nBottom ]; + else + nWeightY = nMax; + + nWeightY = nWeightY ; + nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); + nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); + nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); + nTotalWeightY += nWeightY; + } + + aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); + aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); + aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + } + } + } + } + } + else + { + if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR ) + { + if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) + { + Scanline pLine0, pLine1, pTmp0, pTmp1; + long nOff; + + for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; + pLine0 = pAcc->GetScanline( nTempY ); + pLine1 = pAcc->GetScanline( ++nTempY ); + + for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) + { + nOff = 3L * ( nTempX = pMapIX[ nX ] ); + nTempFX = pMapFX[ nX ]; + + pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; + cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); + + pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; + cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); + + aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); + aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); + aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + } + } + } + else + { + Scanline pTmpY, pTmpX; + long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; + long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; + long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; + + for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTop = bVMirr ? ( nY + 1 ) : nY; + nBottom = bVMirr ? nY : ( nY + 1 ) ; + + if( nY ==nEndY ) + { + nLineStart = pMapIY[ nY ]; + nLineRange = 0; + } + else + { + nLineStart = pMapIY[ nTop ] ; + nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); + } + + for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) + { + nLeft = bHMirr ? ( nX + 1 ) : nX; + nRight = bHMirr ? nX : ( nX + 1 ) ; + + if( nX == nEndX ) + { + nRowStart = pMapIX[ nX ]; + nRowRange = 0; + } + else + { + nRowStart = pMapIX[ nLeft ]; + nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); + } + + nSumR = nSumG = nSumB = 0; + nTotalWeightY = 0; + + for(int i = 0; i<= nLineRange; i++) + { + pTmpY = pAcc->GetScanline( nLineStart + i ); + pTmpX = pTmpY + 3L * nRowStart; + nSumRowR = nSumRowG = nSumRowB = 0; + nTotalWeightX = 0; + + for(int j = 0; j <= nRowRange; j++) + { + if(nX == nEndX ) + { + nSumRowB += ( *pTmpX ) << 7L;pTmpX++; + nSumRowG += ( *pTmpX ) << 7L;pTmpX++; + nSumRowR += ( *pTmpX ) << 7L;pTmpX++; + nTotalWeightX += 1 << 7L; + } + else if( j == 0 ) + { + nWeightX = (nMax- pMapFX[ nLeft ]) ; + nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++; + nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++; + nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++; + nTotalWeightX += nWeightX; + } + else if ( nRowRange == j ) + { + nWeightX = pMapFX[ nRight ] ; + nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++; + nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++; + nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++; + nTotalWeightX += nWeightX; + } + else + { + nSumRowB += ( *pTmpX ) << 7L;pTmpX++; + nSumRowG += ( *pTmpX ) << 7L;pTmpX++; + nSumRowR += ( *pTmpX ) << 7L;pTmpX++; + nTotalWeightX += 1 << 7L; + } + } + + if( nY == nEndY ) + nWeightY = nMax; + else if( i == 0 ) + nWeightY = nMax - pMapFY[ nTop ]; + else if( nLineRange == 1 ) + nWeightY = pMapFY[ nTop ]; + else if ( nLineRange == i ) + nWeightY = pMapFY[ nBottom ]; + else + nWeightY = nMax; + + nWeightY = nWeightY ; + nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); + nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); + nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); + nTotalWeightY += nWeightY; + } + + aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); + aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); + aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + + } + } + } + } + else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ) + { + if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) + { + Scanline pLine0, pLine1, pTmp0, pTmp1; + long nOff; + + for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; + pLine0 = pAcc->GetScanline( nTempY ); + pLine1 = pAcc->GetScanline( ++nTempY ); + + for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) + { + nOff = 3L * ( nTempX = pMapIX[ nX ] ); + nTempFX = pMapFX[ nX ]; + + pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L; + cR0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cG0 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cB0 = MAP( *pTmp0, *pTmp1, nTempFX ); + + pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L; + cR1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cG1 = MAP( *pTmp0, *pTmp1, nTempFX ); pTmp0++; pTmp1++; + cB1 = MAP( *pTmp0, *pTmp1, nTempFX ); + + aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); + aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); + aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + } + } + } + else + { + Scanline pTmpY, pTmpX; + long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; + long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; + long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; + + for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTop = bVMirr ? ( nY + 1 ) : nY; + nBottom = bVMirr ? nY : ( nY + 1 ) ; + + if( nY ==nEndY ) + { + nLineStart = pMapIY[ nY ]; + nLineRange = 0; + } + else + { + nLineStart = pMapIY[ nTop ] ; + nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); + } + + for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) + { + nLeft = bHMirr ? ( nX + 1 ) : nX; + nRight = bHMirr ? nX : ( nX + 1 ) ; + + if( nX == nEndX ) + { + nRowStart = pMapIX[ nX ]; + nRowRange = 0; + } + else + { + nRowStart = pMapIX[ nLeft ]; + nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); + } + + nSumR = nSumG = nSumB = 0; + nTotalWeightY = 0; + + for(int i = 0; i<= nLineRange; i++) + { + pTmpY = pAcc->GetScanline( nLineStart + i ); + pTmpX = pTmpY + 3L * nRowStart; + nSumRowR = nSumRowG = nSumRowB = 0; + nTotalWeightX = 0; + + for(int j = 0; j <= nRowRange; j++) + { + if(nX == nEndX ) + { + nSumRowR += ( *pTmpX ) << 7L;pTmpX++; + nSumRowG += ( *pTmpX ) << 7L;pTmpX++; + nSumRowB += ( *pTmpX ) << 7L;pTmpX++; + nTotalWeightX += 1 << 7L; + } + else if( j == 0 ) + { + nWeightX = (nMax- pMapFX[ nLeft ]) ; + nSumRowR += ( nWeightX *( *pTmpX )) ;pTmpX++; + nSumRowG += ( nWeightX *( *pTmpX )) ;pTmpX++; + nSumRowB += ( nWeightX *( *pTmpX )) ;pTmpX++; + nTotalWeightX += nWeightX; + } + else if ( nRowRange == j ) + { + nWeightX = pMapFX[ nRight ] ; + nSumRowR += ( nWeightX *( *pTmpX ) );pTmpX++; + nSumRowG += ( nWeightX *( *pTmpX ) );pTmpX++; + nSumRowB += ( nWeightX *( *pTmpX ) );pTmpX++; + nTotalWeightX += nWeightX; + } + else + { + nSumRowR += ( *pTmpX ) << 7L;pTmpX++; + nSumRowG += ( *pTmpX ) << 7L;pTmpX++; + nSumRowB += ( *pTmpX ) << 7L;pTmpX++; + nTotalWeightX += 1 << 7L; + } + } + + if( nY == nEndY ) + nWeightY = nMax; + else if( i == 0 ) + nWeightY = nMax - pMapFY[ nTop ]; + else if( nLineRange == 1 ) + nWeightY = pMapFY[ nTop ]; + else if ( nLineRange == i ) + nWeightY = pMapFY[ nBottom ]; + else + nWeightY = nMax; + + nWeightY = nWeightY ; + nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); + nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); + nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); + nTotalWeightY += nWeightY; + } + + aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); + aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); + aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + + } + } + } + } + else + { + if( scaleX >= fScaleThresh && scaleY >= fScaleThresh ) + { + for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTempY = pMapIY[ nY ]; nTempFY = pMapFY[ nY ]; + + for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ ) + { + nTempX = pMapIX[ nX ]; nTempFX = pMapFX[ nX ]; + + aCol0 = pAcc->GetPixel( nTempY, nTempX ); + aCol1 = pAcc->GetPixel( nTempY, ++nTempX ); + cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); + cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); + cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); + + aCol1 = pAcc->GetPixel( ++nTempY, nTempX ); + aCol0 = pAcc->GetPixel( nTempY--, --nTempX ); + cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTempFX ); + cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTempFX ); + cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTempFX ); + + aColRes.SetRed( MAP( cR0, cR1, nTempFY ) ); + aColRes.SetGreen( MAP( cG0, cG1, nTempFY ) ); + aColRes.SetBlue( MAP( cB0, cB1, nTempFY ) ); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + } + } + } + else + { + long nSumR, nSumG, nSumB,nLineStart , nLineRange, nRowStart , nRowRange ; + long nLeft, nRight, nTop, nBottom, nWeightX, nWeightY ; + long nSumRowR ,nSumRowG,nSumRowB, nTotalWeightX, nTotalWeightY; + + for( nY = nStartY , nYDst = 0L; nY <= nEndY; nY++, nYDst++ ) + { + nTop = bVMirr ? ( nY + 1 ) : nY; + nBottom = bVMirr ? nY : ( nY + 1 ) ; + + if( nY ==nEndY ) + { + nLineStart = pMapIY[ nY ]; + nLineRange = 0; + } + else + { + nLineStart = pMapIY[ nTop ] ; + nLineRange = ( pMapIY[ nBottom ] == pMapIY[ nTop ] ) ? 1 :( pMapIY[ nBottom ] - pMapIY[ nTop ] ); + } + + for( nX = nStartX , nXDst = 0L; nX <= nEndX; nX++ ) + { + nLeft = bHMirr ? ( nX + 1 ) : nX; + nRight = bHMirr ? nX : ( nX + 1 ) ; + + if( nX == nEndX ) + { + nRowStart = pMapIX[ nX ]; + nRowRange = 0; + } + else + { + nRowStart = pMapIX[ nLeft ]; + nRowRange = ( pMapIX[ nRight ] == pMapIX[ nLeft ] )? 1 : ( pMapIX[ nRight ] - pMapIX[ nLeft ] ); + } + + nSumR = nSumG = nSumB = 0; + nTotalWeightY = 0; + + for(int i = 0; i<= nLineRange; i++) + { + nSumRowR = nSumRowG = nSumRowB = 0; + nTotalWeightX = 0; + + for(int j = 0; j <= nRowRange; j++) + { + aCol0 = pAcc->GetPixel( nLineStart + i, nRowStart + j ); + + if(nX == nEndX ) + { + + nSumRowB += aCol0.GetBlue() << 7L; + nSumRowG += aCol0.GetGreen() << 7L; + nSumRowR += aCol0.GetRed() << 7L; + nTotalWeightX += 1 << 7L; + } + else if( j == 0 ) + { + + nWeightX = (nMax- pMapFX[ nLeft ]) ; + nSumRowB += ( nWeightX *aCol0.GetBlue()) ; + nSumRowG += ( nWeightX *aCol0.GetGreen()) ; + nSumRowR += ( nWeightX *aCol0.GetRed()) ; + nTotalWeightX += nWeightX; + } + else if ( nRowRange == j ) + { + + nWeightX = pMapFX[ nRight ] ; + nSumRowB += ( nWeightX *aCol0.GetBlue() ); + nSumRowG += ( nWeightX *aCol0.GetGreen() ); + nSumRowR += ( nWeightX *aCol0.GetRed() ); + nTotalWeightX += nWeightX; + } + else + { + nSumRowB += aCol0.GetBlue() << 7L; + nSumRowG += aCol0.GetGreen() << 7L; + nSumRowR += aCol0.GetRed() << 7L; + nTotalWeightX += 1 << 7L; + } + } + + if( nY == nEndY ) + nWeightY = nMax; + else if( i == 0 ) + nWeightY = nMax - pMapFY[ nTop ]; + else if( nLineRange == 1 ) + nWeightY = pMapFY[ nTop ]; + else if ( nLineRange == i ) + nWeightY = pMapFY[ nBottom ]; + else + nWeightY = nMax; + + nWeightY = nWeightY ; + nSumB += nWeightY * ( nSumRowB / nTotalWeightX ); + nSumG += nWeightY * ( nSumRowG / nTotalWeightX ); + nSumR += nWeightY * ( nSumRowR / nTotalWeightX ); + nTotalWeightY += nWeightY; + } + + aColRes.SetRed( ( sal_uInt8 ) (( nSumR / nTotalWeightY ) )); + aColRes.SetGreen( ( sal_uInt8 ) (( nSumG / nTotalWeightY) )); + aColRes.SetBlue( ( sal_uInt8 ) (( nSumB / nTotalWeightY ) )); + pWAcc->SetPixel( nYDst, nXDst++, aColRes ); + + } + } + } + } + } + + bRet = true; + } + + delete[] pMapIX; + delete[] pMapIY; + delete[] pMapFX; + delete[] pMapFY; + + ReleaseAccess( pAcc ); + aOutBmp.ReleaseAccess( pWAcc ); + + if( bRet ) + { + ImplAdaptBitCount(aOutBmp); + ImplAssignWithSize(aOutBmp); + } + + if( !bRet ) + bRet = ImplScaleFast( scaleX, scaleY ); + } + + return bRet; +} + +//----------------------------------------------------------------------------------- + +namespace +{ + void ImplCalculateContributions( + const sal_uInt32 aSourceSize, + const sal_uInt32 aDestinationSize, + sal_uInt32& aNumberOfContributions, + double*& pWeights, + sal_uInt32*& pPixels, + sal_uInt32*& pCount, + const Kernel& aKernel) + { + const double fSamplingRadius(aKernel.GetWidth()); + const double fScale(aDestinationSize / static_cast< double >(aSourceSize)); + const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius); + const double fFilterFactor((fScale < 1.0) ? fScale : 1.0); + + aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1; + const sal_uInt32 nAllocSize(aDestinationSize * aNumberOfContributions); + pWeights = new double[nAllocSize]; + pPixels = new sal_uInt32[nAllocSize]; + pCount = new sal_uInt32[aDestinationSize]; + + for(sal_uInt32 i(0); i < aDestinationSize; i++) + { + const sal_uInt32 aIndex(i * aNumberOfContributions); + const double aCenter(i / fScale); + const sal_Int32 aLeft(static_cast< sal_Int32 >(floor(aCenter - fScaledRadius))); + const sal_Int32 aRight(static_cast< sal_Int32 >(ceil(aCenter + fScaledRadius))); + sal_uInt32 aCurrentCount(0); + + for(sal_Int32 j(aLeft); j <= aRight; j++) + { + const double aWeight(aKernel.Calculate(fFilterFactor * (aCenter - static_cast< double>(j)))); + + // Reduce calculations with ignoring weights of 0.0 + if(fabs(aWeight) < 0.0001) + { + continue; + } + + // Handling on edges + const sal_uInt32 aPixelIndex(MinMax(j, 0, aSourceSize - 1)); + const sal_uInt32 nIndex(aIndex + aCurrentCount); + + pWeights[nIndex] = aWeight; + pPixels[nIndex] = aPixelIndex; + + aCurrentCount++; + } + + pCount[i] = aCurrentCount; + } + } + + sal_Bool ImplScaleConvolutionHor( + Bitmap& rSource, + Bitmap& rTarget, + const double& rScaleX, + const Kernel& aKernel) + { + // Do horizontal filtering + OSL_ENSURE(rScaleX > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)"); + const sal_uInt32 nWidth(rSource.GetSizePixel().Width()); + const sal_uInt32 nNewWidth(FRound(nWidth * rScaleX)); + + if(nWidth == nNewWidth) + { + return true; + } + + BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess(); + + if(pReadAcc) + { + double* pWeights = 0; + sal_uInt32* pPixels = 0; + sal_uInt32* pCount = 0; + sal_uInt32 aNumberOfContributions(0); + + const sal_uInt32 nHeight(rSource.GetSizePixel().Height()); + ImplCalculateContributions(nWidth, nNewWidth, aNumberOfContributions, pWeights, pPixels, pCount, aKernel); + rTarget = Bitmap(Size(nNewWidth, nHeight), 24); + BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess(); + bool bResult(0 != pWriteAcc); + + if(bResult) + { + for(sal_uInt32 y(0); y < nHeight; y++) + { + for(sal_uInt32 x(0); x < nNewWidth; x++) + { + const sal_uInt32 aBaseIndex(x * aNumberOfContributions); + double aSum(0.0); + double aValueRed(0.0); + double aValueGreen(0.0); + double aValueBlue(0.0); + + for(sal_uInt32 j(0); j < pCount[x]; j++) + { + const sal_uInt32 aIndex(aBaseIndex + j); + const double aWeight(pWeights[aIndex]); + BitmapColor aColor; + + aSum += aWeight; + + if(pReadAcc->HasPalette()) + { + aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(y, pPixels[aIndex])); + } + else + { + aColor = pReadAcc->GetPixel(y, pPixels[aIndex]); + } + + aValueRed += aWeight * aColor.GetRed(); + aValueGreen += aWeight * aColor.GetGreen(); + aValueBlue += aWeight * aColor.GetBlue(); + } + + const BitmapColor aResultColor( + static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)), + static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)), + static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255))); + + pWriteAcc->SetPixel(y, x, aResultColor); + } + } + + rTarget.ReleaseAccess(pWriteAcc); + } + + rSource.ReleaseAccess(pReadAcc); + delete[] pWeights; + delete[] pCount; + delete[] pPixels; + + if(bResult) + { + return true; + } + } + + return false; + } + + bool ImplScaleConvolutionVer( + Bitmap& rSource, + Bitmap& rTarget, + const double& rScaleY, + const Kernel& aKernel) + { + // Do vertical filtering + OSL_ENSURE(rScaleY > 0.0, "Error in scaling: Mirror given in non-mirror-capable method (!)"); + const sal_uInt32 nHeight(rSource.GetSizePixel().Height()); + const sal_uInt32 nNewHeight(FRound(nHeight * rScaleY)); + + if(nHeight == nNewHeight) + { + return true; + } + + BitmapReadAccess* pReadAcc = rSource.AcquireReadAccess(); + + if(pReadAcc) + { + double* pWeights = 0; + sal_uInt32* pPixels = 0; + sal_uInt32* pCount = 0; + sal_uInt32 aNumberOfContributions(0); + + const sal_uInt32 nWidth(rSource.GetSizePixel().Width()); + ImplCalculateContributions(nHeight, nNewHeight, aNumberOfContributions, pWeights, pPixels, pCount, aKernel); + rTarget = Bitmap(Size(nWidth, nNewHeight), 24); + BitmapWriteAccess* pWriteAcc = rTarget.AcquireWriteAccess(); + bool bResult(0 != pWriteAcc); + + if(pWriteAcc) + { + for(sal_uInt32 x(0); x < nWidth; x++) + { + for(sal_uInt32 y(0); y < nNewHeight; y++) + { + const sal_uInt32 aBaseIndex(y * aNumberOfContributions); + double aSum(0.0); + double aValueRed(0.0); + double aValueGreen(0.0); + double aValueBlue(0.0); + + for(sal_uInt32 j(0); j < pCount[y]; j++) + { + const sal_uInt32 aIndex(aBaseIndex + j); + const double aWeight(pWeights[aIndex]); + BitmapColor aColor; + + aSum += aWeight; + + if(pReadAcc->HasPalette()) + { + aColor = pReadAcc->GetPaletteColor(pReadAcc->GetPixelIndex(pPixels[aIndex], x)); + } + else + { + aColor = pReadAcc->GetPixel(pPixels[aIndex], x); + } + + aValueRed += aWeight * aColor.GetRed(); + aValueGreen += aWeight * aColor.GetGreen(); + aValueBlue += aWeight * aColor.GetBlue(); + } + + const BitmapColor aResultColor( + static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueRed / aSum), 0, 255)), + static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueGreen / aSum), 0, 255)), + static_cast< sal_uInt8 >(MinMax(static_cast< sal_Int32 >(aValueBlue / aSum), 0, 255))); + + if(pWriteAcc->HasPalette()) + { + pWriteAcc->SetPixelIndex(y, x, static_cast< sal_uInt8 >(pWriteAcc->GetBestPaletteIndex(aResultColor))); + } + else + { + pWriteAcc->SetPixel(y, x, aResultColor); + } + } + } + } + + rTarget.ReleaseAccess(pWriteAcc); + rSource.ReleaseAccess(pReadAcc); + + delete[] pWeights; + delete[] pCount; + delete[] pPixels; + + if(bResult) + { + return true; + } + } + + return false; + } +} + +// #121233# Added BMP_SCALE_LANCZOS, BMP_SCALE_BICUBIC, BMP_SCALE_BILINEAR and +// BMP_SCALE_BOX derived from the original commit from Toma Vajngerl (see +// bugzilla task for deitails) Thanks! +sal_Bool Bitmap::ImplScaleConvolution( + const double& rScaleX, + const double& rScaleY, + const Kernel& aKernel) +{ + const bool bMirrorHor(rScaleX < 0.0); + const bool bMirrorVer(rScaleY < 0.0); + const double fScaleX(bMirrorHor ? -rScaleX : rScaleX); + const double fScaleY(bMirrorVer ? -rScaleY : rScaleY); + const sal_uInt32 nWidth(GetSizePixel().Width()); + const sal_uInt32 nHeight(GetSizePixel().Height()); + const sal_uInt32 nNewWidth(FRound(nWidth * fScaleX)); + const sal_uInt32 nNewHeight(FRound(nHeight * fScaleY)); + const bool bScaleHor(nWidth != nNewWidth); + const bool bScaleVer(nHeight != nNewHeight); + const bool bMirror(bMirrorHor || bMirrorVer); + + if(!bMirror && !bScaleHor && !bScaleVer) + { + return true; + } + + bool bResult(true); + sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE); + bool bMirrorAfter(false); + + if(bMirror) + { + if(bMirrorHor) + { + nMirrorFlags |= BMP_MIRROR_HORZ; + } + + if(bMirrorVer) + { + nMirrorFlags |= BMP_MIRROR_VERT; + } + + const sal_uInt32 nStartSize(nWidth * nHeight); + const sal_uInt32 nEndSize(nNewWidth * nNewHeight); + + bMirrorAfter = nStartSize > nEndSize; + + if(!bMirrorAfter) + { + bResult = Mirror(nMirrorFlags); + } + } + + Bitmap aResult; + + if(bResult) + { + const sal_uInt32 nInBetweenSizeHorFirst(nHeight * nNewWidth); + const sal_uInt32 nInBetweenSizeVerFirst(nNewHeight * nWidth); + + if(nInBetweenSizeHorFirst < nInBetweenSizeVerFirst) + { + if(bScaleHor) + { + bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel); + } + + if(bResult && bScaleVer) + { + bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel); + } + } + else + { + if(bScaleVer) + { + bResult = ImplScaleConvolutionVer(*this, aResult, fScaleY, aKernel); + } + + if(bResult && bScaleHor) + { + bResult = ImplScaleConvolutionHor(*this, aResult, fScaleX, aKernel); + } + } + } + + if(bResult && bMirrorAfter) + { + bResult = aResult.Mirror(nMirrorFlags); + } + + if(bResult) + { + ImplAdaptBitCount(aResult); + *this = aResult; + } + + return bResult; +} + +// ------------------------------------------------------------------------ sal_Bool Bitmap::Dither( sal_uLong nDitherFlags ) { diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx index f5e37bdce759..1a518dbd09f2 100644 --- a/vcl/source/gdi/bitmapex.cxx +++ b/vcl/source/gdi/bitmapex.cxx @@ -443,7 +443,9 @@ sal_Bool BitmapEx::Scale( const double& rScaleX, const double& rScaleY, sal_uLon bRet = aBitmap.Scale( rScaleX, rScaleY, nScaleFlag ); if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask ) - aMask.Scale( rScaleX, rScaleY, BMP_SCALE_FAST ); + { + aMask.Scale( rScaleX, rScaleY, nScaleFlag ); + } aBitmapSize = aBitmap.GetSizePixel(); diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx index be936e555d5b..ac209e62b364 100644 --- a/vcl/source/gdi/impgraph.cxx +++ b/vcl/source/gdi/impgraph.cxx @@ -660,7 +660,7 @@ BitmapEx ImpGraphic::ImplGetBitmapEx(const GraphicConversionParameters& rParamet { aRetBmpEx.Scale( rParameters.getSizePixel(), - rParameters.getScaleHighQuality() ? BMP_SCALE_INTERPOLATE : BMP_SCALE_FAST); + rParameters.getScaleHighQuality() ? BMP_SCALE_BESTQUALITY : BMP_SCALE_FASTESTINTERPOLATE); } } else if( ( meType != GRAPHIC_DEFAULT ) && ImplIsSupportedGraphic() ) diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index 28031aab7535..161a8502dca1 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -132,10 +132,16 @@ void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSiz aNewBmpSize.Width() = FRound( fMaxPixelX ); aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH); } + if( aNewBmpSize.Width() && aNewBmpSize.Height() ) - aBitmapEx.Scale( aNewBmpSize ); + { + // #121233# Use best quality for PDF exports + aBitmapEx.Scale( aNewBmpSize, BMP_SCALE_BESTQUALITY ); + } else + { aBitmapEx.SetEmpty(); + } } } diff --git a/vcl/source/helper/canvasbitmap.cxx b/vcl/source/helper/canvasbitmap.cxx index 8ae3ccb987db..8eab29ea66c4 100644 --- a/vcl/source/helper/canvasbitmap.cxx +++ b/vcl/source/helper/canvasbitmap.cxx @@ -457,7 +457,7 @@ uno::Reference< rendering::XBitmap > SAL_CALL VclCanvasBitmap::getScaledBitmap( vos::OGuard aGuard( Application::GetSolarMutex() ); BitmapEx aNewBmp( m_aBitmap ); - aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE ); + aNewBmp.Scale( sizeFromRealSize2D( newSize ), beFast ? BMP_SCALE_FASTESTINTERPOLATE : BMP_SCALE_INTERPOLATE ); return uno::Reference<rendering::XBitmap>( new VclCanvasBitmap( aNewBmp ) ); } |