1#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
9pub struct Color {
10 pub r: u8,
12 pub g: u8,
14 pub b: u8,
16 pub a: u8,
18}
19
20impl Color {
21 pub const fn rgb8(r: u8, g: u8, b: u8) -> Self {
23 Self { r, g, b, a: 255 }
24 }
25
26 pub const fn rgba8(r: u8, g: u8, b: u8, a: u8) -> Self {
28 Self { r, g, b, a }
29 }
30
31 pub fn rgb(r: f64, g: f64, b: f64) -> Self {
36 Self::rgba(r, g, b, 1.0)
37 }
38
39 pub fn rgba(r: f64, g: f64, b: f64, a: f64) -> Self {
44 let r = (r.clamp(0.0, 1.0) * 255.0).round() as u8;
45 let g = (g.clamp(0.0, 1.0) * 255.0).round() as u8;
46 let b = (b.clamp(0.0, 1.0) * 255.0).round() as u8;
47 let a = (a.clamp(0.0, 1.0) * 255.0).round() as u8;
48 Self { r, g, b, a }
49 }
50
51 pub fn hlc(h: f64, l: f64, c: f64) -> Self {
69 Self::hlca(h, l, c, 1.0)
70 }
71
72 #[allow(non_snake_case)]
76 #[allow(clippy::many_single_char_names)]
77 #[allow(clippy::unreadable_literal)]
78 pub fn hlca(h: f64, l: f64, c: f64, a: f64) -> Color {
79 let alpha = a;
80 fn f_inv(t: f64) -> f64 {
83 let d = 6. / 29.;
84 if t > d {
85 t.powi(3)
86 } else {
87 3. * d * d * (t - 4. / 29.)
88 }
89 }
90 let th = h * (std::f64::consts::PI / 180.);
91 let a = c * th.cos();
92 let b = c * th.sin();
93 let ll = (l + 16.) * (1. / 116.);
94 let X = f_inv(ll + a * (1. / 500.));
96 let Y = f_inv(ll);
97 let Z = f_inv(ll - b * (1. / 200.));
98 let r_lin = 3.02172918 * X - 1.61692294 * Y - 0.40480625 * Z;
112 let g_lin = -0.94339358 * X + 1.91584267 * Y + 0.02755094 * Z;
113 let b_lin = 0.06945666 * X - 0.22903204 * Y + 1.15957526 * Z;
114 fn gamma(u: f64) -> f64 {
115 if u <= 0.0031308 {
116 12.92 * u
117 } else {
118 1.055 * u.powf(1. / 2.4) - 0.055
119 }
120 }
121 Color::rgba(gamma(r_lin), gamma(g_lin), gamma(b_lin), alpha)
122 }
123
124 pub fn parse(s: &str) -> Option<Self> {
129 parse_color(s)
130 }
131
132 pub fn with_alpha_factor(self, alpha: f32) -> Self {
135 let mut result = self;
136 result.a = ((result.a as f32) * alpha).round() as u8;
137 result
138 }
139
140 pub fn to_premul_u32(self) -> u32 {
142 let a = self.a as f64 * (1.0 / 255.0);
143 let r = (self.r as f64 * a).round() as u32;
144 let g = (self.g as f64 * a).round() as u32;
145 let b = (self.b as f64 * a).round() as u32;
146 (r << 24) | (g << 16) | (b << 8) | self.a as u32
147 }
148}
149
150impl Color {
152 pub const ALICE_BLUE: Color = Color::rgba8(240, 248, 255, 255);
154 pub const ANTIQUE_WHITE: Color = Color::rgba8(250, 235, 215, 255);
156 pub const AQUA: Color = Color::rgba8(0, 255, 255, 255);
158 pub const AQUAMARINE: Color = Color::rgba8(127, 255, 212, 255);
160 pub const AZURE: Color = Color::rgba8(240, 255, 255, 255);
162 pub const BEIGE: Color = Color::rgba8(245, 245, 220, 255);
164 pub const BISQUE: Color = Color::rgba8(255, 228, 196, 255);
166 pub const BLACK: Color = Color::rgba8(0, 0, 0, 255);
168 pub const BLANCHED_ALMOND: Color = Color::rgba8(255, 235, 205, 255);
170 pub const BLUE: Color = Color::rgba8(0, 0, 255, 255);
172 pub const BLUE_VIOLET: Color = Color::rgba8(138, 43, 226, 255);
174 pub const BROWN: Color = Color::rgba8(165, 42, 42, 255);
176 pub const BURLYWOOD: Color = Color::rgba8(222, 184, 135, 255);
178 pub const CADET_BLUE: Color = Color::rgba8(95, 158, 160, 255);
180 pub const CHARTREUSE: Color = Color::rgba8(127, 255, 0, 255);
182 pub const CHOCOLATE: Color = Color::rgba8(210, 105, 30, 255);
184 pub const CORAL: Color = Color::rgba8(255, 127, 80, 255);
186 pub const CORNFLOWER_BLUE: Color = Color::rgba8(100, 149, 237, 255);
188 pub const CORNSILK: Color = Color::rgba8(255, 248, 220, 255);
190 pub const CRIMSON: Color = Color::rgba8(220, 20, 60, 255);
192 pub const CYAN: Color = Color::rgba8(0, 255, 255, 255);
194 pub const DARK_BLUE: Color = Color::rgba8(0, 0, 139, 255);
196 pub const DARK_CYAN: Color = Color::rgba8(0, 139, 139, 255);
198 pub const DARK_GOLDENROD: Color = Color::rgba8(184, 134, 11, 255);
200 pub const DARK_GRAY: Color = Color::rgba8(169, 169, 169, 255);
202 pub const DARK_GREEN: Color = Color::rgba8(0, 100, 0, 255);
204 pub const DARK_KHAKI: Color = Color::rgba8(189, 183, 107, 255);
206 pub const DARK_MAGENTA: Color = Color::rgba8(139, 0, 139, 255);
208 pub const DARK_OLIVE_GREEN: Color = Color::rgba8(85, 107, 47, 255);
210 pub const DARK_ORANGE: Color = Color::rgba8(255, 140, 0, 255);
212 pub const DARK_ORCHID: Color = Color::rgba8(153, 50, 204, 255);
214 pub const DARK_RED: Color = Color::rgba8(139, 0, 0, 255);
216 pub const DARK_SALMON: Color = Color::rgba8(233, 150, 122, 255);
218 pub const DARK_SEA_GREEN: Color = Color::rgba8(143, 188, 143, 255);
220 pub const DARK_SLATE_BLUE: Color = Color::rgba8(72, 61, 139, 255);
222 pub const DARK_SLATE_GRAY: Color = Color::rgba8(47, 79, 79, 255);
224 pub const DARK_TURQUOISE: Color = Color::rgba8(0, 206, 209, 255);
226 pub const DARK_VIOLET: Color = Color::rgba8(148, 0, 211, 255);
228 pub const DEEP_PINK: Color = Color::rgba8(255, 20, 147, 255);
230 pub const DEEP_SKY_BLUE: Color = Color::rgba8(0, 191, 255, 255);
232 pub const DIM_GRAY: Color = Color::rgba8(105, 105, 105, 255);
234 pub const DODGER_BLUE: Color = Color::rgba8(30, 144, 255, 255);
236 pub const FIREBRICK: Color = Color::rgba8(178, 34, 34, 255);
238 pub const FLORAL_WHITE: Color = Color::rgba8(255, 250, 240, 255);
240 pub const FOREST_GREEN: Color = Color::rgba8(34, 139, 34, 255);
242 pub const FUCHSIA: Color = Color::rgba8(255, 0, 255, 255);
244 pub const GAINSBORO: Color = Color::rgba8(220, 220, 220, 255);
246 pub const GHOST_WHITE: Color = Color::rgba8(248, 248, 255, 255);
248 pub const GOLD: Color = Color::rgba8(255, 215, 0, 255);
250 pub const GOLDENROD: Color = Color::rgba8(218, 165, 32, 255);
252 pub const GRAY: Color = Color::rgba8(128, 128, 128, 255);
254 pub const GREEN: Color = Color::rgba8(0, 128, 0, 255);
256 pub const GREEN_YELLOW: Color = Color::rgba8(173, 255, 47, 255);
258 pub const HONEYDEW: Color = Color::rgba8(240, 255, 240, 255);
260 pub const HOT_PINK: Color = Color::rgba8(255, 105, 180, 255);
262 pub const INDIAN_RED: Color = Color::rgba8(205, 92, 92, 255);
264 pub const INDIGO: Color = Color::rgba8(75, 0, 130, 255);
266 pub const IVORY: Color = Color::rgba8(255, 255, 240, 255);
268 pub const KHAKI: Color = Color::rgba8(240, 230, 140, 255);
270 pub const LAVENDER: Color = Color::rgba8(230, 230, 250, 255);
272 pub const LAVENDER_BLUSH: Color = Color::rgba8(255, 240, 245, 255);
274 pub const LAWN_GREEN: Color = Color::rgba8(124, 252, 0, 255);
276 pub const LEMON_CHIFFON: Color = Color::rgba8(255, 250, 205, 255);
278 pub const LIGHT_BLUE: Color = Color::rgba8(173, 216, 230, 255);
280 pub const LIGHT_CORAL: Color = Color::rgba8(240, 128, 128, 255);
282 pub const LIGHT_CYAN: Color = Color::rgba8(224, 255, 255, 255);
284 pub const LIGHT_GOLDENROD_YELLOW: Color = Color::rgba8(250, 250, 210, 255);
286 pub const LIGHT_GRAY: Color = Color::rgba8(211, 211, 211, 255);
288 pub const LIGHT_GREEN: Color = Color::rgba8(144, 238, 144, 255);
290 pub const LIGHT_PINK: Color = Color::rgba8(255, 182, 193, 255);
292 pub const LIGHT_SALMON: Color = Color::rgba8(255, 160, 122, 255);
294 pub const LIGHT_SEA_GREEN: Color = Color::rgba8(32, 178, 170, 255);
296 pub const LIGHT_SKY_BLUE: Color = Color::rgba8(135, 206, 250, 255);
298 pub const LIGHT_SLATE_GRAY: Color = Color::rgba8(119, 136, 153, 255);
300 pub const LIGHT_STEEL_BLUE: Color = Color::rgba8(176, 196, 222, 255);
302 pub const LIGHT_YELLOW: Color = Color::rgba8(255, 255, 224, 255);
304 pub const LIME: Color = Color::rgba8(0, 255, 0, 255);
306 pub const LIME_GREEN: Color = Color::rgba8(50, 205, 50, 255);
308 pub const LINEN: Color = Color::rgba8(250, 240, 230, 255);
310 pub const MAGENTA: Color = Color::rgba8(255, 0, 255, 255);
312 pub const MAROON: Color = Color::rgba8(128, 0, 0, 255);
314 pub const MEDIUM_AQUAMARINE: Color = Color::rgba8(102, 205, 170, 255);
316 pub const MEDIUM_BLUE: Color = Color::rgba8(0, 0, 205, 255);
318 pub const MEDIUM_ORCHID: Color = Color::rgba8(186, 85, 211, 255);
320 pub const MEDIUM_PURPLE: Color = Color::rgba8(147, 112, 219, 255);
322 pub const MEDIUM_SEA_GREEN: Color = Color::rgba8(60, 179, 113, 255);
324 pub const MEDIUM_SLATE_BLUE: Color = Color::rgba8(123, 104, 238, 255);
326 pub const MEDIUM_SPRING_GREEN: Color = Color::rgba8(0, 250, 154, 255);
328 pub const MEDIUM_TURQUOISE: Color = Color::rgba8(72, 209, 204, 255);
330 pub const MEDIUM_VIOLET_RED: Color = Color::rgba8(199, 21, 133, 255);
332 pub const MIDNIGHT_BLUE: Color = Color::rgba8(25, 25, 112, 255);
334 pub const MINT_CREAM: Color = Color::rgba8(245, 255, 250, 255);
336 pub const MISTY_ROSE: Color = Color::rgba8(255, 228, 225, 255);
338 pub const MOCCASIN: Color = Color::rgba8(255, 228, 181, 255);
340 pub const NAVAJO_WHITE: Color = Color::rgba8(255, 222, 173, 255);
342 pub const NAVY: Color = Color::rgba8(0, 0, 128, 255);
344 pub const OLD_LACE: Color = Color::rgba8(253, 245, 230, 255);
346 pub const OLIVE: Color = Color::rgba8(128, 128, 0, 255);
348 pub const OLIVE_DRAB: Color = Color::rgba8(107, 142, 35, 255);
350 pub const ORANGE: Color = Color::rgba8(255, 165, 0, 255);
352 pub const ORANGE_RED: Color = Color::rgba8(255, 69, 0, 255);
354 pub const ORCHID: Color = Color::rgba8(218, 112, 214, 255);
356 pub const PALE_GOLDENROD: Color = Color::rgba8(238, 232, 170, 255);
358 pub const PALE_GREEN: Color = Color::rgba8(152, 251, 152, 255);
360 pub const PALE_TURQUOISE: Color = Color::rgba8(175, 238, 238, 255);
362 pub const PALE_VIOLET_RED: Color = Color::rgba8(219, 112, 147, 255);
364 pub const PAPAYA_WHIP: Color = Color::rgba8(255, 239, 213, 255);
366 pub const PEACH_PUFF: Color = Color::rgba8(255, 218, 185, 255);
368 pub const PERU: Color = Color::rgba8(205, 133, 63, 255);
370 pub const PINK: Color = Color::rgba8(255, 192, 203, 255);
372 pub const PLUM: Color = Color::rgba8(221, 160, 221, 255);
374 pub const POWDER_BLUE: Color = Color::rgba8(176, 224, 230, 255);
376 pub const PURPLE: Color = Color::rgba8(128, 0, 128, 255);
378 pub const REBECCA_PURPLE: Color = Color::rgba8(102, 51, 153, 255);
380 pub const RED: Color = Color::rgba8(255, 0, 0, 255);
382 pub const ROSY_BROWN: Color = Color::rgba8(188, 143, 143, 255);
384 pub const ROYAL_BLUE: Color = Color::rgba8(65, 105, 225, 255);
386 pub const SADDLE_BROWN: Color = Color::rgba8(139, 69, 19, 255);
388 pub const SALMON: Color = Color::rgba8(250, 128, 114, 255);
390 pub const SANDY_BROWN: Color = Color::rgba8(244, 164, 96, 255);
392 pub const SEA_GREEN: Color = Color::rgba8(46, 139, 87, 255);
394 pub const SEASHELL: Color = Color::rgba8(255, 245, 238, 255);
396 pub const SIENNA: Color = Color::rgba8(160, 82, 45, 255);
398 pub const SILVER: Color = Color::rgba8(192, 192, 192, 255);
400 pub const SKY_BLUE: Color = Color::rgba8(135, 206, 235, 255);
402 pub const SLATE_BLUE: Color = Color::rgba8(106, 90, 205, 255);
404 pub const SLATE_GRAY: Color = Color::rgba8(112, 128, 144, 255);
406 pub const SNOW: Color = Color::rgba8(255, 250, 250, 255);
408 pub const SPRING_GREEN: Color = Color::rgba8(0, 255, 127, 255);
410 pub const STEEL_BLUE: Color = Color::rgba8(70, 130, 180, 255);
412 pub const TAN: Color = Color::rgba8(210, 180, 140, 255);
414 pub const TEAL: Color = Color::rgba8(0, 128, 128, 255);
416 pub const THISTLE: Color = Color::rgba8(216, 191, 216, 255);
418 pub const TOMATO: Color = Color::rgba8(255, 99, 71, 255);
420 pub const TRANSPARENT: Color = Color::rgba8(0, 0, 0, 0);
422 pub const TURQUOISE: Color = Color::rgba8(64, 224, 208, 255);
424 pub const VIOLET: Color = Color::rgba8(238, 130, 238, 255);
426 pub const WHEAT: Color = Color::rgba8(245, 222, 179, 255);
428 pub const WHITE: Color = Color::rgba8(255, 255, 255, 255);
430 pub const WHITE_SMOKE: Color = Color::rgba8(245, 245, 245, 255);
432 pub const YELLOW: Color = Color::rgba8(255, 255, 0, 255);
434 pub const YELLOW_GREEN: Color = Color::rgba8(154, 205, 50, 255);
436}
437
438impl From<[u8; 3]> for Color {
439 fn from(rgb: [u8; 3]) -> Self {
440 Self::rgb8(rgb[0], rgb[1], rgb[2])
441 }
442}
443
444impl From<[u8; 4]> for Color {
445 fn from(rgba: [u8; 4]) -> Self {
446 Self::rgba8(rgba[0], rgba[1], rgba[2], rgba[3])
447 }
448}
449
450fn parse_color(s: &str) -> Option<Color> {
451 let s = s.trim();
452 if let Some(stripped) = s.strip_prefix('#') {
453 Some(color_from_4bit_hex(get_4bit_hex_channels(stripped)?))
454 } else {
455 Some(match s {
456 "aliceblue" => Color::ALICE_BLUE,
457 "antiquewhite" => Color::ANTIQUE_WHITE,
458 "aqua" => Color::AQUA,
459 "aquamarine" => Color::AQUAMARINE,
460 "azure" => Color::AZURE,
461 "beige" => Color::BEIGE,
462 "bisque" => Color::BISQUE,
463 "black" => Color::BLACK,
464 "blanchedalmond" => Color::BLANCHED_ALMOND,
465 "blue" => Color::BLUE,
466 "blueviolet" => Color::BLUE_VIOLET,
467 "brown" => Color::BROWN,
468 "burlywood" => Color::BURLYWOOD,
469 "cadetblue" => Color::CADET_BLUE,
470 "chartreuse" => Color::CHARTREUSE,
471 "chocolate" => Color::CHOCOLATE,
472 "coral" => Color::CORAL,
473 "cornflowerblue" => Color::CORNFLOWER_BLUE,
474 "cornsilk" => Color::CORNSILK,
475 "crimson" => Color::CRIMSON,
476 "cyan" => Color::CYAN,
477 "darkblue" => Color::DARK_BLUE,
478 "darkcyan" => Color::DARK_CYAN,
479 "darkgoldenrod" => Color::DARK_GOLDENROD,
480 "darkgray" => Color::DARK_GRAY,
481 "darkgreen" => Color::DARK_GREEN,
482 "darkkhaki" => Color::DARK_KHAKI,
483 "darkmagenta" => Color::DARK_MAGENTA,
484 "darkolivegreen" => Color::DARK_OLIVE_GREEN,
485 "darkorange" => Color::DARK_ORANGE,
486 "darkorchid" => Color::DARK_ORCHID,
487 "darkred" => Color::DARK_RED,
488 "darksalmon" => Color::DARK_SALMON,
489 "darkseagreen" => Color::DARK_SEA_GREEN,
490 "darkslateblue" => Color::DARK_SLATE_BLUE,
491 "darkslategray" => Color::DARK_SLATE_GRAY,
492 "darkturquoise" => Color::DARK_TURQUOISE,
493 "darkviolet" => Color::DARK_VIOLET,
494 "deeppink" => Color::DEEP_PINK,
495 "deepskyblue" => Color::DEEP_SKY_BLUE,
496 "dimgray" => Color::DIM_GRAY,
497 "dodgerblue" => Color::DODGER_BLUE,
498 "firebrick" => Color::FIREBRICK,
499 "floralwhite" => Color::FLORAL_WHITE,
500 "forestgreen" => Color::FOREST_GREEN,
501 "fuchsia" => Color::FUCHSIA,
502 "gainsboro" => Color::GAINSBORO,
503 "ghostwhite" => Color::GHOST_WHITE,
504 "gold" => Color::GOLD,
505 "goldenrod" => Color::GOLDENROD,
506 "gray" => Color::GRAY,
507 "green" => Color::GREEN,
508 "greenyellow" => Color::GREEN_YELLOW,
509 "honeydew" => Color::HONEYDEW,
510 "hotpink" => Color::HOT_PINK,
511 "indianred" => Color::INDIAN_RED,
512 "indigo" => Color::INDIGO,
513 "ivory" => Color::IVORY,
514 "khaki" => Color::KHAKI,
515 "lavender" => Color::LAVENDER,
516 "lavenderblush" => Color::LAVENDER_BLUSH,
517 "lawngreen" => Color::LAWN_GREEN,
518 "lemonchiffon" => Color::LEMON_CHIFFON,
519 "lightblue" => Color::LIGHT_BLUE,
520 "lightcoral" => Color::LIGHT_CORAL,
521 "lightcyan" => Color::LIGHT_CYAN,
522 "lightgoldenrodyellow" => Color::LIGHT_GOLDENROD_YELLOW,
523 "lightgray" => Color::LIGHT_GRAY,
524 "lightgreen" => Color::LIGHT_GREEN,
525 "lightpink" => Color::LIGHT_PINK,
526 "lightsalmon" => Color::LIGHT_SALMON,
527 "lightseagreen" => Color::LIGHT_SEA_GREEN,
528 "lightskyblue" => Color::LIGHT_SKY_BLUE,
529 "lightslategray" => Color::LIGHT_SLATE_GRAY,
530 "lightsteelblue" => Color::LIGHT_STEEL_BLUE,
531 "lightyellow" => Color::LIGHT_YELLOW,
532 "lime" => Color::LIME,
533 "limegreen" => Color::LIME_GREEN,
534 "linen" => Color::LINEN,
535 "magenta" => Color::MAGENTA,
536 "maroon" => Color::MAROON,
537 "mediumaquamarine" => Color::MEDIUM_AQUAMARINE,
538 "mediumblue" => Color::MEDIUM_BLUE,
539 "mediumorchid" => Color::MEDIUM_ORCHID,
540 "mediumpurple" => Color::MEDIUM_PURPLE,
541 "mediumseagreen" => Color::MEDIUM_SEA_GREEN,
542 "mediumslateblue" => Color::MEDIUM_SLATE_BLUE,
543 "mediumspringgreen" => Color::MEDIUM_SPRING_GREEN,
544 "mediumturquoise" => Color::MEDIUM_TURQUOISE,
545 "mediumvioletred" => Color::MEDIUM_VIOLET_RED,
546 "midnightblue" => Color::MIDNIGHT_BLUE,
547 "mintcream" => Color::MINT_CREAM,
548 "mistyrose" => Color::MISTY_ROSE,
549 "moccasin" => Color::MOCCASIN,
550 "navajowhite" => Color::NAVAJO_WHITE,
551 "navy" => Color::NAVY,
552 "oldlace" => Color::OLD_LACE,
553 "olive" => Color::OLIVE,
554 "olivedrab" => Color::OLIVE_DRAB,
555 "orange" => Color::ORANGE,
556 "orangered" => Color::ORANGE_RED,
557 "orchid" => Color::ORCHID,
558 "palegoldenrod" => Color::PALE_GOLDENROD,
559 "palegreen" => Color::PALE_GREEN,
560 "paleturquoise" => Color::PALE_TURQUOISE,
561 "palevioletred" => Color::PALE_VIOLET_RED,
562 "papayawhip" => Color::PAPAYA_WHIP,
563 "peachpuff" => Color::PEACH_PUFF,
564 "peru" => Color::PERU,
565 "pink" => Color::PINK,
566 "plum" => Color::PLUM,
567 "powderblue" => Color::POWDER_BLUE,
568 "purple" => Color::PURPLE,
569 "rebeccapurple" => Color::REBECCA_PURPLE,
570 "red" => Color::RED,
571 "rosybrown" => Color::ROSY_BROWN,
572 "royalblue" => Color::ROYAL_BLUE,
573 "saddlebrown" => Color::SADDLE_BROWN,
574 "salmon" => Color::SALMON,
575 "sandybrown" => Color::SANDY_BROWN,
576 "seagreen" => Color::SEA_GREEN,
577 "seashell" => Color::SEASHELL,
578 "sienna" => Color::SIENNA,
579 "silver" => Color::SILVER,
580 "skyblue" => Color::SKY_BLUE,
581 "slateblue" => Color::SLATE_BLUE,
582 "slategray" => Color::SLATE_GRAY,
583 "snow" => Color::SNOW,
584 "springgreen" => Color::SPRING_GREEN,
585 "steelblue" => Color::STEEL_BLUE,
586 "tan" => Color::TAN,
587 "teal" => Color::TEAL,
588 "thistle" => Color::THISTLE,
589 "tomato" => Color::TOMATO,
590 "transparent" => Color::TRANSPARENT,
591 "turquoise" => Color::TURQUOISE,
592 "violet" => Color::VIOLET,
593 "wheat" => Color::WHEAT,
594 "white" => Color::WHITE,
595 "whitesmoke" => Color::WHITE_SMOKE,
596 "yellow" => Color::YELLOW,
597 "yellowgreen" => Color::YELLOW_GREEN,
598 _ => return None,
599 })
600 }
601}
602
603const fn get_4bit_hex_channels(hex_str: &str) -> Option<[u8; 8]> {
606 let mut four_bit_channels = match hex_str.as_bytes() {
607 &[b'#', r, g, b] | &[r, g, b] => [r, r, g, g, b, b, b'f', b'f'],
608 &[b'#', r, g, b, a] | &[r, g, b, a] => [r, r, g, g, b, b, a, a],
609 &[b'#', r0, r1, g0, g1, b0, b1] | &[r0, r1, g0, g1, b0, b1] => {
610 [r0, r1, g0, g1, b0, b1, b'f', b'f']
611 }
612 &[b'#', r0, r1, g0, g1, b0, b1, a0, a1] | &[r0, r1, g0, g1, b0, b1, a0, a1] => {
613 [r0, r1, g0, g1, b0, b1, a0, a1]
614 }
615 _ => return None,
616 };
617
618 let mut i = 0;
621 while i < four_bit_channels.len() {
622 let ascii = four_bit_channels[i];
623 let as_hex = match hex_from_ascii_byte(ascii) {
624 Ok(hex) => hex,
625 Err(_) => return None,
626 };
627 four_bit_channels[i] = as_hex;
628 i += 1;
629 }
630 Some(four_bit_channels)
631}
632
633const fn color_from_4bit_hex(components: [u8; 8]) -> Color {
634 let [r0, r1, g0, g1, b0, b1, a0, a1] = components;
635 Color::rgba8(r0 << 4 | r1, g0 << 4 | g1, b0 << 4 | b1, a0 << 4 | a1)
636}
637
638const fn hex_from_ascii_byte(b: u8) -> Result<u8, u8> {
639 match b {
640 b'0'..=b'9' => Ok(b - b'0'),
641 b'A'..=b'F' => Ok(b - b'A' + 10),
642 b'a'..=b'f' => Ok(b - b'a' + 10),
643 _ => Err(b),
644 }
645}