chroma_rust/color/
color.rs

1use crate::utils::{conversion, parser};
2
3/// Color is a struct that represents a color in RGBA format.
4#[derive(Debug, PartialEq, Clone)]
5pub struct Color {
6    pub(crate) rgba: (u8, u8, u8, f64),
7}
8
9impl Color {
10    pub fn new(r: u8, g: u8, b: u8, alpha: f64) -> Color {
11        Color {
12            rgba: (r, g, b, alpha),
13        }
14    }
15}
16
17impl From<&str> for Color {
18    fn from(str: &str) -> Self {
19        let low_str = str.to_lowercase();
20        let (r, g, b, a) = match &low_str {
21            str if str.starts_with("#") => conversion::hex::hex2rgb(str),
22            str if str.starts_with("rgba") => parser::parse_rgba_str(str),
23            str if str.starts_with("rgb") => parser::parse_rgb_str(str),
24            str if str.starts_with("lab") => {
25                let (l, a, b) = parser::parse_lab_str(str);
26                conversion::lab::lab2rgb((l, a, b))
27            }
28            str if str.starts_with("hsl") => {
29                let (h, s, l) = parser::parse_hsl_str(str);
30                let (r, g, b) = conversion::hsl::hsl2rgb((h, s, l));
31                (r, g, b, 1.0)
32            }
33            str if str.starts_with("hsv") => {
34                let (h, s, v) = parser::parse_hsv_str(str);
35                let (r, g, b) = conversion::hsv::hsv2rgb((h, s, v));
36                (r, g, b, 1.0)
37            }
38            str if str.starts_with("cmyk") => {
39                let (c, m, y, k) = parser::parse_cmyk_str(str);
40                let (r, g, b) = conversion::cmyk::cmyk2rgb((c, m, y, k));
41                (r, g, b, 1.0)
42            }
43            _ => {
44                let found = crate::W3CX11.get(str);
45                match found {
46                    Some(hex) => conversion::hex::hex2rgb(hex),
47                    None => panic!("Color not found"),
48                }
49            }
50        };
51        Color::new(r, g, b, a)
52    }
53}
54
55impl From<u32> for Color {
56    fn from(num: u32) -> Self {
57        let (r, g, b) = conversion::num::num2rgb(num);
58        Color {
59            rgba: (r, g, b, 1.0),
60        }
61    }
62}
63
64impl Iterator for Color {
65    type Item = f64;
66
67    fn next(&mut self) -> Option<Self::Item> {
68        let (r, g, b, a) = self.rgba();
69        vec![r as f64, g as f64, b as f64, a].into_iter().next()
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_color_from_hex_str() {
79        let hex_color = Color::from("#ff0000");
80        assert_eq!(hex_color.rgba, (255, 0, 0, 1.0));
81
82        let hex_color = Color::from("#abcdef");
83        assert_eq!(hex_color.hex(), "#abcdef");
84    }
85
86    #[test]
87    fn test_color_from_rgb_str() {
88        let rgb_color = Color::from("rgb(255, 255, 255)");
89        assert_eq!(
90            rgb_color,
91            Color {
92                rgba: (255, 255, 255, 1.)
93            }
94        );
95
96        let rgba_color = Color::from("rgba(255, 255, 255, 0.6)");
97        assert_eq!(
98            rgba_color,
99            Color {
100                rgba: (255, 255, 255, 0.6)
101            }
102        );
103    }
104
105    #[test]
106    fn test_color_from_lab_str() {
107        let lab_color = Color::from("lab(100, 0, 0)");
108        assert_eq!(
109            lab_color,
110            Color {
111                rgba: (255, 255, 255, 1.)
112            }
113        );
114    }
115
116    #[test]
117    fn test_color_from_name_str() {
118        let name_color = Color::from("mediumspringgreen");
119        assert_eq!(
120            name_color,
121            Color {
122                rgba: (0, 250, 154, 1.)
123            }
124        );
125    }
126
127    #[test]
128    fn test_color_from_hsl_str() {
129        let hsl_color = Color::from("hsl(0, 100%, 50%)");
130        assert_eq!(
131            hsl_color,
132            Color {
133                rgba: (255, 0, 0, 1.)
134            }
135        );
136
137        let hsl_color = Color::from("hsl(120, 100%, 50%)");
138        assert_eq!(
139            hsl_color,
140            Color {
141                rgba: (0, 255, 0, 1.)
142            }
143        );
144
145        let hsl_color = Color::from("hsl(240, 100%, 50%)");
146        assert_eq!(
147            hsl_color,
148            Color {
149                rgba: (0, 0, 255, 1.)
150            }
151        );
152    }
153
154    #[test]
155    fn test_color_from_hsv_str() {
156        let hsv_color = Color::from("hsv(0°,0%,75%)");
157        assert_eq!(
158            hsv_color,
159            Color {
160                rgba: (191, 191, 191, 1.)
161            }
162        );
163
164        let hsv_color = Color::from("hsv(120, 100%, 100%)");
165        assert_eq!(
166            hsv_color,
167            Color {
168                rgba: (0, 255, 0, 1.)
169            }
170        );
171
172        let hsv_color = Color::from("hsv(240, 100%, 100%)");
173        assert_eq!(
174            hsv_color,
175            Color {
176                rgba: (0, 0, 255, 1.)
177            }
178        );
179    }
180
181    #[test]
182    fn test_color_from_num() {
183        let num_color = Color::from(0xff0000);
184        assert_eq!(
185            num_color,
186            Color {
187                rgba: (255, 0, 0, 1.)
188            }
189        );
190
191        let num_color = Color::from(0xffff00);
192        assert_eq!(
193            num_color,
194            Color {
195                rgba: (255, 255, 0, 1.)
196            }
197        );
198
199        let num_color = Color::from(0x00ff00);
200        assert_eq!(
201            num_color,
202            Color {
203                rgba: (0, 255, 0, 1.)
204            }
205        );
206
207        let num_color = Color::from(11259375);
208        assert_eq!(num_color.hex(), "#abcdef");
209    }
210
211    #[test]
212    fn test_color_from_cmyk_str() {
213        let cmyk_color = Color::from("cmyk(0, 100%, 100%, 0)");
214        assert_eq!(cmyk_color.hex(), "#ff0000");
215
216        let cmyk_color = Color::from("cmyk(100%, 0, 100%, 0)");
217        assert_eq!(cmyk_color.hex(), "#00ff00");
218
219        let cmyk_color = Color::from("cmyk(100%, 100%, 0, 0)");
220        assert_eq!(cmyk_color.hex(), "#0000ff");
221
222        let cmyk_color = Color::from("cmyk(0, 0, 0, 100%)");
223        assert_eq!(cmyk_color.hex(), "#000000");
224
225        let cmyk_color = Color::from("cmyk(0, 0, 0, 0)");
226        assert_eq!(cmyk_color.hex(), "#ffffff");
227
228        let cmyk_color = Color::from("cmyk(20%, 80%, 0, 0)");
229        assert_eq!(cmyk_color.hex(), "#cc33ff");
230
231        let cmyk_color = Color::from("cmyk(35%, 0, 60%, 0)");
232        assert_eq!(cmyk_color.hex(), "#a6ff66");
233    }
234}