summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tools/color.hxx8
-rw-r--r--tools/qa/cppunit/test_color.cxx13
-rw-r--r--tools/source/generic/color.cxx32
3 files changed, 53 insertions, 0 deletions
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: */