include/tools/color.hxx         |    8 ++++++++
 tools/qa/cppunit/test_color.cxx |   13 +++++++++++++
 tools/source/generic/color.cxx  |   32 ++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)

New commits:
commit 8662293d17a875f4389ea21be00e768e3de3d048
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Nov 29 08:28:28 2021 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Nov 29 09:51:16 2021 +0100

    tools Color: implement MSO-style luminance modulation/offset filter
    
    To be used when a filtered theme color will be applied on the UI, and
    not at PPTX import time.
    
    Change-Id: Ifb56e38e59b529ef436063c407ee156d76a77f9c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126011
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/include/tools/color.hxx b/include/tools/color.hxx
index a34b55863701..6ab0fa3ba67d 100644
--- a/include/tools/color.hxx
+++ b/include/tools/color.hxx
@@ -335,6 +335,14 @@ public:
      **/
     void ApplyTintOrShade(sal_Int16 n100thPercent);
 
+    /**
+     * Apply luminance offset and/or modulation.
+     *
+     * The input values are in percentages (in 100th percents). 100% 
modulation and 0% offset
+     * results in no change.
+     */
+    void ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff);
+
     /** Inverts color. 1 and 0 are switched.
       * Note that the result will be the complementary color.
       * For example, if you have red, you will get cyan: FF0000 -> 00FFFF.
diff --git a/tools/qa/cppunit/test_color.cxx b/tools/qa/cppunit/test_color.cxx
index f3ffd9c692cd..3dd4225cb20f 100644
--- a/tools/qa/cppunit/test_color.cxx
+++ b/tools/qa/cppunit/test_color.cxx
@@ -22,6 +22,7 @@ public:
     void testVariables();
     void test_asRGBColor();
     void test_ApplyTintOrShade();
+    void test_ApplyLumModOff();
     void testGetColorError();
     void testInvert();
     void testBColor();
@@ -31,6 +32,7 @@ public:
     CPPUNIT_TEST(testVariables);
     CPPUNIT_TEST(test_asRGBColor);
     CPPUNIT_TEST(test_ApplyTintOrShade);
+    CPPUNIT_TEST(test_ApplyLumModOff);
     CPPUNIT_TEST(testGetColorError);
     CPPUNIT_TEST(testInvert);
     CPPUNIT_TEST(testBColor);
@@ -163,6 +165,17 @@ void Test::test_ApplyTintOrShade()
     CPPUNIT_ASSERT_EQUAL(OUString("000000"), createTintShade(0x80, 0x80, 0x80, 
u"808080", -10000));
 }
 
+void Test::test_ApplyLumModOff()
+{
+    // Kind of blue.
+    Color aColor(0x44, 0x72, 0xC4);
+
+    // PowerPoint calls this "Ligher 40%".
+    aColor.ApplyLumModOff(6000, 4000);
+
+    CPPUNIT_ASSERT_EQUAL(OUString("8faadc"), aColor.AsRGBHexString());
+}
+
 void Test::testGetColorError()
 {
     CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), Color(0xAA, 0xBB, 
0xCC).GetColorError(Color(0xAA, 0xBB, 0xCC)));
diff --git a/tools/source/generic/color.cxx b/tools/source/generic/color.cxx
index cf4e084b722f..5df32719eb2c 100644
--- a/tools/source/generic/color.cxx
+++ b/tools/source/generic/color.cxx
@@ -230,4 +230,36 @@ void Color::ApplyTintOrShade(sal_Int16 n100thPercent)
     B = sal_uInt8(std::lround(aBColor.getBlue()  * 255.0));
 }
 
+void Color::ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff)
+{
+    if (nMod == 10000 && nOff == 0)
+    {
+        return;
+    }
+    // Switch to HSL, where applying these transforms is easier.
+    basegfx::BColor aBColor = basegfx::utils::rgb2hsl(getBColor());
+
+    // 50% is half luminance, 200% is double luminance. Unit is 100th percent.
+    aBColor.setBlue(std::clamp(aBColor.getBlue() * nMod / 10000, 0.0, 1.0));
+    // If color changes to black or white, it will stay gray if luminance 
changes again.
+    if ((aBColor.getBlue() == 0.0) || (aBColor.getBlue() == 1.0))
+    {
+        aBColor.setGreen(0.0);
+    }
+
+    // Luminance offset means hue and saturation is left unchanged. Unit is 
100th percent.
+    aBColor.setBlue(std::clamp(aBColor.getBlue() + static_cast<double>(nOff) / 
10000, 0.0, 1.0));
+    // If color changes to black or white, it will stay gray if luminance 
changes again.
+    if ((aBColor.getBlue() == 0.0) || (aBColor.getBlue() == 1.0))
+    {
+        aBColor.setGreen(0.0);
+    }
+
+    // Switch back to RGB.
+    aBColor = basegfx::utils::hsl2rgb(aBColor);
+    R = sal_uInt8(std::lround(aBColor.getRed()   * 255.0));
+    G = sal_uInt8(std::lround(aBColor.getGreen() * 255.0));
+    B = sal_uInt8(std::lround(aBColor.getBlue()  * 255.0));
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to