You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by al...@apache.org on 2013/08/29 14:40:19 UTC

svn commit: r1518625 - in /openoffice/branches/AOO401/main/vcl: inc/vcl/bitmapex.hxx inc/vcl/bmpacc.hxx source/gdi/bitmapex.cxx source/gdi/bmpacc.cxx source/gdi/outdev2.cxx

Author: alg
Date: Thu Aug 29 12:40:18 2013
New Revision: 1518625

URL: http://svn.apache.org/r1518625
Log:
i122778 Enhanced own transformer for drawing transformed bitmaps

Modified:
    openoffice/branches/AOO401/main/vcl/inc/vcl/bitmapex.hxx
    openoffice/branches/AOO401/main/vcl/inc/vcl/bmpacc.hxx
    openoffice/branches/AOO401/main/vcl/source/gdi/bitmapex.cxx
    openoffice/branches/AOO401/main/vcl/source/gdi/bmpacc.cxx
    openoffice/branches/AOO401/main/vcl/source/gdi/outdev2.cxx

Modified: openoffice/branches/AOO401/main/vcl/inc/vcl/bitmapex.hxx
URL: http://svn.apache.org/viewvc/openoffice/branches/AOO401/main/vcl/inc/vcl/bitmapex.hxx?rev=1518625&r1=1518624&r2=1518625&view=diff
==============================================================================
--- openoffice/branches/AOO401/main/vcl/inc/vcl/bitmapex.hxx (original)
+++ openoffice/branches/AOO401/main/vcl/inc/vcl/bitmapex.hxx Thu Aug 29 12:40:18 2013
@@ -393,25 +393,42 @@ public:
         @param rTransformation
         The back transformation for each pixel in (0 .. fWidth),(0 .. fHeight) to
         local pixel coordiantes
+
+        @param bSmooth
+        Defines if pixel interpolation is to be used to create the result 
     */
     BitmapEx TransformBitmapEx(
         double fWidth,
         double fHeight,
-        const basegfx::B2DHomMatrix& rTransformation) const;
+        const basegfx::B2DHomMatrix& rTransformation,
+        bool bSmooth = true) const;
 
     /** Create transformed Bitmap
 
         @param rTransformation
-        The transformation from unit coordinates to target
+        The transformation from unit coordinates to the unit range
+
+        @param rVisibleRange
+        The relative visible range in unit coordinates, relative to (0,0,1,1) which
+        defines the whole target area
 
         @param fMaximumArea
         A limitation for the maximum size of pixels to use for the result
 
+        @param bSmooth
+        Defines if pixel interpolation is to be used to create the result 
+
+        The traget size of the result bitmap is defined by transforming the given
+        rTargetRange with the given rTransformation; the area of the result is
+        linearly scaled to not exceed the given fMaximumArea
+
         @return The transformed bitmap
     */
     BitmapEx getTransformed(
         const basegfx::B2DHomMatrix& rTransformation, 
-        double fMaximumArea = 500000.0) const;
+        const basegfx::B2DRange& rVisibleRange,
+        double fMaximumArea = 500000.0,
+        bool bSmooth = true) const;
 
     /** Create ColorStack-modified version of this BitmapEx
 

Modified: openoffice/branches/AOO401/main/vcl/inc/vcl/bmpacc.hxx
URL: http://svn.apache.org/viewvc/openoffice/branches/AOO401/main/vcl/inc/vcl/bmpacc.hxx?rev=1518625&r1=1518624&r2=1518625&view=diff
==============================================================================
--- openoffice/branches/AOO401/main/vcl/inc/vcl/bmpacc.hxx (original)
+++ openoffice/branches/AOO401/main/vcl/inc/vcl/bmpacc.hxx Thu Aug 29 12:40:18 2013
@@ -171,6 +171,16 @@ public:
     inline BitmapColor          GetColor( long nY, long nX ) const;
     inline sal_uInt8            GetPixelIndex( long nY, long nX ) const;
     inline sal_uInt8            GetLuminance( long nY, long nX ) const;
+
+    /** Get the interpolated color at coordinates fY, fX; if outside, return rFallback */
+    BitmapColor GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const;
+
+    /** Get the color at coordinates fY, fX; if outside, return rFallback. Automatically does the correct
+        inside/outside checks, e.g. static_cast< sal_uInt32 >(-0.25) *is* 0, not -1 and has to be outside */
+    BitmapColor GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const;
+
+    /** Get the color at coordinates nY, nX; if outside, return rFallback */
+    BitmapColor GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const;
 };
 
 // ---------------------

Modified: openoffice/branches/AOO401/main/vcl/source/gdi/bitmapex.cxx
URL: http://svn.apache.org/viewvc/openoffice/branches/AOO401/main/vcl/source/gdi/bitmapex.cxx?rev=1518625&r1=1518624&r2=1518625&view=diff
==============================================================================
--- openoffice/branches/AOO401/main/vcl/source/gdi/bitmapex.cxx (original)
+++ openoffice/branches/AOO401/main/vcl/source/gdi/bitmapex.cxx Thu Aug 29 12:40:18 2013
@@ -837,180 +837,87 @@ sal_uInt8 BitmapEx::GetTransparency(sal_
 
 namespace
 {
-	void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
-	{
-		double fDeltaX(rSource.getX() - nIntX);
-		double fDeltaY(rSource.getY() - nIntY);
-		sal_Int32 nIndX(0L);
-		sal_Int32 nIndY(0L);
-
-		if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
-		{
-			nIndX++;
-		}
-		else if(fDeltaX < 0.0 && nIntX >= 1L)
-		{
-			fDeltaX = -fDeltaX;
-			nIndX--;
-		}
-			
-		if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
-		{
-			nIndY++;
-		}
-		else if(fDeltaY < 0.0 && nIntY >= 1L)
-		{
-			fDeltaY = -fDeltaY;
-			nIndY--;
-		}
-
-		if(nIndX || nIndY)
-		{
-			const double fColorToReal(1.0 / 255.0);
-			double fR(rValue.GetRed() * fColorToReal);
-			double fG(rValue.GetGreen() * fColorToReal);
-			double fB(rValue.GetBlue() * fColorToReal);
-			double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
-
-			if(nIndX)
-			{
-				const double fMulA(fDeltaX * fColorToReal);
-				double fMulB(1.0 - fDeltaX);
-				const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX));
-
-				fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA);
-				fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA);
-				fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA);
-
-				if(nIndY)
-				{
-					fMulB *= fColorToReal;
-					const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
-					const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX));
-
-					fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA);
-					fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA);
-					fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA);
-				}
-			}
-
-			if(nIndY)
-			{
-				if(!nIndX)
-				{
-					const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
-						
-					fRBottom = aBottom.GetRed() * fColorToReal;
-					fGBottom = aBottom.GetGreen() * fColorToReal;
-					fBBottom = aBottom.GetBlue() * fColorToReal;
-				}
-
-				const double fMulB(1.0 - fDeltaY);
-					
-				fR = (fR * fMulB) + (fRBottom * fDeltaY);
-				fG = (fG * fMulB) + (fGBottom * fDeltaY);
-				fB = (fB * fMulB) + (fBBottom * fDeltaY);
-			}
-
-			rValue.SetRed((sal_uInt8)(fR * 255.0));
-			rValue.SetGreen((sal_uInt8)(fG * 255.0));
-			rValue.SetBlue((sal_uInt8)(fB * 255.0));
-		}
-	}
-
-	Bitmap impTransformBitmap(
+    Bitmap impTransformBitmap(
         const Bitmap& rSource, 
         const Size aDestinationSize, 
         const basegfx::B2DHomMatrix& rTransform, 
         bool bSmooth)
-	{
+    {
         Bitmap aDestination(aDestinationSize, 24);
         BitmapWriteAccess* pWrite = aDestination.AcquireWriteAccess();
 
-		if(pWrite)
-		{
-			const Size aContentSizePixel(rSource.GetSizePixel());
-			BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
-
-			if(pRead)
-			{
-				const Size aDestinationSizePixel(aDestination.GetSizePixel());
-				bool bWorkWithIndex(rSource.GetBitCount() <= 8);
-				BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
-
-				for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
-				{
-					for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
-					{
-						const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
-						const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX()));
+        if(pWrite)
+        {
+            //const Size aContentSizePixel(rSource.GetSizePixel());
+            BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
 
-						if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth())
-						{
-							const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY()));
+            if(pRead)
+            {
+                const Size aDestinationSizePixel(aDestination.GetSizePixel());
+                const BitmapColor aOutside(BitmapColor(0xff, 0xff, 0xff));
 
-							if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight())
-							{
-                                // inside pixel
-                                BitmapColor aValue;
-
-                                if(bWorkWithIndex)
-                                {
-                                    aValue = pRead->GetPaletteColor(pRead->GetPixelIndex(nIntY, nIntX));
-                                }
-                                else
-                                {
-                                    aValue = pRead->GetPixel(nIntY, nIntX);
-                                }
-
-                                if(bSmooth)
-                                {
-                                    impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead);
-                                }
-
-                                pWrite->SetPixel(y, x, aValue);
-                                continue;
-							}
-						}
+                for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
+                {
+                    for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
+                    {
+                        const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
 
-						// here are outside pixels. Complete mask
-						if(bWorkWithIndex)
-						{
-							pWrite->SetPixel(y, x, aOutside);
-						}
-					}
-				}
+                        if(bSmooth)
+                        {
+                            pWrite->SetPixel(
+                                y, 
+                                x, 
+                                pRead->GetInterpolatedColorWithFallback(
+                                    aSourceCoor.getY(), 
+                                    aSourceCoor.getX(), 
+                                    aOutside));
+                        }
+                        else
+                        {
+                            // this version does the correct <= 0.0 checks, so no need
+                            // to do the static_cast< sal_Int32 > self and make an error
+                            pWrite->SetPixel(
+                                y, 
+                                x, 
+                                pRead->GetColorWithFallback(
+                                    aSourceCoor.getY(), 
+                                    aSourceCoor.getX(), 
+                                    aOutside));
+                        }
+                    }
+                }
 
-				delete pRead;
-			}
+                delete pRead;
+            }
 
-			delete pWrite;
-		}
+            delete pWrite;
+        }
 
         rSource.AdaptBitCount(aDestination);
 
         return aDestination;
-	}
+    }
 } // end of anonymous namespace
+
 BitmapEx BitmapEx::TransformBitmapEx(
     double fWidth,
     double fHeight,
-    const basegfx::B2DHomMatrix& rTransformation) const
+    const basegfx::B2DHomMatrix& rTransformation,
+    bool bSmooth) const
 {
     if(fWidth <= 1 || fHeight <= 1)
         return BitmapEx();
 
     // force destination to 24 bit, we want to smooth output
     const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight));
-    static bool bDoSmoothAtAll(true);
-    const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll));
+    const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth));
 
     // create mask
     if(IsTransparent())
     {
         if(IsAlpha())
         {
-            const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bDoSmoothAtAll));
+            const Bitmap aAlpha(impTransformBitmap(GetAlpha().GetBitmap(), aDestinationSize, rTransformation, bSmooth));
             return BitmapEx(aDestination, AlphaMask(aAlpha));
         }
         else
@@ -1027,7 +934,9 @@ BitmapEx BitmapEx::TransformBitmapEx(
 
 BitmapEx BitmapEx::getTransformed(
     const basegfx::B2DHomMatrix& rTransformation, 
-    double fMaximumArea) const
+    const basegfx::B2DRange& rVisibleRange,
+    double fMaximumArea,
+    bool bSmooth) const
 {
     BitmapEx aRetval;
 
@@ -1040,20 +949,31 @@ BitmapEx BitmapEx::getTransformed(
     if(!nSourceWidth || !nSourceHeight)
         return aRetval;
 
-    // Get dest range
+    // Get aOutlineRange
     basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
+
     aOutlineRange.transform(rTransformation);
 
-    // get target size
-    double fWidth(aOutlineRange.getWidth());
-    double fHeight(aOutlineRange.getHeight());
+    // create visible range from it by moving from relative to absolute
+    basegfx::B2DRange aVisibleRange(rVisibleRange);
+
+    aVisibleRange.transform(
+        basegfx::tools::createScaleTranslateB2DHomMatrix(
+            aOutlineRange.getRange(),
+            aOutlineRange.getMinimum()));
+
+    // get target size (which is visible range's size)
+    double fWidth(aVisibleRange.getWidth());
+    double fHeight(aVisibleRange.getHeight());
 
     if(fWidth < 1.0 || fHeight < 1.0)
+    {
         return aRetval;
+    }
 
     // test if discrete size (pixel) maybe too big and limit it
     const double fArea(fWidth * fHeight);
-    const bool bNeedToReduce(fArea > fMaximumArea);
+    const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea));
     double fReduceFactor(1.0);
 
     if(bNeedToReduce)
@@ -1074,8 +994,10 @@ BitmapEx BitmapEx::getTransformed(
     // aOutlineRange
     aTransform = rTransformation * aTransform;
     
-    // substract top-left of aOutlineRange
-    aTransform.translate(-aOutlineRange.getMinX(), -aOutlineRange.getMinY());
+    // substract top-left of absolute VisibleRange
+    aTransform.translate(
+        -aVisibleRange.getMinX(), 
+        -aVisibleRange.getMinY());
 
     // scale to target pixels (if needed)
     if(bNeedToReduce)
@@ -1087,7 +1009,7 @@ BitmapEx BitmapEx::getTransformed(
     aTransform.invert();
 
     // create bitmap using source, destination and linear back-transformation
-    aRetval = TransformBitmapEx(fWidth, fHeight, aTransform);
+    aRetval = TransformBitmapEx(fWidth, fHeight, aTransform, bSmooth);
 
     return aRetval;
 }

Modified: openoffice/branches/AOO401/main/vcl/source/gdi/bmpacc.cxx
URL: http://svn.apache.org/viewvc/openoffice/branches/AOO401/main/vcl/source/gdi/bmpacc.cxx?rev=1518625&r1=1518624&r2=1518625&view=diff
==============================================================================
--- openoffice/branches/AOO401/main/vcl/source/gdi/bmpacc.cxx (original)
+++ openoffice/branches/AOO401/main/vcl/source/gdi/bmpacc.cxx Thu Aug 29 12:40:18 2013
@@ -324,6 +324,126 @@ sal_uInt16 BitmapReadAccess::GetBestPale
 	return( HasPalette() ? mpBuffer->maPalette.GetBestIndex( rBitmapColor ) : 0 );
 }
 
+BitmapColor BitmapReadAccess::GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
+{
+    // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
+    // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
+    if(mpBuffer && fX >= 0.0 && fY >= 0.0)
+    {
+        const sal_Int32 nX(static_cast< sal_Int32 >(fX));
+        const sal_Int32 nY(static_cast< sal_Int32 >(fY));
+
+        if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+        {
+            // get base-return value from inside pixel
+            BitmapColor aRetval(GetColor(nY, nX));
+
+            // calculate deltas and indices for neighbour accesses
+            sal_Int16 nDeltaX((fX - (nX + 0.5)) * 255.0); // [-255 .. 255]
+            sal_Int16 nDeltaY((fY - (nY + 0.5)) * 255.0); // [-255 .. 255]
+            sal_Int16 nIndX(0);
+            sal_Int16 nIndY(0);
+
+            if(nDeltaX > 0)
+            {
+                nIndX = nX + 1;
+            }
+            else
+            {
+                nIndX = nX - 1;
+                nDeltaX = -nDeltaX;
+            }
+
+            if(nDeltaY > 0)
+            {
+                nIndY = nY + 1;
+            }
+            else
+            {
+                nIndY = nY - 1;
+                nDeltaY = -nDeltaY;
+            }
+
+            // get right/left neighbour
+            BitmapColor aXCol(rFallback);
+
+            if(nDeltaX && nIndX >= 0 && nIndX < mpBuffer->mnWidth)
+            {
+                aXCol = GetColor(nY, nIndX);
+            }
+
+            // get top/bottom neighbour
+            BitmapColor aYCol(rFallback);
+
+            if(nDeltaY && nIndY >= 0 && nIndY < mpBuffer->mnHeight)
+            {
+                aYCol = GetColor(nIndY, nX);
+            }
+
+            // get one of four edge neighbours
+            BitmapColor aXYCol(rFallback);
+
+            if(nDeltaX && nDeltaY && nIndX >=0 && nIndY >= 0 && nIndX < mpBuffer->mnWidth && nIndY < mpBuffer->mnHeight)
+            {
+                aXYCol = GetColor(nIndY, nIndX);
+            }
+
+            // merge return value with right/left neighbour
+            if(aXCol != aRetval)
+            {
+                aRetval.Merge(aXCol, 255 - nDeltaX);
+            }
+
+            // merge top/bottom neighbour with edge
+            if(aYCol != aXYCol)
+            {
+                aYCol.Merge(aXYCol, 255 - nDeltaX);
+            }
+
+            // merge return value with already merged top/bottom neighbour
+            if(aRetval != aYCol)
+            {
+                aRetval.Merge(aYCol, 255 - nDeltaY);
+            }
+
+            return aRetval;
+        }
+    }
+
+    return rFallback;
+}
+
+BitmapColor BitmapReadAccess::GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const
+{
+    // ask directly doubles >= 0.0 here to avoid rounded values of 0 at small negative
+    // double values, e.g. static_cast< sal_Int32 >(-0.25) is 0, not -1, but *has* to be outside (!)
+    if(mpBuffer && fX >= 0.0 && fY >= 0.0)
+    {
+        const sal_Int32 nX(static_cast< sal_Int32 >(fX));
+        const sal_Int32 nY(static_cast< sal_Int32 >(fY));
+
+        if(nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+        {
+            return GetColor(nY, nX);
+        }
+    }
+
+    return rFallback;
+}
+
+BitmapColor BitmapReadAccess::GetColorWithFallback( long nY, long nX, const BitmapColor& rFallback ) const
+{
+    if(mpBuffer)
+    {
+        if(nX >= 0 && nY >= 0 && nX < mpBuffer->mnWidth && nY < mpBuffer->mnHeight)
+        {
+            return GetColor(nY, nX);
+        }
+    }
+
+    return rFallback;
+}
+
 // ---------------------
 // - BitmapWriteAccess -
 // ---------------------

Modified: openoffice/branches/AOO401/main/vcl/source/gdi/outdev2.cxx
URL: http://svn.apache.org/viewvc/openoffice/branches/AOO401/main/vcl/source/gdi/outdev2.cxx?rev=1518625&r1=1518624&r2=1518625&view=diff
==============================================================================
--- openoffice/branches/AOO401/main/vcl/source/gdi/outdev2.cxx (original)
+++ openoffice/branches/AOO401/main/vcl/source/gdi/outdev2.cxx Thu Aug 29 12:40:18 2013
@@ -43,6 +43,7 @@
 #include <window.h>
 #include <outdata.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 #define BAND_MAX_SIZE 512000
 
@@ -818,8 +819,9 @@ void OutputDevice::DrawTransformedBitmap
     const bool bSheared(!basegfx::fTools::equalZero(fShearX));
     const bool bMirroredX(basegfx::fTools::less(aScale.getX(), 0.0));
     const bool bMirroredY(basegfx::fTools::less(aScale.getY(), 0.0));
+    static bool bForceToOwnTransformer(false);
 
-    if(!bRotated && !bSheared && !bMirroredX && !bMirroredY)
+    if(!bForceToOwnTransformer && !bRotated && !bSheared && !bMirroredX && !bMirroredY)
     {
         // with no rotation, shear or mirroring it can be mapped to DrawBitmapEx
         // do *not* execute the mirroring here, it's done in the fallback
@@ -840,7 +842,7 @@ void OutputDevice::DrawTransformedBitmap
     const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
     const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile && !bPrinter);
 
-    if(bTryDirectPaint)
+    if(!bForceToOwnTransformer && bTryDirectPaint)
     {
         // try to paint directly
         const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
@@ -873,7 +875,7 @@ void OutputDevice::DrawTransformedBitmap
     if(!bDone)
     {
         // take the fallback when no rotate and shear, but mirror (else we would have done this above)
-        if(!bRotated && !bSheared)
+        if(!bForceToOwnTransformer && !bRotated && !bSheared)
         {
             // with no rotation or shear it can be mapped to DrawBitmapEx
             // do *not* execute the mirroring here, it's done in the fallback
@@ -886,14 +888,115 @@ void OutputDevice::DrawTransformedBitmap
 
         // fallback; create transformed bitmap the hard way (back-transform
         // the pixels) and paint
-        basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
-        const double fMaximumArea(bMetafile ? 800000.0 : 200000.0);
-        const BitmapEx aTransformed(rBitmapEx.getTransformed(aFullTransform, fMaximumArea));
-        aTargetRange.transform(rTransformation);
-        const Point aDestPt(basegfx::fround(aTargetRange.getMinX()), basegfx::fround(aTargetRange.getMinY()));
-        const Size aDestSize(basegfx::fround(aTargetRange.getWidth()), basegfx::fround(aTargetRange.getHeight()));
+        basegfx::B2DRange aVisibleRange(0.0, 0.0, 1.0, 1.0);
 
-        DrawBitmapEx(aDestPt, aDestSize, aTransformed);
+        // limit maximum area to something looking good for non-pixel-based targets (metafile, printer)
+        double fMaximumArea(1000000.0);
+
+        if(!bMetafile && !bPrinter)
+        {
+            // limit TargetRange to existing pixels (if pixel device)
+            // first get discrete range of object
+            basegfx::B2DRange aFullPixelRange(aVisibleRange);
+
+            aFullPixelRange.transform(aFullTransform);
+
+            if(basegfx::fTools::equalZero(aFullPixelRange.getWidth()) || basegfx::fTools::equalZero(aFullPixelRange.getHeight()))
+            {
+                // object is outside of visible area
+                return;
+            }
+
+            // now get discrete target pixels; start with OutDev pixel size and evtl.
+            // intersect with active clipping area
+            basegfx::B2DRange aOutPixel(
+                0.0, 
+                0.0, 
+                GetOutputSizePixel().Width(), 
+                GetOutputSizePixel().Height());
+
+            if(IsClipRegion())
+            {
+                const Rectangle aRegionRectangle(GetActiveClipRegion().GetBoundRect());
+
+                aOutPixel.intersect( // caution! Range from rectangle, one too much (!)
+                    basegfx::B2DRange(
+                        aRegionRectangle.Left(),
+                        aRegionRectangle.Top(),
+                        aRegionRectangle.Right() + 1,
+                        aRegionRectangle.Bottom() + 1));
+            }
+
+            if(aOutPixel.isEmpty())
+            {
+                // no active output area
+                return;
+            }
+
+            // if aFullPixelRange is not completely inside of aOutPixel,
+            // reduction of target pixels is possible
+            basegfx::B2DRange aVisiblePixelRange(aFullPixelRange);
+
+            if(!aOutPixel.isInside(aFullPixelRange)) 
+            {
+                aVisiblePixelRange.intersect(aOutPixel);
+
+                if(aVisiblePixelRange.isEmpty())
+                {
+                    // nothing in visible part, reduces to nothing
+                    return;
+                }
+
+                // aVisiblePixelRange contains the reduced output area in
+                // discrete coordinates. To make it useful everywhere, make it relative to
+                // the object range
+                basegfx::B2DHomMatrix aMakeVisibleRangeRelative;
+
+                aVisibleRange = aVisiblePixelRange;
+                aMakeVisibleRangeRelative.translate(
+                    -aFullPixelRange.getMinX(), 
+                    -aFullPixelRange.getMinY());
+                aMakeVisibleRangeRelative.scale(
+                    1.0 / aFullPixelRange.getWidth(),
+                    1.0 / aFullPixelRange.getHeight());
+                aVisibleRange.transform(aMakeVisibleRangeRelative);
+            }
+
+            // for pixel devices, do *not* limit size, else OutputDevice::ImplDrawAlpha
+            // will create another, badly scaled bitmap to do the job. Nonetheless, do a
+            // maximum clipping of something big (1600x1280x2). Add 1.0 to avoid rounding
+            // errors in rough estimations
+            const double fNewMaxArea(aVisiblePixelRange.getWidth() * aVisiblePixelRange.getHeight());
+
+            fMaximumArea = std::min(4096000.0, fNewMaxArea + 1.0);
+        }
+
+        if(!aVisibleRange.isEmpty())
+        {
+            static bool bDoSmoothAtAll(true);
+            const BitmapEx aTransformed(
+                rBitmapEx.getTransformed(
+                    aFullTransform, 
+                    aVisibleRange, 
+                    fMaximumArea, 
+                    bDoSmoothAtAll));
+            basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
+
+            // get logic object target range
+            aTargetRange.transform(rTransformation);
+
+            // get from unified/relative VisibleRange to logoc one
+            aVisibleRange.transform(
+                basegfx::tools::createScaleTranslateB2DHomMatrix(
+                    aTargetRange.getRange(),
+                    aTargetRange.getMinimum()));
+
+            // extract point and size; do not remove size, the bitmap may have been prepared reduced by purpose
+            const Point aDestPt(basegfx::fround(aVisibleRange.getMinX()), basegfx::fround(aVisibleRange.getMinY()));
+            const Size aDestSize(basegfx::fround(aVisibleRange.getWidth()), basegfx::fround(aVisibleRange.getHeight()));
+
+            DrawBitmapEx(aDestPt, aDestSize, aTransformed);
+        }
     }
 }