summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <quikee@gmail.com>2012-07-24 22:01:18 +0200
committerTomaž Vajngerl <quikee@gmail.com>2012-07-24 22:17:27 +0200
commit53d51dbee6d4037c4cfc3fa743de8dac76da48c6 (patch)
tree48a43fab9c2807dbbad088f13bdc400e658a55d8
parent963cababc65c945412963f7d66578b544d5f720b (diff)
One pass scale, rotate and crop using bilinear filtering and averaging.
With this commit I reintroduce one pass scale, rotate and crop that was located in grfmgr2.cxx (now in Bitmap class) and was used for preparing bitmaps for displaying on screen. By default the combination of two filters is used: bilinear, which is a similar algorithm than the "old" one, but with the same result, and averaging algorithm. Bilinear filtering is used for bitmap enlarging and shrinking till factor 0.6. Below this bilinear gives bad results because of limited sampling. For such cases averaging is used which is a simple algorithm for shrinking. In averaging the algorithm calculates the average of samples which result is the new pixel. Currently both algorithms are not optimised. One pass scale, rotate and crop should only be used for displaying of images. Change-Id: I5a1330b58a7cbb6fde8546e16c3e8c140afca565
-rw-r--r--svtools/source/graphic/grfmgr2.cxx137
-rw-r--r--vcl/inc/vcl/bitmap.hxx112
-rw-r--r--vcl/inc/vcl/bitmapex.hxx5
-rw-r--r--vcl/source/gdi/bitmap3.cxx406
-rw-r--r--vcl/source/gdi/bitmapex.cxx42
5 files changed, 578 insertions, 124 deletions
diff --git a/svtools/source/graphic/grfmgr2.cxx b/svtools/source/graphic/grfmgr2.cxx
index f072f77c6f8c..f3b6a073b9ec 100644
--- a/svtools/source/graphic/grfmgr2.cxx
+++ b/svtools/source/graphic/grfmgr2.cxx
@@ -44,7 +44,6 @@
// - defines -
// -----------
-#define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
#define WATERMARK_LUM_OFFSET 50
#define WATERMARK_CON_OFFSET -70
@@ -267,14 +266,16 @@ sal_Bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
const Point& rPoint, const Size& rSize,
- const BitmapEx& rBitmapEx, const GraphicAttr& rAttr,
- const sal_uLong nFlags, BitmapEx* pBmpEx )
+ const BitmapEx& rBitmapEx, const GraphicAttr& rAttributes,
+ const sal_uLong nFlags, BitmapEx* pResultBitmapEx )
{
bool bRet = false;
Point aOutPointInPixels;
Size aOutSizeInPixels;
- int nRotation = rAttr.GetRotation() % 3600;
- Size aUnrotatedSizeInPixels( pOutputDevice->LogicToPixel( rSize ) );
+ int nRotation = rAttributes.GetRotation() % 3600;
+
+ Point aUnrotatedPointInPixels( pOutputDevice->LogicToPixel( rPoint ) );
+ Size aUnrotatedSizeInPixels( pOutputDevice->LogicToPixel( rSize ) );
BitmapEx aBitmapEx( rBitmapEx );
@@ -283,69 +284,70 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
if( nRotation )
{
- Polygon aRotationPolygon( Rectangle( rPoint, rSize ) );
- aRotationPolygon.Rotate( rPoint, nRotation );
- const Rectangle aRotationBoundRectangle( aRotationPolygon.GetBoundRect() );
- aOutPointInPixels = pOutputDevice->LogicToPixel( aRotationBoundRectangle.TopLeft() );
- aOutSizeInPixels = pOutputDevice->LogicToPixel( aRotationBoundRectangle.GetSize() );
-
- // rotate the image before further processing
- aBitmapEx.Rotate( nRotation, COL_TRANSPARENT );
+ Polygon aPoly( Rectangle( rPoint, rSize ) );
+ aPoly.Rotate( rPoint, nRotation );
+ const Rectangle aRotationBoundRect( aPoly.GetBoundRect() );
+ aOutPointInPixels = pOutputDevice->LogicToPixel( aRotationBoundRect.TopLeft() );
+ aOutSizeInPixels = pOutputDevice->LogicToPixel( aRotationBoundRect.GetSize() );
}
else
{
- aOutPointInPixels = pOutputDevice->LogicToPixel( rPoint );
+ aOutPointInPixels = aUnrotatedPointInPixels;
aOutSizeInPixels = aUnrotatedSizeInPixels;
}
- Point aOutPoint;
- Size aOutSize;
- const Size& rBitmapSizePixels = rBitmapEx.GetSizePixel();
- long nStartX(-1), nStartY(-1), nEndX(-1), nEndY(-1);
- bool isHorizontalMirrored = ( rAttr.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
- bool isVerticalMirrored = ( rAttr.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
+ Point aOutPoint;
+ Size aOutSize;
+
+ const Size& rBitmapSizePixels = rBitmapEx.GetSizePixel();
+ Rectangle aCropRectangle(-1, -1, -1, -1);
+ bool isHorizontalMirrored = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
+ bool isVerticalMirrored = ( rAttributes.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
- Rectangle aBmpRect( aOutPointInPixels, aOutSizeInPixels );
+ Rectangle aBitmapRectangle( aOutPointInPixels, aOutSizeInPixels );
// calculate output sizes
- if( !pBmpEx )
+ if( !pResultBitmapEx )
{
- Point aPoint;
- Rectangle aOutRect( aPoint, pOutputDevice->GetOutputSizePixel() );
+ Rectangle aOutRect( Point(), pOutputDevice->GetOutputSizePixel() );
if( pOutputDevice->GetOutDevType() == OUTDEV_WINDOW )
{
- const Region aPaintRgn( ( (Window*) pOutputDevice )->GetPaintRegion() );
- if( !aPaintRgn.IsNull() )
+ const Region aPaintRegion( ( (Window*) pOutputDevice )->GetPaintRegion() );
+
+ if( !aPaintRegion.IsNull() )
{
- aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRgn.GetBoundRect() ) );
+ aOutRect.Intersection( pOutputDevice->LogicToPixel( aPaintRegion.GetBoundRect() ) );
}
}
- aOutRect.Intersection( aBmpRect );
+ aOutRect.Intersection( aBitmapRectangle );
if( !aOutRect.IsEmpty() )
{
aOutPoint = pOutputDevice->PixelToLogic( aOutRect.TopLeft() );
- aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() );
- nStartX = aOutRect.Left() - aBmpRect.Left();
- nStartY = aOutRect.Top() - aBmpRect.Top();
- nEndX = aOutRect.Right() - aBmpRect.Left();
- nEndY = aOutRect.Bottom() - aBmpRect.Top();
+ aOutSize = pOutputDevice->PixelToLogic( aOutRect.GetSize() );
+
+ aCropRectangle = Rectangle(
+ aOutRect.Left() - aBitmapRectangle.Left(),
+ aOutRect.Top() - aBitmapRectangle.Top(),
+ aOutRect.Right() - aBitmapRectangle.Left(),
+ aOutRect.Bottom() - aBitmapRectangle.Top() );
+
}
- else
- nStartX = -1L; // invalid
}
else
{
aOutPoint = pOutputDevice->PixelToLogic( aOutPointInPixels );
- aOutSize = pOutputDevice->PixelToLogic( aOutSizeInPixels );
- nStartX = nStartY = 0;
- nEndX = aOutSizeInPixels.Width() - 1L;
- nEndY = aOutSizeInPixels.Height() - 1L;
+ aOutSize = pOutputDevice->PixelToLogic( aOutSizeInPixels );
+
+ aCropRectangle = Rectangle(
+ 0, 0,
+ aOutSizeInPixels.Width() - 1,
+ aOutSizeInPixels.Height() - 1 );
}
- if( nStartX < 0L )
+ if( aCropRectangle.GetWidth() <= 0 && aCropRectangle.GetHeight() <= 0)
return false;
// do transformation
@@ -365,43 +367,44 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
else
{
// calculate scaling factors
- double fScaleX = aBmpRect.GetWidth() / (double) aBitmapEx.GetSizePixel().Width();
- double fScaleY = aBmpRect.GetHeight() / (double) aBitmapEx.GetSizePixel().Height();
-
- // calculate crop regions on original non-scaled bitmap
- long nOriginalStartX = nStartX / fScaleX;
- long nOriginalEndX = nEndX / fScaleX;
- long nOriginalStartY = nStartY / fScaleY;
- long nOriginalEndY = nEndY / fScaleY;
-
- Size aScaleSize( nEndX - nStartX + 1, nEndY - nStartY + 1 );
-
- // crop the bitmap, so we deal with a smaller bitmap
- // todo: join crop and scale step into one step on Bitmap to decrease processing
- bRet = aBitmapEx.Crop( Rectangle( nOriginalStartX, nOriginalStartY, nOriginalEndX, nOriginalEndY ) );
+ double fScaleX = aUnrotatedSizeInPixels.Width() / (double) rBitmapSizePixels.Width();
+ double fScaleY = aUnrotatedSizeInPixels.Height() / (double) rBitmapSizePixels.Height();
// mirror the image - this should not impact the picture dimenstions
if( isHorizontalMirrored || isVerticalMirrored )
- bRet = aBitmapEx.Mirror( rAttr.GetMirrorFlags() );
+ bRet = aBitmapEx.Mirror( rAttributes.GetMirrorFlags() );
// depending on the flags, scale the image to the desired proportions
// use FAST scale if no smooth scale is desired
- if( !( nFlags & GRFMGR_DRAW_SMOOTHSCALE ))
- bRet = aBitmapEx.Scale( aScaleSize, BMP_SCALE_FAST );
- else
- bRet = aBitmapEx.Scale( aScaleSize );
+ if( nFlags & GRFMGR_DRAW_SMOOTHSCALE)
+ {
+ Polygon aPoly( Rectangle( Point(), aUnrotatedSizeInPixels) );
+ aPoly.Rotate( Point(), nRotation );
+ Rectangle aNewBound( aPoly.GetBoundRect() );
+ Rectangle aCropRectangle2 (
+ aCropRectangle.Left() + aNewBound.Left(),
+ aCropRectangle.Top() + aNewBound.Top(),
+ aCropRectangle.Right() + aNewBound.Left(),
+ aCropRectangle.Bottom() + aNewBound.Top());
+
+ bRet = aBitmapEx.ScaleCropRotate( fScaleX, fScaleY, aCropRectangle2, nRotation, COL_TRANSPARENT );
+ }
}
if( bRet )
{
// attribute adjustment if neccessary
- if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsTransparent() )
- ImplAdjust( aBitmapEx, rAttr, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
+ if( rAttributes.IsSpecialDrawMode()
+ || rAttributes.IsAdjusted()
+ || rAttributes.IsTransparent() )
+ {
+ ImplAdjust( aBitmapEx, rAttributes, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
+ }
// OutDev adjustment if neccessary
- if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER &&
- pOutputDevice->GetBitCount() <= 8 &&
- aBitmapEx.GetBitCount() >= 8 )
+ if( pOutputDevice->GetOutDevType() != OUTDEV_PRINTER
+ && pOutputDevice->GetBitCount() <= 8
+ && aBitmapEx.GetBitCount() >= 8 )
{
aBitmapEx.Dither( BMP_DITHER_MATRIX );
}
@@ -410,12 +413,12 @@ sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOutputDevice,
// create output
if( bRet )
{
- if( pBmpEx )
+ if( pResultBitmapEx )
{
- if( !rAttr.IsTransparent() && !aBitmapEx.IsAlpha() )
+ if( !rAttributes.IsTransparent() && !aBitmapEx.IsAlpha() )
aBitmapEx = BitmapEx( aBitmapEx.GetBitmap().CreateDisplayBitmap( pOutputDevice ), aBitmapEx.GetMask() );
- *pBmpEx = aBitmapEx;
+ *pResultBitmapEx = aBitmapEx;
}
pOutputDevice->DrawBitmapEx( aOutPoint, aOutSize, aBitmapEx);
}
diff --git a/vcl/inc/vcl/bitmap.hxx b/vcl/inc/vcl/bitmap.hxx
index 5c2832e2f105..e1e489f06faf 100644
--- a/vcl/inc/vcl/bitmap.hxx
+++ b/vcl/inc/vcl/bitmap.hxx
@@ -343,10 +343,9 @@ class VCL_DLLPUBLIC Bitmap
{
private:
- ImpBitmap* mpImpBmp;
- MapMode maPrefMapMode;
- Size maPrefSize;
-
+ ImpBitmap* mpImpBmp;
+ MapMode maPrefMapMode;
+ Size maPrefSize;
public:
@@ -356,59 +355,63 @@ public:
SAL_DLLPRIVATE void ImplSetImpBitmap( ImpBitmap* pImpBmp );
SAL_DLLPRIVATE void ImplAssignWithSize( const Bitmap& rBitmap );
- SAL_DLLPRIVATE static sal_Bool ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, sal_uLong nOffset, sal_Bool bMSOFormat = sal_False );
- SAL_DLLPRIVATE static sal_Bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset );
- SAL_DLLPRIVATE static sal_Bool ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader, sal_Bool& bTopDown, sal_Bool bMSOFormat = sal_False );
- SAL_DLLPRIVATE static sal_Bool ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, sal_Bool bQuad );
- SAL_DLLPRIVATE static sal_Bool ImplReadDIBBits( SvStream& rIStm, DIBInfoHeader& rHeader, BitmapWriteAccess& rAcc, sal_Bool bTopDown );
- SAL_DLLPRIVATE sal_Bool ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bCompressed ) const;
- SAL_DLLPRIVATE static sal_Bool ImplWriteDIBFileHeader( SvStream& rOStm, BitmapReadAccess& rAcc );
- SAL_DLLPRIVATE static sal_Bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc );
- SAL_DLLPRIVATE static sal_Bool ImplWriteDIBBits( SvStream& rOStm, BitmapReadAccess& rAcc,
- sal_uLong nCompression, sal_uInt32& rImageSize );
+ SAL_DLLPRIVATE static sal_Bool ImplReadDIB( SvStream& rIStm, Bitmap& rBmp, sal_uLong nOffset, sal_Bool bMSOFormat = sal_False );
+ SAL_DLLPRIVATE static sal_Bool ImplReadDIBFileHeader( SvStream& rIStm, sal_uLong& rOffset );
+ SAL_DLLPRIVATE static sal_Bool ImplReadDIBInfoHeader( SvStream& rIStm, DIBInfoHeader& rHeader, sal_Bool& bTopDown, sal_Bool bMSOFormat = sal_False );
+ SAL_DLLPRIVATE static sal_Bool ImplReadDIBPalette( SvStream& rIStm, BitmapWriteAccess& rAcc, sal_Bool bQuad );
+ SAL_DLLPRIVATE static sal_Bool ImplReadDIBBits( SvStream& rIStm, DIBInfoHeader& rHeader, BitmapWriteAccess& rAcc, sal_Bool bTopDown );
+ SAL_DLLPRIVATE sal_Bool ImplWriteDIB( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bCompressed ) const;
+ SAL_DLLPRIVATE static sal_Bool ImplWriteDIBFileHeader( SvStream& rOStm, BitmapReadAccess& rAcc );
+ SAL_DLLPRIVATE static sal_Bool ImplWriteDIBPalette( SvStream& rOStm, BitmapReadAccess& rAcc );
+ SAL_DLLPRIVATE static sal_Bool ImplWriteDIBBits( SvStream& rOStm, BitmapReadAccess& rAcc,
+ sal_uLong nCompression, sal_uInt32& rImageSize );
SAL_DLLPRIVATE static void ImplDecodeRLE( sal_uInt8* pBuffer, DIBInfoHeader& rHeader,
- BitmapWriteAccess& rAcc, sal_Bool bRLE4 );
- SAL_DLLPRIVATE static sal_Bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bRLE4 );
-
- 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 ImplScaleConvolution( const double& rScaleX, const double& rScaleY, Kernel& aKernel);
-
- SAL_DLLPRIVATE static void ImplCalculateContributions( const int aSourceSize, const int aDestinationSize,
+ BitmapWriteAccess& rAcc, sal_Bool bRLE4 );
+ SAL_DLLPRIVATE static sal_Bool ImplWriteRLE( SvStream& rOStm, BitmapReadAccess& rAcc, sal_Bool bRLE4 );
+
+ 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 ImplScaleConvolution( const double& rScaleX, const double& rScaleY, Kernel& aKernel);
+ SAL_DLLPRIVATE bool ImplTransformAveraging( const double& rScaleX, const double& rScaleY,
+ const Rectangle& rRotatedRectangle, const long nAngle10, const Color& rFillColor );
+ SAL_DLLPRIVATE bool ImplTransformBilinearFiltering( const double& rScaleX, const double& rScaleY,
+ const Rectangle& rRotatedRectangle, const long nAngle10, const Color& rFillColor );
+
+ SAL_DLLPRIVATE static void ImplCalculateContributions( const int aSourceSize, const int aDestinationSize,
int& aNumberOfContributions, double*& pWeights, int*& pPixels, int*& pCount,
Kernel& aKernel );
- SAL_DLLPRIVATE bool ImplConvolutionPass( Bitmap& aNewBitmap, const int nNewSize, BitmapReadAccess* pReadAcc,
+ 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();
- SAL_DLLPRIVATE sal_Bool ImplMakeGreyscales( sal_uInt16 nGreyscales );
- SAL_DLLPRIVATE sal_Bool ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor = NULL );
- SAL_DLLPRIVATE sal_Bool ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor = NULL );
- SAL_DLLPRIVATE sal_Bool ImplConvertGhosted();
- SAL_DLLPRIVATE sal_Bool ImplDitherMatrix();
- SAL_DLLPRIVATE sal_Bool ImplDitherFloyd();
- SAL_DLLPRIVATE sal_Bool ImplDitherFloyd16();
- SAL_DLLPRIVATE sal_Bool ImplReduceSimple( sal_uInt16 nColorCount );
- SAL_DLLPRIVATE sal_Bool ImplReducePopular( sal_uInt16 nColorCount );
- SAL_DLLPRIVATE sal_Bool ImplReduceMedian( sal_uInt16 nColorCount );
+ SAL_DLLPRIVATE sal_Bool ImplMakeMono( sal_uInt8 cThreshold );
+ SAL_DLLPRIVATE sal_Bool ImplMakeMonoDither();
+ SAL_DLLPRIVATE sal_Bool ImplMakeGreyscales( sal_uInt16 nGreyscales );
+ SAL_DLLPRIVATE sal_Bool ImplConvertUp( sal_uInt16 nBitCount, Color* pExtColor = NULL );
+ SAL_DLLPRIVATE sal_Bool ImplConvertDown( sal_uInt16 nBitCount, Color* pExtColor = NULL );
+ SAL_DLLPRIVATE sal_Bool ImplConvertGhosted();
+ SAL_DLLPRIVATE sal_Bool ImplDitherMatrix();
+ SAL_DLLPRIVATE sal_Bool ImplDitherFloyd();
+ SAL_DLLPRIVATE sal_Bool ImplDitherFloyd16();
+ SAL_DLLPRIVATE sal_Bool ImplReduceSimple( sal_uInt16 nColorCount );
+ SAL_DLLPRIVATE sal_Bool ImplReducePopular( sal_uInt16 nColorCount );
+ SAL_DLLPRIVATE sal_Bool ImplReduceMedian( sal_uInt16 nColorCount );
SAL_DLLPRIVATE void ImplMedianCut( sal_uLong* pColBuf, BitmapPalette& rPal,
- 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,
+ 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 );
- 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 );
- SAL_DLLPRIVATE sal_Bool ImplSolarize( const BmpFilterParam* pFilterParam, const Link* pProgress );
- SAL_DLLPRIVATE sal_Bool ImplSepia( const BmpFilterParam* pFilterParam, const Link* pProgress );
- SAL_DLLPRIVATE sal_Bool ImplMosaic( const BmpFilterParam* pFilterParam, const Link* pProgress );
- SAL_DLLPRIVATE sal_Bool ImplPopArt( const BmpFilterParam* pFilterParam, const Link* pProgress );
-
- SAL_DLLPRIVATE bool ImplSeparableBlurFilter( const double aRadius = 0.7 );
- SAL_DLLPRIVATE bool ImplSeparableUnsharpenFilter( const double aRadius = 0.7 );
- SAL_DLLPRIVATE void ImplBlurContributions( const int aSize, const int aNumberOfContributions,
+ 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 );
+ SAL_DLLPRIVATE sal_Bool ImplSolarize( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE sal_Bool ImplSepia( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE sal_Bool ImplMosaic( const BmpFilterParam* pFilterParam, const Link* pProgress );
+ SAL_DLLPRIVATE sal_Bool ImplPopArt( const BmpFilterParam* pFilterParam, const Link* pProgress );
+
+ SAL_DLLPRIVATE bool ImplSeparableBlurFilter( const double aRadius = 0.7 );
+ SAL_DLLPRIVATE bool ImplSeparableUnsharpenFilter( const double aRadius = 0.7 );
+ SAL_DLLPRIVATE void ImplBlurContributions( const int aSize, const int aNumberOfContributions,
double* pBlurVector, double*& pWeights, int*& pPixels, int*& pCount );
public:
@@ -633,8 +636,7 @@ public:
@return sal_True, if the operation was completed successfully.
*/
- sal_Bool Scale( const Size& rNewSize,
- sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
+ sal_Bool Scale( const Size& rNewSize, sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
/** Scale the bitmap
@@ -646,8 +648,12 @@ public:
@return sal_True, if the operation was completed successfully.
*/
- sal_Bool Scale( const double& rScaleX, const double& rScaleY,
- sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
+ sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
+
+ /** Scale, crop and rotate the bitmap */
+ sal_Bool ScaleCropRotate(
+ const double& rScaleX, const double& rScaleY, const Rectangle& rRectPixel, long nAngle10,
+ const Color& rFillColor, sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
/** Rotate bitmap by the specified angle
diff --git a/vcl/inc/vcl/bitmapex.hxx b/vcl/inc/vcl/bitmapex.hxx
index 845981aa5c1e..a29c27177679 100644
--- a/vcl/inc/vcl/bitmapex.hxx
+++ b/vcl/inc/vcl/bitmapex.hxx
@@ -268,6 +268,11 @@ public:
*/
sal_Bool Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
+ /** Scale, crop and rotate the bitmap */
+ sal_Bool ScaleCropRotate(
+ const double& rScaleX, const double& rScaleY, const Rectangle& rRectPixel, long nAngle10,
+ const Color& rFillColor, sal_uLong nScaleFlag = BMP_SCALE_DEFAULT );
+
/** Rotate bitmap by the specified angle
@param nAngle10
diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx
index 4bef1650e524..b1a028cfe67c 100644
--- a/vcl/source/gdi/bitmap3.cxx
+++ b/vcl/source/gdi/bitmap3.cxx
@@ -907,7 +907,7 @@ sal_Bool Bitmap::ImplConvertGhosted()
sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong nScaleFlag )
{
- sal_Bool bRet;
+ bool bRet;
if( ( rScaleX != 1.0 ) || ( rScaleY != 1.0 ) )
{
@@ -945,7 +945,7 @@ sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong
}
}
else
- bRet = sal_True;
+ bRet = true;
return bRet;
}
@@ -955,7 +955,7 @@ sal_Bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uLong
sal_Bool Bitmap::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
{
const Size aSize( GetSizePixel() );
- sal_Bool bRet;
+ bool bRet;
if( aSize.Width() && aSize.Height() )
{
@@ -2377,4 +2377,404 @@ bool Bitmap::ImplConvolutionPass(Bitmap& aNewBitmap, const int nNewSize, BitmapR
return true;
}
+sal_Bool Bitmap::ScaleCropRotate(
+ const double& rScaleX, const double& rScaleY, const Rectangle& rRectPixel, long nAngle10,
+ const Color& rFillColor, sal_uLong /* nScaleFlag */ )
+{
+ bool bRet;
+
+ if ( rScaleY < 0.6 && rScaleX < 0.6 )
+ {
+ bRet = ImplTransformAveraging( rScaleX, rScaleY, rRectPixel, nAngle10, rFillColor);
+ }
+ else
+ {
+ bRet = ImplTransformBilinearFiltering( rScaleX, rScaleY, rRectPixel, nAngle10, rFillColor);
+ }
+
+ return bRet;
+}
+
+// Scaling algorithm best for shrinking below factor 0.5 where algorithms with limited sampling range show bad results (bilinear, bicubic).
+// The algoritm determines the sampling range for one pixel and calculates the average of samples which is the resulting pixel.
+bool Bitmap::ImplTransformAveraging( const double& rScaleX, const double& rScaleY, const Rectangle& rRotatedRectangle, const long nAngle10, const Color& rFillColor )
+{
+ const Size aSizePix( GetSizePixel() );
+
+ const int nStartX = rRotatedRectangle.Left();
+ const int nStartY = rRotatedRectangle.Top();
+ const int nEndX = rRotatedRectangle.Right();
+ const int nEndY = rRotatedRectangle.Bottom();
+
+ const int nTargetWidth = rRotatedRectangle.GetWidth();
+ const int nTargetHeight = rRotatedRectangle.GetHeight();
+
+ const int nOriginWidth = aSizePix.Width();
+ const int nOriginHeight = aSizePix.Height();
+
+ const int nScaledWidth = FRound( nOriginWidth * rScaleX );
+ const int nScaledHeight = FRound( nOriginHeight * rScaleY );
+
+ const double aReverseScaleX = 1.0 / rScaleX;
+ const double aReverseScaleY = 1.0 / rScaleY;
+
+ const double fCosAngle = cos( nAngle10 * F_PI1800 );
+ const double fSinAngle = sin( nAngle10 * F_PI1800 );
+
+ if( nTargetWidth <= 1L || nTargetHeight <= 1L )
+ return false;
+
+ BitmapColor aColor, aResultColor;
+
+ Bitmap aOutBmp( Size( nTargetWidth, nTargetHeight ), 24 );
+
+ BitmapReadAccess* pReadAccess = AcquireReadAccess();
+ BitmapWriteAccess* pWriteAccess = aOutBmp.AcquireWriteAccess();
+
+ if( !pReadAccess || !pWriteAccess )
+ return false;
+
+ const BitmapColor aFillColor( pWriteAccess->GetBestMatchingColor( rFillColor ) );
+
+ int x, y, xOut, yOut;
+ int aCount;
+ double aSumRed, aSumGreen, aSumBlue;
+
+ for( y = nStartY, yOut = 0; y <= nEndY; y++, yOut++ )
+ {
+ for( x = nStartX, xOut = 0; x <= nEndX; x++, xOut++ )
+ {
+ double unrotatedX = fCosAngle * x - fSinAngle * y;
+ double unrotatedY = fSinAngle * x + fCosAngle * y;
+
+ if ( unrotatedX < 0
+ || unrotatedX >= nScaledWidth
+ || unrotatedY < 0
+ || unrotatedY >= nScaledHeight)
+ {
+ pWriteAccess->SetPixel( yOut, xOut, aFillColor );
+ }
+ else
+ {
+ double dYStart = ((unrotatedY + 0.5) * aReverseScaleY) - 0.5;
+ double dYEnd = ((unrotatedY + 1.5) * aReverseScaleY) - 0.5;
+
+ int yStart = MinMax( dYStart, 0, nOriginHeight - 1);
+ int yEnd = MinMax( dYEnd, 0, nOriginHeight - 1);
+
+ double dXStart = ((unrotatedX + 0.5) * aReverseScaleX) - 0.5;
+ double dXEnd = ((unrotatedX + 1.5) * aReverseScaleX) - 0.5;
+
+ int xStart = MinMax( dXStart, 0, nOriginWidth - 1);
+ int xEnd = MinMax( dXEnd, 0, nOriginWidth - 1);
+
+ aSumRed = aSumGreen = aSumBlue = 0.0;
+ aCount = 0;
+
+ for (int yIn = yStart; yIn <= yEnd; yIn++)
+ {
+ for (int xIn = xStart; xIn <= xEnd; xIn++)
+ {
+ aColor = pReadAccess->GetPixel( yIn, xIn );
+
+ if( pReadAccess->HasPalette() )
+ aColor = pReadAccess->GetPaletteColor( aColor );
+
+ aSumRed += aColor.GetRed();
+ aSumGreen += aColor.GetGreen();
+ aSumBlue += aColor.GetBlue();
+
+ aCount++;
+ }
+ }
+
+ aResultColor.SetRed( MinMax( aSumRed / aCount, 0, 255) );
+ aResultColor.SetGreen( MinMax( aSumGreen / aCount, 0, 255) );
+ aResultColor.SetBlue( MinMax( aSumBlue / aCount, 0, 255) );
+
+ pWriteAccess->SetPixel( yOut, xOut, aResultColor );
+ }
+ }
+ }
+
+ ReleaseAccess( pReadAccess );
+ aOutBmp.ReleaseAccess( pWriteAccess );
+ ImplAssignWithSize( aOutBmp );
+
+ return true;
+}
+
+// Bilinear filtering used for shrinking and enlarging the source bitmap. Filtering is also used for rotation.
+// Filtering shows bad results at shrinking for a factor less than 0.5 because of limited sampling.
+bool Bitmap::ImplTransformBilinearFiltering( const double& rScaleX, const double& rScaleY, const Rectangle& rRotatedRectangle, const long nAngle10, const Color& rFillColor )
+{
+ const Size aSizePix( GetSizePixel() );
+
+ const int nOriginWidth = aSizePix.Width();
+ const int nOriginHeight = aSizePix.Height();
+
+ const int nScaledWidth = FRound( aSizePix.Width() * rScaleX );
+ const int nScaledHeight = FRound( aSizePix.Height() * rScaleY );
+
+ const int nStartX = rRotatedRectangle.Left();
+ const int nStartY = rRotatedRectangle.Top();
+ const int nEndX = rRotatedRectangle.Right();
+ const int nEndY = rRotatedRectangle.Bottom();
+
+ const int nTargetWidth = rRotatedRectangle.GetWidth();
+ const int nTargetHeight = rRotatedRectangle.GetHeight();
+
+ const double fCosAngle = cos( nAngle10 * F_PI1800 );
+ const double fSinAngle = sin( nAngle10 * F_PI1800 );
+
+ Bitmap aOutBmp( Size( nTargetWidth, nTargetHeight ), 24 );
+
+ BitmapReadAccess* pReadAccess = AcquireReadAccess();
+ BitmapWriteAccess* pWriteAccess = aOutBmp.AcquireWriteAccess();
+
+ if( !pReadAccess || !pWriteAccess )
+ return false;
+
+ const BitmapColor aFillColor( pWriteAccess->GetBestMatchingColor( rFillColor ) );
+
+ double aReverseScaleX = 1.0 / rScaleX;
+ double aReverseScaleY = 1.0 / rScaleY;
+
+ BitmapColor aColor00, aColor01, aColor10, aColor11, aResultColor;
+
+ int x, y, xOut, yOut;
+
+ for( y = nStartY, yOut = 0; y <= nEndY; y++, yOut++ )
+ {
+ for( x = nStartX, xOut = 0; x <= nEndX; x++, xOut++ )
+ {
+ double unrotatedX = fCosAngle * x - fSinAngle * y;
+ double unrotatedY = fSinAngle * x + fCosAngle * y;
+
+ if ( unrotatedX < 0
+ || unrotatedX >= nScaledWidth
+ || unrotatedY < 0
+ || unrotatedY >= nScaledHeight)
+ {
+ pWriteAccess->SetPixel( yOut, xOut, aFillColor );
+ }
+ else
+ {
+ double sy0 = ((unrotatedY + 0.5) * aReverseScaleY) - 0.5;
+
+ int y0 = MinMax( floor( sy0 ), 0, nOriginHeight - 1);
+ int y1 = MinMax( y0 + 1, 0, nOriginHeight - 1);
+
+ double sx0 = ((unrotatedX + 0.5) * aReverseScaleX) - 0.5;
+ int x0 = MinMax( floor( sx0 ), 0, nOriginWidth - 1);
+ int x1 = MinMax( x0 + 1, 0, nOriginWidth - 1);
+
+ aColor00 = pReadAccess->GetPixel( y0, x0 );
+ aColor01 = pReadAccess->GetPixel( y1, x0 );
+ aColor10 = pReadAccess->GetPixel( y0, x1 );
+ aColor11 = pReadAccess->GetPixel( y1, x1 );
+
+ if( pReadAccess->HasPalette() )
+ {
+ aColor00 = pReadAccess->GetPaletteColor( aColor00 );
+ aColor01 = pReadAccess->GetPaletteColor( aColor01 );
+ aColor10 = pReadAccess->GetPaletteColor( aColor10 );
+ aColor11 = pReadAccess->GetPaletteColor( aColor11 );
+ }
+
+ double fx0 = sx0 - x0;
+ double fy0 = sy0 - y0;
+ double fx1 = 1.0 - fx0;
+ double fy1 = 1.0 - fy0;
+
+ double w00 = fx1 * fy1;
+ double w01 = fx1 * fy0;
+ double w10 = fx0 * fy1;
+ double w11 = fx0 * fy0;
+
+ double red = aColor00.GetRed() * w00 + aColor10.GetRed() * w10 + aColor01.GetRed() * w01 + aColor11.GetRed() * w11;
+ double green = aColor00.GetGreen() * w00 + aColor10.GetGreen() * w10 + aColor01.GetGreen() * w01 + aColor11.GetGreen() * w11;
+ double blue = aColor00.GetBlue() * w00 + aColor10.GetBlue() * w10 + aColor01.GetBlue() * w01 + aColor11.GetBlue() * w11;
+
+ aResultColor.SetRed( MinMax(red, 0, 255) );
+ aResultColor.SetGreen( MinMax(green, 0, 255) );
+ aResultColor.SetBlue( MinMax(blue, 0, 255) );
+
+ pWriteAccess->SetPixel( yOut, xOut, aResultColor );
+ }
+ }
+ }
+
+ ReleaseAccess( pReadAccess );
+ aOutBmp.ReleaseAccess( pWriteAccess );
+ ImplAssignWithSize( aOutBmp );
+
+ return true;
+}
+
+/*bool Bitmap::ImplScaleSuperFast( const double& rScaleX, const double& rScaleY, const Rectangle& rRectPixel )
+{
+ const Size aSizePix( GetSizePixel() );
+
+ const int nOriginWidth = aSizePix.Width();
+ const int nOriginHeight = aSizePix.Height();
+
+ const int nStartX = rRectPixel.Left();
+ const int nStartY = rRectPixel.Top();
+ const int nEndX = rRectPixel.Right();
+ const int nEndY = rRectPixel.Bottom();
+
+ const int nTargetWidth = rRectPixel.GetWidth();
+ const int nTargetHeight = rRectPixel.GetHeight();
+
+ BitmapColor aColor00, aColor01, aColor10, aColor11, aResultColor;
+
+ Bitmap aOutBmp( Size( nTargetWidth, nTargetHeight ), 24 );
+
+ BitmapReadAccess* pReadAccess = AcquireReadAccess();
+ BitmapWriteAccess* pWriteAccess = aOutBmp.AcquireWriteAccess();
+
+ if( !pReadAccess || !pWriteAccess )
+ return false;
+
+ double aReverseScaleX = 1.0 / rScaleX;
+ double aReverseScaleY = 1.0 / rScaleY;
+
+ int x, y, xOut, yOut;
+
+ for( y = nStartY, yOut = 0; y <= nEndY; y++, yOut++ )
+ {
+ double sy0 = ((y + 0.5) * aReverseScaleY) - 0.5;
+
+ int y0 = MinMax( floor( sy0 ), 0, nOriginHeight - 1);
+ int y1 = MinMax( y0 + 1, 0, nOriginHeight - 1);
+
+ for( x = nStartX, xOut = 0; x <= nEndX; x++, xOut++ )
+ {
+ double sx0 = ((x + 0.5) * aReverseScaleX) - 0.5;
+ int x0 = MinMax( floor( sx0 ), 0, nOriginWidth - 1);
+ int x1 = MinMax( x0 + 1, 0, nOriginWidth - 1);
+
+ aColor00 = pReadAccess->GetPixel( y0, x0 );
+ aColor01 = pReadAccess->GetPixel( y1, x0 );
+ aColor10 = pReadAccess->GetPixel( y0, x1 );
+ aColor11 = pReadAccess->GetPixel( y1, x1 );
+
+ if( pReadAccess->HasPalette() )
+ {
+ aColor00 = pReadAccess->GetPaletteColor( aColor00 );
+ aColor01 = pReadAccess->GetPaletteColor( aColor01 );
+ aColor10 = pReadAccess->GetPaletteColor( aColor10 );
+ aColor11 = pReadAccess->GetPaletteColor( aColor11 );
+ }
+
+ double fx0 = sx0 - x0;
+ double fy0 = sy0 - y0;
+ double fx1 = 1.0 - fx0;
+ double fy1 = 1.0 - fy0;
+
+ double w00 = fx1 * fy1;
+ double w01 = fx1 * fy0;
+ double w10 = fx0 * fy1;
+ double w11 = fx0 * fy0;
+
+ double red = aColor00.GetRed() * w00 + aColor10.GetRed() * w10 + aColor01.GetRed() * w01 + aColor11.GetRed() * w11;
+ double green = aColor00.GetGreen() * w00 + aColor10.GetGreen() * w10 + aColor01.GetGreen() * w01 + aColor11.GetGreen() * w11;
+ double blue = aColor00.GetBlue() * w00 + aColor10.GetBlue() * w10 + aColor01.GetBlue() * w01 + aColor11.GetBlue() * w11;
+
+ aResultColor.SetRed( MinMax(red, 0, 255) );
+ aResultColor.SetGreen( MinMax(green, 0, 255) );
+ aResultColor.SetBlue( MinMax(blue, 0, 255) );
+
+ pWriteAccess->SetPixel( yOut, xOut, aResultColor );
+ }
+ }
+
+ ReleaseAccess( pReadAccess );
+ aOutBmp.ReleaseAccess( pWriteAccess );
+ ImplAssignWithSize( aOutBmp );
+
+ return true;
+}
+bool Bitmap::ImplScaleSuper( const double& rScaleX, const double& rScaleY, const Rectangle& rRectPixel, const long nAngle10, const Color& rFillColor )
+{
+ Rectangle aRect( rRectPixel );
+
+ const int nStartX = aRect.Left();
+ const int nStartY = aRect.Top();
+ const int nEndX = aRect.Right();
+ const int nEndY = aRect.Bottom();
+
+ const int nTargetWidth = aRect.GetWidth();
+ const int nTargetHeight = aRect.GetHeight();
+
+ const int nOriginWidth = GetSizePixel().Width();
+ const int nOriginHeight = GetSizePixel().Height();
+
+ const double aReverseScaleX = 1.0 / rScaleX;
+ const double aReverseScaleY = 1.0 / rScaleY;
+
+ if( nTargetWidth <= 1L || nTargetHeight <= 1L )
+ return false;
+
+ BitmapColor aColor, aResultColor;
+
+ Bitmap aOutBmp( Size( nTargetWidth, nTargetHeight ), 24 );
+
+ BitmapReadAccess* pReadAccess = AcquireReadAccess();
+ BitmapWriteAccess* pWriteAccess = aOutBmp.AcquireWriteAccess();
+
+ if( !pReadAccess || !pWriteAccess )
+ return false;
+
+ int x, y, xOut, yOut;
+ int aCount;
+ double aSumRed, aSumGreen, aSumBlue;
+
+ for( y = nStartY, yOut = 0; y <= nEndY; y++, yOut++ )
+ {
+ int yStart = MinMax( floor( y * aReverseScaleY ), 0, nOriginHeight - 1);
+ int yEnd = MinMax( floor( (y+1) * aReverseScaleY ), 0, nOriginHeight - 1);
+
+ for( x = nStartX, xOut = 0; x <= nEndX; x++, xOut++ )
+ {
+ int xStart = MinMax( floor( x * aReverseScaleX ), 0, nOriginWidth - 1);
+ int xEnd = MinMax( floor( (x+1) * aReverseScaleX ), 0, nOriginWidth - 1);
+
+ aSumRed = aSumGreen = aSumBlue = 0.0;
+ aCount = 0;
+
+ for (int yIn = yStart; yIn < yEnd; yIn++)
+ {
+ for (int xIn = xStart; xIn < xEnd; xIn++)
+ {
+ aColor = pReadAccess->GetPixel( yIn, xIn );
+
+ if( pReadAccess->HasPalette() )
+ aColor = pReadAccess->GetPaletteColor( aColor );
+
+ aSumRed += aColor.GetRed();
+ aSumGreen += aColor.GetGreen();
+ aSumBlue += aColor.GetBlue();
+
+ aCount++;
+ }
+ }
+
+ aResultColor.SetRed( MinMax(aSumRed / aCount, 0, 255) );
+ aResultColor.SetGreen( MinMax(aSumGreen / aCount, 0, 255) );
+ aResultColor.SetBlue( MinMax(aSumBlue / aCount, 0, 255) );
+
+ pWriteAccess->SetPixel( yOut, xOut, aResultColor );
+ }
+ }
+
+ ReleaseAccess( pReadAccess );
+ aOutBmp.ReleaseAccess( pWriteAccess );
+ ImplAssignWithSize( aOutBmp );
+
+ return true;
+}
+*/
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx
index d1d42629f7b1..e9a3ab4b390a 100644
--- a/vcl/source/gdi/bitmapex.cxx
+++ b/vcl/source/gdi/bitmapex.cxx
@@ -443,7 +443,47 @@ sal_Bool BitmapEx::Scale( const Size& rNewSize, sal_uLong nScaleFlag )
return bRet;
}
-// ------------------------------------------------------------------
+sal_Bool BitmapEx::ScaleCropRotate(
+ const double& rScaleX, const double& rScaleY, const Rectangle& rRectPixel, long nAngle10,
+ const Color& rFillColor, sal_uLong nScaleFlag )
+{
+ sal_Bool bRet = sal_False;
+
+ if( !!aBitmap )
+ {
+ const sal_Bool bTransRotate = ( Color( COL_TRANSPARENT ) == rFillColor );
+
+ if( bTransRotate )
+ {
+ if( eTransparent == TRANSPARENT_COLOR )
+ {
+ bRet = aBitmap.ScaleCropRotate( rScaleX, rScaleY, rRectPixel, nAngle10, aTransparentColor, nScaleFlag );
+ }
+ else
+ {
+ bRet = aBitmap.ScaleCropRotate( rScaleX, rScaleY, rRectPixel, nAngle10, COL_BLACK, nScaleFlag );
+ if( eTransparent == TRANSPARENT_NONE )
+ {
+ aMask = Bitmap( aBitmapSize, 1 );
+ aMask.Erase( COL_BLACK );
+ eTransparent = TRANSPARENT_BITMAP;
+ }
+
+ if( bRet && !!aMask )
+ aMask.ScaleCropRotate( rScaleX, rScaleY, rRectPixel, nAngle10, COL_WHITE, nScaleFlag );
+ }
+ }
+ else
+ {
+ bRet = aBitmap.ScaleCropRotate( rScaleX, rScaleY, rRectPixel, nAngle10, rFillColor, nScaleFlag );
+
+ if( bRet && ( eTransparent == TRANSPARENT_BITMAP ) && !!aMask )
+ aMask.ScaleCropRotate( rScaleX, rScaleY, rRectPixel, nAngle10, COL_WHITE, nScaleFlag );
+ }
+ }
+
+ return bRet;
+}
sal_Bool BitmapEx::Rotate( long nAngle10, const Color& rFillColor )
{