xref: /core/include/tools/color.hxx (revision d14d1341)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 #ifndef INCLUDED_TOOLS_COLOR_HXX
20 #define INCLUDED_TOOLS_COLOR_HXX
21 
22 #include <sal/types.h>
23 #include <tools/toolsdllapi.h>
24 #include <com/sun/star/uno/Any.hxx>
25 #include <basegfx/color/bcolor.hxx>
26 
27 namespace color
28 {
29 
30 constexpr sal_uInt32 extractRGB(sal_uInt32 nColorNumber)
31 {
32     return nColorNumber & 0x00FFFFFF;
33 }
34 
35 }
36 
37 // Color
38 
39 class SAL_WARN_UNUSED TOOLS_DLLPUBLIC Color
40 {
41     // data intentionally public; read the commit log!
42 public:
43     union
44     {
45         sal_uInt32 mValue;
46         struct
47         {
48 #ifdef OSL_BIGENDIAN
49                 sal_uInt8 A;
50                 sal_uInt8 R;
51                 sal_uInt8 G;
52                 sal_uInt8 B;
53 #else
54                 sal_uInt8 B;
55                 sal_uInt8 G;
56                 sal_uInt8 R;
57                 sal_uInt8 A;
58 #endif
59         };
60     };
61 
62 public:
63     constexpr Color()
64         : mValue(0) // black
65     {}
66 
67     constexpr Color(sal_uInt32 nColor)
68         : mValue(nColor)
69     {}
70 
71     constexpr Color(sal_uInt8 nTransparency, sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue)
72         : mValue(sal_uInt32(nBlue) | (sal_uInt32(nGreen) << 8) | (sal_uInt32(nRed) << 16) | (sal_uInt32(nTransparency) << 24))
73     {}
74 
75     constexpr Color(sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue)
76         : Color(0, nRed, nGreen, nBlue)
77     {}
78 
79     // constructor to create a tools-Color from ::basegfx::BColor
80     explicit Color(const basegfx::BColor& rBColor)
81         : Color(0,
82                 sal_uInt8(std::lround(rBColor.getRed() * 255.0)),
83                 sal_uInt8(std::lround(rBColor.getGreen() * 255.0)),
84                 sal_uInt8(std::lround(rBColor.getBlue() * 255.0)))
85     {}
86 
87     /** Primarily used when passing Color objects to UNO API */
88     constexpr explicit operator sal_uInt32() const
89     {
90         return mValue;
91     }
92 
93     constexpr explicit operator sal_Int32() const
94     {
95         return sal_Int32(mValue);
96     }
97 
98     bool operator<(const Color& aCompareColor) const
99     {
100         return mValue < aCompareColor.mValue;
101     }
102 
103     void SetRed(sal_uInt8 nRed);
104     sal_uInt8 GetRed() const
105     {
106         return R;
107     }
108     void SetGreen(sal_uInt8 nGreen);
109     sal_uInt8 GetGreen() const
110     {
111         return G;
112     }
113     void SetBlue(sal_uInt8 nBlue);
114     sal_uInt8 GetBlue() const
115     {
116         return B;
117     }
118     void SetTransparency(sal_uInt8 nTransparency);
119     sal_uInt8 GetTransparency() const
120     {
121         return A;
122     }
123 
124     Color GetRGBColor() const
125     {
126         return color::extractRGB(mValue);
127     }
128 
129     sal_uInt16 GetColorError(const Color& rCompareColor) const;
130 
131     sal_uInt8 GetLuminance() const;
132     void IncreaseLuminance(sal_uInt8 cLumInc);
133     void DecreaseLuminance(sal_uInt8 cLumDec);
134 
135     void DecreaseContrast(sal_uInt8 cContDec);
136 
137     /**
138      * Apply tint or shade to a color.
139      *
140      * The input value is the percentage (in 100th of percent) of how much the
141      * color changes towards the black (shade) or white (tint). If the value
142      * is positive, the color is tinted, if the value is negative, the color is
143      * shaded.
144      **/
145     void ApplyTintOrShade(sal_Int16 n100thPercent);
146 
147     void Invert();
148 
149     void Merge(const Color& rMergeColor, sal_uInt8 cTransparency);
150 
151     bool IsRGBEqual(const Color& rColor) const;
152 
153     // comparison with luminance thresholds
154     bool IsDark() const;
155     bool IsBright() const;
156 
157     // color space conversion tools
158     // the range for h/s/b is:
159     // Hue: 0-360 degree
160     // Saturation: 0-100%
161     // Brightness: 0-100%
162     static Color HSBtoRGB(sal_uInt16 nHue, sal_uInt16 nSaturation, sal_uInt16 nBrightness);
163     void RGBtoHSB(sal_uInt16& nHue, sal_uInt16& nSaturation, sal_uInt16& nBrightness) const;
164 
165     bool operator==(const Color& rColor) const
166     {
167         return mValue == rColor.mValue;
168     }
169     bool operator!=(const Color& rColor) const
170     {
171         return !(Color::operator==(rColor));
172     }
173 
174     // Return color as RGB hex string
175     // for example "00ff00" for green color
176     OUString AsRGBHexString() const;
177 
178     // get ::basegfx::BColor from this color
179     basegfx::BColor getBColor() const
180     {
181         return basegfx::BColor(GetRed() / 255.0, GetGreen() / 255.0, GetBlue() / 255.0);
182     }
183 };
184 
185 inline void Color::SetRed( sal_uInt8 nRed )
186 {
187     R = nRed;
188 }
189 
190 inline void Color::SetGreen( sal_uInt8 nGreen )
191 {
192     G = nGreen;
193 }
194 
195 inline void Color::SetBlue( sal_uInt8 nBlue )
196 {
197     B = nBlue;
198 }
199 
200 inline void Color::SetTransparency( sal_uInt8 nTransparency )
201 {
202     A = nTransparency;
203 }
204 
205 inline bool Color::IsRGBEqual( const Color& rColor ) const
206 {
207     return color::extractRGB(mValue) == color::extractRGB(rColor.mValue);
208 }
209 
210 inline sal_uInt8 Color::GetLuminance() const
211 {
212     return sal_uInt8((B * 29UL + G * 151UL + R * 76UL) >> 8);
213 }
214 
215 constexpr sal_uInt8 ColorChannelMerge(sal_uInt8 nDst, sal_uInt8 nSrc, sal_uInt8 nSrcTrans)
216 {
217     return sal_uInt8(((sal_Int32(nDst) - nSrc) * nSrcTrans + ((nSrc << 8) | nDst)) >> 8);
218 }
219 
220 inline void Color::Invert()
221 {
222     R = ~R;
223     G = ~G;
224     B = ~B;
225 }
226 
227 inline sal_uInt16 Color::GetColorError( const Color& rColor ) const
228 {
229     return static_cast<sal_uInt16>(
230         abs(static_cast<int>(GetBlue()) - rColor.GetBlue()) +
231         abs(static_cast<int>(GetGreen()) - rColor.GetGreen()) +
232         abs(static_cast<int>(GetRed()) - rColor.GetRed()));
233 }
234 
235 inline void Color::Merge( const Color& rMergeColor, sal_uInt8 cTransparency )
236 {
237     R = ColorChannelMerge(R, rMergeColor.R, cTransparency);
238     G = ColorChannelMerge(G, rMergeColor.G, cTransparency);
239     B = ColorChannelMerge(B, rMergeColor.B, cTransparency);
240 }
241 
242 // to reduce the noise when moving these into and out of Any
243 inline bool operator >>=( const css::uno::Any & rAny, Color & value )
244 {
245   sal_Int32 nTmp;
246   if (!(rAny >>= nTmp))
247       return false;
248   value = Color(nTmp);
249   return true;
250 }
251 
252 inline void operator <<=( css::uno::Any & rAny, Color value )
253 {
254     rAny <<= sal_Int32(value);
255 }
256 namespace com { namespace sun { namespace star { namespace uno {
257     template<>
258     inline Any makeAny( Color const & value )
259     {
260         return Any(sal_Int32(value));
261     }
262 } } } }
263 
264 // Test compile time conversion of Color to sal_uInt32
265 
266 static_assert (sal_uInt32(Color(0x00, 0x12, 0x34, 0x56)) == 0x00123456);
267 static_assert (sal_uInt32(Color(0x12, 0x34, 0x56)) == 0x00123456);
268 
269 // Color types
270 
271 constexpr ::Color COL_BLACK                   ( 0x00, 0x00, 0x00 );
272 constexpr ::Color COL_BLUE                    ( 0x00, 0x00, 0x80 );
273 constexpr ::Color COL_GREEN                   ( 0x00, 0x80, 0x00 );
274 constexpr ::Color COL_CYAN                    ( 0x00, 0x80, 0x80 );
275 constexpr ::Color COL_RED                     ( 0x80, 0x00, 0x00 );
276 constexpr ::Color COL_MAGENTA                 ( 0x80, 0x00, 0x80 );
277 constexpr ::Color COL_BROWN                   ( 0x80, 0x80, 0x00 );
278 constexpr ::Color COL_GRAY                    ( 0x80, 0x80, 0x80 );
279 constexpr ::Color COL_GRAY3                   ( 0xCC, 0xCC, 0xCC );
280 constexpr ::Color COL_GRAY7                   ( 0x66, 0x66, 0x66 );
281 constexpr ::Color COL_LIGHTGRAY               ( 0xC0, 0xC0, 0xC0 );
282 constexpr ::Color COL_LIGHTBLUE               ( 0x00, 0x00, 0xFF );
283 constexpr ::Color COL_LIGHTGREEN              ( 0x00, 0xFF, 0x00 );
284 constexpr ::Color COL_LIGHTCYAN               ( 0x00, 0xFF, 0xFF );
285 constexpr ::Color COL_LIGHTRED                ( 0xFF, 0x00, 0x00 );
286 constexpr ::Color COL_LIGHTMAGENTA            ( 0xFF, 0x00, 0xFF );
287 constexpr ::Color COL_LIGHTGRAYBLUE           ( 0xE0, 0xE0, 0xFF );
288 constexpr ::Color COL_YELLOW                  ( 0xFF, 0xFF, 0x00 );
289 constexpr ::Color COL_WHITE                   ( 0xFF, 0xFF, 0xFF );
290 constexpr ::Color COL_TRANSPARENT             ( 0xFF, 0xFF, 0xFF, 0xFF );
291 constexpr ::Color COL_AUTO                    ( 0xFF, 0xFF, 0xFF, 0xFF );
292 constexpr ::Color COL_AUTHOR1_DARK            ( 198,  146,   0 );
293 constexpr ::Color COL_AUTHOR1_NORMAL          ( 255,  255, 158 );
294 constexpr ::Color COL_AUTHOR1_LIGHT           ( 255,  255, 195 );
295 constexpr ::Color COL_AUTHOR2_DARK            (   6,   70, 162 );
296 constexpr ::Color COL_AUTHOR2_NORMAL          ( 216,  232, 255 );
297 constexpr ::Color COL_AUTHOR2_LIGHT           ( 233,  242, 255 );
298 constexpr ::Color COL_AUTHOR3_DARK            (  87,  157,  28 );
299 constexpr ::Color COL_AUTHOR3_NORMAL          ( 218,  248, 193 );
300 constexpr ::Color COL_AUTHOR3_LIGHT           ( 226,  250, 207 );
301 constexpr ::Color COL_AUTHOR4_DARK            ( 105,   43, 157 );
302 constexpr ::Color COL_AUTHOR4_NORMAL          ( 228,  210, 245 );
303 constexpr ::Color COL_AUTHOR4_LIGHT           ( 239,  228, 248 );
304 constexpr ::Color COL_AUTHOR5_DARK            ( 197,    0,  11 );
305 constexpr ::Color COL_AUTHOR5_NORMAL          ( 254,  205, 208 );
306 constexpr ::Color COL_AUTHOR5_LIGHT           ( 255,  227, 229 );
307 constexpr ::Color COL_AUTHOR6_DARK            (   0,  128, 128 );
308 constexpr ::Color COL_AUTHOR6_NORMAL          ( 210,  246, 246 );
309 constexpr ::Color COL_AUTHOR6_LIGHT           ( 230,  250, 250 );
310 constexpr ::Color COL_AUTHOR7_DARK            ( 140,  132,   0 );
311 constexpr ::Color COL_AUTHOR7_NORMAL          ( 237,  252, 163 );
312 constexpr ::Color COL_AUTHOR7_LIGHT           ( 242,  254, 181 );
313 constexpr ::Color COL_AUTHOR8_DARK            (  53,   85, 107 );
314 constexpr ::Color COL_AUTHOR8_NORMAL          ( 211,  222, 232 );
315 constexpr ::Color COL_AUTHOR8_LIGHT           ( 226,  234, 241 );
316 constexpr ::Color COL_AUTHOR9_DARK            ( 209,  118,   0 );
317 constexpr ::Color COL_AUTHOR9_NORMAL          ( 255,  226, 185 );
318 constexpr ::Color COL_AUTHOR9_LIGHT           ( 255,  231, 199 );
319 
320 template<typename charT, typename traits>
321 inline std::basic_ostream<charT, traits>& operator <<(std::basic_ostream<charT, traits>& rStream, const Color& rColor)
322 {
323     return rStream << "c[" << std::hex << std::setfill ('0')
324                    << std::setw(2) << static_cast<int>(rColor.GetRed())
325                    << std::setw(2) << static_cast<int>(rColor.GetGreen())
326                    << std::setw(2) << static_cast<int>(rColor.GetBlue())
327                    << std::setw(2) << static_cast<int>(rColor.GetTransparency()) << "]";
328 }
329 
330 #endif
331 
332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
333