1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <oox/drawingml/color.hxx>
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
25 #include <oox/helper/containerhelper.hxx>
26 #include <oox/helper/graphichelper.hxx>
27 #include <oox/drawingml/drawingmltypes.hxx>
28 #include <oox/token/namespaces.hxx>
29 #include <oox/token/tokens.hxx>
31 namespace oox::drawingml
{
35 /** Global storage for predefined color values used in OOXML file formats. */
36 struct PresetColorsPool
38 typedef ::std::vector
< ::Color
> ColorVector
;
40 ColorVector maDmlColors
; /// Predefined colors in DrawingML, indexed by XML token.
41 ColorVector maVmlColors
; /// Predefined colors in VML, indexed by XML token.
42 ColorVector maHighlightColors
; /// Predefined colors in DrawingML for highlight, indexed by XML token.
44 explicit PresetColorsPool();
47 PresetColorsPool::PresetColorsPool() :
48 maDmlColors( static_cast< size_t >( XML_TOKEN_COUNT
), API_RGB_TRANSPARENT
),
49 maVmlColors( static_cast< size_t >( XML_TOKEN_COUNT
), API_RGB_TRANSPARENT
),
50 maHighlightColors( static_cast<size_t>(XML_TOKEN_COUNT
), API_RGB_TRANSPARENT
)
52 // predefined colors in DrawingML (map XML token identifiers to RGB values)
53 static const std::pair
<sal_Int32
, ::Color
> spnDmlColors
[] =
55 {XML_aliceBlue
, ::Color(0xF0F8FF)}, {XML_antiqueWhite
, ::Color(0xFAEBD7)},
56 {XML_aqua
, ::Color(0x00FFFF)}, {XML_aquamarine
, ::Color(0x7FFFD4)},
57 {XML_azure
, ::Color(0xF0FFFF)}, {XML_beige
, ::Color(0xF5F5DC)},
58 {XML_bisque
, ::Color(0xFFE4C4)}, {XML_black
, ::Color(0x000000)},
59 {XML_blanchedAlmond
, ::Color(0xFFEBCD)}, {XML_blue
, ::Color(0x0000FF)},
60 {XML_blueViolet
, ::Color(0x8A2BE2)}, {XML_brown
, ::Color(0xA52A2A)},
61 {XML_burlyWood
, ::Color(0xDEB887)}, {XML_cadetBlue
, ::Color(0x5F9EA0)},
62 {XML_chartreuse
, ::Color(0x7FFF00)}, {XML_chocolate
, ::Color(0xD2691E)},
63 {XML_coral
, ::Color(0xFF7F50)}, {XML_cornflowerBlue
, ::Color(0x6495ED)},
64 {XML_cornsilk
, ::Color(0xFFF8DC)}, {XML_crimson
, ::Color(0xDC143C)},
65 {XML_cyan
, ::Color(0x00FFFF)}, {XML_deepPink
, ::Color(0xFF1493)},
66 {XML_deepSkyBlue
, ::Color(0x00BFFF)}, {XML_dimGray
, ::Color(0x696969)},
67 {XML_dkBlue
, ::Color(0x00008B)}, {XML_dkCyan
, ::Color(0x008B8B)},
68 {XML_dkGoldenrod
, ::Color(0xB8860B)}, {XML_dkGray
, ::Color(0xA9A9A9)},
69 {XML_dkGreen
, ::Color(0x006400)}, {XML_dkKhaki
, ::Color(0xBDB76B)},
70 {XML_dkMagenta
, ::Color(0x8B008B)}, {XML_dkOliveGreen
, ::Color(0x556B2F)},
71 {XML_dkOrange
, ::Color(0xFF8C00)}, {XML_dkOrchid
, ::Color(0x9932CC)},
72 {XML_dkRed
, ::Color(0x8B0000)}, {XML_dkSalmon
, ::Color(0xE9967A)},
73 {XML_dkSeaGreen
, ::Color(0x8FBC8B)}, {XML_dkSlateBlue
, ::Color(0x483D8B)},
74 {XML_dkSlateGray
, ::Color(0x2F4F4F)}, {XML_dkTurquoise
, ::Color(0x00CED1)},
75 {XML_dkViolet
, ::Color(0x9400D3)}, {XML_dodgerBlue
, ::Color(0x1E90FF)},
76 {XML_firebrick
, ::Color(0xB22222)}, {XML_floralWhite
, ::Color(0xFFFAF0)},
77 {XML_forestGreen
, ::Color(0x228B22)}, {XML_fuchsia
, ::Color(0xFF00FF)},
78 {XML_gainsboro
, ::Color(0xDCDCDC)}, {XML_ghostWhite
, ::Color(0xF8F8FF)},
79 {XML_gold
, ::Color(0xFFD700)}, {XML_goldenrod
, ::Color(0xDAA520)},
80 {XML_gray
, ::Color(0x808080)}, {XML_green
, ::Color(0x008000)},
81 {XML_greenYellow
, ::Color(0xADFF2F)}, {XML_honeydew
, ::Color(0xF0FFF0)},
82 {XML_hotPink
, ::Color(0xFF69B4)}, {XML_indianRed
, ::Color(0xCD5C5C)},
83 {XML_indigo
, ::Color(0x4B0082)}, {XML_ivory
, ::Color(0xFFFFF0)},
84 {XML_khaki
, ::Color(0xF0E68C)}, {XML_lavender
, ::Color(0xE6E6FA)},
85 {XML_lavenderBlush
, ::Color(0xFFF0F5)}, {XML_lawnGreen
, ::Color(0x7CFC00)},
86 {XML_lemonChiffon
, ::Color(0xFFFACD)}, {XML_lime
, ::Color(0x00FF00)},
87 {XML_limeGreen
, ::Color(0x32CD32)}, {XML_linen
, ::Color(0xFAF0E6)},
88 {XML_ltBlue
, ::Color(0xADD8E6)}, {XML_ltCoral
, ::Color(0xF08080)},
89 {XML_ltCyan
, ::Color(0xE0FFFF)}, {XML_ltGoldenrodYellow
, ::Color(0xFAFA78)},
90 {XML_ltGray
, ::Color(0xD3D3D3)}, {XML_ltGreen
, ::Color(0x90EE90)},
91 {XML_ltPink
, ::Color(0xFFB6C1)}, {XML_ltSalmon
, ::Color(0xFFA07A)},
92 {XML_ltSeaGreen
, ::Color(0x20B2AA)}, {XML_ltSkyBlue
, ::Color(0x87CEFA)},
93 {XML_ltSlateGray
, ::Color(0x778899)}, {XML_ltSteelBlue
, ::Color(0xB0C4DE)},
94 {XML_ltYellow
, ::Color(0xFFFFE0)}, {XML_magenta
, ::Color(0xFF00FF)},
95 {XML_maroon
, ::Color(0x800000)}, {XML_medAquamarine
, ::Color(0x66CDAA)},
96 {XML_medBlue
, ::Color(0x0000CD)}, {XML_medOrchid
, ::Color(0xBA55D3)},
97 {XML_medPurple
, ::Color(0x9370DB)}, {XML_medSeaGreen
, ::Color(0x3CB371)},
98 {XML_medSlateBlue
, ::Color(0x7B68EE)}, {XML_medSpringGreen
, ::Color(0x00FA9A)},
99 {XML_medTurquoise
, ::Color(0x48D1CC)}, {XML_medVioletRed
, ::Color(0xC71585)},
100 {XML_midnightBlue
, ::Color(0x191970)}, {XML_mintCream
, ::Color(0xF5FFFA)},
101 {XML_mistyRose
, ::Color(0xFFE4E1)}, {XML_moccasin
, ::Color(0xFFE4B5)},
102 {XML_navajoWhite
, ::Color(0xFFDEAD)}, {XML_navy
, ::Color(0x000080)},
103 {XML_oldLace
, ::Color(0xFDF5E6)}, {XML_olive
, ::Color(0x808000)},
104 {XML_oliveDrab
, ::Color(0x6B8E23)}, {XML_orange
, ::Color(0xFFA500)},
105 {XML_orangeRed
, ::Color(0xFF4500)}, {XML_orchid
, ::Color(0xDA70D6)},
106 {XML_paleGoldenrod
, ::Color(0xEEE8AA)}, {XML_paleGreen
, ::Color(0x98FB98)},
107 {XML_paleTurquoise
, ::Color(0xAFEEEE)}, {XML_paleVioletRed
, ::Color(0xDB7093)},
108 {XML_papayaWhip
, ::Color(0xFFEFD5)}, {XML_peachPuff
, ::Color(0xFFDAB9)},
109 {XML_peru
, ::Color(0xCD853F)}, {XML_pink
, ::Color(0xFFC0CB)},
110 {XML_plum
, ::Color(0xDDA0DD)}, {XML_powderBlue
, ::Color(0xB0E0E6)},
111 {XML_purple
, ::Color(0x800080)}, {XML_red
, ::Color(0xFF0000)},
112 {XML_rosyBrown
, ::Color(0xBC8F8F)}, {XML_royalBlue
, ::Color(0x4169E1)},
113 {XML_saddleBrown
, ::Color(0x8B4513)}, {XML_salmon
, ::Color(0xFA8072)},
114 {XML_sandyBrown
, ::Color(0xF4A460)}, {XML_seaGreen
, ::Color(0x2E8B57)},
115 {XML_seaShell
, ::Color(0xFFF5EE)}, {XML_sienna
, ::Color(0xA0522D)},
116 {XML_silver
, ::Color(0xC0C0C0)}, {XML_skyBlue
, ::Color(0x87CEEB)},
117 {XML_slateBlue
, ::Color(0x6A5ACD)}, {XML_slateGray
, ::Color(0x708090)},
118 {XML_snow
, ::Color(0xFFFAFA)}, {XML_springGreen
, ::Color(0x00FF7F)},
119 {XML_steelBlue
, ::Color(0x4682B4)}, {XML_tan
, ::Color(0xD2B48C)},
120 {XML_teal
, ::Color(0x008080)}, {XML_thistle
, ::Color(0xD8BFD8)},
121 {XML_tomato
, ::Color(0xFF6347)}, {XML_turquoise
, ::Color(0x40E0D0)},
122 {XML_violet
, ::Color(0xEE82EE)}, {XML_wheat
, ::Color(0xF5DEB3)},
123 {XML_white
, ::Color(0xFFFFFF)}, {XML_whiteSmoke
, ::Color(0xF5F5F5)},
124 {XML_yellow
, ::Color(0xFFFF00)}, {XML_yellowGreen
, ::Color(0x9ACD32)}
126 for(auto const& nEntry
: spnDmlColors
)
127 maDmlColors
[ static_cast< size_t >(nEntry
.first
) ] = nEntry
.second
;
129 // predefined colors in VML (map XML token identifiers to RGB values)
130 static const std::pair
<sal_Int32
, ::Color
> spnVmlColors
[] =
132 {XML_aqua
, ::Color(0x00FFFF)}, {XML_black
, ::Color(0x000000)},
133 {XML_blue
, ::Color(0x0000FF)}, {XML_fuchsia
, ::Color(0xFF00FF)},
134 {XML_gray
, ::Color(0x808080)}, {XML_green
, ::Color(0x008000)},
135 {XML_lime
, ::Color(0x00FF00)}, {XML_maroon
, ::Color(0x800000)},
136 {XML_navy
, ::Color(0x000080)}, {XML_olive
, ::Color(0x808000)},
137 {XML_purple
, ::Color(0x800080)}, {XML_red
, ::Color(0xFF0000)},
138 {XML_silver
, ::Color(0xC0C0C0)}, {XML_teal
, ::Color(0x008080)},
139 {XML_white
, ::Color(0xFFFFFF)}, {XML_yellow
, ::Color(0xFFFF00)}
141 for(auto const& nEntry
: spnVmlColors
)
142 maVmlColors
[ static_cast< size_t >(nEntry
.first
) ] = nEntry
.second
;
144 // predefined highlight colors in DML (map XML token identifiers to RGB values)
145 static const std::pair
<sal_Int32
, ::Color
> spnHighlightColors
[] =
147 // tdf#131841 Predefined color for OOXML highlight.
148 {XML_black
, ::Color(0x000000)}, {XML_blue
, ::Color(0x0000FF)},
149 {XML_cyan
, ::Color(0x00FFFF)}, {XML_darkBlue
, ::Color(0x00008B)},
150 {XML_darkCyan
, ::Color(0x008B8B)}, {XML_darkGray
, ::Color(0xA9A9A9)},
151 {XML_darkGreen
, ::Color(0x006400)}, {XML_darkMagenta
, ::Color(0x800080)},
152 {XML_darkRed
, ::Color(0x8B0000)}, {XML_darkYellow
, ::Color(0x808000)},
153 {XML_green
, ::Color(0x00FF00)}, {XML_lightGray
, ::Color(0xD3D3D3)},
154 {XML_magenta
, ::Color(0xFF00FF)}, {XML_red
, ::Color(0xFF0000)},
155 {XML_white
, ::Color(0xFFFFFF)}, {XML_yellow
, ::Color(0xFFFF00)}
157 for (auto const& nEntry
: spnHighlightColors
)
158 maHighlightColors
[static_cast<size_t>(nEntry
.first
)] = nEntry
.second
;
161 struct StaticPresetColorsPool
: public ::rtl::Static
< PresetColorsPool
, StaticPresetColorsPool
> {};
163 const double DEC_GAMMA
= 2.3;
164 const double INC_GAMMA
= 1.0 / DEC_GAMMA
;
166 void lclRgbToRgbComponents( sal_Int32
& ornR
, sal_Int32
& ornG
, sal_Int32
& ornB
, ::Color nRgb
)
168 ornR
= nRgb
.GetRed();
169 ornG
= nRgb
.GetGreen();
170 ornB
= nRgb
.GetBlue();
173 sal_Int32
lclRgbComponentsToRgb( sal_Int32 nR
, sal_Int32 nG
, sal_Int32 nB
)
175 return static_cast< sal_Int32
>( (nR
<< 16) | (nG
<< 8) | nB
);
178 sal_Int32
lclRgbCompToCrgbComp( sal_Int32 nRgbComp
)
180 return static_cast< sal_Int32
>( nRgbComp
* MAX_PERCENT
/ 255 );
183 sal_Int32
lclCrgbCompToRgbComp( sal_Int32 nCrgbComp
)
185 return static_cast< sal_Int32
>( nCrgbComp
* 255 / MAX_PERCENT
);
188 sal_Int32
lclGamma( sal_Int32 nComp
, double fGamma
)
190 return static_cast< sal_Int32
>( pow( static_cast< double >( nComp
) / MAX_PERCENT
, fGamma
) * MAX_PERCENT
+ 0.5 );
193 void lclSetValue( sal_Int32
& ornValue
, sal_Int32 nNew
, sal_Int32 nMax
= MAX_PERCENT
)
195 OSL_ENSURE( (0 <= nNew
) && (nNew
<= nMax
), "lclSetValue - invalid value" );
196 if( (0 <= nNew
) && (nNew
<= nMax
) )
200 void lclModValue( sal_Int32
& ornValue
, sal_Int32 nMod
, sal_Int32 nMax
= MAX_PERCENT
)
202 OSL_ENSURE( (0 <= nMod
), "lclModValue - invalid modificator" );
203 ornValue
= getLimitedValue
< sal_Int32
, double >( static_cast< double >( ornValue
) * nMod
/ MAX_PERCENT
, 0, nMax
);
206 void lclOffValue( sal_Int32
& ornValue
, sal_Int32 nOff
, sal_Int32 nMax
= MAX_PERCENT
)
208 OSL_ENSURE( (-nMax
<= nOff
) && (nOff
<= nMax
), "lclOffValue - invalid offset" );
209 ornValue
= getLimitedValue
< sal_Int32
, sal_Int32
>( ornValue
+ nOff
, 0, nMax
);
215 meMode( COLOR_UNUSED
),
219 mnAlpha( MAX_PERCENT
)
223 ::Color
Color::getDmlPresetColor( sal_Int32 nToken
, ::Color nDefaultRgb
)
225 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
226 able to catch the existing vector entries without corresponding XML
228 ::Color nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maDmlColors
, nToken
, API_RGB_TRANSPARENT
);
229 return (sal_Int32(nRgbValue
) >= 0) ? nRgbValue
: nDefaultRgb
;
232 ::Color
Color::getVmlPresetColor( sal_Int32 nToken
, ::Color nDefaultRgb
)
234 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
235 able to catch the existing vector entries without corresponding XML
237 ::Color nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maVmlColors
, nToken
, API_RGB_TRANSPARENT
);
238 return (sal_Int32(nRgbValue
) >= 0) ? nRgbValue
: nDefaultRgb
;
241 ::Color
Color::getHighlightColor(sal_Int32 nToken
, ::Color nDefaultRgb
)
243 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
244 able to catch the existing vector entries without corresponding XML
246 ::Color nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maHighlightColors
, nToken
, API_RGB_TRANSPARENT
);
247 return (sal_Int32(nRgbValue
) >= 0) ? nRgbValue
: nDefaultRgb
;
250 void Color::setUnused()
252 meMode
= COLOR_UNUSED
;
255 void Color::setSrgbClr( ::Color nRgb
)
257 setSrgbClr(sal_Int32(nRgb
));
260 void Color::setSrgbClr( sal_Int32 nRgb
)
262 OSL_ENSURE( (0 <= nRgb
) && (nRgb
<= 0xFFFFFF), "Color::setSrgbClr - invalid RGB value" );
264 lclRgbToRgbComponents( mnC1
, mnC2
, mnC3
, ::Color(ColorTransparency
, nRgb
) );
267 void Color::setScrgbClr( sal_Int32 nR
, sal_Int32 nG
, sal_Int32 nB
)
269 OSL_ENSURE( (0 <= nR
) && (nR
<= MAX_PERCENT
), "Color::setScrgbClr - invalid red value" );
270 OSL_ENSURE( (0 <= nG
) && (nG
<= MAX_PERCENT
), "Color::setScrgbClr - invalid green value" );
271 OSL_ENSURE( (0 <= nB
) && (nB
<= MAX_PERCENT
), "Color::setScrgbClr - invalid blue value" );
273 mnC1
= getLimitedValue
< sal_Int32
, sal_Int32
>( nR
, 0, MAX_PERCENT
);
274 mnC2
= getLimitedValue
< sal_Int32
, sal_Int32
>( nG
, 0, MAX_PERCENT
);
275 mnC3
= getLimitedValue
< sal_Int32
, sal_Int32
>( nB
, 0, MAX_PERCENT
);
278 void Color::setHslClr( sal_Int32 nHue
, sal_Int32 nSat
, sal_Int32 nLum
)
280 OSL_ENSURE( (0 <= nHue
) && (nHue
<= MAX_DEGREE
), "Color::setHslClr - invalid hue value" );
281 OSL_ENSURE( (0 <= nSat
) && (nSat
<= MAX_PERCENT
), "Color::setHslClr - invalid saturation value" );
282 OSL_ENSURE( (0 <= nLum
) && (nLum
<= MAX_PERCENT
), "Color::setHslClr - invalid luminance value" );
284 mnC1
= getLimitedValue
< sal_Int32
, sal_Int32
>( nHue
, 0, MAX_DEGREE
);
285 mnC2
= getLimitedValue
< sal_Int32
, sal_Int32
>( nSat
, 0, MAX_PERCENT
);
286 mnC3
= getLimitedValue
< sal_Int32
, sal_Int32
>( nLum
, 0, MAX_PERCENT
);
289 void Color::setPrstClr( sal_Int32 nToken
)
291 ::Color nRgbValue
= getDmlPresetColor( nToken
, API_RGB_TRANSPARENT
);
292 OSL_ENSURE( sal_Int32(nRgbValue
) >= 0, "Color::setPrstClr - invalid preset color token" );
293 if( sal_Int32(nRgbValue
) >= 0 )
294 setSrgbClr( nRgbValue
);
297 void Color::setHighlight(sal_Int32 nToken
)
299 ::Color nRgbValue
= getHighlightColor(nToken
, API_RGB_TRANSPARENT
);
300 OSL_ENSURE( sal_Int32(nRgbValue
) >= 0, "Color::setPrstClr - invalid preset color token" );
301 if ( sal_Int32(nRgbValue
) >= 0 )
302 setSrgbClr( nRgbValue
);
305 void Color::setSchemeClr( sal_Int32 nToken
)
307 OSL_ENSURE( nToken
!= XML_TOKEN_INVALID
, "Color::setSchemeClr - invalid color token" );
308 meMode
= (nToken
== XML_phClr
) ? COLOR_PH
: COLOR_SCHEME
;
312 void Color::setPaletteClr( sal_Int32 nPaletteIdx
)
314 OSL_ENSURE( nPaletteIdx
>= 0, "Color::setPaletteClr - invalid palette index" );
315 meMode
= COLOR_PALETTE
;
319 void Color::setSysClr( sal_Int32 nToken
, sal_Int32 nLastRgb
)
321 OSL_ENSURE( (-1 <= nLastRgb
) && (nLastRgb
<= 0xFFFFFF), "Color::setSysClr - invalid RGB value" );
322 meMode
= COLOR_SYSTEM
;
327 void Color::addTransformation( sal_Int32 nElement
, sal_Int32 nValue
)
329 /* Execute alpha transformations directly, store other transformations in
330 a vector, they may depend on a scheme base color which will be resolved
331 in Color::getColor(). */
332 sal_Int32 nToken
= getBaseToken( nElement
);
335 case XML_alpha
: lclSetValue( mnAlpha
, nValue
); break;
336 case XML_alphaMod
: lclModValue( mnAlpha
, nValue
); break;
337 case XML_alphaOff
: lclOffValue( mnAlpha
, nValue
); break;
338 default: maTransforms
.emplace_back( nToken
, nValue
);
340 sal_Int32 nSize
= maInteropTransformations
.getLength();
341 maInteropTransformations
.realloc(nSize
+ 1);
342 auto pInteropTransformations
= maInteropTransformations
.getArray();
343 pInteropTransformations
[nSize
].Name
= getColorTransformationName( nToken
);
344 pInteropTransformations
[nSize
].Value
<<= nValue
;
347 void Color::addChartTintTransformation( double fTint
)
349 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( fTint
* MAX_PERCENT
+ 0.5, -MAX_PERCENT
, MAX_PERCENT
);
351 maTransforms
.emplace_back( XML_shade
, nValue
+ MAX_PERCENT
);
352 else if( nValue
> 0 )
353 maTransforms
.emplace_back( XML_tint
, MAX_PERCENT
- nValue
);
356 void Color::addExcelTintTransformation( double fTint
)
358 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( fTint
* MAX_PERCENT
+ 0.5, -MAX_PERCENT
, MAX_PERCENT
);
359 maTransforms
.emplace_back( XLS_TOKEN( tint
), nValue
);
362 void Color::clearTransformations()
364 maTransforms
.clear();
365 maInteropTransformations
.realloc(0);
369 OUString
Color::getColorTransformationName( sal_Int32 nElement
)
373 case XML_red
: return "red";
374 case XML_redMod
: return "redMod";
375 case XML_redOff
: return "redOff";
376 case XML_green
: return "green";
377 case XML_greenMod
: return "greenMod";
378 case XML_greenOff
: return "greenOff";
379 case XML_blue
: return "blue";
380 case XML_blueMod
: return "blueMod";
381 case XML_blueOff
: return "blueOff";
382 case XML_alpha
: return "alpha";
383 case XML_alphaMod
: return "alphaMod";
384 case XML_alphaOff
: return "alphaOff";
385 case XML_hue
: return "hue";
386 case XML_hueMod
: return "hueMod";
387 case XML_hueOff
: return "hueOff";
388 case XML_sat
: return "sat";
389 case XML_satMod
: return "satMod";
390 case XML_satOff
: return "satOff";
391 case XML_lum
: return "lum";
392 case XML_lumMod
: return "lumMod";
393 case XML_lumOff
: return "lumOff";
394 case XML_shade
: return "shade";
395 case XML_tint
: return "tint";
396 case XML_gray
: return "gray";
397 case XML_comp
: return "comp";
398 case XML_inv
: return "inv";
399 case XML_gamma
: return "gamma";
400 case XML_invGamma
: return "invGamma";
402 SAL_WARN( "oox.drawingml", "Color::getColorTransformationName - unexpected transformation type" );
406 sal_Int32
Color::getColorTransformationToken( std::u16string_view sName
)
408 if( sName
== u
"red" )
410 else if( sName
== u
"redMod" )
412 else if( sName
== u
"redOff" )
414 else if( sName
== u
"green" )
416 else if( sName
== u
"greenMod" )
418 else if( sName
== u
"greenOff" )
420 else if( sName
== u
"blue" )
422 else if( sName
== u
"blueMod" )
424 else if( sName
== u
"blueOff" )
426 else if( sName
== u
"alpha" )
428 else if( sName
== u
"alphaMod" )
430 else if( sName
== u
"alphaOff" )
432 else if( sName
== u
"hue" )
434 else if( sName
== u
"hueMod" )
436 else if( sName
== u
"hueOff" )
438 else if( sName
== u
"sat" )
440 else if( sName
== u
"satMod" )
442 else if( sName
== u
"satOff" )
444 else if( sName
== u
"lum" )
446 else if( sName
== u
"lumMod" )
448 else if( sName
== u
"lumOff" )
450 else if( sName
== u
"shade" )
452 else if( sName
== u
"tint" )
454 else if( sName
== u
"gray" )
456 else if( sName
== u
"comp" )
458 else if( sName
== u
"inv" )
460 else if( sName
== u
"gamma" )
462 else if( sName
== u
"invGamma" )
465 SAL_WARN( "oox.drawingml", "Color::getColorTransformationToken - unexpected transformation type" );
466 return XML_TOKEN_INVALID
;
469 bool Color::equals(const Color
& rOther
, const GraphicHelper
& rGraphicHelper
, ::Color nPhClr
) const
471 if (getColor(rGraphicHelper
, nPhClr
) != rOther
.getColor(rGraphicHelper
, nPhClr
))
474 return getTransparency() == rOther
.getTransparency();
477 void Color::clearTransparence()
479 mnAlpha
= MAX_PERCENT
;
482 ::Color
Color::getColor( const GraphicHelper
& rGraphicHelper
, ::Color nPhClr
) const
484 const sal_Int32 nTempC1
= mnC1
;
485 const sal_Int32 nTempC2
= mnC2
;
486 const sal_Int32 nTempC3
= mnC3
;
487 const ColorMode eTempMode
= meMode
;
491 case COLOR_UNUSED
: mnC1
= sal_Int32(API_RGB_TRANSPARENT
); break;
493 case COLOR_RGB
: break; // nothing to do
494 case COLOR_CRGB
: break; // nothing to do
495 case COLOR_HSL
: break; // nothing to do
497 case COLOR_SCHEME
: setResolvedRgb( rGraphicHelper
.getSchemeColor( mnC1
) ); break;
498 case COLOR_PALETTE
: setResolvedRgb( rGraphicHelper
.getPaletteColor( mnC1
) ); break;
499 case COLOR_SYSTEM
: setResolvedRgb( rGraphicHelper
.getSystemColor( mnC1
, ::Color(ColorTransparency
, mnC2
) ) ); break;
500 case COLOR_PH
: setResolvedRgb( nPhClr
); break;
502 case COLOR_FINAL
: return ::Color(ColorTransparency
, mnC1
);
505 // if color is UNUSED or turns to UNUSED in setResolvedRgb, do not perform transformations
506 if( meMode
!= COLOR_UNUSED
)
508 for (auto const& transform
: maTransforms
)
510 switch( transform
.mnToken
)
512 case XML_red
: toCrgb(); lclSetValue( mnC1
, transform
.mnValue
); break;
513 case XML_redMod
: toCrgb(); lclModValue( mnC1
, transform
.mnValue
); break;
514 case XML_redOff
: toCrgb(); lclOffValue( mnC1
, transform
.mnValue
); break;
515 case XML_green
: toCrgb(); lclSetValue( mnC2
, transform
.mnValue
); break;
516 case XML_greenMod
: toCrgb(); lclModValue( mnC2
, transform
.mnValue
); break;
517 case XML_greenOff
: toCrgb(); lclOffValue( mnC2
, transform
.mnValue
); break;
518 case XML_blue
: toCrgb(); lclSetValue( mnC3
, transform
.mnValue
); break;
519 case XML_blueMod
: toCrgb(); lclModValue( mnC3
, transform
.mnValue
); break;
520 case XML_blueOff
: toCrgb(); lclOffValue( mnC3
, transform
.mnValue
); break;
522 case XML_hue
: toHsl(); lclSetValue( mnC1
, transform
.mnValue
, MAX_DEGREE
); break;
523 case XML_hueMod
: toHsl(); lclModValue( mnC1
, transform
.mnValue
, MAX_DEGREE
); break;
524 case XML_hueOff
: toHsl(); lclOffValue( mnC1
, transform
.mnValue
, MAX_DEGREE
); break;
525 case XML_sat
: toHsl(); lclSetValue( mnC2
, transform
.mnValue
); break;
526 case XML_satMod
: toHsl(); lclModValue( mnC2
, transform
.mnValue
); break;
527 case XML_satOff
: toHsl(); lclOffValue( mnC2
, transform
.mnValue
); break;
531 lclSetValue( mnC3
, transform
.mnValue
);
532 // if color changes to black or white, it will stay gray if luminance changes again
533 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
537 lclModValue( mnC3
, transform
.mnValue
);
538 // if color changes to black or white, it will stay gray if luminance changes again
539 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
543 lclOffValue( mnC3
, transform
.mnValue
);
544 // if color changes to black or white, it will stay gray if luminance changes again
545 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
549 // shade: 0% = black, 100% = original color
551 OSL_ENSURE( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
), "Color::getColor - invalid shade value" );
552 if( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
) )
554 double fFactor
= static_cast< double >( transform
.mnValue
) / MAX_PERCENT
;
555 mnC1
= static_cast< sal_Int32
>( mnC1
* fFactor
);
556 mnC2
= static_cast< sal_Int32
>( mnC2
* fFactor
);
557 mnC3
= static_cast< sal_Int32
>( mnC3
* fFactor
);
561 // tint: 0% = white, 100% = original color
563 OSL_ENSURE( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
), "Color::getColor - invalid tint value" );
564 if( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
) )
566 double fFactor
= static_cast< double >( transform
.mnValue
) / MAX_PERCENT
;
567 mnC1
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC1
) * fFactor
);
568 mnC2
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC2
) * fFactor
);
569 mnC3
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC3
) * fFactor
);
572 case XLS_TOKEN( tint
):
573 // Excel tint: move luminance relative to current value
575 OSL_ENSURE( (-MAX_PERCENT
<= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
), "Color::getColor - invalid tint value" );
576 if( (-MAX_PERCENT
<= transform
.mnValue
) && (transform
.mnValue
< 0) )
578 // negative: luminance towards 0% (black)
579 lclModValue( mnC3
, transform
.mnValue
+ MAX_PERCENT
);
581 else if( (0 < transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
) )
583 // positive: luminance towards 100% (white)
584 mnC3
= MAX_PERCENT
- mnC3
;
585 lclModValue( mnC3
, MAX_PERCENT
- transform
.mnValue
);
586 mnC3
= MAX_PERCENT
- mnC3
;
591 // change color to gray, weighted RGB: 22% red, 72% green, 6% blue
593 mnC1
= mnC2
= mnC3
= (mnC1
* 22 + mnC2
* 72 + mnC3
* 6) / 100;
597 // comp: rotate hue by 180 degrees, do not change lum/sat
599 mnC1
= (mnC1
+ (180 * PER_DEGREE
)) % MAX_DEGREE
;
602 // invert percentual RGB values
604 mnC1
= MAX_PERCENT
- mnC1
;
605 mnC2
= MAX_PERCENT
- mnC2
;
606 mnC3
= MAX_PERCENT
- mnC3
;
610 // increase gamma of color
612 mnC1
= lclGamma( mnC1
, INC_GAMMA
);
613 mnC2
= lclGamma( mnC2
, INC_GAMMA
);
614 mnC3
= lclGamma( mnC3
, INC_GAMMA
);
617 // decrease gamma of color
619 mnC1
= lclGamma( mnC1
, DEC_GAMMA
);
620 mnC2
= lclGamma( mnC2
, DEC_GAMMA
);
621 mnC3
= lclGamma( mnC3
, DEC_GAMMA
);
626 // store resulting RGB value in mnC1
628 mnC1
= lclRgbComponentsToRgb( mnC1
, mnC2
, mnC3
);
630 else // if( meMode != COLOR_UNUSED )
632 mnC1
= sal_Int32(API_RGB_TRANSPARENT
);
635 sal_Int32 nRet
= mnC1
;
636 // Restore the original values when the color depends on one of the input
637 // parameters (rGraphicHelper or nPhClr)
638 if( eTempMode
>= COLOR_SCHEME
&& eTempMode
<= COLOR_PH
)
647 meMode
= COLOR_FINAL
;
649 if( meMode
== COLOR_FINAL
)
650 maTransforms
.clear();
651 return ::Color(ColorTransparency
, nRet
);
654 bool Color::hasTransparency() const
656 return mnAlpha
< MAX_PERCENT
;
659 sal_Int16
Color::getTransparency() const
661 return sal_Int16(std::round( (1.0 * (MAX_PERCENT
- mnAlpha
)) / PER_PERCENT
) );
664 // private --------------------------------------------------------------------
666 void Color::setResolvedRgb( ::Color nRgb
) const
668 meMode
= (sal_Int32(nRgb
) < 0) ? COLOR_UNUSED
: COLOR_RGB
;
669 lclRgbToRgbComponents( mnC1
, mnC2
, mnC3
, nRgb
);
672 void Color::toRgb() const
681 mnC1
= lclCrgbCompToRgbComp( lclGamma( mnC1
, INC_GAMMA
) );
682 mnC2
= lclCrgbCompToRgbComp( lclGamma( mnC2
, INC_GAMMA
) );
683 mnC3
= lclCrgbCompToRgbComp( lclGamma( mnC3
, INC_GAMMA
) );
688 double fR
= 0.0, fG
= 0.0, fB
= 0.0;
689 if( (mnC2
== 0) || (mnC3
== MAX_PERCENT
) )
691 fR
= fG
= fB
= static_cast< double >( mnC3
) / MAX_PERCENT
;
695 // base color from hue
696 double fHue
= static_cast< double >( mnC1
) / MAX_DEGREE
* 6.0; // interval [0.0, 6.0)
697 if( fHue
<= 1.0 ) { fR
= 1.0; fG
= fHue
; } // red...yellow
698 else if( fHue
<= 2.0 ) { fR
= 2.0 - fHue
; fG
= 1.0; } // yellow...green
699 else if( fHue
<= 3.0 ) { fG
= 1.0; fB
= fHue
- 2.0; } // green...cyan
700 else if( fHue
<= 4.0 ) { fG
= 4.0 - fHue
; fB
= 1.0; } // cyan...blue
701 else if( fHue
<= 5.0 ) { fR
= fHue
- 4.0; fB
= 1.0; } // blue...magenta
702 else { fR
= 1.0; fB
= 6.0 - fHue
; } // magenta...red
705 double fSat
= static_cast< double >( mnC2
) / MAX_PERCENT
;
706 fR
= (fR
- 0.5) * fSat
+ 0.5;
707 fG
= (fG
- 0.5) * fSat
+ 0.5;
708 fB
= (fB
- 0.5) * fSat
+ 0.5;
711 double fLum
= 2.0 * static_cast< double >( mnC3
) / MAX_PERCENT
- 1.0; // interval [-1.0, 1.0]
714 double fShade
= fLum
+ 1.0; // interval [0.0, 1.0] (black...full color)
719 else if( fLum
> 0.0 )
721 double fTint
= 1.0 - fLum
; // interval [0.0, 1.0] (white...full color)
722 fR
= 1.0 - ((1.0 - fR
) * fTint
);
723 fG
= 1.0 - ((1.0 - fG
) * fTint
);
724 fB
= 1.0 - ((1.0 - fB
) * fTint
);
727 mnC1
= static_cast< sal_Int32
>( fR
* 255.0 + 0.5 );
728 mnC2
= static_cast< sal_Int32
>( fG
* 255.0 + 0.5 );
729 mnC3
= static_cast< sal_Int32
>( fB
* 255.0 + 0.5 );
733 OSL_FAIL( "Color::toRgb - unexpected color mode" );
737 void Color::toCrgb() const
746 mnC1
= lclGamma( lclRgbCompToCrgbComp( mnC1
), DEC_GAMMA
);
747 mnC2
= lclGamma( lclRgbCompToCrgbComp( mnC2
), DEC_GAMMA
);
748 mnC3
= lclGamma( lclRgbCompToCrgbComp( mnC3
), DEC_GAMMA
);
754 OSL_FAIL( "Color::toCrgb - unexpected color mode" );
758 void Color::toHsl() const
768 double fR
= static_cast< double >( mnC1
) / 255.0; // red [0.0, 1.0]
769 double fG
= static_cast< double >( mnC2
) / 255.0; // green [0.0, 1.0]
770 double fB
= static_cast< double >( mnC3
) / 255.0; // blue [0.0, 1.0]
771 double fMin
= ::std::min( ::std::min( fR
, fG
), fB
);
772 double fMax
= ::std::max( ::std::max( fR
, fG
), fB
);
773 double fD
= fMax
- fMin
;
775 using ::rtl::math::approxEqual
;
777 // hue: 0deg = red, 120deg = green, 240deg = blue
778 if( fD
== 0.0 ) // black/gray/white
780 else if( approxEqual(fMax
, fR
, 64) ) // magenta...red...yellow
781 mnC1
= static_cast< sal_Int32
>( ((fG
- fB
) / fD
* 60.0 + 360.0) * PER_DEGREE
+ 0.5 ) % MAX_DEGREE
;
782 else if( approxEqual(fMax
, fG
, 64) ) // yellow...green...cyan
783 mnC1
= static_cast< sal_Int32
>( ((fB
- fR
) / fD
* 60.0 + 120.0) * PER_DEGREE
+ 0.5 );
784 else // cyan...blue...magenta
785 mnC1
= static_cast< sal_Int32
>( ((fR
- fG
) / fD
* 60.0 + 240.0) * PER_DEGREE
+ 0.5 );
787 // luminance: 0% = black, 50% = full color, 100% = white
788 mnC3
= static_cast< sal_Int32
>( (fMin
+ fMax
) / 2.0 * MAX_PERCENT
+ 0.5 );
790 // saturation: 0% = gray, 100% = full color
791 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) // black/white
793 else if( mnC3
<= 50 * PER_PERCENT
) // dark...full color
794 mnC2
= static_cast< sal_Int32
>( fD
/ (fMin
+ fMax
) * MAX_PERCENT
+ 0.5 );
795 else // full color...light
796 mnC2
= static_cast< sal_Int32
>( fD
/ (2.0 - fMax
- fMin
) * MAX_PERCENT
+ 0.5 );
803 OSL_FAIL( "Color::toHsl - unexpected color mode" );
809 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */