basegfx/source/color/bcolormodifier.cxx | 51 ++++++++++++++++++++++++ basegfx/test/BColorModifierTest.cxx | 33 +++++++++++++++ include/basegfx/color/bcolormodifier.hxx | 25 +++++++++++ svgio/inc/svgfecolormatrixnode.hxx | 3 - svgio/qa/cppunit/SvgImportTest.cxx | 4 - svgio/source/svgreader/svgfecolormatrixnode.cxx | 27 ++++++++---- 6 files changed, 132 insertions(+), 11 deletions(-)
New commits: commit a62513e1e80e39f9928e9e1815a84761403a4f2b Author: Xisco Fauli <xiscofa...@libreoffice.org> AuthorDate: Thu Jun 15 12:19:39 2023 +0200 Commit: Xisco Fauli <xiscofa...@libreoffice.org> CommitDate: Thu Jun 22 08:23:53 2023 +0200 tdf#155735: Add support for hueRotate type Change-Id: I9c7ada2908c0739708fbc9e28ac58430350da7a9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153112 Tested-by: Jenkins Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/basegfx/source/color/bcolormodifier.cxx b/basegfx/source/color/bcolormodifier.cxx index 480af66e7588..8d6f99a3faf5 100644 --- a/basegfx/source/color/bcolormodifier.cxx +++ b/basegfx/source/color/bcolormodifier.cxx @@ -187,6 +187,57 @@ namespace basegfx return "saturate"; } + BColorModifier_hueRotate::BColorModifier_hueRotate(double fRad) + { + const double fCos = cos(fRad); + const double fSin = sin(fRad); + + maHueMatrix.set(0, 0, 0.213 + fCos * 0.787 - fSin * 0.213); + maHueMatrix.set(0, 1, 0.715 - fCos * 0.715 - fSin * 0.715); + maHueMatrix.set(0, 2, 0.072 - fCos * 0.072 + fSin * 0.928); + maHueMatrix.set(1, 0, 0.213 - fCos * 0.213 + fSin * 0.143); + maHueMatrix.set(1, 1, 0.715 + fCos * 0.285 + fSin * 0.140); + maHueMatrix.set(1, 2, 0.072 - fCos * 0.072 - fSin * 0.283); + maHueMatrix.set(2, 0, 0.213 - fCos * 0.213 - fSin * 0.787); + maHueMatrix.set(2, 1, 0.715 - fCos * 0.715 + fSin * 0.715); + maHueMatrix.set(2, 2, 0.072 + fCos * 0.928 + fSin * 0.072); + } + + BColorModifier_hueRotate::~BColorModifier_hueRotate() + { + } + + bool BColorModifier_hueRotate::operator==(const BColorModifier& rCompare) const + { + const BColorModifier_hueRotate* pCompare = dynamic_cast< const BColorModifier_hueRotate* >(&rCompare); + + if(!pCompare) + { + return false; + } + + return maHueMatrix == pCompare->maHueMatrix; + } + + ::basegfx::BColor BColorModifier_hueRotate::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 = maHueMatrix * aColorMatrix; + return ::basegfx::BColor( + std::clamp(aColorMatrix.get(0, 0), 0.0, 1.0), + std::clamp(aColorMatrix.get(1, 0), 0.0, 1.0), + std::clamp(aColorMatrix.get(2, 0), 0.0, 1.0)); + } + + OUString BColorModifier_hueRotate::getModifierName() const + { + return "hueRotate"; + } + BColorModifier_black_and_white::~BColorModifier_black_and_white() { } diff --git a/basegfx/test/BColorModifierTest.cxx b/basegfx/test/BColorModifierTest.cxx index 053540018206..d6e0648d2c17 100755 --- a/basegfx/test/BColorModifierTest.cxx +++ b/basegfx/test/BColorModifierTest.cxx @@ -237,6 +237,38 @@ public: CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2)); } + void testHueRotate() + { + const basegfx::BColorModifierSharedPtr aBColorModifier + = std::make_shared<basegfx::BColorModifier_hueRotate>(basegfx::deg2rad(180.0)); + + CPPUNIT_ASSERT_EQUAL(maWhite, aBColorModifier->getModifiedColor(maWhite)); + CPPUNIT_ASSERT_EQUAL(maGray, aBColorModifier->getModifiedColor(maGray)); + CPPUNIT_ASSERT_EQUAL(maBlack, aBColorModifier->getModifiedColor(maBlack)); + + BColor aExpectedRed(0.0, 0.426, 0.426); + CPPUNIT_ASSERT_EQUAL(aExpectedRed, aBColorModifier->getModifiedColor(maRed)); + BColor aExpectedGreen(1.0, 0.43, 1.0); + CPPUNIT_ASSERT_EQUAL(aExpectedGreen, aBColorModifier->getModifiedColor(maGreen)); + BColor aExpectedBlue(0.144, 0.144, 0); + CPPUNIT_ASSERT_EQUAL(aExpectedBlue, aBColorModifier->getModifiedColor(maBlue)); + BColor aExpectedYellow(0.856, 0.856, 1.0); + CPPUNIT_ASSERT_EQUAL(aExpectedYellow, aBColorModifier->getModifiedColor(maYellow)); + BColor aExpectedMagenta(0.0, 0.57, 0.0); + CPPUNIT_ASSERT_EQUAL(aExpectedMagenta, aBColorModifier->getModifiedColor(maMagenta)); + BColor aExpectedCyan(1.0, 0.574, 0.574); + 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_hueRotate>(basegfx::deg2rad(180.0)); + CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2)); + } + CPPUNIT_TEST_SUITE(bcolormodifier); CPPUNIT_TEST(testGray); CPPUNIT_TEST(testInvert); @@ -244,6 +276,7 @@ public: CPPUNIT_TEST(testStack); CPPUNIT_TEST(testSaturate); CPPUNIT_TEST(testLuminanceToAlpha); + CPPUNIT_TEST(testHueRotate); CPPUNIT_TEST_SUITE_END(); }; diff --git a/include/basegfx/color/bcolormodifier.hxx b/include/basegfx/color/bcolormodifier.hxx index c8fe3a2a88b4..5a3ca0a78adf 100644 --- a/include/basegfx/color/bcolormodifier.hxx +++ b/include/basegfx/color/bcolormodifier.hxx @@ -236,6 +236,31 @@ namespace basegfx 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. + + See: + https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_hueRotate final : public BColorModifier + { + private: + basegfx::B3DHomMatrix maHueMatrix; + + public: + BColorModifier_hueRotate(double fRad); + + virtual ~BColorModifier_hueRotate() 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; + }; + /** convert color to black and white returns black when the luminance of the given color is less than diff --git a/svgio/inc/svgfecolormatrixnode.hxx b/svgio/inc/svgfecolormatrixnode.hxx index 631da8877372..a63d44715457 100644 --- a/svgio/inc/svgfecolormatrixnode.hxx +++ b/svgio/inc/svgfecolormatrixnode.hxx @@ -28,6 +28,7 @@ namespace svgio::svgreader enum class ColorType { None, + HueRotate, Saturate, LuminanceToAlpha }; @@ -36,7 +37,7 @@ class SvgFeColorMatrixNode final : public SvgNode { private: ColorType maType; - SvgNumber maValues; + OUString maValuesContent; public: SvgFeColorMatrixNode(SvgDocument& rDocument, SvgNode* pParent); diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index 87c99ba72509..87beb7742405 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -165,8 +165,8 @@ CPPUNIT_TEST_FIXTURE(Test, testFeColorMatrix) //assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor", "modifier", "matrix"); assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[1]", "modifier", "saturate"); - //assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor", "modifier", "hueRotate"); - assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", "modifier", "luminance_to_alpha"); + assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", "modifier", "hueRotate"); + assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[3]", "modifier", "luminance_to_alpha"); } CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur) diff --git a/svgio/source/svgreader/svgfecolormatrixnode.cxx b/svgio/source/svgreader/svgfecolormatrixnode.cxx index 2a02ddc3c0bd..42611e48efdd 100644 --- a/svgio/source/svgreader/svgfecolormatrixnode.cxx +++ b/svgio/source/svgreader/svgfecolormatrixnode.cxx @@ -26,7 +26,6 @@ namespace svgio::svgreader SvgFeColorMatrixNode::SvgFeColorMatrixNode(SvgDocument& rDocument, SvgNode* pParent) : SvgNode(SVGToken::FeColorMatrix, rDocument, pParent) , maType(ColorType::None) - , maValues(1.0) { } @@ -50,17 +49,16 @@ void SvgFeColorMatrixNode::parseAttribute(const OUString& /*rTokenName*/, SVGTok { maType = ColorType::Saturate; } + else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"hueRotate")) + { + maType = ColorType::HueRotate; + } } break; } case SVGToken::Values: { - SvgNumber aNum; - - if (readSingleNumber(aContent, aNum)) - { - maValues = aNum; - } + maValuesContent = aContent; break; } default: @@ -82,10 +80,23 @@ void SvgFeColorMatrixNode::apply(drawinglayer::primitive2d::Primitive2DContainer } else if (maType == ColorType::Saturate) { + SvgNumber aNum(1.0); + readSingleNumber(maValuesContent, aNum); + const drawinglayer::primitive2d::Primitive2DReference xRef( new drawinglayer::primitive2d::ModifiedColorPrimitive2D( std::move(rTarget), - std::make_shared<basegfx::BColorModifier_saturate>(maValues.getNumber()))); + std::make_shared<basegfx::BColorModifier_saturate>(aNum.getNumber()))); + rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; + } + else if (maType == ColorType::HueRotate) + { + SvgNumber aNum(0.0); + readSingleNumber(maValuesContent, aNum); + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + std::move(rTarget), std::make_shared<basegfx::BColorModifier_hueRotate>( + basegfx::deg2rad(aNum.getNumber())))); rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef }; } }