summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2019-04-20 11:06:11 +0900
committerTomaž Vajngerl <quikee@gmail.com>2019-04-21 14:20:19 +0200
commitd487d6e082bc7ce652217578ffd37397a59cc3ca (patch)
treec6498c4b2f4cb042013547d32a8ad98a30c238d5 /tools
parentd077b19a3f617f5ef3d65fc20a136a9107c47199 (diff)
rework Color to have R,G,B,A public variables
Color is a wrapper around a sal_uInt32 variable. With a union, separate channels R, G, B, A sal_uInt8 variables can be added that occupy the same memory. This makes it much easier to access each color component separately, which is used quite a lot by various algorithms. This also adds the variables to public so everyone can enjoy the benefits. Tests have been extended to make sure this doesn't break the existing algroithms. Change-Id: I2e78e12df68e8c7f0f49420eef5e659b335ee397 Reviewed-on: https://gerrit.libreoffice.org/71002 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/CppunitTest_tools_test.mk1
-rw-r--r--tools/qa/cppunit/test_color.cxx124
-rw-r--r--tools/source/generic/color.cxx50
3 files changed, 150 insertions, 25 deletions
diff --git a/tools/CppunitTest_tools_test.mk b/tools/CppunitTest_tools_test.mk
index 3971606c9a9d..ad56d893ae80 100644
--- a/tools/CppunitTest_tools_test.mk
+++ b/tools/CppunitTest_tools_test.mk
@@ -34,6 +34,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,tools_test, \
$(eval $(call gb_CppunitTest_use_sdk_api,tools_test))
$(eval $(call gb_CppunitTest_use_libraries,tools_test, \
+ basegfx \
sal \
tl \
test \
diff --git a/tools/qa/cppunit/test_color.cxx b/tools/qa/cppunit/test_color.cxx
index 10da454b9497..571a1f37291d 100644
--- a/tools/qa/cppunit/test_color.cxx
+++ b/tools/qa/cppunit/test_color.cxx
@@ -21,17 +21,85 @@ namespace
class Test: public CppUnit::TestFixture
{
public:
+ void testConstruction();
+ void testVariables();
void test_asRGBColor();
void test_readAndWriteStream();
void test_ApplyTintOrShade();
+ void testGetColorError();
+ void testInvert();
+ void testBColor();
CPPUNIT_TEST_SUITE(Test);
+ CPPUNIT_TEST(testConstruction);
+ CPPUNIT_TEST(testVariables);
CPPUNIT_TEST(test_asRGBColor);
CPPUNIT_TEST(test_readAndWriteStream);
CPPUNIT_TEST(test_ApplyTintOrShade);
+ CPPUNIT_TEST(testGetColorError);
+ CPPUNIT_TEST(testInvert);
+ CPPUNIT_TEST(testBColor);
CPPUNIT_TEST_SUITE_END();
};
+void Test::testConstruction()
+{
+ // Compile time construction of the Color and representation as a sal_uInt32
+
+ Color aColor = Color(0xFF, 0xFF, 0x00);
+
+ switch (sal_uInt32(aColor))
+ {
+ case sal_uInt32(Color(0xFF, 0xFF, 0x00)):
+ break;
+ case sal_uInt32(Color(0x00, 0x00, 0xFF, 0xFF)):
+ break;
+ default:
+ CPPUNIT_ASSERT(false);
+ break;
+ }
+}
+
+void Test::testVariables()
+{
+ Color aColor(0x44, 0x88, 0xAA);
+ CPPUNIT_ASSERT_EQUAL(int(0x00), int(aColor.A));
+ CPPUNIT_ASSERT_EQUAL(int(0x44), int(aColor.R));
+ CPPUNIT_ASSERT_EQUAL(int(0x88), int(aColor.G));
+ CPPUNIT_ASSERT_EQUAL(int(0xAA), int(aColor.B));
+ CPPUNIT_ASSERT_EQUAL(int(0x004488AA), int(aColor.mValue));
+
+ aColor.mValue = 0xAABBCCDD;
+ CPPUNIT_ASSERT_EQUAL(int(0xAA), int(aColor.A));
+ CPPUNIT_ASSERT_EQUAL(int(0xBB), int(aColor.R));
+ CPPUNIT_ASSERT_EQUAL(int(0xCC), int(aColor.G));
+ CPPUNIT_ASSERT_EQUAL(int(0xDD), int(aColor.B));
+
+ aColor.A = 0x11;
+ CPPUNIT_ASSERT_EQUAL(int(0x11BBCCDD), int(aColor.mValue));
+
+ aColor.R = 0x22;
+ CPPUNIT_ASSERT_EQUAL(int(0x1122CCDD), int(aColor.mValue));
+
+ aColor.G = 0x33;
+ CPPUNIT_ASSERT_EQUAL(int(0x112233DD), int(aColor.mValue));
+
+ aColor.B = 0x44;
+ CPPUNIT_ASSERT_EQUAL(int(0x11223344), int(aColor.mValue));
+
+ aColor.SetTransparency(0x77);
+ CPPUNIT_ASSERT_EQUAL(int(0x77223344), int(aColor.mValue));
+
+ aColor.SetRed(0x88);
+ CPPUNIT_ASSERT_EQUAL(int(0x77883344), int(aColor.mValue));
+
+ aColor.SetGreen(0x99);
+ CPPUNIT_ASSERT_EQUAL(int(0x77889944), int(aColor.mValue));
+
+ aColor.SetBlue(0xAA);
+ CPPUNIT_ASSERT_EQUAL(int(0x778899AA), int(aColor.mValue));
+}
+
void Test::test_asRGBColor()
{
Color aColor;
@@ -131,6 +199,62 @@ void Test::test_ApplyTintOrShade()
CPPUNIT_ASSERT_EQUAL(OUString("404040"), createTintShade(0x80, 0x80, 0x80, "808080", -5000));
// 100% shade
CPPUNIT_ASSERT_EQUAL(OUString("000000"), createTintShade(0x80, 0x80, 0x80, "808080", -10000));
+}
+
+void Test::testGetColorError()
+{
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), Color(0xAA, 0xBB, 0xCC).GetColorError(Color(0xAA, 0xBB, 0xCC)));
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA1, 0xB0, 0xC0)));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA0, 0xB1, 0xC0)));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(0), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA0, 0xB0, 0xC1)));
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA1, 0xB1, 0xC0)));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA0, 0xB1, 0xC1)));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA1, 0xB0, 0xC1)));
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA1, 0xB1, 0xC1)));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA1, 0xB1, 0xC1)));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt8(1), Color(0xA0, 0xB0, 0xC0).GetColorError(Color(0xA1, 0xB1, 0xC1)));
+}
+
+void Test::testInvert()
+{
+ Color aColor = Color(0xFF, 0x00, 0x88);
+ aColor.Invert();
+ CPPUNIT_ASSERT_EQUAL(Color(0x00, 0xFF, 0x77).AsRGBHexString(), aColor.AsRGBHexString());
+
+ // Alpha should be unaffected
+ aColor = Color(0x22, 0xFF, 0x00, 0x88);
+ aColor.Invert();
+ CPPUNIT_ASSERT_EQUAL(Color(0x22, 0x00, 0xFF, 0x77).AsRGBHexString(), aColor.AsRGBHexString());
+}
+
+void Test::testBColor()
+{
+ Color aColor;
+
+ aColor = Color(basegfx::BColor(0.0, 0.0, 0.0));
+
+ CPPUNIT_ASSERT_EQUAL(Color(0x00, 0x00, 0x00).AsRGBHexString(), aColor.AsRGBHexString());
+ CPPUNIT_ASSERT_EQUAL(0.0, aColor.getBColor().getRed());
+ CPPUNIT_ASSERT_EQUAL(0.0, aColor.getBColor().getGreen());
+ CPPUNIT_ASSERT_EQUAL(0.0, aColor.getBColor().getBlue());
+
+ aColor = Color(basegfx::BColor(1.0, 1.0, 1.0));
+
+ CPPUNIT_ASSERT_EQUAL(Color(0xFF, 0xFF, 0xFF).AsRGBHexString(), aColor.AsRGBHexString());
+ CPPUNIT_ASSERT_EQUAL(1.0, aColor.getBColor().getRed());
+ CPPUNIT_ASSERT_EQUAL(1.0, aColor.getBColor().getGreen());
+ CPPUNIT_ASSERT_EQUAL(1.0, aColor.getBColor().getBlue());
+
+ aColor = Color(basegfx::BColor(0.5, 0.25, 0.125));
+
+ CPPUNIT_ASSERT_EQUAL(Color(0x80, 0x40, 0x20).AsRGBHexString(), aColor.AsRGBHexString());
+ // FP error is rather big, but that's normal
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.500, aColor.getBColor().getRed(), 1E-2);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.250, aColor.getBColor().getGreen(), 1E-2);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(0.125, aColor.getBColor().getBlue(), 1E-2);
}
diff --git a/tools/source/generic/color.cxx b/tools/source/generic/color.cxx
index 4c26d76e98c8..4bb5221c13d6 100644
--- a/tools/source/generic/color.cxx
+++ b/tools/source/generic/color.cxx
@@ -31,25 +31,25 @@
sal_uInt8 Color::GetColorError( const Color& rCompareColor ) const
{
- const long nErrAbs = labs( static_cast<long>(rCompareColor.GetRed()) - GetRed() ) +
- labs( static_cast<long>(rCompareColor.GetGreen()) - GetGreen() ) +
- labs( static_cast<long>(rCompareColor.GetBlue()) - GetBlue() );
+ const long nErrAbs = labs(long(rCompareColor.R) - R) +
+ labs(long(rCompareColor.G) - G) +
+ labs(long(rCompareColor.B) - B);
return static_cast<sal_uInt8>(FRound( nErrAbs * 0.3333333333 ));
}
-void Color::IncreaseLuminance( sal_uInt8 cLumInc )
+void Color::IncreaseLuminance(sal_uInt8 cLumInc)
{
- SetRed( static_cast<sal_uInt8>(std::clamp( static_cast<long>(COLORDATA_RED( mnColor )) + cLumInc, 0L, 255L )) );
- SetGreen( static_cast<sal_uInt8>(std::clamp( static_cast<long>(COLORDATA_GREEN( mnColor )) + cLumInc, 0L, 255L )) );
- SetBlue( static_cast<sal_uInt8>(std::clamp( static_cast<long>(COLORDATA_BLUE( mnColor )) + cLumInc, 0L, 255L )) );
+ R = sal_uInt8(std::clamp(long(R) + cLumInc, 0L, 255L));
+ G = sal_uInt8(std::clamp(long(G) + cLumInc, 0L, 255L));
+ B = sal_uInt8(std::clamp(long(B) + cLumInc, 0L, 255L));
}
-void Color::DecreaseLuminance( sal_uInt8 cLumDec )
+void Color::DecreaseLuminance(sal_uInt8 cLumDec)
{
- SetRed( static_cast<sal_uInt8>(std::clamp( static_cast<long>(COLORDATA_RED( mnColor )) - cLumDec, 0L, 255L )) );
- SetGreen( static_cast<sal_uInt8>(std::clamp( static_cast<long>(COLORDATA_GREEN( mnColor )) - cLumDec, 0L, 255L )) );
- SetBlue( static_cast<sal_uInt8>(std::clamp( static_cast<long>(COLORDATA_BLUE( mnColor )) - cLumDec, 0L, 255L )) );
+ R = sal_uInt8(std::clamp(long(R) - cLumDec, 0L, 255L));
+ G = sal_uInt8(std::clamp(long(G) - cLumDec, 0L, 255L));
+ B = sal_uInt8(std::clamp(long(B) - cLumDec, 0L, 255L));
}
void Color::DecreaseContrast( sal_uInt8 cContDec )
@@ -59,17 +59,17 @@ void Color::DecreaseContrast( sal_uInt8 cContDec )
const double fM = ( 128.0 - 0.4985 * cContDec ) / 128.0;
const double fOff = 128.0 - fM * 128.0;
- SetRed( static_cast<sal_uInt8>(std::clamp( FRound( COLORDATA_RED( mnColor ) * fM + fOff ), 0L, 255L )) );
- SetGreen( static_cast<sal_uInt8>(std::clamp( FRound( COLORDATA_GREEN( mnColor ) * fM + fOff ), 0L, 255L )) );
- SetBlue( static_cast<sal_uInt8>(std::clamp( FRound( COLORDATA_BLUE( mnColor ) * fM + fOff ), 0L, 255L )) );
+ R = sal_uInt8(std::clamp(FRound(R * fM + fOff), 0L, 255L));
+ G = sal_uInt8(std::clamp(FRound(G * fM + fOff), 0L, 255L));
+ B = sal_uInt8(std::clamp(FRound(B * fM + fOff), 0L, 255L));
}
}
void Color::Invert()
{
- SetRed( ~COLORDATA_RED( mnColor ) );
- SetGreen( ~COLORDATA_GREEN( mnColor ) );
- SetBlue( ~COLORDATA_BLUE( mnColor ) );
+ R = ~R;
+ G = ~G;
+ B = ~B;
}
bool Color::IsDark() const
@@ -89,9 +89,9 @@ void Color::RGBtoHSB( sal_uInt16& nHue, sal_uInt16& nSat, sal_uInt16& nBri ) con
sal_uInt8 c[3];
sal_uInt8 cMax, cMin;
- c[0] = GetRed();
- c[1] = GetGreen();
- c[2] = GetBlue();
+ c[0] = R;
+ c[1] = G;
+ c[2] = B;
cMax = c[0];
if( c[1] > cMax )
@@ -186,13 +186,13 @@ Color Color::HSBtoRGB( sal_uInt16 nHue, sal_uInt16 nSat, sal_uInt16 nBri )
SvStream& Color::Read( SvStream& rIStm )
{
- rIStm.ReadUInt32( mnColor );
+ rIStm.ReadUInt32(mValue);
return rIStm;
}
SvStream& Color::Write( SvStream& rOStm ) const
{
- rOStm.WriteUInt32( mnColor );
+ rOStm.WriteUInt32(mValue);
return rOStm;
}
@@ -290,9 +290,9 @@ void Color::ApplyTintOrShade(sal_Int16 n100thPercent)
aBColor.setBlue(fResult);
aBColor = basegfx::utils::hsl2rgb(aBColor);
- SetRed(sal_uInt8(( aBColor.getRed() * 255.0) + 0.5));
- SetGreen(sal_uInt8((aBColor.getGreen() * 255.0) + 0.5));
- SetBlue(sal_uInt8(( aBColor.getBlue() * 255.0) + 0.5));
+ 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));
}
SvStream& WriteColor( SvStream& rOStream, const Color& rColor )