1 package color
2
3 import (
4 "fmt"
5 "math"
6 "regexp"
7 "strconv"
8 "strings"
9
10 "github.com/lucasb-eyer/go-colorful"
11 "github.com/mazznoer/csscolorparser"
12 )
13
14 var themeColorRegex = regexp.MustCompile(`^(N[1-7]|B[1-6]|AA[245]|AB[45])$`)
15
16 func IsThemeColor(colorString string) bool {
17 return themeColorRegex.MatchString(colorString)
18 }
19
20 func Darken(colorString string) (string, error) {
21 if IsThemeColor(colorString) {
22 switch {
23 case colorString[0] == 'B':
24 switch colorString[1] {
25 case '1', '2':
26 return B1, nil
27 case '3':
28 return B2, nil
29 case '4':
30 return B3, nil
31 case '5':
32 return B4, nil
33 case '6':
34 return B5, nil
35 }
36
37 case colorString[0:2] == "AA":
38 switch colorString[2] {
39 case '2', '4':
40 return AA2, nil
41 case '5':
42 return AA4, nil
43 }
44
45 case colorString[0:2] == "AB":
46 switch colorString[2] {
47 case '4':
48 return AB4, nil
49 case '5':
50 return AB5, nil
51 }
52
53 case colorString[0] == 'N':
54 switch colorString[1] {
55 case '1', '2':
56 return N1, nil
57 case '3':
58 return N2, nil
59 case '4':
60 return N3, nil
61 case '5':
62 return N4, nil
63 case '6':
64 return N5, nil
65 case '7':
66 return N6, nil
67 }
68 }
69
70 return "", fmt.Errorf("invalid color \"%s\"", colorString)
71 }
72
73 return darkenCSS(colorString)
74 }
75
76 func darkenCSS(colorString string) (string, error) {
77 c, err := csscolorparser.Parse(colorString)
78 if err != nil {
79 return "", err
80 }
81 h, s, l := colorful.Color{R: c.R, G: c.G, B: c.B}.Hsl()
82
83 return colorful.Hsl(h, s, l-.1).Clamped().Hex(), nil
84 }
85
86 func LuminanceCategory(colorString string) (string, error) {
87 l, err := Luminance(colorString)
88 if err != nil {
89 return "", err
90 }
91
92 switch {
93 case l >= .88:
94 return "bright", nil
95 case l >= .55:
96 return "normal", nil
97 case l >= .30:
98 return "dark", nil
99 default:
100 return "darker", nil
101 }
102 }
103
104 func Luminance(colorString string) (float64, error) {
105 c, err := csscolorparser.Parse(colorString)
106 if err != nil {
107 return 0, err
108 }
109
110
111 l := float64(
112 float64(0.299)*float64(c.R) +
113 float64(0.587)*float64(c.G) +
114 float64(0.114)*float64(c.B),
115 )
116 return l, nil
117 }
118
119 const (
120 N1 = "N1"
121 N2 = "N2"
122 N3 = "N3"
123 N4 = "N4"
124 N5 = "N5"
125 N6 = "N6"
126 N7 = "N7"
127
128
129 B1 = "B1"
130 B2 = "B2"
131 B3 = "B3"
132 B4 = "B4"
133 B5 = "B5"
134 B6 = "B6"
135
136
137 AA2 = "AA2"
138 AA4 = "AA4"
139 AA5 = "AA5"
140
141
142 AB4 = "AB4"
143 AB5 = "AB5"
144
145
146 Empty = ""
147 None = "none"
148 )
149
150 type RGB struct {
151 Red uint8
152 Green uint8
153 Blue uint8
154 }
155
156
157 func (c *RGB) IsLight() bool {
158 r := float64(c.Red)
159 g := float64(c.Green)
160 b := float64(c.Blue)
161
162 hsp := math.Sqrt(0.299*math.Pow(r, 2) + 0.587*math.Pow(g, 2) + 0.114*math.Pow(b, 2))
163
164 return hsp > 130
165 }
166
167
168 func Hex2RGB(hex string) (RGB, error) {
169 var rgb RGB
170 if len(hex) > 3 && hex[0] == '#' {
171 hex = hex[1:]
172 } else {
173 return RGB{}, fmt.Errorf("cannot parse hex color %v", hex)
174 }
175 values, err := strconv.ParseUint(hex, 16, 32)
176 if err != nil {
177 return RGB{}, err
178 }
179
180 rgb = RGB{
181 Red: uint8(values >> 16),
182 Green: uint8((values >> 8) & 0xFF),
183 Blue: uint8(values & 0xFF),
184 }
185
186 return rgb, nil
187 }
188
189
190 var namedRgbMap = map[string][]uint8{
191 "aliceblue": {240, 248, 255},
192 "antiquewhite": {250, 235, 215},
193 "aqua": {0, 255, 255},
194 "aquamarine": {127, 255, 212},
195 "azure": {240, 255, 255},
196 "beige": {245, 245, 220},
197 "bisque": {255, 228, 196},
198 "black": {0, 0, 0},
199 "blanchedalmond": {255, 235, 205},
200 "blue": {0, 0, 255},
201 "blueviolet": {138, 43, 226},
202 "brown": {165, 42, 42},
203 "burlywood": {222, 184, 135},
204 "cadetblue": {95, 158, 160},
205 "chartreuse": {127, 255, 0},
206 "chocolate": {210, 105, 30},
207 "coral": {255, 127, 80},
208 "cornflowerblue": {100, 149, 237},
209 "cornsilk": {255, 248, 220},
210 "crimson": {220, 20, 60},
211 "cyan": {0, 255, 255},
212 "darkblue": {0, 0, 139},
213 "darkcyan": {0, 139, 139},
214 "darkgoldenrod": {184, 134, 11},
215 "darkgray": {169, 169, 169},
216 "darkgreen": {0, 100, 0},
217 "darkgrey": {169, 169, 169},
218 "darkkhaki": {189, 183, 107},
219 "darkmagenta": {139, 0, 139},
220 "darkolivegreen": {85, 107, 47},
221 "darkorange": {255, 140, 0},
222 "darkorchid": {153, 50, 204},
223 "darkred": {139, 0, 0},
224 "darksalmon": {233, 150, 122},
225 "darkseagreen": {143, 188, 143},
226 "darkslateblue": {72, 61, 139},
227 "darkslategray": {47, 79, 79},
228 "darkslategrey": {47, 79, 79},
229 "darkturquoise": {0, 206, 209},
230 "darkviolet": {148, 0, 211},
231 "deeppink": {255, 20, 147},
232 "deepskyblue": {0, 191, 255},
233 "dimgray": {105, 105, 105},
234 "dimgrey": {105, 105, 105},
235 "dodgerblue": {30, 144, 255},
236 "firebrick": {178, 34, 34},
237 "floralwhite": {255, 250, 240},
238 "forestgreen": {34, 139, 34},
239 "fuchsia": {255, 0, 255},
240 "gainsboro": {220, 220, 220},
241 "ghostwhite": {248, 248, 255},
242 "gold": {255, 215, 0},
243 "goldenrod": {218, 165, 32},
244 "gray": {128, 128, 128},
245 "green": {0, 128, 0},
246 "greenyellow": {173, 255, 47},
247 "grey": {128, 128, 128},
248 "honeydew": {240, 255, 240},
249 "hotpink": {255, 105, 180},
250 "indianred": {205, 92, 92},
251 "indigo": {75, 0, 130},
252 "ivory": {255, 255, 240},
253 "khaki": {240, 230, 140},
254 "lavender": {230, 230, 250},
255 "lavenderblush": {255, 240, 245},
256 "lawngreen": {124, 252, 0},
257 "lemonchiffon": {255, 250, 205},
258 "lightblue": {173, 216, 230},
259 "lightcoral": {240, 128, 128},
260 "lightcyan": {224, 255, 255},
261 "lightgoldenrodyellow": {250, 250, 210},
262 "lightgray": {211, 211, 211},
263 "lightgreen": {144, 238, 144},
264 "lightgrey": {211, 211, 211},
265 "lightpink": {255, 182, 193},
266 "lightsalmon": {255, 160, 122},
267 "lightseagreen": {32, 178, 170},
268 "lightskyblue": {135, 206, 250},
269 "lightslategray": {119, 136, 153},
270 "lightslategrey": {119, 136, 153},
271 "lightsteelblue": {176, 196, 222},
272 "lightyellow": {255, 255, 224},
273 "lime": {0, 255, 0},
274 "limegreen": {50, 205, 50},
275 "linen": {250, 240, 230},
276 "magenta": {255, 0, 255},
277 "maroon": {128, 0, 0},
278 "mediumaquamarine": {102, 205, 170},
279 "mediumblue": {0, 0, 205},
280 "mediumorchid": {186, 85, 211},
281 "mediumpurple": {147, 112, 219},
282 "mediumseagreen": {60, 179, 113},
283 "mediumslateblue": {123, 104, 238},
284 "mediumspringgreen": {0, 250, 154},
285 "mediumturquoise": {72, 209, 204},
286 "mediumvioletred": {199, 21, 133},
287 "midnightblue": {25, 25, 112},
288 "muintcream": {245, 255, 250},
289 "mistyrose": {255, 228, 225},
290 "moccasin": {255, 228, 181},
291 "navajowhite": {255, 222, 173},
292 "navy": {0, 0, 128},
293 "oldlace": {253, 245, 230},
294 "olive": {128, 128, 0},
295 "olivedrab": {107, 142, 35},
296 "orange": {255, 165, 0},
297 "orangered": {255, 69, 0},
298 "orchid": {218, 112, 214},
299 "palegoldenrod": {238, 232, 170},
300 "palegreen": {152, 251, 152},
301 "paleturquoise": {175, 238, 238},
302 "palevioletred": {219, 112, 147},
303 "papayawhip": {255, 239, 213},
304 "peachpuff": {255, 218, 185},
305 "peru": {205, 133, 63},
306 "pink": {255, 192, 203},
307 "plum": {221, 160, 221},
308 "powderblue": {176, 224, 230},
309 "purple": {128, 0, 128},
310 "red": {255, 0, 0},
311 "rebeccapurple": {102, 51, 153},
312 "rosybrown": {188, 143, 143},
313 "royalblue": {65, 105, 225},
314 "saddlebrown": {139, 69, 19},
315 "salmon": {250, 128, 114},
316 "sandybrown": {244, 164, 96},
317 "seagreen": {46, 139, 87},
318 "seashell": {255, 245, 238},
319 "sienna": {160, 82, 45},
320 "silver": {192, 192, 192},
321 "skyblue": {135, 206, 235},
322 "slateblue": {106, 90, 205},
323 "slategray": {112, 128, 144},
324 "slategrey": {112, 128, 144},
325 "snow": {255, 250, 250},
326 "springgreen": {0, 255, 127},
327 "steelblue": {70, 130, 180},
328 "tan": {210, 180, 140},
329 "teal": {0, 128, 128},
330 "thistle": {216, 191, 216},
331 "tomato": {255, 99, 71},
332 "turquoise": {64, 224, 208},
333 "violet": {238, 130, 238},
334 "wheat": {245, 222, 179},
335 "white": {255, 255, 255},
336 "whitesmoke": {245, 245, 245},
337 "yellow": {255, 255, 0},
338 "yellowgreen": {154, 205, 50},
339 }
340
341 func Name2RGB(name string) RGB {
342 if rgb, ok := namedRgbMap[strings.ToLower(name)]; ok {
343 return RGB{
344 Red: rgb[0],
345 Green: rgb[1],
346 Blue: rgb[2],
347 }
348 }
349 return RGB{}
350 }
351
352 var NamedColors = []string{
353 "currentcolor",
354 "transparent",
355 "aliceblue",
356 "antiquewhite",
357 "aqua",
358 "aquamarine",
359 "azure",
360 "beige",
361 "bisque",
362 "black",
363 "blanchedalmond",
364 "blue",
365 "blueviolet",
366 "brown",
367 "burlywood",
368 "cadetblue",
369 "chartreuse",
370 "chocolate",
371 "coral",
372 "cornflowerblue",
373 "cornsilk",
374 "crimson",
375 "cyan",
376 "darkblue",
377 "darkcyan",
378 "darkgoldenrod",
379 "darkgray",
380 "darkgrey",
381 "darkgreen",
382 "darkkhaki",
383 "darkmagenta",
384 "darkolivegreen",
385 "darkorange",
386 "darkorchid",
387 "darkred",
388 "darksalmon",
389 "darkseagreen",
390 "darkslateblue",
391 "darkslategray",
392 "darkslategrey",
393 "darkturquoise",
394 "darkviolet",
395 "deeppink",
396 "deepskyblue",
397 "dimgray",
398 "dimgrey",
399 "dodgerblue",
400 "firebrick",
401 "floralwhite",
402 "forestgreen",
403 "fuchsia",
404 "gainsboro",
405 "ghostwhite",
406 "gold",
407 "goldenrod",
408 "gray",
409 "grey",
410 "green",
411 "greenyellow",
412 "honeydew",
413 "hotpink",
414 "indianred",
415 "indigo",
416 "ivory",
417 "khaki",
418 "lavender",
419 "lavenderblush",
420 "lawngreen",
421 "lemonchiffon",
422 "lightblue",
423 "lightcoral",
424 "lightcyan",
425 "lightgoldenrodyellow",
426 "lightgray",
427 "lightgrey",
428 "lightgreen",
429 "lightpink",
430 "lightsalmon",
431 "lightseagreen",
432 "lightskyblue",
433 "lightslategray",
434 "lightslategrey",
435 "lightsteelblue",
436 "lightyellow",
437 "lime",
438 "limegreen",
439 "linen",
440 "magenta",
441 "maroon",
442 "mediumaquamarine",
443 "mediumblue",
444 "mediumorchid",
445 "mediumpurple",
446 "mediumseagreen",
447 "mediumslateblue",
448 "mediumspringgreen",
449 "mediumturquoise",
450 "mediumvioletred",
451 "midnightblue",
452 "mintcream",
453 "mistyrose",
454 "moccasin",
455 "navajowhite",
456 "navy",
457 "oldlace",
458 "olive",
459 "olivedrab",
460 "orange",
461 "orangered",
462 "orchid",
463 "palegoldenrod",
464 "palegreen",
465 "paleturquoise",
466 "palevioletred",
467 "papayawhip",
468 "peachpuff",
469 "peru",
470 "pink",
471 "plum",
472 "powderblue",
473 "purple",
474 "rebeccapurple",
475 "red",
476 "rosybrown",
477 "royalblue",
478 "saddlebrown",
479 "salmon",
480 "sandybrown",
481 "seagreen",
482 "seashell",
483 "sienna",
484 "silver",
485 "skyblue",
486 "slateblue",
487 "slategray",
488 "slategrey",
489 "snow",
490 "springgreen",
491 "steelblue",
492 "tan",
493 "teal",
494 "thistle",
495 "tomato",
496 "turquoise",
497 "violet",
498 "wheat",
499 "white",
500 "whitesmoke",
501 "yellow",
502 "yellowgreen",
503 }
504
505 var ColorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`)
506
View as plain text