drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx | 3 drawinglayer/source/primitive2d/glowprimitive2d.cxx | 3 drawinglayer/source/primitive2d/patternfillprimitive2d.cxx | 6 drawinglayer/source/primitive2d/shadowprimitive2d.cxx | 3 drawinglayer/source/primitive2d/softedgeprimitive2d.cxx | 3 drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx | 5 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 8 drawinglayer/source/tools/converters.cxx | 24 - include/drawinglayer/converters.hxx | 8 include/vcl/BitmapTools.hxx | 4 svgio/inc/svgfilternode.hxx | 3 svgio/qa/cppunit/SvgImportTest.cxx | 161 ++++++++++- svgio/qa/cppunit/data/arithmetic.svg | 8 svgio/qa/cppunit/data/arithmetic2.svg | 8 svgio/qa/cppunit/data/tdf160726.svg | 43 ++ svgio/source/svgreader/svgfeblendnode.cxx | 72 +++- svgio/source/svgreader/svgfecompositenode.cxx | 67 +++- svgio/source/svgreader/svgfilternode.cxx | 21 - vcl/source/bitmap/BitmapTools.cxx | 114 ------- 19 files changed, 345 insertions(+), 219 deletions(-)
New commits: commit 4b6e0f2c88debaedb514c868e061c21e15215b6e Author: Xisco Fauli <xiscofa...@libreoffice.org> AuthorDate: Sun Apr 21 20:41:55 2024 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Mon Apr 22 11:53:41 2024 +0200 tdf#160726, tdf#48062: Simplify how BitmapExs are created In my initial approach, I tranformed the primitive2DContainers before converting them to BitmapEx. This caused circles like https://bugs.documentfoundation.org/attachment.cgi?id=193790 not to be displayed. Simplify how BitmapExs are created by just using the range both primitive2DContainers have in common. This way, DrawBitmapInRect can be dropped now Change-Id: I2401dc87b98e04b9cf9f5ebade2b5622d884fc3a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166391 Tested-by: Xisco Fauli <xiscofa...@libreoffice.org> Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx b/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx index 22a20f095d24..e50e59a1d76d 100644 --- a/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx +++ b/drawinglayer/source/drawinglayeruno/xprimitive2drenderer.cxx @@ -147,8 +147,7 @@ namespace drawinglayer::unorenderer convertToBitmapEx( std::move(xEmbedSeq), aViewInformation2D, - nDiscreteWidth, - nDiscreteHeight, + basegfx::B2DRange(0, 0, nDiscreteWidth, nDiscreteHeight), MaximumQuadraticPixels)); if(!aBitmapEx.IsEmpty()) diff --git a/drawinglayer/source/primitive2d/glowprimitive2d.cxx b/drawinglayer/source/primitive2d/glowprimitive2d.cxx index 6bf9dea8af83..5cec7a46f532 100644 --- a/drawinglayer/source/primitive2d/glowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/glowprimitive2d.cxx @@ -176,7 +176,8 @@ void GlowPrimitive2D::create2DDecomposition( // I have now added a helper that just creates the mask without having // to render the content, use it, it's faster const AlphaMask aAlpha(::drawinglayer::createAlphaMask( - std::move(xEmbedSeq), aViewInformation2D, nDiscreteClippedWidth, nDiscreteClippedHeight, + std::move(xEmbedSeq), aViewInformation2D, + basegfx::B2DRange(0, 0, nDiscreteClippedWidth, nDiscreteClippedHeight), nMaximumQuadraticPixels)); if (aAlpha.IsEmpty()) diff --git a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx index 516b0042d960..8068a386970c 100644 --- a/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/patternfillprimitive2d.cxx @@ -136,8 +136,7 @@ namespace drawinglayer::primitive2d convertToBitmapEx( std::move(xEmbedSeq), aViewInformation2D, - mnDiscreteWidth, - mnDiscreteHeight, + basegfx::B2DRange(0, 0, mnDiscreteWidth, mnDiscreteHeight), mnDiscreteWidth * mnDiscreteHeight)); if(!aBitmapEx.IsEmpty()) @@ -197,8 +196,7 @@ namespace drawinglayer::primitive2d return convertToBitmapEx( std::move(xEmbedSeq), aViewInformation2D, - nWidth, - nHeight, + basegfx::B2DRange(0, 0, nWidth, nHeight), nWidth * nHeight); } diff --git a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx index 5de34c5440b6..c32f37bd9e8e 100644 --- a/drawinglayer/source/primitive2d/shadowprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/shadowprimitive2d.cxx @@ -217,7 +217,8 @@ void ShadowPrimitive2D::create2DDecomposition( // I have now added a helper that just creates the mask without having // to render the content, use it, it's faster const AlphaMask aAlpha(::drawinglayer::createAlphaMask( - std::move(xEmbedSeq), aViewInformation2D, nDiscreteClippedWidth, nDiscreteClippedHeight, + std::move(xEmbedSeq), aViewInformation2D, + basegfx::B2DRange(0, 0, nDiscreteClippedWidth, nDiscreteClippedHeight), nMaximumQuadraticPixels)); // if we have no shadow, we are done diff --git a/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx b/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx index e6f92f312f59..fb0124284643 100644 --- a/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/softedgeprimitive2d.cxx @@ -174,7 +174,8 @@ void SoftEdgePrimitive2D::create2DDecomposition( // Otherwise, blurring of edges will fail in cases like running in a // slideshow or exporting to PDF. const BitmapEx aBitmapEx(::drawinglayer::convertToBitmapEx( - std::move(xEmbedSeq), aViewInformation2D, nDiscreteClippedWidth, nDiscreteClippedHeight, + std::move(xEmbedSeq), aViewInformation2D, + basegfx::B2DRange(0, 0, nDiscreteClippedWidth, nDiscreteClippedHeight), nMaximumQuadraticPixels, true)); if (aBitmapEx.IsEmpty()) diff --git a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx index 6bfc95878332..5347378cc43f 100644 --- a/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx +++ b/drawinglayer/source/processor2d/d2dpixelprocessor2d.cxx @@ -1060,8 +1060,9 @@ sal::systools::COMReference<ID2D1Bitmap> D2DPixelProcessor2D::implCreateAlpha_B2 // use new mode to create AlphaChannel (not just AlphaMask) for transparency channel const AlphaMask aAlpha(::drawinglayer::createAlphaMask( - std::move(xEmbedSeq), aEmptyViewInformation2D, nDiscreteClippedWidth, - nDiscreteClippedHeight, nMaximumQuadraticPixels, true)); + std::move(xEmbedSeq), aEmptyViewInformation2D, + basegfx::B2DRange(0, 0, nDiscreteClippedWidth, nDiscreteClippedHeight), + nMaximumQuadraticPixels, true)); sal::systools::COMReference<ID2D1Bitmap> pRetval; if (aAlpha.IsEmpty()) diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index d93d98fef51a..e3c7703aeaa3 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -2524,9 +2524,11 @@ void VclMetafileProcessor2D::processTransparencePrimitive2D( // limitation to paint the content const auto aViewInformation2D(geometry::createViewInformation2D({})); const sal_uInt32 nMaximumQuadraticPixels(500000); - const BitmapEx aBitmapEx(convertToBitmapEx( - std::move(xEmbedSeq), aViewInformation2D, basegfx::fround(aDiscreteRange.getWidth()), - basegfx::fround(aDiscreteRange.getHeight()), nMaximumQuadraticPixels)); + const BitmapEx aBitmapEx( + convertToBitmapEx(std::move(xEmbedSeq), aViewInformation2D, + basegfx::B2DRange(0, 0, basegfx::fround(aDiscreteRange.getWidth()), + basegfx::fround(aDiscreteRange.getHeight())), + nMaximumQuadraticPixels)); // add to target metafile (will create MetaFloatTransparentAction) mpOutputDevice->DrawBitmapEx(Point(basegfx::fround<tools::Long>(aLogicRange.getMinX()), diff --git a/drawinglayer/source/tools/converters.cxx b/drawinglayer/source/tools/converters.cxx index cf339f8aaa20..a040a7cd3ac1 100644 --- a/drawinglayer/source/tools/converters.cxx +++ b/drawinglayer/source/tools/converters.cxx @@ -73,7 +73,7 @@ bool implPrepareConversion(drawinglayer::primitive2d::Primitive2DContainer& rSeq AlphaMask implcreateAlphaMask(drawinglayer::primitive2d::Primitive2DContainer& rSequence, const drawinglayer::geometry::ViewInformation2D& rViewInformation2D, - const Size& rSizePixel, bool bUseLuminance) + const Size& rSizePixel, const Point& rPoint, bool bUseLuminance) { ScopedVclPtrInstance<VirtualDevice> pContent; @@ -122,12 +122,11 @@ AlphaMask implcreateAlphaMask(drawinglayer::primitive2d::Primitive2DContainer& r // get alpha channel from vdev pContent->EnableMapMode(false); - const Point aEmptyPoint; // Convert from transparency->alpha. // FIXME in theory I should be able to directly construct alpha by using black as background // and white as foreground, but that doesn't work for some reason. - Bitmap aContentBitmap = pContent->GetBitmap(aEmptyPoint, rSizePixel); + Bitmap aContentBitmap = pContent->GetBitmap(rPoint, rSizePixel); aContentBitmap.Invert(); return AlphaMask(aContentBitmap); @@ -138,34 +137,39 @@ namespace drawinglayer { AlphaMask createAlphaMask(drawinglayer::primitive2d::Primitive2DContainer&& rSeq, const geometry::ViewInformation2D& rViewInformation2D, - sal_uInt32 nDiscreteWidth, sal_uInt32 nDiscreteHeight, + const basegfx::B2DRange& rTargetRange, sal_uInt32 nMaxSquarePixels, bool bUseLuminance) { drawinglayer::primitive2d::Primitive2DContainer aSequence(std::move(rSeq)); + sal_uInt32 nDiscreteWidth = rTargetRange.getWidth(); + sal_uInt32 nDiscreteHeight = rTargetRange.getHeight(); if (!implPrepareConversion(aSequence, nDiscreteWidth, nDiscreteHeight, nMaxSquarePixels)) { return AlphaMask(); } + const Point aPoint(rTargetRange.getMinX(), rTargetRange.getMinY()); const Size aSizePixel(nDiscreteWidth, nDiscreteHeight); - return implcreateAlphaMask(aSequence, rViewInformation2D, aSizePixel, bUseLuminance); + return implcreateAlphaMask(aSequence, rViewInformation2D, aSizePixel, aPoint, bUseLuminance); } BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSeq, const geometry::ViewInformation2D& rViewInformation2D, - sal_uInt32 nDiscreteWidth, sal_uInt32 nDiscreteHeight, + const basegfx::B2DRange& rTargetRange, sal_uInt32 nMaxSquarePixels, bool bForceAlphaMaskCreation) { drawinglayer::primitive2d::Primitive2DContainer aSequence(std::move(rSeq)); + sal_uInt32 nDiscreteWidth = rTargetRange.getWidth(); + sal_uInt32 nDiscreteHeight = rTargetRange.getHeight(); if (!implPrepareConversion(aSequence, nDiscreteWidth, nDiscreteHeight, nMaxSquarePixels)) { return BitmapEx(); } - const Point aEmptyPoint; + const Point aPoint(rTargetRange.getMinX(), rTargetRange.getMinY()); const Size aSizePixel(nDiscreteWidth, nDiscreteHeight); // Create target VirtualDevice. Go back to using a simple RGB @@ -224,7 +228,7 @@ BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSe pContentProcessor->process(aSequence); // create final BitmapEx result (content) - Bitmap aRetval(pContent->GetBitmap(aEmptyPoint, aSizePixel)); + Bitmap aRetval(pContent->GetBitmap(aPoint, aSizePixel)); #ifdef DBG_UTIL static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore @@ -245,7 +249,7 @@ BitmapEx convertToBitmapEx(drawinglayer::primitive2d::Primitive2DContainer&& rSe // Create the AlphaMask using a method that does this always correct (also used // now in GlowPrimitive2D and ShadowPrimitive2D which both only need the // AlphaMask to do their job, so speeding that up, too). - AlphaMask aAlpha(implcreateAlphaMask(aSequence, rViewInformation2D, aSizePixel, false)); + AlphaMask aAlpha(implcreateAlphaMask(aSequence, rViewInformation2D, aSizePixel, aPoint, false)); #ifdef DBG_UTIL if (bDoSaveForVisualControl) @@ -356,7 +360,7 @@ BitmapEx convertPrimitive2DContainerToBitmapEx(primitive2d::Primitive2DContainer primitive2d::Primitive2DContainer xEmbedSeq{ xEmbedRef }; BitmapEx aBitmapEx(convertToBitmapEx(std::move(xEmbedSeq), aViewInformation2D, - nDiscreteWidth, nDiscreteHeight, + basegfx::B2DRange(0, 0, nDiscreteWidth, nDiscreteHeight), nMaximumQuadraticPixels)); if (aBitmapEx.IsEmpty()) diff --git a/include/drawinglayer/converters.hxx b/include/drawinglayer/converters.hxx index d090b1e0a921..4e4d621f5d6a 100644 --- a/include/drawinglayer/converters.hxx +++ b/include/drawinglayer/converters.hxx @@ -33,15 +33,15 @@ namespace drawinglayer // for any content (e.g. gradients) AlphaMask DRAWINGLAYER_DLLPUBLIC createAlphaMask( drawinglayer::primitive2d::Primitive2DContainer&& rSeq, - const geometry::ViewInformation2D& rViewInformation2D, sal_uInt32 nDiscreteWidth, - sal_uInt32 nDiscreteHeight, sal_uInt32 nMaxSquarePixels, bool bUseLuminance = false); + const geometry::ViewInformation2D& rViewInformation2D, const basegfx::B2DRange& rTargetRange, + sal_uInt32 nMaxSquarePixels, bool bUseLuminance = false); // Helper for convertPrimitive2DContainerToBitmapEx below, but can be also used // directly BitmapEx DRAWINGLAYER_DLLPUBLIC convertToBitmapEx( drawinglayer::primitive2d::Primitive2DContainer&& rSeq, - const geometry::ViewInformation2D& rViewInformation2D, sal_uInt32 nDiscreteWidth, - sal_uInt32 nDiscreteHeight, sal_uInt32 nMaxSquarePixels, bool bForceAlphaMaskCreation = false); + const geometry::ViewInformation2D& rViewInformation2D, const basegfx::B2DRange& rTargetRange, + sal_uInt32 nMaxSquarePixels, bool bForceAlphaMaskCreation = false); // helper to convert any Primitive2DSequence to a good quality BitmapEx, // using default parameters diff --git a/include/vcl/BitmapTools.hxx b/include/vcl/BitmapTools.hxx index de0ad84ea3da..d321d2be79a3 100644 --- a/include/vcl/BitmapTools.hxx +++ b/include/vcl/BitmapTools.hxx @@ -66,10 +66,6 @@ VCL_DLLPUBLIC BitmapEx CanvasTransformBitmap( const BitmapEx& rBitmap, ::basegfx::B2DRectangle const & rDestRect, ::basegfx::B2DHomMatrix const & rLocalTransform ); -VCL_DLLPUBLIC BitmapEx DrawBitmapInRect( const BitmapEx& rBitmap, - ::basegfx::B2DRectangle const & rBitmapRect, - ::basegfx::B2DRectangle const & rDestRect ); - VCL_DLLPUBLIC void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask & rNewMask); VCL_DLLPUBLIC void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const BitmapEx& rBitmap, BitmapEx & aBmpEx, basegfx::B2DPolyPolygon const & rClipPath); diff --git a/svgio/inc/svgfilternode.hxx b/svgio/inc/svgfilternode.hxx index ec42d3c52df4..7aa522173a87 100644 --- a/svgio/inc/svgfilternode.hxx +++ b/svgio/inc/svgfilternode.hxx @@ -23,7 +23,6 @@ #include "svgnode.hxx" #include "svgstyleattributes.hxx" #include <basegfx/matrix/b2dhommatrix.hxx> -#include <vcl/bitmapex.hxx> typedef std::unordered_map<OUString, drawinglayer::primitive2d::Primitive2DContainer> IdGraphicSourceMapper; @@ -47,8 +46,6 @@ public: drawinglayer::primitive2d::Primitive2DContainer pGraphicSource) const; const drawinglayer::primitive2d::Primitive2DContainer* findGraphicSource(const OUString& rStr) const; - - static BitmapEx convertToBitmapEx(const drawinglayer::primitive2d::Primitive2DContainer* pSeq); }; } // end of namespace svgio::svgreader diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index e05fe539e1c0..93d43fae85e2 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -1614,16 +1614,167 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf160517) xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/tdf160517.svg"); assertXPath(pDocument, - "/primitive2D/transform/bitmap"_ostr, "height"_ostr, "100"); + "/primitive2D/transform/bitmap"_ostr, "height"_ostr, "110"); assertXPath(pDocument, - "/primitive2D/transform/bitmap"_ostr, "width"_ostr, "100"); + "/primitive2D/transform/bitmap"_ostr, "width"_ostr, "110"); assertXPath(pDocument, - "/primitive2D/transform/bitmap/data"_ostr, 100); + "/primitive2D/transform/bitmap/data"_ostr, 110); + + assertXPath(pDocument, + "/primitive2D/transform/bitmap"_ostr, "xy11"_ostr, "110"); + assertXPath(pDocument, + "/primitive2D/transform/bitmap"_ostr, "xy12"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy13"_ostr, "10"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy21"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy22"_ostr, "110"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy23"_ostr, "10"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy31"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy32"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D//transform/bitmap"_ostr, "xy33"_ostr, "1"); // Check the color of a pixel in the middle - const OUString sDataRow = getXPath(pDocument, "/primitive2D/transform/bitmap/data[50]"_ostr, "row"_ostr); + const OUString sDataRow = getXPath(pDocument, "/primitive2D/transform/bitmap/data[55]"_ostr, "row"_ostr); std::vector<OUString> aPixels = comphelper::string::split(sDataRow, ','); - CPPUNIT_ASSERT_EQUAL(OUString("008100"), aPixels[50]); + CPPUNIT_ASSERT_EQUAL(OUString("008100"), aPixels[55]); +} + +CPPUNIT_TEST_FIXTURE(Test, testArithmeticComposite) +{ + xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/arithmetic.svg"); + + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "height"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "width"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap/data"_ostr, 150); + + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy11"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy12"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy13"_ostr, "50"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy21"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy22"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy23"_ostr, "50"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy31"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy32"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy33"_ostr, "1"); + + // Check the colors in the diagonal + OUString sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[25]"_ostr, "row"_ostr); + std::vector<OUString> aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ff8000"), aPixels[25]); + + sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[75]"_ostr, "row"_ostr); + aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ff8000"), aPixels[75]); + + sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[125]"_ostr, "row"_ostr); + aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("000000"), aPixels[125]); +} + +CPPUNIT_TEST_FIXTURE(Test, testArithmeticComposite2) +{ + xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/arithmetic2.svg"); + + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "height"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "width"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap/data"_ostr, 150); + + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy11"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy12"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy13"_ostr, "20"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy21"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy22"_ostr, "150"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy23"_ostr, "20"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy31"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy32"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy33"_ostr, "1"); + + // Check the colors in the diagonal + OUString sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[25]"_ostr, "row"_ostr); + std::vector<OUString> aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ff0000"), aPixels[25]); + + sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[75]"_ostr, "row"_ostr); + aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ff8000"), aPixels[75]); + + sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[125]"_ostr, "row"_ostr); + aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("008000"), aPixels[125]); +} + +CPPUNIT_TEST_FIXTURE(Test, testTdf160726) +{ + xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/tdf160726.svg"); + + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "height"_ostr, "250"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "width"_ostr, "250"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap/data"_ostr, 250); + + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy11"_ostr, "250"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy12"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy13"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy21"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy22"_ostr, "250"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy23"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy31"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy32"_ostr, "0"); + assertXPath(pDocument, + "/primitive2D/transform/transform/bitmap"_ostr, "xy33"_ostr, "1"); + + // Check the colors in the diagonal + OUString sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[50]"_ostr, "row"_ostr); + std::vector<OUString> aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ff0000"), aPixels[50]); + + sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[125]"_ostr, "row"_ostr); + aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ffff00"), aPixels[125]); + + sDataRow = getXPath(pDocument, "/primitive2D/transform/transform/bitmap/data[200]"_ostr, "row"_ostr); + aPixels = comphelper::string::split(sDataRow, ','); + CPPUNIT_ASSERT_EQUAL(OUString("ffff00"), aPixels[200]); } CPPUNIT_TEST_FIXTURE(Test, testTdf149880) diff --git a/svgio/qa/cppunit/data/arithmetic.svg b/svgio/qa/cppunit/data/arithmetic.svg new file mode 100644 index 000000000000..cc22eedbe10e --- /dev/null +++ b/svgio/qa/cppunit/data/arithmetic.svg @@ -0,0 +1,8 @@ +<svg width="100" height="140" viewBox="0 0 200 280" xmlns="http://www.w3.org/2000/svg"> + <filter id="filter" filterUnits="userSpaceOnUse" x="0" y="0" width="100%" height="100%"> + <feFlood x="50" y="50" width="100" height="100" flood-color="red" flood-opacity="1" result="img1"></feFlood> + <feFlood x="50" y="50" width="100" height="100" flood-color="green" flood-opacity="1" result="img2"></feFlood> + <feComposite in="img1" in2="img2" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite> + </filter> + <use style="filter: url(#filter)"></use> +</svg> diff --git a/svgio/qa/cppunit/data/arithmetic2.svg b/svgio/qa/cppunit/data/arithmetic2.svg new file mode 100644 index 000000000000..ba58e309398b --- /dev/null +++ b/svgio/qa/cppunit/data/arithmetic2.svg @@ -0,0 +1,8 @@ +<svg width="100" height="140" viewBox="0 0 200 280" xmlns="http://www.w3.org/2000/svg"> + <filter id="filter" filterUnits="userSpaceOnUse" x="0" y="0" width="100%" height="100%"> + <feFlood x="20" y="20" width="100" height="100" flood-color="red" flood-opacity="1" result="img1"></feFlood> + <feFlood x="50" y="50" width="100" height="100" flood-color="green" flood-opacity="1" result="img2"></feFlood> + <feComposite in="img1" in2="img2" operator="arithmetic" k1="0" k2="1" k3="1" k4="0"></feComposite> + </filter> + <use style="filter: url(#filter)"></use> +</svg> diff --git a/svgio/qa/cppunit/data/tdf160726.svg b/svgio/qa/cppunit/data/tdf160726.svg new file mode 100644 index 000000000000..7a9ac339984c --- /dev/null +++ b/svgio/qa/cppunit/data/tdf160726.svg @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + width="500" + height="500" + viewBox="0 0 500 500" + version="1.1"> + <defs + id="defs2"> + <filter + height="2" + width="2" + id="filter2103"> + <feOffset + result="result1" + id="feOffset2097" + dy="50" + dx="50" /> + <feColorMatrix + result="result2" + values="1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 " + id="feColorMatrix2099" /> + <feComposite + operator="arithmetic" + in="result2" + id="feComposite2101" + in2="SourceGraphic" + k1="0" + k2="1" + k3="1" + k4="0"/> + </filter> + </defs> + <g> + <circle + r="100" + cy="100" + cx="100" + id="circle2113" + style="fill:#ff0000;filter:url(#filter2103)" /> + </g> +</svg> diff --git a/svgio/source/svgreader/svgfeblendnode.cxx b/svgio/source/svgreader/svgfeblendnode.cxx index e1440185ff23..eace3a53f63e 100644 --- a/svgio/source/svgreader/svgfeblendnode.cxx +++ b/svgio/source/svgreader/svgfeblendnode.cxx @@ -87,48 +87,74 @@ void SvgFeBlendNode::parseAttribute(SVGToken aSVGToken, const OUString& aContent void SvgFeBlendNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTarget, const SvgFilterNode* pParent) const { + const drawinglayer::primitive2d::Primitive2DContainer* pSource + = pParent->findGraphicSource(maIn); + const drawinglayer::primitive2d::Primitive2DContainer* pSource2 + = pParent->findGraphicSource(maIn2); + if (maMode == Mode::Normal) { - if (const drawinglayer::primitive2d::Primitive2DContainer* rSource2 - = pParent->findGraphicSource(maIn2)) + // Process maIn2 first + if (pSource2) { - rTarget = *rSource2; + rTarget = *pSource2; } - if (const drawinglayer::primitive2d::Primitive2DContainer* rSource - = pParent->findGraphicSource(maIn)) + if (pSource) { - rTarget.append(*rSource); + rTarget.append(*pSource); } } else if (maMode == Mode::Screen) { basegfx::B2DRange aRange, aRange2; - BitmapEx aBmpEx, aBmpEx2; - - if (const drawinglayer::primitive2d::Primitive2DContainer* pSource - = pParent->findGraphicSource(maIn)) + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + if (pSource) { - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; aRange = pSource->getB2DRange(aViewInformation2D); - aBmpEx = convertToBitmapEx(pSource); } - if (const drawinglayer::primitive2d::Primitive2DContainer* pSource2 - = pParent->findGraphicSource(maIn2)) + if (pSource2) { - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; aRange2 = pSource2->getB2DRange(aViewInformation2D); - aBmpEx2 = convertToBitmapEx(pSource2); } - basegfx::B2DRectangle aBaseRect(std::min(aRange.getMinX(), aRange2.getMinX()), - std::min(aRange.getMinY(), aRange2.getMinY()), - std::max(aRange.getMaxX(), aRange2.getMaxX()), - std::max(aRange.getMaxY(), aRange2.getMaxY())); + const sal_Int32 nX1 = std::min(aRange.getMinX(), aRange2.getMinX()); + const sal_Int32 nY1 = std::min(aRange.getMinY(), aRange2.getMinY()); + const sal_Int32 nX2 = std::max(aRange.getMaxX(), aRange2.getMaxX()); + const sal_Int32 nY2 = std::max(aRange.getMaxY(), aRange2.getMaxY()); + + const basegfx::B2DRange aBaseRange(nX1, nY1, nX1 + nX2, nY1 + nY2); - aBmpEx = vcl::bitmap::DrawBitmapInRect(aBmpEx, aRange, aBaseRect); - aBmpEx2 = vcl::bitmap::DrawBitmapInRect(aBmpEx2, aRange2, aBaseRect); + BitmapEx aBmpEx, aBmpEx2; + + if (pSource) + { + drawinglayer::primitive2d::Primitive2DContainer aSource(*pSource); + aBmpEx = drawinglayer::convertToBitmapEx( + std::move(aSource), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } + else + { + aBmpEx = drawinglayer::convertToBitmapEx( + std::move(rTarget), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } + + if (pSource2) + { + drawinglayer::primitive2d::Primitive2DContainer aSource(*pSource2); + aBmpEx2 = drawinglayer::convertToBitmapEx( + std::move(aSource), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } + else + { + aBmpEx2 = drawinglayer::convertToBitmapEx( + std::move(rTarget), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } BitmapScreenBlendFilter aScreenBlendFilter(aBmpEx, aBmpEx2); BitmapEx aResBmpEx = aScreenBlendFilter.execute(); @@ -136,7 +162,7 @@ void SvgFeBlendNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTar const drawinglayer::primitive2d::Primitive2DReference xRef( new drawinglayer::primitive2d::BitmapPrimitive2D( aResBmpEx, basegfx::utils::createScaleTranslateB2DHomMatrix( - aBaseRect.getRange(), aBaseRect.getMinimum()))); + aBaseRange.getRange(), aBaseRange.getMinimum()))); rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; } diff --git a/svgio/source/svgreader/svgfecompositenode.cxx b/svgio/source/svgreader/svgfecompositenode.cxx index 3eba9f300062..91364363ca22 100644 --- a/svgio/source/svgreader/svgfecompositenode.cxx +++ b/svgio/source/svgreader/svgfecompositenode.cxx @@ -148,13 +148,17 @@ void SvgFeCompositeNode::parseAttribute(SVGToken aSVGToken, const OUString& aCon void SvgFeCompositeNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTarget, const SvgFilterNode* pParent) const { + const drawinglayer::primitive2d::Primitive2DContainer* pSource + = pParent->findGraphicSource(maIn); + const drawinglayer::primitive2d::Primitive2DContainer* pSource2 + = pParent->findGraphicSource(maIn2); + if (maOperator != Operator::Arithmetic) { basegfx::B2DPolyPolygon aPolyPolygon, aPolyPolygon2; // Process maIn2 first - if (const drawinglayer::primitive2d::Primitive2DContainer* pSource2 - = pParent->findGraphicSource(maIn2)) + if (pSource2) { rTarget.append(*pSource2); drawinglayer::processor2d::ContourExtractor2D aExtractor( @@ -164,8 +168,7 @@ void SvgFeCompositeNode::apply(drawinglayer::primitive2d::Primitive2DContainer& aPolyPolygon2 = basegfx::utils::mergeToSinglePolyPolygon(rResult); } - if (const drawinglayer::primitive2d::Primitive2DContainer* pSource - = pParent->findGraphicSource(maIn)) + if (pSource) { rTarget.append(*pSource); drawinglayer::processor2d::ContourExtractor2D aExtractor( @@ -209,31 +212,53 @@ void SvgFeCompositeNode::apply(drawinglayer::primitive2d::Primitive2DContainer& else { basegfx::B2DRange aRange, aRange2; - BitmapEx aBmpEx, aBmpEx2; - - if (const drawinglayer::primitive2d::Primitive2DContainer* pSource - = pParent->findGraphicSource(maIn)) + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + if (pSource) { - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; aRange = pSource->getB2DRange(aViewInformation2D); - aBmpEx = convertToBitmapEx(pSource); } - if (const drawinglayer::primitive2d::Primitive2DContainer* pSource2 - = pParent->findGraphicSource(maIn2)) + if (pSource2) { - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; aRange2 = pSource2->getB2DRange(aViewInformation2D); - aBmpEx2 = convertToBitmapEx(pSource2); } - basegfx::B2DRectangle aBaseRect(std::min(aRange.getMinX(), aRange2.getMinX()), - std::min(aRange.getMinY(), aRange2.getMinY()), - std::max(aRange.getMaxX(), aRange2.getMaxX()), - std::max(aRange.getMaxY(), aRange2.getMaxY())); + const sal_uInt32 nX1 = std::min(aRange.getMinX(), aRange2.getMinX()); + const sal_uInt32 nY1 = std::min(aRange.getMinY(), aRange2.getMinY()); + const sal_uInt32 nX2 = std::max(aRange.getMaxX(), aRange2.getMaxX()); + const sal_uInt32 nY2 = std::max(aRange.getMaxY(), aRange2.getMaxY()); + + const basegfx::B2DRange aBaseRange(nX1, nY1, nX1 + nX2, nY1 + nY2); - aBmpEx = vcl::bitmap::DrawBitmapInRect(aBmpEx, aRange, aBaseRect); - aBmpEx2 = vcl::bitmap::DrawBitmapInRect(aBmpEx2, aRange2, aBaseRect); + BitmapEx aBmpEx, aBmpEx2; + + if (pSource) + { + drawinglayer::primitive2d::Primitive2DContainer aSource(*pSource); + aBmpEx = drawinglayer::convertToBitmapEx( + std::move(aSource), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } + else + { + aBmpEx = drawinglayer::convertToBitmapEx( + std::move(rTarget), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } + + if (pSource2) + { + drawinglayer::primitive2d::Primitive2DContainer aSource(*pSource2); + aBmpEx2 = drawinglayer::convertToBitmapEx( + std::move(aSource), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } + else + { + aBmpEx2 = drawinglayer::convertToBitmapEx( + std::move(rTarget), aViewInformation2D, aBaseRange, + aBaseRange.getWidth() * aBaseRange.getHeight()); + } BitmapArithmeticBlendFilter aArithmeticFilter(aBmpEx, aBmpEx2); BitmapEx aResBmpEx = aArithmeticFilter.execute(maK1.getNumber(), maK2.getNumber(), @@ -242,7 +267,7 @@ void SvgFeCompositeNode::apply(drawinglayer::primitive2d::Primitive2DContainer& const drawinglayer::primitive2d::Primitive2DReference xRef( new drawinglayer::primitive2d::BitmapPrimitive2D( aResBmpEx, basegfx::utils::createScaleTranslateB2DHomMatrix( - aBaseRect.getRange(), aBaseRect.getMinimum()))); + aBaseRange.getRange(), aBaseRange.getMinimum()))); rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; } } diff --git a/svgio/source/svgreader/svgfilternode.cxx b/svgio/source/svgreader/svgfilternode.cxx index 4b97563478e1..5b2f7e867523 100644 --- a/svgio/source/svgreader/svgfilternode.cxx +++ b/svgio/source/svgreader/svgfilternode.cxx @@ -25,10 +25,6 @@ #include <svgfegaussianblurnode.hxx> #include <svgfeoffsetnode.hxx> -#include <basegfx/matrix/b2dhommatrixtools.hxx> -#include <drawinglayer/primitive2d/transformprimitive2d.hxx> -#include <drawinglayer/converters.hxx> - namespace svgio::svgreader { SvgFilterNode::SvgFilterNode(SVGToken aType, SvgDocument& rDocument, SvgNode* pParent) @@ -95,23 +91,6 @@ SvgFilterNode::findGraphicSource(const OUString& rStr) const } } -BitmapEx -SvgFilterNode::convertToBitmapEx(const drawinglayer::primitive2d::Primitive2DContainer* pSeq) -{ - drawinglayer::primitive2d::Primitive2DContainer aSequence(*pSeq); - - const drawinglayer::geometry::ViewInformation2D aViewInformation2D; - basegfx::B2DRange aRange = aSequence.getB2DRange(aViewInformation2D); - basegfx::B2DHomMatrix aEmbedding( - basegfx::utils::createTranslateB2DHomMatrix(-aRange.getMinX(), -aRange.getMinY())); - aEmbedding.scale(aRange.getWidth(), aRange.getHeight()); - const drawinglayer::primitive2d::Primitive2DReference xEmbedRef( - new drawinglayer::primitive2d::TransformPrimitive2D(aEmbedding, std::move(aSequence))); - drawinglayer::primitive2d::Primitive2DContainer xEmbedSeq{ xEmbedRef }; - return drawinglayer::convertToBitmapEx(std::move(xEmbedSeq), aViewInformation2D, - aRange.getWidth(), aRange.getHeight(), 500000); -} - } // end of namespace svgio::svgreader /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx index b5186616bb5c..cb094c0831c7 100644 --- a/vcl/source/bitmap/BitmapTools.cxx +++ b/vcl/source/bitmap/BitmapTools.cxx @@ -512,120 +512,6 @@ BitmapEx CanvasTransformBitmap( const BitmapEx& rBitmap, return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); } -BitmapEx DrawBitmapInRect( const BitmapEx& rBitmap, - ::basegfx::B2DRectangle const & rBitmapRect, - ::basegfx::B2DRectangle const & rDestRect ) -{ - if( rDestRect.isEmpty() ) - return BitmapEx(); - - const Size aDestBmpSize( ::basegfx::fround<tools::Long>( rDestRect.getWidth() ), - ::basegfx::fround<tools::Long>( rDestRect.getHeight() ) ); - - Bitmap aSrcBitmap( rBitmap.GetBitmap() ); - Bitmap aSrcAlpha; - - // differentiate mask and alpha channel (on-off - // vs. multi-level transparency) - if( rBitmap.IsAlpha() ) - { - aSrcAlpha = rBitmap.GetAlphaMask().GetBitmap(); - } - - BitmapScopedReadAccess pReadAccess( aSrcBitmap ); - BitmapScopedReadAccess pAlphaReadAccess; - if (rBitmap.IsAlpha()) - pAlphaReadAccess = aSrcAlpha; - - // mapping table, to translate pAlphaReadAccess' pixel - // values into destination alpha values (needed e.g. for - // paletted 1-bit masks). - sal_uInt8 aAlphaMap[256]; - - if( rBitmap.IsAlpha() ) - { - // source already has alpha channel - 1:1 mapping, - // i.e. aAlphaMap[0]=0,...,aAlphaMap[255]=255. - sal_uInt8 val=0; - sal_uInt8* pCur=aAlphaMap; - sal_uInt8* const pEnd=&aAlphaMap[256]; - while(pCur != pEnd) - *pCur++ = val++; - } - // else: mapping table is not used - - Bitmap aDstBitmap(aDestBmpSize, vcl::PixelFormat::N24_BPP); - Bitmap aDstAlpha( AlphaMask( aDestBmpSize ).GetBitmap() ); - - { - // just to be on the safe side: let the - // ScopedAccessors get destructed before - // copy-constructing the resulting bitmap. This will - // rule out the possibility that cached accessor data - // is not yet written back. - BitmapScopedWriteAccess pWriteAccess( aDstBitmap ); - BitmapScopedWriteAccess pAlphaWriteAccess( aDstAlpha ); - - - if( pWriteAccess.get() != nullptr && - pAlphaWriteAccess.get() != nullptr) - { - // for the time being, always read as ARGB - for (tools::Long y(rDestRect.getMinY()); y < rDestRect.getMaxY(); y++) - { - // differentiate mask and alpha channel (on-off - // vs. multi-level transparency) - if( rBitmap.IsAlpha() ) - { - Scanline pScan = pWriteAccess->GetScanline( y - rDestRect.getMinY() ); - Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y - rDestRect.getMinY() ); - // Handling alpha and mask just the same... - for (tools::Long x(rDestRect.getMinX()); x < rDestRect.getMaxX(); x++) - { - if (rBitmapRect.getMinX() <= x && rBitmapRect.getMaxX() > x && rBitmapRect.getMinY() <= y - && rBitmapRect.getMaxY() > y) - { - const sal_uInt8 cAlphaIdx = pAlphaReadAccess->GetPixelIndex( x - rBitmapRect.getMinX(), y - rBitmapRect.getMinY() ); - pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(aAlphaMap[ cAlphaIdx ]) ); - pWriteAccess->SetPixelOnData( pScan, x - rDestRect.getMinX(), pReadAccess->GetPixel( x - rBitmapRect.getMinX(), y - rBitmapRect.getMinY() ) ); - } - else - { - pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(0) ); - } - } - } - else - { - Scanline pScan = pWriteAccess->GetScanline( y - rDestRect.getMinY() ); - Scanline pScanAlpha = pAlphaWriteAccess->GetScanline( y - rDestRect.getMinY() ); - for (tools::Long x(rDestRect.getMinX()); x < rDestRect.getMaxX(); x++) - { - if (rBitmapRect.getMinX() <= x && rBitmapRect.getMaxX() > x && rBitmapRect.getMinY() <= y - && rBitmapRect.getMaxY() > y) - { - pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(255) ); - pWriteAccess->SetPixelOnData( pScan, x - rDestRect.getMinX(), pReadAccess->GetPixel( x - rBitmapRect.getMinX(), y - rBitmapRect.getMinY() ) ); - } - else - { - pAlphaWriteAccess->SetPixelOnData( pScanAlpha, x - rDestRect.getMinX(), BitmapColor(0) ); - } - } - } - } - } - else - { - // TODO(E2): Error handling! - ENSURE_OR_THROW( false, - "DrawBitmapInRect(): could not access bitmap" ); - } - } - - return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); -} - void DrawAlphaBitmapAndAlphaGradient(BitmapEx & rBitmapEx, bool bFixedTransparence, float fTransparence, AlphaMask & rNewMask) { // mix existing and new alpha mask