include/vcl/BitmapScreenBlendFilter.hxx | 29 ++++++ include/vcl/BitmapTools.hxx | 4 svgio/inc/svgfeblendnode.hxx | 7 + svgio/inc/svgtoken.hxx | 1 svgio/source/svgreader/svgfeblendnode.cxx | 96 +++++++++++++++++++- svgio/source/svgreader/svgtoken.cxx | 1 vcl/Library_vcl.mk | 1 vcl/qa/cppunit/BitmapFilterTest.cxx | 57 ++++++++++++ vcl/source/bitmap/BitmapScreenBlendFilter.cxx | 87 ++++++++++++++++++ vcl/source/bitmap/BitmapTools.cxx | 121 +++++++++++++++++++++++++- 10 files changed, 396 insertions(+), 8 deletions(-)
New commits: commit 732ca4879b7e49b171c5930166e4dba7be451841 Author: Xisco Fauli <xiscofa...@libreoffice.org> AuthorDate: Wed Apr 10 18:05:00 2024 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Fri Apr 12 10:47:56 2024 +0200 tdf#159660: Add support for screen mode in feBlend Change-Id: Iefe655a370cca930319290baa2a25d791371f55c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165958 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/include/vcl/BitmapScreenBlendFilter.hxx b/include/vcl/BitmapScreenBlendFilter.hxx new file mode 100644 index 000000000000..a8f816936f49 --- /dev/null +++ b/include/vcl/BitmapScreenBlendFilter.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_VCL_BITMAPSCREENBLENDFILTER_HXX +#define INCLUDED_VCL_BITMAPSCREENBLENDFILTER_HXX + +#include <vcl/bitmapex.hxx> + +class VCL_DLLPUBLIC BitmapScreenBlendFilter +{ +private: + BitmapEx maBitmapEx; + BitmapEx maBitmapEx2; + +public: + BitmapScreenBlendFilter(BitmapEx const& rBmpEx, BitmapEx const& rBmpEx2); + + virtual ~BitmapScreenBlendFilter(); + BitmapEx execute(); +}; +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/BitmapTools.hxx b/include/vcl/BitmapTools.hxx index d321d2be79a3..de0ad84ea3da 100644 --- a/include/vcl/BitmapTools.hxx +++ b/include/vcl/BitmapTools.hxx @@ -66,6 +66,10 @@ 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/svgfeblendnode.hxx b/svgio/inc/svgfeblendnode.hxx index 8ff46adf15ff..5881959ad418 100644 --- a/svgio/inc/svgfeblendnode.hxx +++ b/svgio/inc/svgfeblendnode.hxx @@ -24,12 +24,19 @@ namespace svgio::svgreader { +enum class Mode +{ + Normal, + Screen +}; + class SvgFeBlendNode : public SvgFilterNode { private: OUString maIn; OUString maIn2; OUString maResult; + Mode maMode; public: SvgFeBlendNode(SvgDocument& rDocument, SvgNode* pParent); diff --git a/svgio/inc/svgtoken.hxx b/svgio/inc/svgtoken.hxx index d988f4b2d993..9e6945859cd4 100644 --- a/svgio/inc/svgtoken.hxx +++ b/svgio/inc/svgtoken.hxx @@ -97,6 +97,7 @@ namespace svgio::svgreader FloodOpacity, Operator, Mask, + Mode, ClipPathUnits, MaskUnits, MaskContentUnits, diff --git a/svgio/source/svgreader/svgfeblendnode.cxx b/svgio/source/svgreader/svgfeblendnode.cxx index 6adc0e8e139e..918912fa54d8 100644 --- a/svgio/source/svgreader/svgfeblendnode.cxx +++ b/svgio/source/svgreader/svgfeblendnode.cxx @@ -19,10 +19,19 @@ #include <svgfeblendnode.hxx> #include <o3tl/string_view.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <vcl/bitmapex.hxx> +#include <drawinglayer/converters.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <vcl/BitmapScreenBlendFilter.hxx> +#include <vcl/BitmapTools.hxx> + namespace svgio::svgreader { SvgFeBlendNode::SvgFeBlendNode(SvgDocument& rDocument, SvgNode* pParent) : SvgFilterNode(SVGToken::FeBlend, rDocument, pParent) + , maMode(Mode::Normal) { } @@ -53,6 +62,21 @@ void SvgFeBlendNode::parseAttribute(SVGToken aSVGToken, const OUString& aContent maResult = aContent.trim(); break; } + case SVGToken::Mode: + { + if (!aContent.isEmpty()) + { + if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"normal")) + { + maMode = Mode::Normal; + } + else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"screen")) + { + maMode = Mode::Screen; + } + } + break; + } default: { break; @@ -63,16 +87,74 @@ void SvgFeBlendNode::parseAttribute(SVGToken aSVGToken, const OUString& aContent void SvgFeBlendNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTarget, const SvgFilterNode* pParent) const { - if (const drawinglayer::primitive2d::Primitive2DContainer* rSource2 - = pParent->findGraphicSource(maIn2)) + if (maMode == Mode::Normal) { - rTarget = *rSource2; - } + if (const drawinglayer::primitive2d::Primitive2DContainer* rSource2 + = pParent->findGraphicSource(maIn2)) + { + rTarget = *rSource2; + } - if (const drawinglayer::primitive2d::Primitive2DContainer* rSource - = pParent->findGraphicSource(maIn)) + if (const drawinglayer::primitive2d::Primitive2DContainer* rSource + = pParent->findGraphicSource(maIn)) + { + rTarget.append(*rSource); + } + } + else if (maMode == Mode::Screen) { - rTarget.append(*rSource); + basegfx::B2DRange aRange, aRange2; + BitmapEx aBmpEx, aBmpEx2; + + if (const drawinglayer::primitive2d::Primitive2DContainer* pSource + = pParent->findGraphicSource(maIn)) + { + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + aRange = pSource->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, drawinglayer::primitive2d::Primitive2DContainer(*pSource))); + drawinglayer::primitive2d::Primitive2DContainer xEmbedSeq{ xEmbedRef }; + aBmpEx = drawinglayer::convertToBitmapEx(std::move(xEmbedSeq), aViewInformation2D, + aRange.getWidth(), aRange.getHeight(), 500000); + } + + if (const drawinglayer::primitive2d::Primitive2DContainer* pSource2 + = pParent->findGraphicSource(maIn2)) + { + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + aRange2 = pSource2->getB2DRange(aViewInformation2D); + basegfx::B2DHomMatrix aEmbedding(basegfx::utils::createTranslateB2DHomMatrix( + -aRange2.getMinX(), -aRange2.getMinY())); + aEmbedding.scale(aRange2.getWidth(), aRange2.getHeight()); + const drawinglayer::primitive2d::Primitive2DReference xEmbedRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbedding, drawinglayer::primitive2d::Primitive2DContainer(*pSource2))); + drawinglayer::primitive2d::Primitive2DContainer xEmbedSeq{ xEmbedRef }; + aBmpEx2 + = drawinglayer::convertToBitmapEx(std::move(xEmbedSeq), aViewInformation2D, + aRange2.getWidth(), aRange2.getHeight(), 500000); + } + + 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())); + + aBmpEx = vcl::bitmap::DrawBitmapInRect(aBmpEx, aRange, aBaseRect); + aBmpEx2 = vcl::bitmap::DrawBitmapInRect(aBmpEx2, aRange2, aBaseRect); + + BitmapScreenBlendFilter* pScreenBlendFilter = new BitmapScreenBlendFilter(aBmpEx, aBmpEx2); + BitmapEx aResBmpEx = pScreenBlendFilter->execute(); + + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::BitmapPrimitive2D( + aResBmpEx, basegfx::utils::createScaleTranslateB2DHomMatrix( + aBaseRect.getRange(), aBaseRect.getMinimum()))); + rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; } pParent->addGraphicSourceToMapper(maResult, rTarget); diff --git a/svgio/source/svgreader/svgtoken.cxx b/svgio/source/svgreader/svgtoken.cxx index 3f5ac5c7a306..b019f71c4835 100644 --- a/svgio/source/svgreader/svgtoken.cxx +++ b/svgio/source/svgreader/svgtoken.cxx @@ -95,6 +95,7 @@ constexpr auto aSVGTokenMap = frozen::make_unordered_map<std::u16string_view, SV { u"flood-opacity", SVGToken::FloodOpacity }, { u"operator", SVGToken::Operator }, { u"mask", SVGToken::Mask }, + { u"mode", SVGToken::Mode }, { u"clipPathUnits", SVGToken::ClipPathUnits }, { u"maskUnits", SVGToken::MaskUnits }, { u"maskContentUnits", SVGToken::MaskContentUnits }, diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index a3c2581ae6b7..7b54123dbed2 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -346,6 +346,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/bitmap/BitmapBasicMorphologyFilter \ vcl/source/bitmap/BitmapMaskToAlphaFilter \ vcl/source/bitmap/BitmapMonochromeFilter \ + vcl/source/bitmap/BitmapScreenBlendFilter \ vcl/source/bitmap/BitmapSmoothenFilter \ vcl/source/bitmap/BitmapLightenFilter \ vcl/source/bitmap/BitmapDisabledImageFilter \ diff --git a/vcl/qa/cppunit/BitmapFilterTest.cxx b/vcl/qa/cppunit/BitmapFilterTest.cxx index 0432041cac7c..00ba12b4a925 100644 --- a/vcl/qa/cppunit/BitmapFilterTest.cxx +++ b/vcl/qa/cppunit/BitmapFilterTest.cxx @@ -15,6 +15,7 @@ #include <tools/stream.hxx> #include <vcl/graphicfilter.hxx> +#include <vcl/BitmapScreenBlendFilter.hxx> #include <vcl/BitmapBasicMorphologyFilter.hxx> #include <vcl/BitmapFilterStackBlur.hxx> #include <BitmapSymmetryCheck.hxx> @@ -39,12 +40,14 @@ public: void testBasicMorphology(); void testPerformance(); void testGenerateStripRanges(); + void testScreenBlendFilter(); CPPUNIT_TEST_SUITE(BitmapFilterTest); CPPUNIT_TEST(testBlurCorrectness); CPPUNIT_TEST(testBasicMorphology); CPPUNIT_TEST(testPerformance); CPPUNIT_TEST(testGenerateStripRanges); + CPPUNIT_TEST(testScreenBlendFilter); CPPUNIT_TEST_SUITE_END(); private: @@ -276,6 +279,60 @@ void BitmapFilterTest::testGenerateStripRanges() } } +void BitmapFilterTest::testScreenBlendFilter() +{ + Bitmap aRedBitmap(Size(4, 4), vcl::PixelFormat::N24_BPP); + CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aRedBitmap.getPixelFormat()); + { + BitmapScopedWriteAccess aWriteAccess(aRedBitmap); + aWriteAccess->Erase(COL_LIGHTRED); + } + + Bitmap aGreenBitmap(Size(4, 4), vcl::PixelFormat::N24_BPP); + CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aGreenBitmap.getPixelFormat()); + { + BitmapScopedWriteAccess aWriteAccess(aGreenBitmap); + aWriteAccess->Erase(COL_GREEN); + } + + Bitmap aTransparentBitmap(Size(4, 4), vcl::PixelFormat::N24_BPP); + CPPUNIT_ASSERT_EQUAL(vcl::PixelFormat::N24_BPP, aTransparentBitmap.getPixelFormat()); + { + BitmapScopedWriteAccess aWriteAccess(aTransparentBitmap); + aWriteAccess->Erase(COL_AUTO); + } + + BitmapEx aRedBitmapEx(aRedBitmap); + BitmapEx aGreenBitmapEx(aGreenBitmap); + BitmapEx aTransparentBitmapEx(aTransparentBitmap); + + // same color + { + BitmapScreenBlendFilter* pArithmeticFilter + = new BitmapScreenBlendFilter(aRedBitmapEx, aRedBitmapEx); + BitmapEx aResBitmapEx = pArithmeticFilter->execute(); + CPPUNIT_ASSERT_EQUAL(COL_LIGHTRED, aResBitmapEx.GetPixelColor(2, 2)); + } + + // different color + { + BitmapScreenBlendFilter* pArithmeticFilter + = new BitmapScreenBlendFilter(aRedBitmapEx, aGreenBitmapEx); + BitmapEx aResBitmapEx = pArithmeticFilter->execute(); + CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xFF, 0xFF, 0x80, 0x00), + aResBitmapEx.GetPixelColor(2, 2)); + } + + // transparent + { + BitmapScreenBlendFilter* pArithmeticFilter + = new BitmapScreenBlendFilter(aRedBitmapEx, aTransparentBitmapEx); + BitmapEx aResBitmapEx = pArithmeticFilter->execute(); + CPPUNIT_ASSERT_EQUAL(Color(ColorAlpha, 0xFF, 0xFF, 0xFF, 0xFF), + aResBitmapEx.GetPixelColor(2, 2)); + } +} + } // namespace CPPUNIT_TEST_SUITE_REGISTRATION(BitmapFilterTest); diff --git a/vcl/source/bitmap/BitmapScreenBlendFilter.cxx b/vcl/source/bitmap/BitmapScreenBlendFilter.cxx new file mode 100644 index 000000000000..67525a24cdf9 --- /dev/null +++ b/vcl/source/bitmap/BitmapScreenBlendFilter.cxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <comphelper/diagnose_ex.hxx> +#include <vcl/BitmapScreenBlendFilter.hxx> +#include <vcl/BitmapWriteAccess.hxx> +#include <vcl/BitmapTools.hxx> + +BitmapScreenBlendFilter::BitmapScreenBlendFilter(BitmapEx const& rBitmapEx, + BitmapEx const& rBitmapEx2) + : maBitmapEx(rBitmapEx) + , maBitmapEx2(rBitmapEx2) +{ +} + +BitmapScreenBlendFilter::~BitmapScreenBlendFilter() {} + +static sal_uInt8 lcl_calculate(const sal_uInt8 aColor, const sal_uInt8 aColor2) +{ + const double c1 = aColor / 255.0; + const double c2 = aColor2 / 255.0; + const double result = c2 + c1 - c1 * c2; + return result * 255.0; +} + +BitmapEx BitmapScreenBlendFilter::execute() +{ + if (maBitmapEx.IsEmpty() || maBitmapEx2.IsEmpty()) + return BitmapEx(); + + Size aSize = maBitmapEx.GetBitmap().GetSizePixel(); + Size aSize2 = maBitmapEx2.GetBitmap().GetSizePixel(); + sal_Int32 nHeight = std::min(aSize.getHeight(), aSize2.getHeight()); + sal_Int32 nWidth = std::min(aSize.getWidth(), aSize2.getWidth()); + + BitmapScopedReadAccess pReadAccess(maBitmapEx.GetBitmap()); + Bitmap aDstBitmap(Size(nWidth, nHeight), maBitmapEx.GetBitmap().getPixelFormat(), + &pReadAccess->GetPalette()); + Bitmap aDstAlpha(AlphaMask(Size(nWidth, nHeight)).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 (tools::Long y(0); y < nHeight; ++y) + { + Scanline pScanline = pWriteAccess->GetScanline(y); + Scanline pScanAlpha = pAlphaWriteAccess->GetScanline(y); + for (tools::Long x(0); x < nWidth; ++x) + { + BitmapColor i1 = maBitmapEx.GetPixelColor(x, y); + BitmapColor i2 = maBitmapEx2.GetPixelColor(x, y); + sal_uInt8 r(lcl_calculate(i1.GetRed(), i2.GetRed())); + sal_uInt8 g(lcl_calculate(i1.GetGreen(), i2.GetGreen())); + sal_uInt8 b(lcl_calculate(i1.GetBlue(), i2.GetBlue())); + sal_uInt8 a(lcl_calculate(i1.GetAlpha(), i2.GetAlpha())); + + pWriteAccess->SetPixelOnData(pScanline, x, BitmapColor(r, g, b)); + pAlphaWriteAccess->SetPixelOnData(pScanAlpha, x, BitmapColor(a)); + } + } + } + else + { + // TODO(E2): Error handling! + ENSURE_OR_THROW(false, "BitmapScreenBlendFilter: could not access bitmap"); + } + } + + return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/bitmap/BitmapTools.cxx b/vcl/source/bitmap/BitmapTools.cxx index 2330483bb98b..41f8ff38992c 100644 --- a/vcl/source/bitmap/BitmapTools.cxx +++ b/vcl/source/bitmap/BitmapTools.cxx @@ -512,6 +512,126 @@ BitmapEx CanvasTransformBitmap( const BitmapEx& rBitmap, return BitmapEx(aDstBitmap, AlphaMask(aDstAlpha)); } +BitmapEx DrawBitmapInRect( const BitmapEx& rBitmap, + ::basegfx::B2DRectangle const & rBitmapRect, + ::basegfx::B2DRectangle const & rDestRect ) +{ + if( rBitmapRect.isEmpty() || rDestRect.isEmpty() ) + return BitmapEx(); + + const Size aDestBmpSize( ::basegfx::fround( rDestRect.getWidth() ), + ::basegfx::fround( 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; + + if( !pReadAccess || (!pAlphaReadAccess && rBitmap.IsAlpha()) ) + { + // TODO(E2): Error handling! + ENSURE_OR_THROW( false, + "DrawBitmapInRect(): could not access source bitmap" ); + } + + // 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, aSrcBitmap.getPixelFormat(), &pReadAccess->GetPalette()); + 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) { @@ -644,7 +764,6 @@ void DrawAndClipBitmap(const Point& rPos, const Size& rSize, const BitmapEx& rBi } } - css::uno::Sequence< sal_Int8 > GetMaskDIB(BitmapEx const & aBmpEx) { if ( aBmpEx.IsAlpha() )