Kaydet (Commit) 16f9cf57 authored tarafından Zolnai Tamás's avatar Zolnai Tamás

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
üst 70f15298
# -*- 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:
......@@ -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)
......
/* -*- 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: */
......@@ -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;
......
......@@ -606,7 +606,7 @@ void Test::testCharBackgroundToHighlighting()
mxComponent = loadFromDesktop(getURLFromSrc("/sw/qa/extras/globalfilter/data/char_background.odt"),
"com.sun.star.text.TextDocument");
const OString sFailedMessage = OString("Failed on filter: ") + aFilterNames[nFilter];
OString sFailedMessage = OString("Failed on filter: ") + aFilterNames[nFilter];
SvtFilterOptions& rOpt = SvtFilterOptions::Get();
......@@ -627,7 +627,7 @@ void Test::testCharBackgroundToHighlighting()
// Check highlight color
const uno::Reference< text::XTextRange > xPara = getParagraph(1);
for( int nRun = 1; nRun <= 20; ++nRun )
for( int nRun = 1; nRun <= 19; ++nRun )
{
const uno::Reference<beans::XPropertySet> xRun(getRun(xPara,nRun), uno::UNO_QUERY);
sal_Int32 nHighlightColor = 0;
......@@ -644,17 +644,17 @@ void Test::testCharBackgroundToHighlighting()
case 9: nHighlightColor = 0x008000; break; //dark green
case 10: nHighlightColor = 0x800080; break; //dark magenta
case 11: nHighlightColor = 0x000080; break; //dark blue
case 12: nHighlightColor = 0x000000; break; //black
case 13: nHighlightColor = 0x808000; break; //dark yellow
case 14: nHighlightColor = 0x808080; break; //dark gray
case 15: nHighlightColor = 0x000000; break; //white
case 16: nHighlightColor = 0xff0000; break; //red
case 17: nHighlightColor = 0xC0C0C0; break; //light gray
case 18: nHighlightColor = 0x800000; break; //dark red
case 19: nHighlightColor = 0x008080; break; //dark cyan
case 20: nHighlightColor = 0xffffff; break; //white
case 12: nHighlightColor = 0x808000; break; //dark yellow
case 13: nHighlightColor = 0x808080; break; //dark gray
case 14: nHighlightColor = 0x000000; break; //black
case 15: nHighlightColor = 0xff0000; break; //red
case 16: nHighlightColor = 0xC0C0C0; break; //light gray
case 17: nHighlightColor = 0x800000; break; //dark red
case 18: nHighlightColor = 0x808080; break; //dark gray
case 19: nHighlightColor = 0xffff00; break; //yellow
}
CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), nHighlightColor, getProperty<sal_Int32>(xRun,"CharHighlight"));
const OString sMessage = sFailedMessage +". Index of run with unmatched color: " + OString::number(nRun);
CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage.getStr(), nHighlightColor, getProperty<sal_Int32>(xRun,"CharHighlight"));
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment