From 2afdea17162731888ad8f09fae2bb50e4246d7e9 Mon Sep 17 00:00:00 2001 From: Bartosz Kosiorek Date: Fri, 2 Mar 2018 01:07:57 +0100 Subject: tdf#114738 Add support for transparency for EMF+ records With current EMF+ implementation all filled figures, does not support transparency. This patch add transparency support for following EMF+ records: - DrawDriverString - DrawString - FillEllipse - FillRects - FillPolygon - FillPie - FillPath - FillRegion Change-Id: I1e59ea90bdf5fafc07ff9417fccace44872bbecd Reviewed-on: https://gerrit.libreoffice.org/50609 Tested-by: Jenkins Reviewed-by: Bartosz Kosiorek --- drawinglayer/source/tools/emfphelperdata.cxx | 149 +++++++++++++++------ drawinglayer/source/tools/emfphelperdata.hxx | 4 +- emfio/qa/cppunit/emf/EmfImportTest.cxx | 26 ++++ .../cppunit/emf/data/TestDrawStringTransparent.emf | Bin 0 -> 480 bytes svgio/source/svgreader/svganode.cxx | 2 - svgio/source/svgreader/svggnode.cxx | 2 - 6 files changed, 138 insertions(+), 45 deletions(-) create mode 100644 emfio/qa/cppunit/emf/data/TestDrawStringTransparent.emf diff --git a/drawinglayer/source/tools/emfphelperdata.cxx b/drawinglayer/source/tools/emfphelperdata.cxx index 679a47c1a7f3..0afabe77302d 100644 --- a/drawinglayer/source/tools/emfphelperdata.cxx +++ b/drawinglayer/source/tools/emfphelperdata.cxx @@ -27,8 +27,8 @@ #include "emfpstringformat.hxx" #include #include +#include #include -#include #include #include #include @@ -300,19 +300,19 @@ namespace emfplushelper return maMapTransform * ::basegfx::B2DSize(iwidth, iheight); } - ::basegfx::BColor EmfPlusHelperData::EMFPGetBrushColorOrARGBColor(sal_uInt16 flags, sal_uInt32 brushIndexOrColor) const { - basegfx::BColor color; + Color EmfPlusHelperData::EMFPGetBrushColorOrARGBColor(const sal_uInt16 flags, const sal_uInt32 brushIndexOrColor) const { + Color color; if (flags & 0x8000) // we use a color { color = Color(0xff - (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, - (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff).getBColor(); + (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff); } else // we use a pen { const EMFPPen* pen = static_cast(maEMFPObjects[brushIndexOrColor & 0xff].get()); if (pen) { - color = pen->GetColor().getBColor(); + color = pen->GetColor(); } } return color; @@ -452,7 +452,7 @@ namespace emfplushelper } } - void EmfPlusHelperData::EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, bool isColor, sal_uInt32 brushIndexOrColor) + void EmfPlusHelperData::EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, const bool isColor, const sal_uInt32 brushIndexOrColor) { if (!polygon.count()) return; @@ -460,12 +460,35 @@ namespace emfplushelper if (isColor) // use Color { SAL_INFO("drawinglayer", "EMF+\t Fill polygon, ARGB color: 0x" << std::hex << brushIndexOrColor << std::dec); - mrTargetHolders.Current().append( - o3tl::make_unique( - polygon, - ::Color(0xff - (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff).getBColor())); - mrPropertyHolders.Current().setFillColor(::Color(0xff - (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff).getBColor()); + // EMF Alpha (1 byte): An 8-bit unsigned integer that specifies the transparency of the background, + // ranging from 0 for completely transparent to 0xFF for completely opaque. + const Color color = Color(0xff - (brushIndexOrColor >> 24), (brushIndexOrColor >> 16) & 0xff, (brushIndexOrColor >> 8) & 0xff, brushIndexOrColor & 0xff); + if (color.GetTransparency() < 255) + { + if (color.GetTransparency() == 0) + { + // not transparent + mrTargetHolders.Current().append( + o3tl::make_unique( + polygon, + color.getBColor())); + } + else + { + const drawinglayer::primitive2d::Primitive2DReference aPrimitive( + new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + polygon, + color.getBColor())); + + mrTargetHolders.Current().append( + o3tl::make_unique( + drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }, + color.GetTransparency() / 255.0)); + } + } + + mrPropertyHolders.Current().setFillColor(color.getBColor()); mrPropertyHolders.Current().setFillColorActive(true); mrPropertyHolders.Current().setLineColorActive(false); } @@ -507,7 +530,7 @@ namespace emfplushelper isHatchBlend = false; break; } - ::Color fillColor; + Color fillColor; if (isHatchBlend) { fillColor = brush->solidColor; @@ -1267,27 +1290,52 @@ namespace emfplushelper else { // use system default - locale = Application::GetSettings().GetLanguageTag().getLocale(); + locale = Application::GetSettings().GetLanguageTag().getLocale(); } basegfx::B2DHomMatrix transformMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(MapSize(font->emSize,font->emSize),Map(lx,ly+font->emSize)); - basegfx::BColor color = EMFPGetBrushColorOrARGBColor(flags,brushId); + const Color color = EMFPGetBrushColorOrARGBColor(flags, brushId); - mrPropertyHolders.Current().setTextColor(color); + mrPropertyHolders.Current().setTextColor(color.getBColor()); mrPropertyHolders.Current().setTextColorActive(true); - std::vector emptyVector; - mrTargetHolders.Current().append( - o3tl::make_unique( - transformMatrix, - text, - 0, // text always starts at 0 - stringLength, - emptyVector, // EMF-PLUS has no DX-array - fontAttribute, - locale, - color)); + if (color.GetTransparency() < 255) + { + std::vector emptyVector; + if (color.GetTransparency() == 0) + { + // not transparent + mrTargetHolders.Current().append( + o3tl::make_unique( + transformMatrix, + text, + 0, // text always starts at 0 + stringLength, + emptyVector, // EMF-PLUS has no DX-array + fontAttribute, + locale, + color.getBColor())); + } + else + { + const drawinglayer::primitive2d::Primitive2DReference aPrimitive( + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + transformMatrix, + text, + 0, // text always starts at 0 + stringLength, + emptyVector, // EMF-PLUS has no DX-array + fontAttribute, + locale, + color.getBColor())); + + mrTargetHolders.Current().append( + o3tl::make_unique( + drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }, + color.GetTransparency() / 255.0)); + } + } } else { @@ -1641,7 +1689,7 @@ namespace emfplushelper false, // right-to-left false); // BiDiStrong - basegfx::BColor color = EMFPGetBrushColorOrARGBColor(flags,brushIndexOrColor); + const Color color = EMFPGetBrushColorOrARGBColor(flags, brushIndexOrColor); std::vector aDXArray; // dummy for DX array (not used) // generate TextSimplePortionPrimitive2Ds for all portions of text with @@ -1669,18 +1717,41 @@ namespace emfplushelper MapSize(font->emSize,font->emSize),Map(charsPosX[pos],charsPosY[pos])); if (hasMatrix) transformMatrix *= transform; - - //generate TextSimplePortionPrimitive2D - mrTargetHolders.Current().append( - o3tl::make_unique( - transformMatrix, - text, - pos, // take character at current pos - aLength, // use determined length - aDXArray, // generated DXArray - fontAttribute, - Application::GetSettings().GetLanguageTag().getLocale(), - color)); + if (color.GetTransparency() < 255) + { + if (color.GetTransparency() == 0) + { + // not transparent + mrTargetHolders.Current().append( + o3tl::make_unique( + transformMatrix, + text, + pos, // take character at current pos + aLength, // use determined length + aDXArray, // generated DXArray + fontAttribute, + Application::GetSettings().GetLanguageTag().getLocale(), + color.getBColor())); + } + else + { + const drawinglayer::primitive2d::Primitive2DReference aPrimitive( + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + transformMatrix, + text, + pos, // take character at current pos + aLength, // use determined length + aDXArray, // generated DXArray + fontAttribute, + Application::GetSettings().GetLanguageTag().getLocale(), + color.getBColor())); + + mrTargetHolders.Current().append( + o3tl::make_unique( + drawinglayer::primitive2d::Primitive2DContainer { aPrimitive }, + color.GetTransparency() / 255.0)); + } + } // update pos pos += aLength; diff --git a/drawinglayer/source/tools/emfphelperdata.hxx b/drawinglayer/source/tools/emfphelperdata.hxx index 729835307633..ba58686088f9 100644 --- a/drawinglayer/source/tools/emfphelperdata.hxx +++ b/drawinglayer/source/tools/emfphelperdata.hxx @@ -237,10 +237,10 @@ namespace emfplushelper // primitive creators void EMFPPlusDrawPolygon(const ::basegfx::B2DPolyPolygon& polygon, sal_uInt32 penIndex); - void EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, bool isColor, sal_uInt32 brushIndexOrColor); + void EMFPPlusFillPolygon(const ::basegfx::B2DPolyPolygon& polygon, const bool isColor, const sal_uInt32 brushIndexOrColor); // helper functions - ::basegfx::BColor EMFPGetBrushColorOrARGBColor(sal_uInt16 flags, sal_uInt32 brushIndexOrColor) const; + Color EMFPGetBrushColorOrARGBColor(const sal_uInt16 flags, const sal_uInt32 brushIndexOrColor) const; public: EmfPlusHelperData( diff --git a/emfio/qa/cppunit/emf/EmfImportTest.cxx b/emfio/qa/cppunit/emf/EmfImportTest.cxx index 2c1cad733f06..49c7abde157f 100644 --- a/emfio/qa/cppunit/emf/EmfImportTest.cxx +++ b/emfio/qa/cppunit/emf/EmfImportTest.cxx @@ -39,6 +39,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools void testWorking(); void TestDrawString(); + void TestDrawStringTransparent(); void TestDrawLine(); Primitive2DSequence parseEmf(const OUString& aSource); @@ -47,6 +48,7 @@ public: CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(testWorking); CPPUNIT_TEST(TestDrawString); + CPPUNIT_TEST(TestDrawStringTransparent); CPPUNIT_TEST(TestDrawLine); CPPUNIT_TEST_SUITE_END(); }; @@ -112,6 +114,30 @@ void Test::TestDrawString() assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "familyname", "CALIBRI"); } +void Test::TestDrawStringTransparent() +{ + // This unit checks for a correct import of an EMF+ file with one DrawString Record with transparency + + // first, get the sequence of primitives and dump it + Primitive2DSequence aSequence = parseEmf("/emfio/qa/cppunit/emf/data/TestDrawStringTransparent.emf"); + CPPUNIT_ASSERT_EQUAL(1, static_cast(aSequence.getLength())); + Primitive2dXmlDump dumper; + xmlDocPtr pDocument = dumper.dumpAndParse(comphelper::sequenceToContainer(aSequence)); + CPPUNIT_ASSERT (pDocument); + + //TODO Strange that transparency is set to 0 even if it is not fully transparent + // check correct import of the DrawString: transparency, height, position, text, color and font + assertXPath(pDocument, "/primitive2D/metafile/transform/unifiedtransparence", "transparence", "0"); + + //TODO Where was textsimpleportion gone? + //assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "height", "276"); + //assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "x", "25"); + //assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "y", "323"); + //assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "text", "Transparent Text"); + //assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "fontcolor", "#000000"); + //assertXPath(pDocument, "/primitive2D/metafile/transform/textsimpleportion", "familyname", "CALIBRI"); +} + void Test::TestDrawLine() { // This unit checks for a correct import of an EMF+ file with only one DrawLine Record diff --git a/emfio/qa/cppunit/emf/data/TestDrawStringTransparent.emf b/emfio/qa/cppunit/emf/data/TestDrawStringTransparent.emf new file mode 100644 index 000000000000..73954c4902c7 Binary files /dev/null and b/emfio/qa/cppunit/emf/data/TestDrawStringTransparent.emf differ diff --git a/svgio/source/svgreader/svganode.cxx b/svgio/source/svgreader/svganode.cxx index 8c53d8d660bb..46dd237ca637 100644 --- a/svgio/source/svgreader/svganode.cxx +++ b/svgio/source/svgreader/svganode.cxx @@ -18,8 +18,6 @@ */ #include -#include -#include namespace svgio { diff --git a/svgio/source/svgreader/svggnode.cxx b/svgio/source/svgreader/svggnode.cxx index 28a4ece8607b..d7e0ebcee5f2 100644 --- a/svgio/source/svgreader/svggnode.cxx +++ b/svgio/source/svgreader/svggnode.cxx @@ -18,8 +18,6 @@ */ #include -#include -#include namespace svgio { -- cgit