1use hsluv::*;
2
3#[derive(Clone, Copy, PartialEq, Debug, Serialize, Deserialize)]
7pub enum ColorFormat {
8 Rgba,
9 Hsluv
10}
11
12#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
16pub enum Color {
17 Rgba(f32, f32, f32, f32),
18 Hsluv(f32, f32, f32, f32)
19}
20
21impl PartialEq for Color {
22 fn eq(&self, col: &Color) -> bool {
23 use self::Color::*;
24
25 let distance = match (self, col) {
27 (Rgba(r1, g1, b1, a1), Rgba(r2, g2, b2, a2)) => { (r1-r2)*(r1-r2) + (g1-g2)*(g1-g2) + (b1-b2)*(b1-b2) + (a1-a2)*(a1-a2) }
28 (Hsluv(h1, s1, l1, a1), Hsluv(h2, s2, l2, a2)) => { (h1-h2)*(h1-h2) + (s1-s2)*(s1-s2) + (l1-l2)*(l1-l2) + (a1-a2)*(a1-a2) }
29 _ => { return false; }
30 };
31
32 distance < (0.0001 * 0.0001)
33 }
34}
35
36impl Color {
37 pub fn to_rgba_components(&self) -> (f32, f32, f32, f32) {
41 match self {
42 &Color::Rgba(r, g, b, a) => (r, g, b, a),
43
44 &Color::Hsluv(h, s, l, a) => {
45 let (r, g, b) = hsluv_to_rgb((h as f64, s as f64, l as f64));
46 (r as f32, g as f32, b as f32, a)
47 }
48 }
49 }
50
51 pub fn to_hsluv_components(&self) -> (f32, f32, f32, f32) {
55 match self {
56 &Color::Hsluv(h, s, l, a) => (h, s, l, a),
57
58 &Color::Rgba(r, g, b, a) => {
59 let (h, s, l) = rgb_to_hsluv((r as f64, g as f64, b as f64));
60 let s = if l <= 0.0 { 100.0 } else { s };
61 (h as f32, s as f32, l as f32, a)
62 }
63 }
64 }
65
66 #[inline]
70 pub fn to_format(&self, format: ColorFormat) -> Color {
71 let (r, g, b, a) = self.to_rgba_components();
72
73 match format {
74 ColorFormat::Rgba => Color::Rgba(r, g, b, a),
75 ColorFormat::Hsluv => {
76 let (h, s, l) = rgb_to_hsluv((r as f64, g as f64, b as f64));
77 let s = if l <= 0.0 { 100.0 } else { s };
78 Color::Hsluv(h as f32, s as f32, l as f32, a)
79 }
80 }
81 }
82
83 pub fn with_alpha(&self, new_alpha: f32) -> Color {
87 match self {
88 &Color::Rgba(r, g, b, _) => Color::Rgba(r, g, b, new_alpha),
89 &Color::Hsluv(h, s, l, _) => Color::Hsluv(h, s, l, new_alpha)
90 }
91 }
92}
93
94#[cfg(test)]
95mod test {
96 use super::*;
97
98 #[test]
99 fn can_convert_rgba_to_hsluv() {
100 let rgb = Color::Rgba(0.5, 0.7, 0.2, 0.9);
101 let hsluv = rgb.to_format(ColorFormat::Hsluv);
102
103 if let Color::Hsluv(h, s, l, a) = hsluv {
104 assert!((h-110.3).abs() < 0.1);
105 assert!((s-89.5).abs() < 0.1);
106 assert!((l-67.1).abs() < 0.1);
107 assert!(a == 0.9);
108 } else {
109 assert!(false)
110 }
111 }
112
113 #[test]
114 fn can_convert_hsluv_to_rgba() {
115 let hsluv = Color::Hsluv(24.0, 66.0, 60.0, 0.8);
116 let rgb = hsluv.to_format(ColorFormat::Rgba);
117
118 if let Color::Rgba(r, g, b, a) = rgb {
119 assert!((r-0.89) < 0.1);
120 assert!((g-0.43) < 0.1);
121 assert!((b-0.38) < 0.1);
122 assert!(a == 0.8);
123 } else {
124 assert!(false);
125 }
126 }
127
128 #[test]
129 fn can_get_rgba_components_from_hsluv() {
130 let hsluv = Color::Hsluv(24.0, 66.0, 60.0, 0.8);
131 let (r, g, b, a) = hsluv.to_rgba_components();
132
133 assert!((r-0.89) < 0.1);
134 assert!((g-0.43) < 0.1);
135 assert!((b-0.38) < 0.1);
136 assert!(a == 0.8);
137 }
138}