Branch data TLA Line data Source code
1 : : // Copyright (c) 2014-2022 Thomas Fussell
2 : : // Copyright (c) 2010-2015 openpyxl
3 : : // Copyright (c) 2024-2025 xlnt-community
4 : : //
5 : : // Permission is hereby granted, free of charge, to any person obtaining a copy
6 : : // of this software and associated documentation files (the "Software"), to deal
7 : : // in the Software without restriction, including without limitation the rights
8 : : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : : // copies of the Software, and to permit persons to whom the Software is
10 : : // furnished to do so, subject to the following conditions:
11 : : //
12 : : // The above copyright notice and this permission notice shall be included in
13 : : // all copies or substantial portions of the Software.
14 : : //
15 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : : // THE SOFTWARE
22 : : //
23 : : // @license: http://www.opensource.org/licenses/mit-license.php
24 : : // @author: see AUTHORS file
25 : :
26 : : #pragma once
27 : :
28 : : #include <array>
29 : : #include <cstring>
30 : : #include <functional>
31 : :
32 : : #include <xlnt/xlnt_config.hpp>
33 : : #include <xlnt/utils/optional.hpp>
34 : : #include <xlnt/utils/hash_combine.hpp>
35 : :
36 : : namespace xlnt {
37 : :
38 : : /// <summary>
39 : : /// An indexed color encapsulates a simple index to a color in the indexedColors of the stylesheet.
40 : : /// </summary>
41 : : class XLNT_API indexed_color
42 : : {
43 : : public:
44 : : //TODO: should this be explicit?
45 : : /// <summary>
46 : : /// Constructs an indexed_color from an index.
47 : : /// </summary>
48 : : indexed_color(std::size_t index);
49 : :
50 : : /// <summary>
51 : : /// Returns the index this color points to.
52 : : /// </summary>
53 : : std::size_t index() const;
54 : :
55 : : /// <summary>
56 : : /// Sets the index to index.
57 : : /// </summary>
58 : : void index(std::size_t index);
59 : :
60 : : private:
61 : : /// <summary>
62 : : /// The index of this color
63 : : /// </summary>
64 : : std::size_t index_;
65 : : };
66 : :
67 : : /// <summary>
68 : : /// A theme color encapsulates a color derived from the theme.
69 : : /// </summary>
70 : : class XLNT_API theme_color
71 : : {
72 : : public:
73 : : /// <summary>
74 : : /// Constructs a theme_color from an index.
75 : : /// </summary>
76 : : theme_color(std::size_t index);
77 : :
78 : : /// <summary>
79 : : /// Returns the index of the color in the theme this points to.
80 : : /// </summary>
81 : : std::size_t index() const;
82 : :
83 : : /// <summary>
84 : : /// Sets the index of this color to index.
85 : : /// </summary>
86 : : void index(std::size_t index);
87 : :
88 : : private:
89 : : /// <summary>
90 : : /// The index of the color
91 : : /// </summary>
92 : : std::size_t index_;
93 : : };
94 : :
95 : : /// <summary>
96 : : /// An RGB color describes a color in terms of its red, green, blue, and alpha components.
97 : : /// </summary>
98 : : class XLNT_API rgb_color
99 : : {
100 : : public:
101 : : /// <summary>
102 : : /// Constructs an RGB color from a string in the form \#[aa]rrggbb
103 : : /// </summary>
104 : : rgb_color(const std::string &hex_string);
105 : :
106 : : /// <summary>
107 : : /// Constructs an RGB color from red, green, and blue values in the range 0 to 255
108 : : /// plus an optional alpha which defaults to fully opaque.
109 : : /// </summary>
110 : : rgb_color(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a = 255);
111 : :
112 : : /// <summary>
113 : : /// Returns a string representation of this color in the form \#aarrggbb
114 : : /// </summary>
115 : : std::string hex_string() const;
116 : :
117 : : /// <summary>
118 : : /// Returns a byte representing the red component of this color
119 : : /// </summary>
120 : : std::uint8_t red() const;
121 : :
122 : : /// <summary>
123 : : /// Returns a byte representing the red component of this color
124 : : /// </summary>
125 : : std::uint8_t green() const;
126 : :
127 : : /// <summary>
128 : : /// Returns a byte representing the blue component of this color
129 : : /// </summary>
130 : : std::uint8_t blue() const;
131 : :
132 : : /// <summary>
133 : : /// Returns a byte representing the alpha component of this color
134 : : /// </summary>
135 : : std::uint8_t alpha() const;
136 : :
137 : : /// <summary>
138 : : /// Returns the red, green, and blue components of this color separately in an array in that order.
139 : : /// </summary>
140 : : std::array<std::uint8_t, 3> rgb() const;
141 : :
142 : : /// <summary>
143 : : /// Returns the red, green, blue, and alpha components of this color separately in an array in that order.
144 : : /// </summary>
145 : : std::array<std::uint8_t, 4> rgba() const;
146 : :
147 : : private:
148 : : /// <summary>
149 : : /// The four bytes of this color
150 : : /// </summary>
151 : : std::array<std::uint8_t, 4> rgba_;
152 : : };
153 : :
154 : : /// <summary>
155 : : /// Some colors are references to colors rather than having a particular RGB value.
156 : : /// </summary>
157 : : enum class color_type
158 : : {
159 : : indexed,
160 : : theme,
161 : : rgb
162 : : };
163 : :
164 : : /// <summary>
165 : : /// Colors can be applied to many parts of a cell's style.
166 : : /// </summary>
167 : : class XLNT_API color
168 : : {
169 : : public:
170 : : /// <summary>
171 : : /// Returns the color \#000000
172 : : /// </summary>
173 : : static const color black();
174 : :
175 : : /// <summary>
176 : : /// Returns the color \#ffffff
177 : : /// </summary>
178 : : static const color white();
179 : :
180 : : /// <summary>
181 : : /// Returns the color \#ff0000
182 : : /// </summary>
183 : : static const color red();
184 : :
185 : : /// <summary>
186 : : /// Returns the color \#8b0000
187 : : /// </summary>
188 : : static const color darkred();
189 : :
190 : : /// <summary>
191 : : /// Returns the color \#00ff00
192 : : /// </summary>
193 : : static const color blue();
194 : :
195 : : /// <summary>
196 : : /// Returns the color \#008b00
197 : : /// </summary>
198 : : static const color darkblue();
199 : :
200 : : /// <summary>
201 : : /// Returns the color \#0000ff
202 : : /// </summary>
203 : : static const color green();
204 : :
205 : : /// <summary>
206 : : /// Returns the color \#00008b
207 : : /// </summary>
208 : : static const color darkgreen();
209 : :
210 : : /// <summary>
211 : : /// Returns the color \#ffff00
212 : : /// </summary>
213 : : static const color yellow();
214 : :
215 : : /// <summary>
216 : : /// Returns the color \#cccc00
217 : : /// </summary>
218 : : static const color darkyellow();
219 : :
220 : : /// <summary>
221 : : /// Constructs a default color
222 : : /// </summary>
223 : : color();
224 : :
225 : : /// <summary>
226 : : /// Constructs a color from a given RGB color
227 : : /// </summary>
228 : : color(const rgb_color &rgb);
229 : :
230 : : /// <summary>
231 : : /// Constructs a color from a given indexed color
232 : : /// </summary>
233 : : color(const indexed_color &indexed);
234 : :
235 : : /// <summary>
236 : : /// Constructs a color from a given theme color
237 : : /// </summary>
238 : : color(const theme_color &theme);
239 : :
240 : : /// <summary>
241 : : /// Returns the type of this color
242 : : /// </summary>
243 : : color_type type() const;
244 : :
245 : : /// <summary>
246 : : /// Returns true if this color has been set to auto
247 : : /// </summary>
248 : : bool auto_() const;
249 : :
250 : : /// <summary>
251 : : /// Sets the auto property of this color to value
252 : : /// </summary>
253 : : void auto_(bool value);
254 : :
255 : : /// <summary>
256 : : /// Returns the internal indexed color representing this color. If this is not an RGB color,
257 : : /// an invalid_attribute exception will be thrown.
258 : : /// </summary>
259 : : const rgb_color &rgb() const;
260 : :
261 : : /// <summary>
262 : : /// Returns the internal indexed color representing this color. If this is not an RGB color,
263 : : /// an invalid_attribute exception will be thrown.
264 : : /// </summary>
265 : : rgb_color &rgb();
266 : :
267 : : /// <summary>
268 : : /// Returns the internal indexed color representing this color. If this is not an indexed color,
269 : : /// an invalid_attribute exception will be thrown.
270 : : /// </summary>
271 : : const indexed_color &indexed() const;
272 : :
273 : : /// <summary>
274 : : /// Returns the internal indexed color representing this color. If this is not an indexed color,
275 : : /// an invalid_attribute exception will be thrown.
276 : : /// </summary>
277 : : indexed_color &indexed();
278 : :
279 : : /// <summary>
280 : : /// Returns the internal indexed color representing this color. If this is not a theme color,
281 : : /// an invalid_attribute exception will be thrown.
282 : : /// </summary>
283 : : const theme_color &theme() const;
284 : :
285 : : /// <summary>
286 : : /// Returns the internal indexed color representing this color. If this is not a theme color,
287 : : /// an invalid_attribute exception will be thrown.
288 : : /// </summary>
289 : : theme_color &theme();
290 : :
291 : : /// <summary>
292 : : /// Returns true if tint is set
293 : : /// </summary>
294 : : bool has_tint() const;
295 : :
296 : : /// <summary>
297 : : /// Returns the tint of this color.
298 : : /// </summary>
299 : : double tint() const;
300 : :
301 : : /// <summary>
302 : : /// Sets the tint of this color to tint. Tints lighten or darken an existing color by multiplying the color with the tint.
303 : : /// </summary>
304 : : void tint(double tint);
305 : :
306 : : /// <summary>
307 : : /// Returns true if this color is equivalent to other
308 : : /// </summary>
309 : : bool operator==(const color &other) const;
310 : :
311 : : /// <summary>
312 : : /// Returns true if this color is not equivalent to other
313 : : /// </summary>
314 : : bool operator!=(const color &other) const;
315 : :
316 : : private:
317 : : /// <summary>
318 : : /// Throws an invalid_attribute exception if the given type is different from this color's type
319 : : /// </summary>
320 : : void assert_type(color_type t) const;
321 : :
322 : : /// <summary>
323 : : /// The type of this color
324 : : /// </summary>
325 : : color_type type_;
326 : :
327 : : /// <summary>
328 : : /// The internal RGB color. Only valid when this color has a type of rgb
329 : : /// </summary>
330 : : rgb_color rgb_;
331 : :
332 : : /// <summary>
333 : : /// The internal RGB color. Only valid when this color has a type of indexed
334 : : /// </summary>
335 : : indexed_color indexed_;
336 : :
337 : : /// <summary>
338 : : /// The internal RGB color. Only valid when this color has a type of theme
339 : : /// </summary>
340 : : theme_color theme_;
341 : :
342 : : /// <summary>
343 : : /// The tint of this color
344 : : /// </summary>
345 : : optional<double> tint_;
346 : :
347 : : /// <summary>
348 : : /// Whether or not this is an auto color
349 : : /// </summary>
350 : : bool auto_color = false;
351 : : };
352 : :
353 : : } // namespace xlnt
354 : :
355 : : namespace std {
356 : :
357 : : template<>
358 : : struct hash<xlnt::color>
359 : : {
360 :CBC 45 : size_t operator()(const xlnt::color& c) const
361 : : {
362 : 45 : size_t seed = 0;
363 : : // Start by hashing the type to prevent collisions between different color types
364 : : // that might share an underlying value (e.g., theme(1) vs indexed(1)).
365 [ + ]: 45 : xlnt::detail::hash_combine(seed, static_cast<int>(c.type()));
366 : :
367 : : // Hash auto color flag
368 [ + ]: 45 : xlnt::detail::hash_combine(seed, c.auto_());
369 : :
370 : : // Hash tint if present
371 [ + + + ]: 45 : if (c.has_tint())
372 : : {
373 [ + ]: 8 : xlnt::detail::hash_combine(seed, c.tint());
374 : : }
375 : :
376 [ + + + + : 45 : switch (c.type())
- ]
377 : : {
378 : 6 : case xlnt::color_type::indexed:
379 [ + + ]: 6 : xlnt::detail::hash_combine(seed, c.indexed().index());
380 : 6 : break;
381 : 6 : case xlnt::color_type::theme:
382 [ + + ]: 6 : xlnt::detail::hash_combine(seed, c.theme().index());
383 : 6 : break;
384 : 33 : case xlnt::color_type::rgb:
385 : : {
386 [ + ]: 33 : const auto& rgb = c.rgb();
387 [ + ]: 33 : xlnt::detail::hash_combine(seed, rgb.red());
388 [ + ]: 33 : xlnt::detail::hash_combine(seed, rgb.green());
389 [ + ]: 33 : xlnt::detail::hash_combine(seed, rgb.blue());
390 [ + ]: 33 : xlnt::detail::hash_combine(seed, rgb.alpha());
391 : 33 : break;
392 : : }
393 : : }
394 : 45 : return seed;
395 : : }
396 : : };
397 : :
398 : : } // namespace std
|