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>
36 /** Global storage for predefined color values used in OOXML file formats. */
37 struct PresetColorsPool
39 typedef ::std::vector
< ::Color
> ColorVector
;
41 ColorVector maDmlColors
; /// Predefined colors in DrawingML, indexed by XML token.
42 ColorVector maVmlColors
; /// Predefined colors in VML, 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
)
51 // predefined colors in DrawingML (map XML token identifiers to RGB values)
52 static const std::pair
<sal_Int32
, ::Color
> spnDmlColors
[] =
54 {XML_aliceBlue
, ::Color(0xF0F8FF)}, {XML_antiqueWhite
, ::Color(0xFAEBD7)},
55 {XML_aqua
, ::Color(0x00FFFF)}, {XML_aquamarine
, ::Color(0x7FFFD4)},
56 {XML_azure
, ::Color(0xF0FFFF)}, {XML_beige
, ::Color(0xF5F5DC)},
57 {XML_bisque
, ::Color(0xFFE4C4)}, {XML_black
, ::Color(0x000000)},
58 {XML_blanchedAlmond
, ::Color(0xFFEBCD)}, {XML_blue
, ::Color(0x0000FF)},
59 {XML_blueViolet
, ::Color(0x8A2BE2)}, {XML_brown
, ::Color(0xA52A2A)},
60 {XML_burlyWood
, ::Color(0xDEB887)}, {XML_cadetBlue
, ::Color(0x5F9EA0)},
61 {XML_chartreuse
, ::Color(0x7FFF00)}, {XML_chocolate
, ::Color(0xD2691E)},
62 {XML_coral
, ::Color(0xFF7F50)}, {XML_cornflowerBlue
, ::Color(0x6495ED)},
63 {XML_cornsilk
, ::Color(0xFFF8DC)}, {XML_crimson
, ::Color(0xDC143C)},
64 {XML_cyan
, ::Color(0x00FFFF)}, {XML_deepPink
, ::Color(0xFF1493)},
65 {XML_deepSkyBlue
, ::Color(0x00BFFF)}, {XML_dimGray
, ::Color(0x696969)},
66 {XML_dkBlue
, ::Color(0x00008B)}, {XML_dkCyan
, ::Color(0x008B8B)},
67 {XML_dkGoldenrod
, ::Color(0xB8860B)}, {XML_dkGray
, ::Color(0xA9A9A9)},
68 {XML_dkGreen
, ::Color(0x006400)}, {XML_dkKhaki
, ::Color(0xBDB76B)},
69 {XML_dkMagenta
, ::Color(0x8B008B)}, {XML_dkOliveGreen
, ::Color(0x556B2F)},
70 {XML_dkOrange
, ::Color(0xFF8C00)}, {XML_dkOrchid
, ::Color(0x9932CC)},
71 {XML_dkRed
, ::Color(0x8B0000)}, {XML_dkSalmon
, ::Color(0xE9967A)},
72 {XML_dkSeaGreen
, ::Color(0x8FBC8B)}, {XML_dkSlateBlue
, ::Color(0x483D8B)},
73 {XML_dkSlateGray
, ::Color(0x2F4F4F)}, {XML_dkTurquoise
, ::Color(0x00CED1)},
74 {XML_dkViolet
, ::Color(0x9400D3)}, {XML_dodgerBlue
, ::Color(0x1E90FF)},
75 {XML_firebrick
, ::Color(0xB22222)}, {XML_floralWhite
, ::Color(0xFFFAF0)},
76 {XML_forestGreen
, ::Color(0x228B22)}, {XML_fuchsia
, ::Color(0xFF00FF)},
77 {XML_gainsboro
, ::Color(0xDCDCDC)}, {XML_ghostWhite
, ::Color(0xF8F8FF)},
78 {XML_gold
, ::Color(0xFFD700)}, {XML_goldenrod
, ::Color(0xDAA520)},
79 {XML_gray
, ::Color(0x808080)}, {XML_green
, ::Color(0x008000)},
80 {XML_greenYellow
, ::Color(0xADFF2F)}, {XML_honeydew
, ::Color(0xF0FFF0)},
81 {XML_hotPink
, ::Color(0xFF69B4)}, {XML_indianRed
, ::Color(0xCD5C5C)},
82 {XML_indigo
, ::Color(0x4B0082)}, {XML_ivory
, ::Color(0xFFFFF0)},
83 {XML_khaki
, ::Color(0xF0E68C)}, {XML_lavender
, ::Color(0xE6E6FA)},
84 {XML_lavenderBlush
, ::Color(0xFFF0F5)}, {XML_lawnGreen
, ::Color(0x7CFC00)},
85 {XML_lemonChiffon
, ::Color(0xFFFACD)}, {XML_lime
, ::Color(0x00FF00)},
86 {XML_limeGreen
, ::Color(0x32CD32)}, {XML_linen
, ::Color(0xFAF0E6)},
87 {XML_ltBlue
, ::Color(0xADD8E6)}, {XML_ltCoral
, ::Color(0xF08080)},
88 {XML_ltCyan
, ::Color(0xE0FFFF)}, {XML_ltGoldenrodYellow
, ::Color(0xFAFA78)},
89 {XML_ltGray
, ::Color(0xD3D3D3)}, {XML_ltGreen
, ::Color(0x90EE90)},
90 {XML_ltPink
, ::Color(0xFFB6C1)}, {XML_ltSalmon
, ::Color(0xFFA07A)},
91 {XML_ltSeaGreen
, ::Color(0x20B2AA)}, {XML_ltSkyBlue
, ::Color(0x87CEFA)},
92 {XML_ltSlateGray
, ::Color(0x778899)}, {XML_ltSteelBlue
, ::Color(0xB0C4DE)},
93 {XML_ltYellow
, ::Color(0xFFFFE0)}, {XML_magenta
, ::Color(0xFF00FF)},
94 {XML_maroon
, ::Color(0x800000)}, {XML_medAquamarine
, ::Color(0x66CDAA)},
95 {XML_medBlue
, ::Color(0x0000CD)}, {XML_medOrchid
, ::Color(0xBA55D3)},
96 {XML_medPurple
, ::Color(0x9370DB)}, {XML_medSeaGreen
, ::Color(0x3CB371)},
97 {XML_medSlateBlue
, ::Color(0x7B68EE)}, {XML_medSpringGreen
, ::Color(0x00FA9A)},
98 {XML_medTurquoise
, ::Color(0x48D1CC)}, {XML_medVioletRed
, ::Color(0xC71585)},
99 {XML_midnightBlue
, ::Color(0x191970)}, {XML_mintCream
, ::Color(0xF5FFFA)},
100 {XML_mistyRose
, ::Color(0xFFE4E1)}, {XML_moccasin
, ::Color(0xFFE4B5)},
101 {XML_navajoWhite
, ::Color(0xFFDEAD)}, {XML_navy
, ::Color(0x000080)},
102 {XML_oldLace
, ::Color(0xFDF5E6)}, {XML_olive
, ::Color(0x808000)},
103 {XML_oliveDrab
, ::Color(0x6B8E23)}, {XML_orange
, ::Color(0xFFA500)},
104 {XML_orangeRed
, ::Color(0xFF4500)}, {XML_orchid
, ::Color(0xDA70D6)},
105 {XML_paleGoldenrod
, ::Color(0xEEE8AA)}, {XML_paleGreen
, ::Color(0x98FB98)},
106 {XML_paleTurquoise
, ::Color(0xAFEEEE)}, {XML_paleVioletRed
, ::Color(0xDB7093)},
107 {XML_papayaWhip
, ::Color(0xFFEFD5)}, {XML_peachPuff
, ::Color(0xFFDAB9)},
108 {XML_peru
, ::Color(0xCD853F)}, {XML_pink
, ::Color(0xFFC0CB)},
109 {XML_plum
, ::Color(0xDDA0DD)}, {XML_powderBlue
, ::Color(0xB0E0E6)},
110 {XML_purple
, ::Color(0x800080)}, {XML_red
, ::Color(0xFF0000)},
111 {XML_rosyBrown
, ::Color(0xBC8F8F)}, {XML_royalBlue
, ::Color(0x4169E1)},
112 {XML_saddleBrown
, ::Color(0x8B4513)}, {XML_salmon
, ::Color(0xFA8072)},
113 {XML_sandyBrown
, ::Color(0xF4A460)}, {XML_seaGreen
, ::Color(0x2E8B57)},
114 {XML_seaShell
, ::Color(0xFFF5EE)}, {XML_sienna
, ::Color(0xA0522D)},
115 {XML_silver
, ::Color(0xC0C0C0)}, {XML_skyBlue
, ::Color(0x87CEEB)},
116 {XML_slateBlue
, ::Color(0x6A5ACD)}, {XML_slateGray
, ::Color(0x708090)},
117 {XML_snow
, ::Color(0xFFFAFA)}, {XML_springGreen
, ::Color(0x00FF7F)},
118 {XML_steelBlue
, ::Color(0x4682B4)}, {XML_tan
, ::Color(0xD2B48C)},
119 {XML_teal
, ::Color(0x008080)}, {XML_thistle
, ::Color(0xD8BFD8)},
120 {XML_tomato
, ::Color(0xFF6347)}, {XML_turquoise
, ::Color(0x40E0D0)},
121 {XML_violet
, ::Color(0xEE82EE)}, {XML_wheat
, ::Color(0xF5DEB3)},
122 {XML_white
, ::Color(0xFFFFFF)}, {XML_whiteSmoke
, ::Color(0xF5F5F5)},
123 {XML_yellow
, ::Color(0xFFFF00)}, {XML_yellowGreen
, ::Color(0x9ACD32)}
125 for(auto const& nEntry
: spnDmlColors
)
126 maDmlColors
[ static_cast< size_t >(nEntry
.first
) ] = nEntry
.second
;
128 // predefined colors in VML (map XML token identifiers to RGB values)
129 static const std::pair
<sal_Int32
, ::Color
> spnVmlColors
[] =
131 {XML_aqua
, ::Color(0x00FFFF)}, {XML_black
, ::Color(0x000000)},
132 {XML_blue
, ::Color(0x0000FF)}, {XML_fuchsia
, ::Color(0xFF00FF)},
133 {XML_gray
, ::Color(0x808080)}, {XML_green
, ::Color(0x008000)},
134 {XML_lime
, ::Color(0x00FF00)}, {XML_maroon
, ::Color(0x800000)},
135 {XML_navy
, ::Color(0x000080)}, {XML_olive
, ::Color(0x808000)},
136 {XML_purple
, ::Color(0x800080)}, {XML_red
, ::Color(0xFF0000)},
137 {XML_silver
, ::Color(0xC0C0C0)}, {XML_teal
, ::Color(0x008080)},
138 {XML_white
, ::Color(0xFFFFFF)}, {XML_yellow
, ::Color(0xFFFF00)}
140 for(auto const& nEntry
: spnVmlColors
)
141 maVmlColors
[ static_cast< size_t >(nEntry
.first
) ] = nEntry
.second
;
144 struct StaticPresetColorsPool
: public ::rtl::Static
< PresetColorsPool
, StaticPresetColorsPool
> {};
146 const double DEC_GAMMA
= 2.3;
147 const double INC_GAMMA
= 1.0 / DEC_GAMMA
;
149 void lclRgbToRgbComponents( sal_Int32
& ornR
, sal_Int32
& ornG
, sal_Int32
& ornB
, ::Color nRgb
)
151 ornR
= nRgb
.GetRed();
152 ornG
= nRgb
.GetGreen();
153 ornB
= nRgb
.GetBlue();
156 sal_Int32
lclRgbComponentsToRgb( sal_Int32 nR
, sal_Int32 nG
, sal_Int32 nB
)
158 return static_cast< sal_Int32
>( (nR
<< 16) | (nG
<< 8) | nB
);
161 sal_Int32
lclRgbCompToCrgbComp( sal_Int32 nRgbComp
)
163 return static_cast< sal_Int32
>( nRgbComp
* MAX_PERCENT
/ 255 );
166 sal_Int32
lclCrgbCompToRgbComp( sal_Int32 nCrgbComp
)
168 return static_cast< sal_Int32
>( nCrgbComp
* 255 / MAX_PERCENT
);
171 sal_Int32
lclGamma( sal_Int32 nComp
, double fGamma
)
173 return static_cast< sal_Int32
>( pow( static_cast< double >( nComp
) / MAX_PERCENT
, fGamma
) * MAX_PERCENT
+ 0.5 );
176 void lclSetValue( sal_Int32
& ornValue
, sal_Int32 nNew
, sal_Int32 nMax
= MAX_PERCENT
)
178 OSL_ENSURE( (0 <= nNew
) && (nNew
<= nMax
), "lclSetValue - invalid value" );
179 if( (0 <= nNew
) && (nNew
<= nMax
) )
183 void lclModValue( sal_Int32
& ornValue
, sal_Int32 nMod
, sal_Int32 nMax
= MAX_PERCENT
)
185 OSL_ENSURE( (0 <= nMod
), "lclModValue - invalid modificator" );
186 ornValue
= getLimitedValue
< sal_Int32
, double >( static_cast< double >( ornValue
) * nMod
/ MAX_PERCENT
, 0, nMax
);
189 void lclOffValue( sal_Int32
& ornValue
, sal_Int32 nOff
, sal_Int32 nMax
= MAX_PERCENT
)
191 OSL_ENSURE( (-nMax
<= nOff
) && (nOff
<= nMax
), "lclOffValue - invalid offset" );
192 ornValue
= getLimitedValue
< sal_Int32
, sal_Int32
>( ornValue
+ nOff
, 0, nMax
);
198 meMode( COLOR_UNUSED
),
202 mnAlpha( MAX_PERCENT
)
206 ::Color
Color::getDmlPresetColor( sal_Int32 nToken
, ::Color nDefaultRgb
)
208 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
209 able to catch the existing vector entries without corresponding XML
211 ::Color nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maDmlColors
, nToken
, API_RGB_TRANSPARENT
);
212 return (sal_Int32(nRgbValue
) >= 0) ? nRgbValue
: nDefaultRgb
;
215 ::Color
Color::getVmlPresetColor( sal_Int32 nToken
, ::Color nDefaultRgb
)
217 /* Do not pass nDefaultRgb to ContainerHelper::getVectorElement(), to be
218 able to catch the existing vector entries without corresponding XML
220 ::Color nRgbValue
= ContainerHelper::getVectorElement( StaticPresetColorsPool::get().maVmlColors
, nToken
, API_RGB_TRANSPARENT
);
221 return (sal_Int32(nRgbValue
) >= 0) ? nRgbValue
: nDefaultRgb
;
224 void Color::setUnused()
226 meMode
= COLOR_UNUSED
;
229 void Color::setSrgbClr( ::Color nRgb
)
231 setSrgbClr(sal_Int32(nRgb
));
234 void Color::setSrgbClr( sal_Int32 nRgb
)
236 OSL_ENSURE( (0 <= nRgb
) && (nRgb
<= 0xFFFFFF), "Color::setSrgbClr - invalid RGB value" );
238 lclRgbToRgbComponents( mnC1
, mnC2
, mnC3
, ::Color(nRgb
) );
241 void Color::setScrgbClr( sal_Int32 nR
, sal_Int32 nG
, sal_Int32 nB
)
243 OSL_ENSURE( (0 <= nR
) && (nR
<= MAX_PERCENT
), "Color::setScrgbClr - invalid red value" );
244 OSL_ENSURE( (0 <= nG
) && (nG
<= MAX_PERCENT
), "Color::setScrgbClr - invalid green value" );
245 OSL_ENSURE( (0 <= nB
) && (nB
<= MAX_PERCENT
), "Color::setScrgbClr - invalid blue value" );
247 mnC1
= getLimitedValue
< sal_Int32
, sal_Int32
>( nR
, 0, MAX_PERCENT
);
248 mnC2
= getLimitedValue
< sal_Int32
, sal_Int32
>( nG
, 0, MAX_PERCENT
);
249 mnC3
= getLimitedValue
< sal_Int32
, sal_Int32
>( nB
, 0, MAX_PERCENT
);
252 void Color::setHslClr( sal_Int32 nHue
, sal_Int32 nSat
, sal_Int32 nLum
)
254 OSL_ENSURE( (0 <= nHue
) && (nHue
<= MAX_DEGREE
), "Color::setHslClr - invalid hue value" );
255 OSL_ENSURE( (0 <= nSat
) && (nSat
<= MAX_PERCENT
), "Color::setHslClr - invalid saturation value" );
256 OSL_ENSURE( (0 <= nLum
) && (nLum
<= MAX_PERCENT
), "Color::setHslClr - invalid luminance value" );
258 mnC1
= getLimitedValue
< sal_Int32
, sal_Int32
>( nHue
, 0, MAX_DEGREE
);
259 mnC2
= getLimitedValue
< sal_Int32
, sal_Int32
>( nSat
, 0, MAX_PERCENT
);
260 mnC3
= getLimitedValue
< sal_Int32
, sal_Int32
>( nLum
, 0, MAX_PERCENT
);
263 void Color::setPrstClr( sal_Int32 nToken
)
265 ::Color nRgbValue
= getDmlPresetColor( nToken
, API_RGB_TRANSPARENT
);
266 OSL_ENSURE( sal_Int32(nRgbValue
) >= 0, "Color::setPrstClr - invalid preset color token" );
267 if( sal_Int32(nRgbValue
) >= 0 )
268 setSrgbClr( nRgbValue
);
271 void Color::setSchemeClr( sal_Int32 nToken
)
273 OSL_ENSURE( nToken
!= XML_TOKEN_INVALID
, "Color::setSchemeClr - invalid color token" );
274 meMode
= (nToken
== XML_phClr
) ? COLOR_PH
: COLOR_SCHEME
;
278 void Color::setPaletteClr( sal_Int32 nPaletteIdx
)
280 OSL_ENSURE( nPaletteIdx
>= 0, "Color::setPaletteClr - invalid palette index" );
281 meMode
= COLOR_PALETTE
;
285 void Color::setSysClr( sal_Int32 nToken
, sal_Int32 nLastRgb
)
287 OSL_ENSURE( (-1 <= nLastRgb
) && (nLastRgb
<= 0xFFFFFF), "Color::setSysClr - invalid RGB value" );
288 meMode
= COLOR_SYSTEM
;
293 void Color::addTransformation( sal_Int32 nElement
, sal_Int32 nValue
)
295 /* Execute alpha transformations directly, store other transformations in
296 a vector, they may depend on a scheme base color which will be resolved
297 in Color::getColor(). */
298 sal_Int32 nToken
= getBaseToken( nElement
);
301 case XML_alpha
: lclSetValue( mnAlpha
, nValue
); break;
302 case XML_alphaMod
: lclModValue( mnAlpha
, nValue
); break;
303 case XML_alphaOff
: lclOffValue( mnAlpha
, nValue
); break;
304 default: maTransforms
.emplace_back( nToken
, nValue
);
306 sal_Int32 nSize
= maInteropTransformations
.getLength();
307 maInteropTransformations
.realloc(nSize
+ 1);
308 maInteropTransformations
[nSize
].Name
= getColorTransformationName( nToken
);
309 maInteropTransformations
[nSize
].Value
<<= nValue
;
312 void Color::addChartTintTransformation( double fTint
)
314 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( fTint
* MAX_PERCENT
+ 0.5, -MAX_PERCENT
, MAX_PERCENT
);
316 maTransforms
.emplace_back( XML_shade
, nValue
+ MAX_PERCENT
);
317 else if( nValue
> 0 )
318 maTransforms
.emplace_back( XML_tint
, MAX_PERCENT
- nValue
);
321 void Color::addExcelTintTransformation( double fTint
)
323 sal_Int32 nValue
= getLimitedValue
< sal_Int32
, double >( fTint
* MAX_PERCENT
+ 0.5, -MAX_PERCENT
, MAX_PERCENT
);
324 maTransforms
.emplace_back( XLS_TOKEN( tint
), nValue
);
327 void Color::clearTransformations()
329 maTransforms
.clear();
330 maInteropTransformations
.realloc(0);
334 OUString
Color::getColorTransformationName( sal_Int32 nElement
)
338 case XML_red
: return "red";
339 case XML_redMod
: return "redMod";
340 case XML_redOff
: return "redOff";
341 case XML_green
: return "green";
342 case XML_greenMod
: return "greenMod";
343 case XML_greenOff
: return "greenOff";
344 case XML_blue
: return "blue";
345 case XML_blueMod
: return "blueMod";
346 case XML_blueOff
: return "blueOff";
347 case XML_alpha
: return "alpha";
348 case XML_alphaMod
: return "alphaMod";
349 case XML_alphaOff
: return "alphaOff";
350 case XML_hue
: return "hue";
351 case XML_hueMod
: return "hueMod";
352 case XML_hueOff
: return "hueOff";
353 case XML_sat
: return "sat";
354 case XML_satMod
: return "satMod";
355 case XML_satOff
: return "satOff";
356 case XML_lum
: return "lum";
357 case XML_lumMod
: return "lumMod";
358 case XML_lumOff
: return "lumOff";
359 case XML_shade
: return "shade";
360 case XML_tint
: return "tint";
361 case XML_gray
: return "gray";
362 case XML_comp
: return "comp";
363 case XML_inv
: return "inv";
364 case XML_gamma
: return "gamma";
365 case XML_invGamma
: return "invGamma";
367 SAL_WARN( "oox.drawingml", "Color::getColorTransformationName - unexpected transformation type" );
371 sal_Int32
Color::getColorTransformationToken( const OUString
& sName
)
375 else if( sName
== "redMod" )
377 else if( sName
== "redOff" )
379 else if( sName
== "green" )
381 else if( sName
== "greenMod" )
383 else if( sName
== "greenOff" )
385 else if( sName
== "blue" )
387 else if( sName
== "blueMod" )
389 else if( sName
== "blueOff" )
391 else if( sName
== "alpha" )
393 else if( sName
== "alphaMod" )
395 else if( sName
== "alphaOff" )
397 else if( sName
== "hue" )
399 else if( sName
== "hueMod" )
401 else if( sName
== "hueOff" )
403 else if( sName
== "sat" )
405 else if( sName
== "satMod" )
407 else if( sName
== "satOff" )
409 else if( sName
== "lum" )
411 else if( sName
== "lumMod" )
413 else if( sName
== "lumOff" )
415 else if( sName
== "shade" )
417 else if( sName
== "tint" )
419 else if( sName
== "gray" )
421 else if( sName
== "comp" )
423 else if( sName
== "inv" )
425 else if( sName
== "gamma" )
427 else if( sName
== "invGamma" )
430 SAL_WARN( "oox.drawingml", "Color::getColorTransformationToken - unexpected transformation type" );
431 return XML_TOKEN_INVALID
;
434 bool Color::equals(const Color
& rOther
, const GraphicHelper
& rGraphicHelper
, ::Color nPhClr
) const
436 if (getColor(rGraphicHelper
, nPhClr
) != rOther
.getColor(rGraphicHelper
, nPhClr
))
439 return getTransparency() == rOther
.getTransparency();
442 void Color::clearTransparence()
444 mnAlpha
= MAX_PERCENT
;
447 ::Color
Color::getColor( const GraphicHelper
& rGraphicHelper
, ::Color nPhClr
) const
449 const sal_Int32 nTempC1
= mnC1
;
450 const sal_Int32 nTempC2
= mnC2
;
451 const sal_Int32 nTempC3
= mnC3
;
452 const ColorMode eTempMode
= meMode
;
456 case COLOR_UNUSED
: mnC1
= sal_Int32(API_RGB_TRANSPARENT
); break;
458 case COLOR_RGB
: break; // nothing to do
459 case COLOR_CRGB
: break; // nothing to do
460 case COLOR_HSL
: break; // nothing to do
462 case COLOR_SCHEME
: setResolvedRgb( rGraphicHelper
.getSchemeColor( mnC1
) ); break;
463 case COLOR_PALETTE
: setResolvedRgb( rGraphicHelper
.getPaletteColor( mnC1
) ); break;
464 case COLOR_SYSTEM
: setResolvedRgb( rGraphicHelper
.getSystemColor( mnC1
, ::Color(mnC2
) ) ); break;
465 case COLOR_PH
: setResolvedRgb( nPhClr
); break;
467 case COLOR_FINAL
: return ::Color(mnC1
);
470 // if color is UNUSED or turns to UNUSED in setResolvedRgb, do not perform transformations
471 if( meMode
!= COLOR_UNUSED
)
473 for (auto const& transform
: maTransforms
)
475 switch( transform
.mnToken
)
477 case XML_red
: toCrgb(); lclSetValue( mnC1
, transform
.mnValue
); break;
478 case XML_redMod
: toCrgb(); lclModValue( mnC1
, transform
.mnValue
); break;
479 case XML_redOff
: toCrgb(); lclOffValue( mnC1
, transform
.mnValue
); break;
480 case XML_green
: toCrgb(); lclSetValue( mnC2
, transform
.mnValue
); break;
481 case XML_greenMod
: toCrgb(); lclModValue( mnC2
, transform
.mnValue
); break;
482 case XML_greenOff
: toCrgb(); lclOffValue( mnC2
, transform
.mnValue
); break;
483 case XML_blue
: toCrgb(); lclSetValue( mnC3
, transform
.mnValue
); break;
484 case XML_blueMod
: toCrgb(); lclModValue( mnC3
, transform
.mnValue
); break;
485 case XML_blueOff
: toCrgb(); lclOffValue( mnC3
, transform
.mnValue
); break;
487 case XML_hue
: toHsl(); lclSetValue( mnC1
, transform
.mnValue
, MAX_DEGREE
); break;
488 case XML_hueMod
: toHsl(); lclModValue( mnC1
, transform
.mnValue
, MAX_DEGREE
); break;
489 case XML_hueOff
: toHsl(); lclOffValue( mnC1
, transform
.mnValue
, MAX_DEGREE
); break;
490 case XML_sat
: toHsl(); lclSetValue( mnC2
, transform
.mnValue
); break;
491 case XML_satMod
: toHsl(); lclModValue( mnC2
, transform
.mnValue
); break;
492 case XML_satOff
: toHsl(); lclOffValue( mnC2
, transform
.mnValue
); break;
496 lclSetValue( mnC3
, transform
.mnValue
);
497 // if color changes to black or white, it will stay gray if luminance changes again
498 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
502 lclModValue( mnC3
, transform
.mnValue
);
503 // if color changes to black or white, it will stay gray if luminance changes again
504 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
508 lclOffValue( mnC3
, transform
.mnValue
);
509 // if color changes to black or white, it will stay gray if luminance changes again
510 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) mnC2
= 0;
514 // shade: 0% = black, 100% = original color
516 OSL_ENSURE( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
), "Color::getColor - invalid shade value" );
517 if( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
) )
519 double fFactor
= static_cast< double >( transform
.mnValue
) / MAX_PERCENT
;
520 mnC1
= static_cast< sal_Int32
>( mnC1
* fFactor
);
521 mnC2
= static_cast< sal_Int32
>( mnC2
* fFactor
);
522 mnC3
= static_cast< sal_Int32
>( mnC3
* fFactor
);
526 // tint: 0% = white, 100% = original color
528 OSL_ENSURE( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
), "Color::getColor - invalid tint value" );
529 if( (0 <= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
) )
531 double fFactor
= static_cast< double >( transform
.mnValue
) / MAX_PERCENT
;
532 mnC1
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC1
) * fFactor
);
533 mnC2
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC2
) * fFactor
);
534 mnC3
= static_cast< sal_Int32
>( MAX_PERCENT
- (MAX_PERCENT
- mnC3
) * fFactor
);
537 case XLS_TOKEN( tint
):
538 // Excel tint: move luminance relative to current value
540 OSL_ENSURE( (-MAX_PERCENT
<= transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
), "Color::getColor - invalid tint value" );
541 if( (-MAX_PERCENT
<= transform
.mnValue
) && (transform
.mnValue
< 0) )
543 // negative: luminance towards 0% (black)
544 lclModValue( mnC3
, transform
.mnValue
+ MAX_PERCENT
);
546 else if( (0 < transform
.mnValue
) && (transform
.mnValue
<= MAX_PERCENT
) )
548 // positive: luminance towards 100% (white)
549 mnC3
= MAX_PERCENT
- mnC3
;
550 lclModValue( mnC3
, MAX_PERCENT
- transform
.mnValue
);
551 mnC3
= MAX_PERCENT
- mnC3
;
556 // change color to gray, weighted RGB: 22% red, 72% green, 6% blue
558 mnC1
= mnC2
= mnC3
= (mnC1
* 22 + mnC2
* 72 + mnC3
* 6) / 100;
562 // comp: rotate hue by 180 degrees, do not change lum/sat
564 mnC1
= (mnC1
+ (180 * PER_DEGREE
)) % MAX_DEGREE
;
567 // invert percentual RGB values
569 mnC1
= MAX_PERCENT
- mnC1
;
570 mnC2
= MAX_PERCENT
- mnC2
;
571 mnC3
= MAX_PERCENT
- mnC3
;
575 // increase gamma of color
577 mnC1
= lclGamma( mnC1
, INC_GAMMA
);
578 mnC2
= lclGamma( mnC2
, INC_GAMMA
);
579 mnC3
= lclGamma( mnC3
, INC_GAMMA
);
582 // decrease gamma of color
584 mnC1
= lclGamma( mnC1
, DEC_GAMMA
);
585 mnC2
= lclGamma( mnC2
, DEC_GAMMA
);
586 mnC3
= lclGamma( mnC3
, DEC_GAMMA
);
591 // store resulting RGB value in mnC1
593 mnC1
= lclRgbComponentsToRgb( mnC1
, mnC2
, mnC3
);
595 else // if( meMode != COLOR_UNUSED )
597 mnC1
= sal_Int32(API_RGB_TRANSPARENT
);
600 sal_Int32 nRet
= mnC1
;
601 // Restore the original values when the color depends on one of the input
602 // parameters (rGraphicHelper or nPhClr)
603 if( eTempMode
>= COLOR_SCHEME
&& eTempMode
<= COLOR_PH
)
612 meMode
= COLOR_FINAL
;
614 if( meMode
== COLOR_FINAL
)
615 maTransforms
.clear();
616 return ::Color(nRet
);
619 bool Color::hasTransparency() const
621 return mnAlpha
< MAX_PERCENT
;
624 sal_Int16
Color::getTransparency() const
626 return sal_Int16(std::round( (1.0 * (MAX_PERCENT
- mnAlpha
)) / PER_PERCENT
) );
629 // private --------------------------------------------------------------------
631 void Color::setResolvedRgb( ::Color nRgb
) const
633 meMode
= (sal_Int32(nRgb
) < 0) ? COLOR_UNUSED
: COLOR_RGB
;
634 lclRgbToRgbComponents( mnC1
, mnC2
, mnC3
, nRgb
);
637 void Color::toRgb() const
646 mnC1
= lclCrgbCompToRgbComp( lclGamma( mnC1
, INC_GAMMA
) );
647 mnC2
= lclCrgbCompToRgbComp( lclGamma( mnC2
, INC_GAMMA
) );
648 mnC3
= lclCrgbCompToRgbComp( lclGamma( mnC3
, INC_GAMMA
) );
653 double fR
= 0.0, fG
= 0.0, fB
= 0.0;
654 if( (mnC2
== 0) || (mnC3
== MAX_PERCENT
) )
656 fR
= fG
= fB
= static_cast< double >( mnC3
) / MAX_PERCENT
;
660 // base color from hue
661 double fHue
= static_cast< double >( mnC1
) / MAX_DEGREE
* 6.0; // interval [0.0, 6.0)
662 if( fHue
<= 1.0 ) { fR
= 1.0; fG
= fHue
; } // red...yellow
663 else if( fHue
<= 2.0 ) { fR
= 2.0 - fHue
; fG
= 1.0; } // yellow...green
664 else if( fHue
<= 3.0 ) { fG
= 1.0; fB
= fHue
- 2.0; } // green...cyan
665 else if( fHue
<= 4.0 ) { fG
= 4.0 - fHue
; fB
= 1.0; } // cyan...blue
666 else if( fHue
<= 5.0 ) { fR
= fHue
- 4.0; fB
= 1.0; } // blue...magenta
667 else { fR
= 1.0; fB
= 6.0 - fHue
; } // magenta...red
670 double fSat
= static_cast< double >( mnC2
) / MAX_PERCENT
;
671 fR
= (fR
- 0.5) * fSat
+ 0.5;
672 fG
= (fG
- 0.5) * fSat
+ 0.5;
673 fB
= (fB
- 0.5) * fSat
+ 0.5;
676 double fLum
= 2.0 * static_cast< double >( mnC3
) / MAX_PERCENT
- 1.0; // interval [-1.0, 1.0]
679 double fShade
= fLum
+ 1.0; // interval [0.0, 1.0] (black...full color)
684 else if( fLum
> 0.0 )
686 double fTint
= 1.0 - fLum
; // interval [0.0, 1.0] (white...full color)
687 fR
= 1.0 - ((1.0 - fR
) * fTint
);
688 fG
= 1.0 - ((1.0 - fG
) * fTint
);
689 fB
= 1.0 - ((1.0 - fB
) * fTint
);
692 mnC1
= static_cast< sal_Int32
>( fR
* 255.0 + 0.5 );
693 mnC2
= static_cast< sal_Int32
>( fG
* 255.0 + 0.5 );
694 mnC3
= static_cast< sal_Int32
>( fB
* 255.0 + 0.5 );
698 OSL_FAIL( "Color::toRgb - unexpected color mode" );
702 void Color::toCrgb() const
711 mnC1
= lclGamma( lclRgbCompToCrgbComp( mnC1
), DEC_GAMMA
);
712 mnC2
= lclGamma( lclRgbCompToCrgbComp( mnC2
), DEC_GAMMA
);
713 mnC3
= lclGamma( lclRgbCompToCrgbComp( mnC3
), DEC_GAMMA
);
719 OSL_FAIL( "Color::toCrgb - unexpected color mode" );
723 void Color::toHsl() const
733 double fR
= static_cast< double >( mnC1
) / 255.0; // red [0.0, 1.0]
734 double fG
= static_cast< double >( mnC2
) / 255.0; // green [0.0, 1.0]
735 double fB
= static_cast< double >( mnC3
) / 255.0; // blue [0.0, 1.0]
736 double fMin
= ::std::min( ::std::min( fR
, fG
), fB
);
737 double fMax
= ::std::max( ::std::max( fR
, fG
), fB
);
738 double fD
= fMax
- fMin
;
740 using ::rtl::math::approxEqual
;
742 // hue: 0deg = red, 120deg = green, 240deg = blue
743 if( fD
== 0.0 ) // black/gray/white
745 else if( approxEqual(fMax
, fR
, 64) ) // magenta...red...yellow
746 mnC1
= static_cast< sal_Int32
>( ((fG
- fB
) / fD
* 60.0 + 360.0) * PER_DEGREE
+ 0.5 ) % MAX_DEGREE
;
747 else if( approxEqual(fMax
, fG
, 64) ) // yellow...green...cyan
748 mnC1
= static_cast< sal_Int32
>( ((fB
- fR
) / fD
* 60.0 + 120.0) * PER_DEGREE
+ 0.5 );
749 else // cyan...blue...magenta
750 mnC1
= static_cast< sal_Int32
>( ((fR
- fG
) / fD
* 60.0 + 240.0) * PER_DEGREE
+ 0.5 );
752 // luminance: 0% = black, 50% = full color, 100% = white
753 mnC3
= static_cast< sal_Int32
>( (fMin
+ fMax
) / 2.0 * MAX_PERCENT
+ 0.5 );
755 // saturation: 0% = gray, 100% = full color
756 if( (mnC3
== 0) || (mnC3
== MAX_PERCENT
) ) // black/white
758 else if( mnC3
<= 50 * PER_PERCENT
) // dark...full color
759 mnC2
= static_cast< sal_Int32
>( fD
/ (fMin
+ fMax
) * MAX_PERCENT
+ 0.5 );
760 else // full color...light
761 mnC2
= static_cast< sal_Int32
>( fD
/ (2.0 - fMax
- fMin
) * MAX_PERCENT
+ 0.5 );
768 OSL_FAIL( "Color::toHsl - unexpected color mode" );
772 } // namespace drawingml
775 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */