summaryrefslogtreecommitdiff
path: root/filter
diff options
context:
space:
mode:
authorZolnai Tamás <zolnaitamas2000@gmail.com>2015-07-14 09:44:10 +0200
committerZolnai Tamás <zolnaitamas2000@gmail.com>2015-07-14 10:36:18 +0200
commit16f9cf57e20ffbe34cb184f694f465708250a578 (patch)
tree951f0cc53f96103e5f365ef5bc4a04655800d1e5 /filter
parent70f152983f3425a77df2f65b4798417640d47b76 (diff)
tdf#92471: Improve color conversion to MSO highlighting
The simple color distance on RGB color space is not good enough. It leads to a better result if we use the scheme of the primary colors. This method works well with MSO highlighting color palette, but not neccessarily in general. In highlighting palette light and dark variant of the same color type (e.g. blue and light blue) has the exactly same scheme. Change-Id: Ied08b4c388b8020326709d01d2de290afdd9d77b
Diffstat (limited to 'filter')
-rw-r--r--filter/CppunitTest_filter_utils.mk41
-rw-r--r--filter/Module_filter.mk1
-rw-r--r--filter/qa/cppunit/utils-test.cxx77
-rw-r--r--filter/source/msfilter/util.cxx70
4 files changed, 188 insertions, 1 deletions
diff --git a/filter/CppunitTest_filter_utils.mk b/filter/CppunitTest_filter_utils.mk
new file mode 100644
index 000000000000..4735abb42f09
--- /dev/null
+++ b/filter/CppunitTest_filter_utils.mk
@@ -0,0 +1,41 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,filter_utils))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,filter_utils))
+$(eval $(call gb_CppunitTest_use_ure,filter_utils))
+
+$(eval $(call gb_CppunitTest_use_configuration,filter_utils))
+
+$(eval $(call gb_CppunitTest_use_libraries,filter_utils, \
+ comphelper \
+ unotest \
+ cppuhelper \
+ cppu \
+ msfilter \
+ sal \
+ $(gb_UWINAPI) \
+))
+
+$(eval $(call gb_CppunitTest_use_components,filter_utils,\
+ configmgr/source/configmgr \
+ filter/source/config/cache/filterconfig1 \
+ framework/util/fwk \
+ framework/util/fwl \
+ i18npool/util/i18npool \
+ ucb/source/core/ucb1 \
+ ucb/source/ucp/file/ucpfile1 \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,filter_utils, \
+ filter/qa/cppunit/utils-test \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/filter/Module_filter.mk b/filter/Module_filter.mk
index 33f0f745f1e9..4cb64628d53f 100644
--- a/filter/Module_filter.mk
+++ b/filter/Module_filter.mk
@@ -81,6 +81,7 @@ endif
$(eval $(call gb_Module_add_check_targets,filter,\
CppunitTest_filter_xslt \
CppunitTest_filter_priority \
+ CppunitTest_filter_utils \
))
ifneq ($(DISABLE_CVE_TESTS),TRUE)
diff --git a/filter/qa/cppunit/utils-test.cxx b/filter/qa/cppunit/utils-test.cxx
new file mode 100644
index 000000000000..5e306ef99335
--- /dev/null
+++ b/filter/qa/cppunit/utils-test.cxx
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <sal/types.h>
+#include <rtl/ustrbuf.hxx>
+#include <filter/msfilter/util.hxx>
+
+#include <unotest/bootstrapfixturebase.hxx>
+
+namespace {
+
+class UtilsTest
+ : public test::BootstrapFixtureBase
+{
+public:
+ void testTransColToIco();
+
+ CPPUNIT_TEST_SUITE(UtilsTest);
+ CPPUNIT_TEST(testTransColToIco);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void UtilsTest::testTransColToIco()
+{
+ const sal_uInt32 aStdCol[] = {
+ 0xeeeeee, 0xffff99, 0xff6600, 0xff3333, 0xff00cc, 0xff33ff, 0x9900ff, 0x6666ff, 0x00ccff, 0x66ffff, 0x33ff99, 0x99ff66, 0xccff00,
+ 0xdddddd, 0xffff66, 0xffcc00, 0xff9999, 0xff66cc, 0xff99ff, 0xcc66ff, 0x9999ff, 0x9999ff, 0x99ffff, 0x66ff99, 0x99ff99, 0xccff66,
+ 0xcccccc, 0xffff00, 0xff9900, 0xff6666, 0xff3399, 0xff66ff, 0x9933ff, 0x3333ff, 0x3399ff, 0x00ffff, 0x00ff66, 0x66ff66, 0x99ff33,
+ 0xb2b2b2, 0xcc9900, 0xff3300, 0xff0000, 0xff0066, 0xff00ff, 0x6600ff, 0x0000ff, 0x0066ff, 0x00cccc, 0x00cc33, 0x00cc00, 0x66ff00,
+ 0x999999, 0x996600, 0xcc3300, 0xcc0000, 0xcc0066, 0xcc00cc, 0x6600cc, 0x0000cc, 0x0066cc, 0x009999, 0x009933, 0x009900, 0x66cc00,
+ 0x808080, 0x663300, 0x801900, 0x990000, 0x990066, 0x990099, 0x330099, 0x000099, 0x006699, 0x006666, 0x007826, 0x006600, 0x669900,
+ 0x666666, 0x333300, 0x461900, 0x330000, 0x330033, 0x660066, 0x000033, 0x000066, 0x000080, 0x003333, 0x00331a, 0x003300, 0x193300,
+ 0x333333, 0x666633, 0x661900, 0x663333, 0x660033, 0x663366, 0x330066, 0x333366, 0x003366, 0x336666, 0x006633, 0x336633, 0x336600 };
+
+ const sal_uInt16 aExpected[] = {
+ 8, 7, 6, 6, 5, 5, 5, 2, 3, 3, 10, 4, 7,
+ 16, 7, 7, 6, 5, 5, 5, 2, 2, 3, 4, 4, 7,
+ 16, 7, 7, 6, 12, 5, 12, 2, 10, 3, 4, 4, 14,
+ 16, 14, 6, 6, 6, 5, 2, 2, 2, 3, 4, 4, 4,
+ 15, 14, 6, 6, 12, 5, 12, 2, 10, 10, 11, 11, 14,
+ 15, 1, 13, 13, 12, 12, 9, 9, 10, 10, 11, 11, 14,
+ 15, 14, 13, 13, 12, 12, 9, 9, 9, 10, 10, 11, 11,
+ 1, 14, 13, 13, 1, 12, 1, 9, 1, 10, 1, 11, 1 };
+
+ for( size_t i = 0; i < SAL_N_ELEMENTS(aStdCol); ++i)
+ {
+ const OString sMessage = "Index of unmatched color: " + OString::number(i);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), aExpected[i],
+ static_cast<sal_uInt16>(msfilter::util::TransColToIco( Color(aStdCol[i]) )));
+ }
+
+ // tdf#92471
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast<sal_uInt16>(msfilter::util::TransColToIco( Color( 0x6666ff ))));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast<sal_uInt16>(msfilter::util::TransColToIco( Color( 0x6566ff ))));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast<sal_uInt16>(msfilter::util::TransColToIco( Color( 0x6665ff ))));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), static_cast<sal_uInt16>(msfilter::util::TransColToIco( Color( 0x6666fe ))));
+
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(UtilsTest);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/filter/source/msfilter/util.cxx b/filter/source/msfilter/util.cxx
index b1bfc1c7201a..3a2843e3aa4e 100644
--- a/filter/source/msfilter/util.cxx
+++ b/filter/source/msfilter/util.cxx
@@ -1352,6 +1352,74 @@ bool HasTextBoxContent(sal_uInt32 nShapeType)
}
}
+namespace
+{
+
+// Scheme means pattern of chromatic values.
+// [2,2,1] -> red and green are approximately equal and blue is the dominant color (e.g. blue)
+// [1,1,1] -> all chromatic values are approximately equal (e.g. white, gray, black)
+static void CalculateScheme(const BitmapColor& rBitmapColor, std::vector<int> &vScheme, sal_uInt16 nVariance)
+{
+ vScheme.resize(3,1);
+ if( rBitmapColor.GetRed() > rBitmapColor.GetGreen() + nVariance )
+ ++vScheme[0];
+ if( rBitmapColor.GetRed() > rBitmapColor.GetBlue() + nVariance )
+ ++vScheme[0];
+ if( rBitmapColor.GetGreen() > rBitmapColor.GetRed() + nVariance )
+ ++vScheme[1];
+ if( rBitmapColor.GetGreen() > rBitmapColor.GetBlue() + nVariance )
+ ++vScheme[1];
+ if( rBitmapColor.GetBlue() > rBitmapColor.GetRed() + nVariance )
+ ++vScheme[2];
+ if( rBitmapColor.GetBlue() > rBitmapColor.GetGreen() + nVariance )
+ ++vScheme[2];
+}
+
+static bool HasSimilarScheme(const BitmapColor& rBitmapColor1, const BitmapColor& rBitmapColor2, sal_uInt16 nVariance)
+{
+ std::vector<int> vScheme1, vScheme2;
+ CalculateScheme(rBitmapColor1, vScheme1, nVariance);
+ CalculateScheme(rBitmapColor2, vScheme2, nVariance);
+ for( int i = 0; i < 3; ++i )
+ {
+ if( vScheme1[i] != vScheme2[i] )
+ return false;
+ }
+ return true;
+}
+
+// Find the best match in the color palette using scheme of the input color
+static sal_uInt16 GetBestIndex(const BitmapPalette& rPalette, const BitmapColor& rBitmapColor)
+{
+ sal_uInt16 nReturn = 0;
+ bool bFound = false;
+ sal_uLong nLastErr = 3 * 255 + 1;
+
+ // Prefer those colors which have similar scheme as the input
+ // Allow bigger and bigger variance of the schemes until we find
+ // a color in the palette with similar scheme.
+ for( sal_uInt16 nVariance = 0; nVariance <= 255; ++nVariance )
+ {
+ for( sal_uInt16 i = 0; i < rPalette.GetEntryCount(); ++i )
+ {
+ if( HasSimilarScheme(rBitmapColor, rPalette[i], nVariance) )
+ {
+ sal_uLong nActErr = rBitmapColor.GetColorError( rPalette[i] );
+ if( nActErr < nLastErr )
+ {
+ nLastErr = nActErr;
+ nReturn = i;
+ bFound = true;
+ }
+ }
+ }
+ if( bFound )
+ return nReturn;
+ }
+ return nReturn;
+}
+}
+
sal_uInt8 TransColToIco( const Color& rCol )
{
sal_uInt8 nCol = 0; // ->Auto
@@ -1386,7 +1454,7 @@ sal_uInt8 TransColToIco( const Color& rCol )
for( sal_uInt16 i = 0; i < 16; ++i )
aBmpPal[i] = Color( aColArr[ i ] );
- nCol = static_cast< sal_uInt8 >(aBmpPal.GetBestIndex( rCol ) + 1);
+ nCol = static_cast< sal_uInt8 >(GetBestIndex(aBmpPal, rCol) + 1);
break;
}
return nCol;