Logo ROOT  
Reference Guide
RColor.cxx
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
3 * All rights reserved. *
4 * *
5 * For the licensing terms see $ROOTSYS/LICENSE. *
6 * For the list of contributors see $ROOTSYS/README/CREDITS. *
7 *************************************************************************/
8
9#include "ROOT/RColor.hxx"
10
11#include <unordered_map>
12
13using namespace ROOT::Experimental;
14
15using namespace std::string_literals;
16
19constexpr RColor::RGB_t RColor::kLime;
20constexpr RColor::RGB_t RColor::kAqua;
21constexpr RColor::RGB_t RColor::kPurple;
22constexpr RColor::RGB_t RColor::kGrey;
24constexpr RColor::RGB_t RColor::kNavy;
27constexpr RColor::RGB_t RColor::kOlive;
28constexpr RColor::RGB_t RColor::kSilver;
29constexpr RColor::RGB_t RColor::kMaroon;
33constexpr float RColor::kTransparent;
34constexpr float RColor::kSemiTransparent;
35constexpr float RColor::kOpaque;
36
37std::string kAuto{"auto"};
38
39///////////////////////////////////////////////////////////////////////////
40/// returns true if color stored as RGB
41
42bool RColor::IsRGB() const
43{
44 return (fColor.length() == 7) && (fColor[0] == '#');
45}
46
47///////////////////////////////////////////////////////////////////////////
48/// returns true if color stored as RGBA
49
50bool RColor::IsRGBA() const
51{
52 return (fColor.length() == 9) && (fColor[0] == '#');
53}
54
55///////////////////////////////////////////////////////////////////////////
56/// Set color as RGB
57
59{
60 fColor = "#"s + toHex(r) + toHex(g) + toHex(b);
61}
62
63///////////////////////////////////////////////////////////////////////////
64/// Set color as RGB
65
67{
68 fColor = "#"s + toHex(r) + toHex(g) + toHex(b) + toHex(alpha);
69}
70
71
72///////////////////////////////////////////////////////////////////////////
73/// Returns true if color specified as name
74
75bool RColor::IsName() const
76{
77 return !fColor.empty() && (fColor[0] != '#') && (fColor[0] != '[') && (fColor != kAuto);
78}
79
80///////////////////////////////////////////////////////////////////////////
81/// Returns true if color specified as auto color
82
83bool RColor::IsAuto() const
84{
85 return fColor == kAuto;
86}
87
88///////////////////////////////////////////////////////////////////////////
89/// Returns if color codes ordinal value from palette
90
92{
93 auto len = fColor.length();
94 return (len > 2) && (fColor[0] == '[') && (fColor[len-1] == ']');
95}
96
97///////////////////////////////////////////////////////////////////////////
98/// Set color as ordinal value from RPalette
99/// When object will be painted on the client side,
100/// actual color will be extracted from the RPalette
101/// Only 5 digits after . are stored
102
103void RColor::SetOrdinal(float val)
104{
105 if (val <= 0.) {
106 fColor = "[0]"s;
107 } else if (val >= 1.) {
108 fColor = "[1]"s;
109 } else {
110 char sbuf[30];
111 auto len = snprintf(sbuf, sizeof(sbuf),"[%7.5f]", val);
112 while ((len > 5) && (sbuf[len-2] == '0')) {
113 sbuf[len-2] = ']';
114 sbuf[len-1] = 0;
115 len--;
116 }
117 fColor = sbuf;
118 }
119}
120
121///////////////////////////////////////////////////////////////////////////
122/// Return ordinal value, which was set before with SetOrdinal() call
123
125{
126 return IsOrdinal() ? std::stof(fColor.substr(1, fColor.length()-2)) : -1;
127}
128
129
130///////////////////////////////////////////////////////////////////////////
131/// Set color alpha, can only be done if real color was assigned before
132
134{
135 if (fColor.empty())
136 return;
137
138 if (IsRGB()) {
139 if (alpha != 0xFF)
140 fColor += toHex(alpha);
141 } else if (IsRGBA()) {
142 fColor.resize(7);
143 if (alpha != 0xFF)
144 fColor += toHex(alpha);
145 } else if (IsName() && (alpha != 0xFF)) {
146 auto rgb = ConvertNameToRGB(fColor);
147 if (rgb.size() == 3)
148 SetRGBA(rgb[0], rgb[1], rgb[2], alpha);
149 }
150}
151
152
153///////////////////////////////////////////////////////////////////////////
154/// Converts string name of color in RGB value - when possible
155
156std::vector<uint8_t> RColor::ConvertNameToRGB(const std::string &name)
157{
158
159 // see https://www.december.com/html/spec/colorsvghex.html
160
161 static std::unordered_map<std::string,RGB_t> known_colors = {
162 {"black", kWhite},
163 {"green", kGreen},
164 {"lime", kLime},
165 {"aqua", kAqua},
166 {"purple", kPurple},
167 {"grey", kGrey},
168 {"fuchsia", kFuchsia},
169 {"navy", kNavy},
170 {"blue", kBlue},
171 {"teal", kTeal},
172 {"olive", kOlive},
173 {"silver", kSilver},
174 {"maroon", kMaroon},
175 {"red", kRed},
176 {"yellow", kYellow},
177 {"white", kWhite}
178 };
179
180 auto known = known_colors.find(name);
181 if (known != known_colors.end()) {
182 std::vector<uint8_t> res;
183 res.resize(3);
184 res[0] = known->second[0];
185 res[1] = known->second[1];
186 res[2] = known->second[2];
187 return res;
188 }
189
190 return {};
191}
192
193
194///////////////////////////////////////////////////////////////////////////
195/// Returns color as RGBA array, includes optionally alpha parameter 0..255
196
197std::vector<uint8_t> RColor::AsRGBA() const
198{
199 if (fColor.empty())
200 return {};
201
202 std::vector<uint8_t> rgba;
203
204 if (IsRGB())
205 rgba.resize(3);
206 else if (IsRGBA())
207 rgba.resize(4);
208
209 if (rgba.size() > 0) {
210 try {
211 rgba[0] = std::stoi(fColor.substr(1,2), nullptr, 16);
212 rgba[1] = std::stoi(fColor.substr(3,2), nullptr, 16);
213 rgba[2] = std::stoi(fColor.substr(5,2), nullptr, 16);
214 if (rgba.size() == 4)
215 rgba[3] = std::stoi(fColor.substr(7,2), nullptr, 16);
216 } catch(...) {
217 rgba.clear();
218 }
219 return rgba;
220 }
221
222 if (IsName())
223 return ConvertNameToRGB(fColor);
224
225 return {};
226}
227
228
229
230///////////////////////////////////////////////////////////////////////////
231/// Converts integer from 0 to 255 into hex format with two digits like 00
232
234{
235 static const char *digits = "0123456789ABCDEF";
236 std::string res(2,'0');
237 res[0] = digits[v >> 4];
238 res[1] = digits[v & 0xf];
239 return res;
240}
241
242
243///////////////////////////////////////////////////////////////////////////
244/// Set RGB values as hex
245
246bool RColor::SetRGBHex(const std::string &hex)
247{
248 if (hex.length() != 6) return false;
249
250 try {
251 SetRGB( std::stoi(hex.substr(0,2), nullptr, 16),
252 std::stoi(hex.substr(2,2), nullptr, 16),
253 std::stoi(hex.substr(4,2), nullptr, 16));
254 } catch (...) {
255 return false;
256 }
257 return true;
258}
259
260///////////////////////////////////////////////////////////////////////////
261/// Set Alpha value as hex
262
263bool RColor::SetAlphaHex(const std::string &hex)
264{
265 if (hex.length() != 6) return false;
266
267 SetAlpha(std::stoi(hex, nullptr, 16));
268 return true;
269}
270
271///////////////////////////////////////////////////////////////////////////
272/// Returns color value in hex format like "66FF66" - without any prefix
273/// Alpha parameter can be optionally included
274
275std::string RColor::AsHex(bool with_alpha) const
276{
277 auto rgba = AsRGBA();
278 std::string res;
279 if (!rgba.empty()) {
280 res = toHex(rgba[0]) + toHex(rgba[1]) + toHex(rgba[2]);
281 if (with_alpha)
282 res += toHex((rgba.size() == 4) ? rgba[3] : 0xff);
283 }
284 return res;
285}
286
287///////////////////////////////////////////////////////////////////////////
288/// Returns color value as it will be used in SVG drawing
289/// It either include hex format #66FF66 or just plain SVG name
290
291std::string RColor::AsSVG() const
292{
293 if (IsName() || IsRGB() || IsRGBA())
294 return fColor;
295
296 return ""s;
297}
298
299
300///////////////////////////////////////////////////////////////////////////
301/// Returns the Hue, Light, Saturation (HLS) definition of this RColor
302/// If color was not specified as hex, method returns false
303
304bool RColor::GetHLS(float &hue, float &light, float &satur) const
305{
306 auto arr = AsRGBA();
307 if (arr.size() < 3)
308 return false;
309
310 float red = arr[0]/255., green = arr[1]/255., blue = arr[2]/255.;
311
312 hue = light = satur = 0.;
313
314 float rnorm, gnorm, bnorm, minval, maxval, msum, mdiff;
315 minval = maxval = 0 ;
316
317 minval = red;
318 if (green < minval) minval = green;
319 if (blue < minval) minval = blue;
320 maxval = red;
321 if (green > maxval) maxval = green;
322 if (blue > maxval) maxval = blue;
323
324 rnorm = gnorm = bnorm = 0;
325 mdiff = maxval - minval;
326 msum = maxval + minval;
327 light = 0.5 * msum;
328 if (maxval != minval) {
329 rnorm = (maxval - red)/mdiff;
330 gnorm = (maxval - green)/mdiff;
331 bnorm = (maxval - blue)/mdiff;
332 } else {
333 satur = hue = 0;
334 return true;
335 }
336
337 if (light < 0.5) satur = mdiff/msum;
338 else satur = mdiff/(2.0 - msum);
339
340 if (red == maxval) hue = 60.0 * (6.0 + bnorm - gnorm);
341 else if (green == maxval) hue = 60.0 * (2.0 + rnorm - bnorm);
342 else hue = 60.0 * (4.0 + gnorm - rnorm);
343
344 if (hue > 360) hue = hue - 360;
345 return true;
346}
347
348///////////////////////////////////////////////////////////////////////////
349/// Set the color value from the Hue, Light, Saturation (HLS).
350
351void RColor::SetHLS(float hue, float light, float satur)
352{
353 float rh, rl, rs, rm1, rm2;
354 rh = rl = rs = 0;
355 if (hue > 0) { rh = hue; if (rh > 360) rh = 360; }
356 if (light > 0) { rl = light; if (rl > 1) rl = 1; }
357 if (satur > 0) { rs = satur; if (rs > 1) rs = 1; }
358
359 if (rl <= 0.5) rm2 = rl*(1.0 + rs);
360 else rm2 = rl + rs - rl*rs;
361 rm1 = 2.0*rl - rm2;
362
363 if (!rs) {
364 SetRGB((uint8_t) (rl*255.), (uint8_t) (rl*255.), (uint8_t) (rl*255.));
365 return;
366 }
367
368 auto toRGB = [rm1, rm2] (float h) {
369 if (h > 360) h = h - 360;
370 if (h < 0) h = h + 360;
371 if (h < 60 ) return rm1 + (rm2-rm1)*h/60;
372 if (h < 180) return rm2;
373 if (h < 240) return rm1 + (rm2-rm1)*(240-h)/60;
374 return rm1;
375 };
376
377 SetRGB(toRGB(rh+120), toRGB(rh), toRGB(rh-120));
378}
379
380///////////////////////////////////////////////////////////////////////////
381/// Set the color value from the Hue, Light, Saturation (HLS).
382
384{
385 static RColor autoColor("auto");
386 return autoColor;
387}
388
uint8_t
Definition: Converters.cxx:876
ROOT::R::TRInterface & r
Definition: Object.C:4
std::string kAuto
Definition: RColor.cxx:37
#define b(i)
Definition: RSha256.hxx:100
#define g(i)
Definition: RSha256.hxx:105
#define h(i)
Definition: RSha256.hxx:106
@ kTeal
Definition: Rtypes.h:67
@ kRed
Definition: Rtypes.h:66
@ kBlack
Definition: Rtypes.h:65
@ kGreen
Definition: Rtypes.h:66
@ kWhite
Definition: Rtypes.h:65
@ kBlue
Definition: Rtypes.h:66
@ kYellow
Definition: Rtypes.h:66
@ kFuchsia
Definition: TColor.h:118
char name[80]
Definition: TGX11.cxx:110
#define snprintf
Definition: civetweb.c:1540
The color class.
Definition: RColor.hxx:33
static std::vector< uint8_t > ConvertNameToRGB(const std::string &name)
Converts string name of color in RGB value - when possible.
Definition: RColor.cxx:156
static constexpr R__DLLEXPORT RGB_t kRed
Definition: RColor.hxx:191
static constexpr R__DLLEXPORT RGB_t kLime
Definition: RColor.hxx:180
bool IsOrdinal() const
Returns if color codes ordinal value from palette.
Definition: RColor.cxx:91
void SetRGB(const RGB_t &rgb)
Set r/g/b components of color.
Definition: RColor.hxx:80
std::string fColor
string representation of color
Definition: RColor.hxx:39
static constexpr R__DLLEXPORT RGB_t kYellow
Definition: RColor.hxx:192
void SetOrdinal(float val)
Set color as ordinal value from RPalette When object will be painted on the client side,...
Definition: RColor.cxx:103
void SetHLS(float hue, float light, float satur)
Set the Red Green and Blue (RGB) values from the Hue, Light, Saturation (HLS).
Definition: RColor.cxx:351
static constexpr R__DLLEXPORT RGB_t kPurple
Definition: RColor.hxx:182
static constexpr R__DLLEXPORT RGB_t kGreen
Definition: RColor.hxx:179
bool GetHLS(float &hue, float &light, float &satur) const
Return the Hue, Light, Saturation (HLS) definition of this RColor.
Definition: RColor.cxx:304
bool SetRGBHex(const std::string &hex)
Set RGB values as hex.
Definition: RColor.cxx:246
std::vector< uint8_t > AsRGBA() const
Returns color as RGBA array, trying also convert color name into RGBA value.
Definition: RColor.cxx:197
static const RColor & AutoColor()
Set the color value from the Hue, Light, Saturation (HLS).
Definition: RColor.cxx:383
static constexpr R__DLLEXPORT RGB_t kFuchsia
Definition: RColor.hxx:184
static constexpr R__DLLEXPORT RGB_t kWhite
Definition: RColor.hxx:193
bool IsRGBA() const
returns true if color stored as RGBA
Definition: RColor.cxx:50
bool SetAlphaHex(const std::string &hex)
Set Alpha value as hex.
Definition: RColor.cxx:263
void SetAlpha(uint8_t alpha)
Set alpha as value from range 0..255.
Definition: RColor.cxx:133
std::string AsSVG() const
Returns color value as it will be used in SVG drawing It either include hex format #66FF66 or just pl...
Definition: RColor.cxx:291
static constexpr R__DLLEXPORT RGB_t kGrey
Definition: RColor.hxx:183
bool IsName() const
Returns true if color specified as name.
Definition: RColor.cxx:75
static constexpr R__DLLEXPORT RGB_t kTeal
Definition: RColor.hxx:187
static constexpr R__DLLEXPORT RGB_t kAqua
Definition: RColor.hxx:181
static constexpr R__DLLEXPORT RGB_t kBlue
Definition: RColor.hxx:186
static constexpr R__DLLEXPORT RGB_t kNavy
Definition: RColor.hxx:185
std::string AsHex(bool with_alpha=false) const
Returns color value in hex format like "66FF66" - without any prefix Alpha parameter can be optionall...
Definition: RColor.cxx:275
static constexpr R__DLLEXPORT RGB_t kOlive
Definition: RColor.hxx:188
float GetOrdinal() const
Return ordinal value, which was set before with SetOrdinal() call.
Definition: RColor.cxx:124
static constexpr R__DLLEXPORT RGB_t kMaroon
Definition: RColor.hxx:190
std::array< uint8_t, 3 > RGB_t
Definition: RColor.hxx:35
static std::string toHex(uint8_t v)
Converts integer from 0 to 255 into hex format with two digits like 00.
Definition: RColor.cxx:233
static constexpr R__DLLEXPORT RGB_t kSilver
Definition: RColor.hxx:189
bool IsRGB() const
returns true if color stored as RGB
Definition: RColor.cxx:42
void SetRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha)
Set r/g/b/a components of color, a is integer between 0..255.
Definition: RColor.cxx:66
bool IsAuto() const
Returns true if color specified as auto color.
Definition: RColor.cxx:83
static constexpr double s