1use anyhow::Error;
6
7pub(crate) fn srgb_to_linear(l: u8) -> f32 {
8 let l = l as f32 * 255.0f32.recip();
9
10 if l <= 0.04045 {
11 l * 12.92f32.recip()
12 } else {
13 ((l + 0.055) * 1.055f32.recip()).powf(2.4)
14 }
15}
16
17#[derive(Hash, Eq, PartialEq, Debug, Clone, Copy)]
19pub struct Color {
20 pub r: u8,
22 pub g: u8,
24 pub b: u8,
26 pub a: u8,
28}
29
30impl Color {
31 pub const fn new() -> Color {
33 Color { r: 0, g: 0, b: 0, a: 255 }
34 }
35
36 pub const fn white() -> Color {
38 Color { r: 255, g: 255, b: 255, a: 255 }
39 }
40
41 pub const fn red() -> Color {
43 Color { r: 255, g: 0, b: 0, a: 255 }
44 }
45
46 pub const fn green() -> Color {
48 Color { r: 0, g: 255, b: 0, a: 255 }
49 }
50
51 pub const fn blue() -> Color {
53 Color { r: 0, g: 0, b: 255, a: 255 }
54 }
55
56 pub const fn fuchsia() -> Color {
58 Color { r: 255, g: 0, b: 255, a: 255 }
59 }
60
61 fn extract_hex_slice(hash_code: &str, start_index: usize) -> Result<u8, Error> {
62 Ok(u8::from_str_radix(&hash_code[start_index..start_index + 2], 16)?)
63 }
64
65 pub fn from_hash_code(hash_code: &str) -> Result<Color, Error> {
67 let mut new_color = Color::new();
68 new_color.r = Color::extract_hex_slice(&hash_code, 1)?;
69 new_color.g = Color::extract_hex_slice(&hash_code, 3)?;
70 new_color.b = Color::extract_hex_slice(&hash_code, 5)?;
71 if hash_code.len() > 8 {
72 new_color.a = Color::extract_hex_slice(&hash_code, 7)?;
73 }
74 Ok(new_color)
75 }
76
77 pub fn to_linear_premult_rgba(&self) -> [f32; 4] {
79 let alpha = self.a as f32 * 255.0f32.recip();
80
81 [
82 srgb_to_linear(self.r) * alpha,
83 srgb_to_linear(self.g) * alpha,
84 srgb_to_linear(self.b) * alpha,
85 alpha,
86 ]
87 }
88
89 pub fn to_linear_bgra(&self) -> [f32; 4] {
91 [
92 srgb_to_linear(self.b),
93 srgb_to_linear(self.g),
94 srgb_to_linear(self.r),
95 self.a as f32 * 255.0f32.recip(),
96 ]
97 }
98
99 pub fn to_srgb_premult_rgba(&self) -> [f32; 4] {
101 let recip = 255.0f32.recip();
102 let alpha = self.a as f32 * recip;
103
104 [
105 self.r as f32 * recip * alpha,
106 self.g as f32 * recip * alpha,
107 self.b as f32 * recip * alpha,
108 alpha,
109 ]
110 }
111}
112
113impl Default for Color {
114 fn default() -> Self {
115 Color::new()
116 }
117}