diff options
-rw-r--r-- | basegfx/source/color/bcolormodifier.cxx | 32 | ||||
-rwxr-xr-x | basegfx/test/BColorModifierTest.cxx | 85 | ||||
-rw-r--r-- | include/basegfx/color/bcolormodifier.hxx | 28 | ||||
-rw-r--r-- | svgio/inc/svgfecolormatrixnode.hxx | 3 | ||||
-rw-r--r-- | svgio/inc/svgtools.hxx | 2 | ||||
-rw-r--r-- | svgio/qa/cppunit/SvgImportTest.cxx | 8 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfecolormatrixnode.cxx | 13 | ||||
-rw-r--r-- | svgio/source/svgreader/svgtools.cxx | 34 |
8 files changed, 200 insertions, 5 deletions
diff --git a/basegfx/source/color/bcolormodifier.cxx b/basegfx/source/color/bcolormodifier.cxx index 8d6f99a3faf5..829b0abda659 100644 --- a/basegfx/source/color/bcolormodifier.cxx +++ b/basegfx/source/color/bcolormodifier.cxx @@ -142,6 +142,38 @@ namespace basegfx return "interpolate"; } + BColorModifier_matrix::~BColorModifier_matrix() + { + } + + bool BColorModifier_matrix::operator==(const BColorModifier& rCompare) const + { + const BColorModifier_matrix* pCompare = dynamic_cast< const BColorModifier_matrix* >(&rCompare); + + if(!pCompare) + { + return false; + } + + return maMatrix == pCompare->maMatrix; + } + + ::basegfx::BColor BColorModifier_matrix::getModifiedColor(const ::basegfx::BColor& aSourceColor) const + { + basegfx::B3DHomMatrix aColorMatrix; + aColorMatrix.set(0, 0, aSourceColor.getRed()); + aColorMatrix.set(1, 0, aSourceColor.getGreen()); + aColorMatrix.set(2, 0, aSourceColor.getBlue()); + + aColorMatrix = maMatrix * aColorMatrix; + return ::basegfx::BColor(aColorMatrix.get(0, 0), aColorMatrix.get(1, 0), aColorMatrix.get(2, 0)); + } + + OUString BColorModifier_matrix::getModifierName() const + { + return "matrix"; + } + BColorModifier_saturate::BColorModifier_saturate(double fValue) { maSatMatrix.set(0, 0, 0.213 + 0.787 * fValue); diff --git a/basegfx/test/BColorModifierTest.cxx b/basegfx/test/BColorModifierTest.cxx index d6e0648d2c17..17b6a0c22257 100755 --- a/basegfx/test/BColorModifierTest.cxx +++ b/basegfx/test/BColorModifierTest.cxx @@ -269,6 +269,89 @@ public: CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2)); } + void testMatrix() + { + // green matrix + basegfx::B3DHomMatrix aMatrix; + aMatrix.set(0, 0, 0.0); + aMatrix.set(0, 1, 0.0); + aMatrix.set(0, 2, 0.0); + aMatrix.set(0, 3, 0.0); + aMatrix.set(1, 0, 1.0); + aMatrix.set(1, 1, 1.0); + aMatrix.set(1, 2, 1.0); + aMatrix.set(1, 3, 1.0); + aMatrix.set(2, 0, 0.0); + aMatrix.set(2, 1, 0.0); + aMatrix.set(2, 2, 0.0); + aMatrix.set(2, 3, 0.0); + + const basegfx::BColorModifierSharedPtr aBColorModifier + = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix); + + BColor aExpectedWhite(0.0, 3.0, 0.0); + CPPUNIT_ASSERT_EQUAL(aExpectedWhite, aBColorModifier->getModifiedColor(maWhite)); + BColor aExpectedGray(0.0, 1.5, 0.0); + CPPUNIT_ASSERT_EQUAL(aExpectedGray, aBColorModifier->getModifiedColor(maGray)); + CPPUNIT_ASSERT_EQUAL(maBlack, aBColorModifier->getModifiedColor(maBlack)); + + CPPUNIT_ASSERT_EQUAL(maGreen, aBColorModifier->getModifiedColor(maRed)); + CPPUNIT_ASSERT_EQUAL(maGreen, aBColorModifier->getModifiedColor(maGreen)); + CPPUNIT_ASSERT_EQUAL(maGreen, aBColorModifier->getModifiedColor(maBlue)); + BColor aExpectedYellow(0.0, 2.0, 0.0); + CPPUNIT_ASSERT_EQUAL(aExpectedYellow, aBColorModifier->getModifiedColor(maYellow)); + BColor aExpectedMagenta = aExpectedYellow; + CPPUNIT_ASSERT_EQUAL(aExpectedMagenta, aBColorModifier->getModifiedColor(maMagenta)); + BColor aExpectedCyan = aExpectedYellow; + CPPUNIT_ASSERT_EQUAL(aExpectedCyan, aBColorModifier->getModifiedColor(maCyan)); + + CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier)); + const basegfx::BColorModifierSharedPtr aBColorModifierInvert + = std::make_shared<basegfx::BColorModifier_invert>(); + CPPUNIT_ASSERT(*aBColorModifier != *aBColorModifierInvert); + + const basegfx::BColorModifierSharedPtr aBColorModifier2 + = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix); + CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2)); + } + + void testIdentityMatrix() + { + basegfx::B3DHomMatrix aMatrix; + aMatrix.set(0, 0, 1.0); + aMatrix.set(0, 1, 0.0); + aMatrix.set(0, 2, 0.0); + aMatrix.set(1, 0, 0.0); + aMatrix.set(1, 1, 1.0); + aMatrix.set(1, 2, 0.0); + aMatrix.set(2, 0, 0.0); + aMatrix.set(2, 1, 0.0); + aMatrix.set(2, 2, 1.0); + + const basegfx::BColorModifierSharedPtr aBColorModifier + = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix); + + CPPUNIT_ASSERT_EQUAL(maWhite, aBColorModifier->getModifiedColor(maWhite)); + CPPUNIT_ASSERT_EQUAL(maGray, aBColorModifier->getModifiedColor(maGray)); + CPPUNIT_ASSERT_EQUAL(maBlack, aBColorModifier->getModifiedColor(maBlack)); + + CPPUNIT_ASSERT_EQUAL(maRed, aBColorModifier->getModifiedColor(maRed)); + CPPUNIT_ASSERT_EQUAL(maGreen, aBColorModifier->getModifiedColor(maGreen)); + CPPUNIT_ASSERT_EQUAL(maBlue, aBColorModifier->getModifiedColor(maBlue)); + CPPUNIT_ASSERT_EQUAL(maYellow, aBColorModifier->getModifiedColor(maYellow)); + CPPUNIT_ASSERT_EQUAL(maMagenta, aBColorModifier->getModifiedColor(maMagenta)); + CPPUNIT_ASSERT_EQUAL(maCyan, aBColorModifier->getModifiedColor(maCyan)); + + CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier)); + const basegfx::BColorModifierSharedPtr aBColorModifierInvert + = std::make_shared<basegfx::BColorModifier_invert>(); + CPPUNIT_ASSERT(*aBColorModifier != *aBColorModifierInvert); + + const basegfx::BColorModifierSharedPtr aBColorModifier2 + = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix); + CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2)); + } + CPPUNIT_TEST_SUITE(bcolormodifier); CPPUNIT_TEST(testGray); CPPUNIT_TEST(testInvert); @@ -277,6 +360,8 @@ public: CPPUNIT_TEST(testSaturate); CPPUNIT_TEST(testLuminanceToAlpha); CPPUNIT_TEST(testHueRotate); + CPPUNIT_TEST(testMatrix); + CPPUNIT_TEST(testIdentityMatrix); CPPUNIT_TEST_SUITE_END(); }; diff --git a/include/basegfx/color/bcolormodifier.hxx b/include/basegfx/color/bcolormodifier.hxx index 5a3ca0a78adf..ceffae841847 100644 --- a/include/basegfx/color/bcolormodifier.hxx +++ b/include/basegfx/color/bcolormodifier.hxx @@ -21,6 +21,7 @@ #include <config_options.h> #include <basegfx/basegfxdllapi.h> +#include <basegfx/matrix/b3dhommatrix.hxx> #include <basegfx/color/bcolor.hxx> #include <basegfx/matrix/b3dhommatrix.hxx> #include <rtl/ustring.hxx> @@ -236,6 +237,33 @@ namespace basegfx SAL_DLLPRIVATE virtual OUString getModifierName() const override; }; + /** Apply matrix + This derivation is used for the svg importer and does exactly what SVG + defines for this needed case. + + See: + https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_matrix final : public BColorModifier + { + private: + basegfx::B3DHomMatrix maMatrix; + + public: + BColorModifier_matrix(basegfx::B3DHomMatrix aMatrix) + : maMatrix(aMatrix) + { + } + + virtual ~BColorModifier_matrix() override; + + // compare operator + SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) const override; + // compute modified color + SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const ::basegfx::BColor& aSourceColor) const override; + SAL_DLLPRIVATE virtual OUString getModifierName() const override; + }; + /** Apply hueRotate This derivation is used for the svg importer and does exactly what SVG defines for this needed case. diff --git a/svgio/inc/svgfecolormatrixnode.hxx b/svgio/inc/svgfecolormatrixnode.hxx index a63d44715457..78d8b027f653 100644 --- a/svgio/inc/svgfecolormatrixnode.hxx +++ b/svgio/inc/svgfecolormatrixnode.hxx @@ -21,7 +21,7 @@ #include "svgnode.hxx" #include "svgstyleattributes.hxx" -#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> namespace svgio::svgreader { @@ -29,6 +29,7 @@ enum class ColorType { None, HueRotate, + Matrix, Saturate, LuminanceToAlpha }; diff --git a/svgio/inc/svgtools.hxx b/svgio/inc/svgtools.hxx index fd9bdd396d9d..1bca409001b6 100644 --- a/svgio/inc/svgtools.hxx +++ b/svgio/inc/svgtools.hxx @@ -20,6 +20,7 @@ #pragma once #include <basegfx/color/bcolor.hxx> +#include <basegfx/range/b3drange.hxx> #include <basegfx/range/b2drange.hxx> #include <basegfx/vector/b2ivector.hxx> #include <rtl/ustrbuf.hxx> @@ -109,6 +110,7 @@ namespace svgio::svgreader bool match_colorKeyword(basegfx::BColor& rColor, const OUString& rName); bool read_color(const OUString& rCandidate, basegfx::BColor& rColor, SvgNumber& rOpacity); basegfx::B2DRange readViewBox(std::u16string_view rCandidate, InfoProvider const & rInfoProvider); + basegfx::B3DHomMatrix readFilterMatrix(std::u16string_view rCandidate, InfoProvider const & rInfoProvider); basegfx::B2DHomMatrix readTransform(std::u16string_view rCandidate, InfoProvider const & rInfoProvider); bool readSingleNumber(std::u16string_view rCandidate, SvgNumber& aNum); bool readLocalLink(std::u16string_view rCandidate, OUString& rURL); diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index 87beb7742405..df1337090ff3 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -163,10 +163,10 @@ CPPUNIT_TEST_FIXTURE(Test, testFeColorMatrix) CPPUNIT_ASSERT (pDocument); - //assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor", "modifier", "matrix"); - assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[1]", "modifier", "saturate"); - assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", "modifier", "hueRotate"); - assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[3]", "modifier", "luminance_to_alpha"); + assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[1]", "modifier", "matrix"); + assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", "modifier", "saturate"); + assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[3]", "modifier", "hueRotate"); + assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[4]", "modifier", "luminance_to_alpha"); } CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur) diff --git a/svgio/source/svgreader/svgfecolormatrixnode.cxx b/svgio/source/svgreader/svgfecolormatrixnode.cxx index 42611e48efdd..5f8e03c4318b 100644 --- a/svgio/source/svgreader/svgfecolormatrixnode.cxx +++ b/svgio/source/svgreader/svgfecolormatrixnode.cxx @@ -53,6 +53,10 @@ void SvgFeColorMatrixNode::parseAttribute(const OUString& /*rTokenName*/, SVGTok { maType = ColorType::HueRotate; } + else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"matrix")) + { + maType = ColorType::Matrix; + } } break; } @@ -99,6 +103,15 @@ void SvgFeColorMatrixNode::apply(drawinglayer::primitive2d::Primitive2DContainer basegfx::deg2rad(aNum.getNumber())))); rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; } + else if (maType == ColorType::Matrix) + { + basegfx::B3DHomMatrix aMatrix = readFilterMatrix(maValuesContent, *this); + + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + std::move(rTarget), std::make_shared<basegfx::BColorModifier_matrix>(aMatrix))); + rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; + } } } // end of namespace svgio::svgreader diff --git a/svgio/source/svgreader/svgtools.cxx b/svgio/source/svgreader/svgtools.cxx index af10626af3ad..f885086497c1 100644 --- a/svgio/source/svgreader/svgtools.cxx +++ b/svgio/source/svgreader/svgtools.cxx @@ -24,6 +24,7 @@ #include <o3tl/string_view.hxx> #include <basegfx/matrix/b2dhommatrix.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/matrix/b3dhommatrix.hxx> #include <svgtoken.hxx> #include <unordered_map> @@ -844,6 +845,39 @@ namespace svgio::svgreader return basegfx::B2DRange(); } + basegfx::B3DHomMatrix readFilterMatrix(std::u16string_view rCandidate, InfoProvider const & rInfoProvider) + { + basegfx::B3DHomMatrix aMatrix; + const sal_Int32 nLen(rCandidate.size()); + + sal_Int32 nPos(0); + skip_char(rCandidate, ' ', ',', nPos, nLen); + + SvgNumber aVal; + + // create a 3x5 matrix using the first 15 values from the list of 20 matrix values. + // FIXME: support alpha (the last 5 values) + for (sal_uInt16 nRow = 0; nRow < 3; ++nRow) + { + for (sal_uInt16 nColumn = 0; nColumn < 5; ++nColumn) + { + // return earlier if there are not enough values + if (nPos >= nLen) + { + return basegfx::B3DHomMatrix(); + } + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aMatrix.set(nRow, nColumn, aVal.solve(rInfoProvider)); + skip_char(rCandidate, ' ', ',', nPos, nLen); + } + } + } + + return aMatrix; + } + basegfx::B2DHomMatrix readTransform(std::u16string_view rCandidate, InfoProvider const & rInfoProvider) { basegfx::B2DHomMatrix aMatrix; |