11
#include <system_error>
13
#include <celcompat/charconv.h>
16
using namespace std::string_view_literals;
21
using ColorMap = std::map<std::string_view, Color>;
23
const ColorMap* buildX11ColorMap()
27
{ "aliceblue"sv, Color((std::uint8_t)240, (std::uint8_t)248, (std::uint8_t)255) },
28
{ "antiquewhite"sv, Color((std::uint8_t)250, (std::uint8_t)235, (std::uint8_t)215) },
29
{ "aqua"sv, Color((std::uint8_t)0, (std::uint8_t)255, (std::uint8_t)255) },
30
{ "aquamarine"sv, Color((std::uint8_t)127, (std::uint8_t)255, (std::uint8_t)212) },
31
{ "azure"sv, Color((std::uint8_t)240, (std::uint8_t)255, (std::uint8_t)255) },
32
{ "beige"sv, Color((std::uint8_t)245, (std::uint8_t)245, (std::uint8_t)220) },
33
{ "bisque"sv, Color((std::uint8_t)255, (std::uint8_t)228, (std::uint8_t)196) },
34
{ "black"sv, Color((std::uint8_t)0, (std::uint8_t)0, (std::uint8_t)0) },
35
{ "blanchedalmond"sv, Color((std::uint8_t)255, (std::uint8_t)235, (std::uint8_t)205) },
36
{ "blue"sv, Color((std::uint8_t)0, (std::uint8_t)0, (std::uint8_t)255) },
37
{ "blueviolet"sv, Color((std::uint8_t)138, (std::uint8_t)43, (std::uint8_t)226) },
38
{ "brown"sv, Color((std::uint8_t)165, (std::uint8_t)42, (std::uint8_t)42) },
39
{ "burlywood"sv, Color((std::uint8_t)222, (std::uint8_t)184, (std::uint8_t)135) },
40
{ "cadetblue"sv, Color((std::uint8_t)95, (std::uint8_t)158, (std::uint8_t)160) },
41
{ "chartreuse"sv, Color((std::uint8_t)127, (std::uint8_t)255, (std::uint8_t)0) },
42
{ "chocolate"sv, Color((std::uint8_t)210, (std::uint8_t)105, (std::uint8_t)30) },
43
{ "coral"sv, Color((std::uint8_t)255, (std::uint8_t)127, (std::uint8_t)80) },
44
{ "cornflowerblue"sv, Color((std::uint8_t)100, (std::uint8_t)149, (std::uint8_t)237) },
45
{ "cornsilk"sv, Color((std::uint8_t)255, (std::uint8_t)248, (std::uint8_t)220) },
46
{ "crimson"sv, Color((std::uint8_t)220, (std::uint8_t)20, (std::uint8_t)60) },
47
{ "cyan"sv, Color((std::uint8_t)0, (std::uint8_t)255, (std::uint8_t)255) },
48
{ "darkblue"sv, Color((std::uint8_t)0, (std::uint8_t)0, (std::uint8_t)139) },
49
{ "darkcyan"sv, Color((std::uint8_t)0, (std::uint8_t)139, (std::uint8_t)139) },
50
{ "darkgoldenrod"sv, Color((std::uint8_t)184, (std::uint8_t)134, (std::uint8_t)11) },
51
{ "darkgray"sv, Color((std::uint8_t)169, (std::uint8_t)169, (std::uint8_t)169) },
52
{ "darkgreen"sv, Color((std::uint8_t)0, (std::uint8_t)100, (std::uint8_t)0) },
53
{ "darkkhaki"sv, Color((std::uint8_t)189, (std::uint8_t)183, (std::uint8_t)107) },
54
{ "darkmagenta"sv, Color((std::uint8_t)139, (std::uint8_t)0, (std::uint8_t)139) },
55
{ "darkolivegreen"sv, Color((std::uint8_t)85, (std::uint8_t)107, (std::uint8_t)47) },
56
{ "darkorange"sv, Color((std::uint8_t)255, (std::uint8_t)140, (std::uint8_t)0) },
57
{ "darkorchid"sv, Color((std::uint8_t)153, (std::uint8_t)50, (std::uint8_t)204) },
58
{ "darkred"sv, Color((std::uint8_t)139, (std::uint8_t)0, (std::uint8_t)0) },
59
{ "darksalmon"sv, Color((std::uint8_t)233, (std::uint8_t)150, (std::uint8_t)122) },
60
{ "darkseagreen"sv, Color((std::uint8_t)143, (std::uint8_t)188, (std::uint8_t)143) },
61
{ "darkslateblue"sv, Color((std::uint8_t)72, (std::uint8_t)61, (std::uint8_t)139) },
62
{ "darkslategray"sv, Color((std::uint8_t)47, (std::uint8_t)79, (std::uint8_t)79) },
63
{ "darkturquoise"sv, Color((std::uint8_t)0, (std::uint8_t)206, (std::uint8_t)209) },
64
{ "darkviolet"sv, Color((std::uint8_t)148, (std::uint8_t)0, (std::uint8_t)211) },
65
{ "deeppink"sv, Color((std::uint8_t)255, (std::uint8_t)20, (std::uint8_t)147) },
66
{ "deepskyblue"sv, Color((std::uint8_t)0, (std::uint8_t)191, (std::uint8_t)255) },
67
{ "dimgray"sv, Color((std::uint8_t)105, (std::uint8_t)105, (std::uint8_t)105) },
68
{ "dodgerblue"sv, Color((std::uint8_t)30, (std::uint8_t)144, (std::uint8_t)255) },
69
{ "firebrick"sv, Color((std::uint8_t)178, (std::uint8_t)34, (std::uint8_t)34) },
70
{ "floralwhite"sv, Color((std::uint8_t)255, (std::uint8_t)250, (std::uint8_t)240) },
71
{ "forestgreen"sv, Color((std::uint8_t)34, (std::uint8_t)139, (std::uint8_t)34) },
72
{ "fuchsia"sv, Color((std::uint8_t)255, (std::uint8_t)0, (std::uint8_t)255) },
73
{ "gainsboro"sv, Color((std::uint8_t)220, (std::uint8_t)220, (std::uint8_t)220) },
74
{ "ghostwhite"sv, Color((std::uint8_t)248, (std::uint8_t)248, (std::uint8_t)255) },
75
{ "gold"sv, Color((std::uint8_t)255, (std::uint8_t)215, (std::uint8_t)0) },
76
{ "goldenrod"sv, Color((std::uint8_t)218, (std::uint8_t)165, (std::uint8_t)32) },
77
{ "gray"sv, Color((std::uint8_t)128, (std::uint8_t)128, (std::uint8_t)128) },
78
{ "green"sv, Color((std::uint8_t)0, (std::uint8_t)128, (std::uint8_t)0) },
79
{ "greenyellow"sv, Color((std::uint8_t)173, (std::uint8_t)255, (std::uint8_t)47) },
80
{ "honeydew"sv, Color((std::uint8_t)240, (std::uint8_t)255, (std::uint8_t)240) },
81
{ "hotpink"sv, Color((std::uint8_t)255, (std::uint8_t)105, (std::uint8_t)180) },
82
{ "indianred"sv, Color((std::uint8_t)205, (std::uint8_t)92, (std::uint8_t)92) },
83
{ "indigo"sv, Color((std::uint8_t)75, (std::uint8_t)0, (std::uint8_t)130) },
84
{ "ivory"sv, Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)240) },
85
{ "khaki"sv, Color((std::uint8_t)240, (std::uint8_t)230, (std::uint8_t)140) },
86
{ "lavender"sv, Color((std::uint8_t)230, (std::uint8_t)230, (std::uint8_t)250) },
87
{ "lavenderblush"sv, Color((std::uint8_t)255, (std::uint8_t)240, (std::uint8_t)245) },
88
{ "lawngreen"sv, Color((std::uint8_t)124, (std::uint8_t)252, (std::uint8_t)0) },
89
{ "lemonchiffon"sv, Color((std::uint8_t)255, (std::uint8_t)250, (std::uint8_t)205) },
90
{ "lightblue"sv, Color((std::uint8_t)173, (std::uint8_t)216, (std::uint8_t)230) },
91
{ "lightcoral"sv, Color((std::uint8_t)240, (std::uint8_t)128, (std::uint8_t)128) },
92
{ "lightcyan"sv, Color((std::uint8_t)224, (std::uint8_t)255, (std::uint8_t)255) },
93
{ "lightgoldenrodyellow"sv, Color((std::uint8_t)250, (std::uint8_t)250, (std::uint8_t)210) },
94
{ "lightgreen"sv, Color((std::uint8_t)144, (std::uint8_t)238, (std::uint8_t)144) },
95
{ "lightgrey"sv, Color((std::uint8_t)211, (std::uint8_t)211, (std::uint8_t)211) },
96
{ "lightpink"sv, Color((std::uint8_t)255, (std::uint8_t)182, (std::uint8_t)193) },
97
{ "lightsalmon"sv, Color((std::uint8_t)255, (std::uint8_t)160, (std::uint8_t)122) },
98
{ "lightseagreen"sv, Color((std::uint8_t)32, (std::uint8_t)178, (std::uint8_t)170) },
99
{ "lightskyblue"sv, Color((std::uint8_t)135, (std::uint8_t)206, (std::uint8_t)250) },
100
{ "lightslategray"sv, Color((std::uint8_t)119, (std::uint8_t)136, (std::uint8_t)153) },
101
{ "lightsteelblue"sv, Color((std::uint8_t)176, (std::uint8_t)196, (std::uint8_t)222) },
102
{ "lightyellow"sv, Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)224) },
103
{ "lime"sv, Color((std::uint8_t)0, (std::uint8_t)255, (std::uint8_t)0) },
104
{ "limegreen"sv, Color((std::uint8_t)50, (std::uint8_t)205, (std::uint8_t)50) },
105
{ "linen"sv, Color((std::uint8_t)250, (std::uint8_t)240, (std::uint8_t)230) },
106
{ "magenta"sv, Color((std::uint8_t)255, (std::uint8_t)0, (std::uint8_t)255) },
107
{ "maroon"sv, Color((std::uint8_t)128, (std::uint8_t)0, (std::uint8_t)0) },
108
{ "mediumaquamarine"sv, Color((std::uint8_t)102, (std::uint8_t)205, (std::uint8_t)170) },
109
{ "mediumblue"sv, Color((std::uint8_t)0, (std::uint8_t)0, (std::uint8_t)205) },
110
{ "mediumorchid"sv, Color((std::uint8_t)186, (std::uint8_t)85, (std::uint8_t)211) },
111
{ "mediumpurple"sv, Color((std::uint8_t)147, (std::uint8_t)112, (std::uint8_t)219) },
112
{ "mediumseagreen"sv, Color((std::uint8_t)60, (std::uint8_t)179, (std::uint8_t)113) },
113
{ "mediumslateblue"sv, Color((std::uint8_t)123, (std::uint8_t)104, (std::uint8_t)238) },
114
{ "mediumspringgreen"sv, Color((std::uint8_t)0, (std::uint8_t)250, (std::uint8_t)154) },
115
{ "mediumturquoise"sv, Color((std::uint8_t)72, (std::uint8_t)209, (std::uint8_t)204) },
116
{ "mediumvioletred"sv, Color((std::uint8_t)199, (std::uint8_t)21, (std::uint8_t)133) },
117
{ "midnightblue"sv, Color((std::uint8_t)25, (std::uint8_t)25, (std::uint8_t)112) },
118
{ "mintcream"sv, Color((std::uint8_t)245, (std::uint8_t)255, (std::uint8_t)250) },
119
{ "mistyrose"sv, Color((std::uint8_t)255, (std::uint8_t)228, (std::uint8_t)225) },
120
{ "moccasin"sv, Color((std::uint8_t)255, (std::uint8_t)228, (std::uint8_t)181) },
121
{ "navajowhite"sv, Color((std::uint8_t)255, (std::uint8_t)222, (std::uint8_t)173) },
122
{ "navy"sv, Color((std::uint8_t)0, (std::uint8_t)0, (std::uint8_t)128) },
123
{ "oldlace"sv, Color((std::uint8_t)253, (std::uint8_t)245, (std::uint8_t)230) },
124
{ "olive"sv, Color((std::uint8_t)128, (std::uint8_t)128, (std::uint8_t)0) },
125
{ "olivedrab"sv, Color((std::uint8_t)107, (std::uint8_t)142, (std::uint8_t)35) },
126
{ "orange"sv, Color((std::uint8_t)255, (std::uint8_t)165, (std::uint8_t)0) },
127
{ "orangered"sv, Color((std::uint8_t)255, (std::uint8_t)69, (std::uint8_t)0) },
128
{ "orchid"sv, Color((std::uint8_t)218, (std::uint8_t)112, (std::uint8_t)214) },
129
{ "palegoldenrod"sv, Color((std::uint8_t)238, (std::uint8_t)232, (std::uint8_t)170) },
130
{ "palegreen"sv, Color((std::uint8_t)152, (std::uint8_t)251, (std::uint8_t)152) },
131
{ "paleturquoise"sv, Color((std::uint8_t)175, (std::uint8_t)238, (std::uint8_t)238) },
132
{ "palevioletred"sv, Color((std::uint8_t)219, (std::uint8_t)112, (std::uint8_t)147) },
133
{ "papayawhip"sv, Color((std::uint8_t)255, (std::uint8_t)239, (std::uint8_t)213) },
134
{ "peachpuff"sv, Color((std::uint8_t)255, (std::uint8_t)218, (std::uint8_t)185) },
135
{ "peru"sv, Color((std::uint8_t)205, (std::uint8_t)133, (std::uint8_t)63) },
136
{ "pink"sv, Color((std::uint8_t)255, (std::uint8_t)192, (std::uint8_t)203) },
137
{ "plum"sv, Color((std::uint8_t)221, (std::uint8_t)160, (std::uint8_t)221) },
138
{ "powderblue"sv, Color((std::uint8_t)176, (std::uint8_t)224, (std::uint8_t)230) },
139
{ "purple"sv, Color((std::uint8_t)128, (std::uint8_t)0, (std::uint8_t)128) },
140
{ "red"sv, Color((std::uint8_t)255, (std::uint8_t)0, (std::uint8_t)0) },
141
{ "rosybrown"sv, Color((std::uint8_t)188, (std::uint8_t)143, (std::uint8_t)143) },
142
{ "royalblue"sv, Color((std::uint8_t)65, (std::uint8_t)105, (std::uint8_t)225) },
143
{ "saddlebrown"sv, Color((std::uint8_t)139, (std::uint8_t)69, (std::uint8_t)19) },
144
{ "salmon"sv, Color((std::uint8_t)250, (std::uint8_t)128, (std::uint8_t)114) },
145
{ "sandybrown"sv, Color((std::uint8_t)244, (std::uint8_t)164, (std::uint8_t)96) },
146
{ "seagreen"sv, Color((std::uint8_t)46, (std::uint8_t)139, (std::uint8_t)87) },
147
{ "seashell"sv, Color((std::uint8_t)255, (std::uint8_t)245, (std::uint8_t)238) },
148
{ "sienna"sv, Color((std::uint8_t)160, (std::uint8_t)82, (std::uint8_t)45) },
149
{ "silver"sv, Color((std::uint8_t)192, (std::uint8_t)192, (std::uint8_t)192) },
150
{ "skyblue"sv, Color((std::uint8_t)135, (std::uint8_t)206, (std::uint8_t)235) },
151
{ "slateblue"sv, Color((std::uint8_t)106, (std::uint8_t)90, (std::uint8_t)205) },
152
{ "slategray"sv, Color((std::uint8_t)112, (std::uint8_t)128, (std::uint8_t)144) },
153
{ "snow"sv, Color((std::uint8_t)255, (std::uint8_t)250, (std::uint8_t)250) },
154
{ "springgreen"sv, Color((std::uint8_t)0, (std::uint8_t)255, (std::uint8_t)127) },
155
{ "steelblue"sv, Color((std::uint8_t)70, (std::uint8_t)130, (std::uint8_t)180) },
156
{ "tan"sv, Color((std::uint8_t)210, (std::uint8_t)180, (std::uint8_t)140) },
157
{ "teal"sv, Color((std::uint8_t)0, (std::uint8_t)128, (std::uint8_t)128) },
158
{ "thistle"sv, Color((std::uint8_t)216, (std::uint8_t)191, (std::uint8_t)216) },
159
{ "tomato"sv, Color((std::uint8_t)255, (std::uint8_t)99, (std::uint8_t)71) },
160
{ "turquoise"sv, Color((std::uint8_t)64, (std::uint8_t)224, (std::uint8_t)208) },
161
{ "violet"sv, Color((std::uint8_t)238, (std::uint8_t)130, (std::uint8_t)238) },
162
{ "wheat"sv, Color((std::uint8_t)245, (std::uint8_t)222, (std::uint8_t)179) },
163
{ "white"sv, Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)255) },
164
{ "whitesmoke"sv, Color((std::uint8_t)245, (std::uint8_t)245, (std::uint8_t)245) },
165
{ "yellow"sv, Color((std::uint8_t)255, (std::uint8_t)255, (std::uint8_t)0) },
166
{ "yellowgreen"sv, Color((std::uint8_t)154, (std::uint8_t)205, (std::uint8_t)50) },
170
bool parseHexColor(std::string_view s, Color& c)
172
using celestia::compat::from_chars;
178
if (auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), value, 16);
179
ec == std::errc{} && ptr == s.data() + s.size())
181
c = Color(static_cast<std::uint8_t>((value >> 8) * UINT32_C(0x11)),
182
static_cast<std::uint8_t>(((value & UINT32_C(0x0f0)) >> 4) * UINT32_C(0x11)),
183
static_cast<std::uint8_t>((value & UINT32_C(0x00f)) * UINT32_C(0x11)));
189
if (auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), value, 16);
190
ec == std::errc{} && ptr == s.data() + s.size())
192
c = Color(static_cast<std::uint8_t>(value >> 16),
193
static_cast<std::uint8_t>((value & UINT32_C(0x00ff00)) >> 8),
194
static_cast<std::uint8_t>(value & UINT32_C(0x0000ff)));
200
if (auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), value, 16);
201
ec == std::errc{} && ptr == s.data() + s.size())
203
c = Color(static_cast<std::uint8_t>(value >> 24),
204
static_cast<std::uint8_t>((value & UINT32_C(0x00ff0000)) >> 16),
205
static_cast<std::uint8_t>((value & UINT32_C(0x0000ff00)) >> 8),
206
static_cast<std::uint8_t>(value & UINT32_C(0x000000ff)));
226
Color Color::fromHSV(float h, float s, float v)
236
float j = std::floor(h);
239
float p = v * (1.0f - s);
240
float q = v * (1.0f - s * f);
241
float t = v * (1.0f - s * (1.0f - f));
243
switch(static_cast<int>(j))
260
const Color Color::White = Color(1.0f, 1.0f, 1.0f);
261
const Color Color::Black = Color(0.0f, 0.0f, 0.0f);
267
bool Color::parse(std::string_view s, Color& c)
269
using celestia::compat::from_chars;
271
if (s.empty()) { return false; }
275
return parseHexColor(s.substr(1), c);
279
static const ColorMap* x11Colors = nullptr;
283
if (x11Colors == nullptr)
285
x11Colors = buildX11ColorMap();
288
auto it = x11Colors->find(s);
289
if (it != x11Colors->end())