1use std::fmt::{Display, Error};
2
3pub trait Color: Copy {
4 type Type;
5 fn complement(&self) -> Self::Type;
6
7 fn get_rgba(&self) -> RgbaColorType;
8 fn get_hsla(&self) -> HslaColorType;
9 fn set_opacity(&mut self, a: f64) -> Self::Type;
10}
11
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub struct RgbaColorType {
14 pub r: f64,
15 pub g: f64,
16 pub b: f64,
17 pub a: f64,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub struct HslaColorType {
22 pub h: f64,
23 pub s: f64,
24 pub l: f64,
25 pub a: f64,
26}
27
28impl RgbaColorType {
29 pub fn new(r: f64, g: f64, b: f64) -> RgbaColorType {
30 RgbaColorType {
31 r: r,
32 g: g,
33 b: b,
34 a: 1.0,
35 }
36 }
37}
38
39impl HslaColorType {
40 pub fn new(h: f64, s: f64, l: f64) -> HslaColorType {
41 let mut a = HslaColorType {
42 h: h,
43 s: s,
44 l: l,
45 a: 1.0,
46 };
47 a.validate();
48 a
49 }
50
51 fn validate(&mut self) {
52 self.h = self.h % 360.0;
53 if self.h < 0.0 {
54 self.h += 360.0
55 };
56
57 if self.s < 0.0 {
58 self.s = 0.0
59 };
60 if self.s > 100.0 {
61 self.s = 100.0
62 };
63 if self.l < 0.0 {
64 self.l = 0.0
65 };
66 if self.l > 100.0 {
67 self.l = 100.0
68 };
69 }
70}
71fn hue2rgb(p: f64, q: f64, t: f64) -> f64 {
72 let mut t = t;
73 if t < 0.0 {
74 t += 1.0;
75 }
76 if t > 1.0 {
77 t -= 1.0;
78 }
79 if t < 1.0 / 6.0 {
80 p + (q - p) * 6.0 * t
81 } else if t < 1.0 / 2.0 {
82 q
83 } else if t < 2.0 / 3.0 {
84 p + (q - p) * (2.0 / 3.0 - t) * 6.0
85 } else {
86 p
87 }
88}
89
90impl From<[f64; 3]> for RgbaColorType {
91 fn from(c: [f64; 3]) -> RgbaColorType {
92 RgbaColorType::new(c[0], c[1], c[2])
93 }
94}
95impl From<[u8; 3]> for RgbaColorType {
96 fn from(c: [u8; 3]) -> RgbaColorType {
97 RgbaColorType::new(
98 c[0] as f64 / 255.0,
99 c[1] as f64 / 255.0,
100 c[2] as f64 / 255.0,
101 )
102 }
103}
104
105impl Into<[u8; 3]> for RgbaColorType {
106 fn into(self) -> [u8; 3] {
107 [
108 (self.r * 255.0).round() as u8,
109 (self.g * 255.0).round() as u8,
110 (self.b * 255.0).round() as u8,
111 ]
112 }
113}
114impl Into<[u8; 4]> for RgbaColorType {
115 fn into(self) -> [u8; 4] {
116 [
117 (self.r * 255.0).round() as u8,
118 (self.g * 255.0).round() as u8,
119 (self.b * 255.0).round() as u8,
120 (self.a * 255.0).round() as u8,
121 ]
122 }
123}
124impl Into<[f64; 4]> for RgbaColorType {
125 fn into(self) -> [f64; 4] {
126 [self.r, self.g, self.b, self.a]
127 }
128}
129
130impl Into<[f32; 4]> for RgbaColorType {
131 fn into(self) -> [f32; 4] {
132 [self.r as f32, self.g as f32, self.b as f32, self.a as f32]
133 }
134}
135impl From<HslaColorType> for RgbaColorType {
136 fn from(c: HslaColorType) -> RgbaColorType {
137 let h: f64 = c.h / 360.0;
138 let s: f64 = c.s / 100.0;
139 let l: f64 = c.l / 100.0;
140
141 let mut r: f64 = l;
142 let mut g: f64 = l;
143 let mut b: f64 = l;
144
145 if s != 0.0 {
146 let q = if l < 0.5 {
147 l * (1.0 + s)
148 } else {
149 l + s - l * s
150 };
151 let p = 2.0 * l - q;
152 r = hue2rgb(p, q, h + 1.0 / 3.0);
153 g = hue2rgb(p, q, h);
154 b = hue2rgb(p, q, h - 1.0 / 3.0);
155 }
156 RgbaColorType::new(r, g, b)
157 }
158}
159impl From<RgbaColorType> for HslaColorType {
160 fn from(c: RgbaColorType) -> HslaColorType {
161 let mut h: f64;
162 let mut s: f64;
163 let mut l: f64;
164 let r: f64 = c.r;
165 let g: f64 = c.g;
166 let b: f64 = c.b;
167
168 let max: f64 = c.r.max(c.g).max(c.b);
169 let min: f64 = c.r.min(c.g).min(c.b);
170 h = (max + min) / 2.0;
171 s = h;
172 l = h;
173
174 let error = 0.00001;
175 if (max - min).abs() < error {
176 h = 0.0;
179 s = 0.0;
180 } else {
181 let d = max - min;
182 s = if l > 0.5 {
183 d / (2.0 - max - min)
184 } else {
185 d / (max + min)
186 };
187 if (max - r).abs() < error {
188 h = (g - b) / d + (if g < b { 6.0 } else { 0.0 })
189 } else if (max - g).abs() < error {
190 h = (b - r) / d + 2.0
191 } else if (max - b).abs() < error {
192 h = (r - g) / d + 4.0;
193 }
194
195 h /= 6.0;
196 }
197 h *= 360.0;
198 s *= 100.0;
199 l *= 100.0;
200
201 HslaColorType::new(h, s, l)
202 }
203}
204impl Display for RgbaColorType {
205 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
206 fmt.write_str(format!("RGB({:?}, {:?}, {:?})", self.r, self.g, self.b).as_str())
207 }
208}
209impl Color for RgbaColorType {
210 type Type = RgbaColorType;
211
212 fn set_opacity(&mut self, a: f64) -> Self::Type {
213 self.a = a;
214 *self
215 }
216
217 fn complement(&self) -> Self::Type {
218 RgbaColorType{r:1.0 - self.r, g: 1.0 - self.g, b: 1.0 - self.b, a: self.a}
219 }
220 fn get_hsla(&self) -> HslaColorType {
221 (*self).into()
222 }
223 fn get_rgba(&self) -> RgbaColorType {
224 *self
225 }
226}
227
228mod tests {
229 use super::*;
230 #[test]
231 fn test_new() {
232 let c = RgbaColorType::new(0.1, 0.2, 0.3);
233 assert_eq!(
234 c,
235 RgbaColorType {
236 r: 0.1,
237 g: 0.2,
238 b: 0.3,
239 a: 1.0
240 }
241 );
242 }
243
244 #[test]
245 fn test_complement() {
246 let c = RgbaColorType::new(0.1, 0.2, 0.3);
247 assert_eq!(
248 c.complement(),
249 RgbaColorType {
250 r: 0.9,
251 g: 0.8,
252 b: 0.7,
253 a: 1.0
254 }
255 );
256 }
257
258 #[test]
259 fn test_from_array() {
260 let a: RgbaColorType = RgbaColorType::from([1.0, 0.5, 0.0]);
261 assert_eq!(
262 a,
263 RgbaColorType {
264 r: 1.0,
265 g: 0.5,
266 b: 0.0,
267 a: 1.0
268 }
269 );
270 }
271
272 #[test]
273 fn test_from_bytes() {
274 let a = RgbaColorType::from([255, 255, 255]);
275 assert_eq!(
276 a,
277 RgbaColorType {
278 r: 1.0,
279 g: 1.0,
280 b: 1.0,
281 a: 1.0
282 }
283 );
284 let b = RgbaColorType::from([128, 128, 128]);
285 assert!(
286 error(
287 b,
288 RgbaColorType {
289 r: 0.5,
290 g: 0.5,
291 b: 0.5,
292 a: 1.0
293 }
294 ) < 0.005
295 );
296 }
297 #[test]
298 fn test_into() {
299 let a = RgbaColorType::new(1.0, 0.5, 0.25);
300 let arr: [u8; 3] = a.into();
301 assert_eq!(arr, [255, 128, 64]);
302 }
303 #[test]
304 fn test_conv() {
305 let a = RgbaColorType::new(1.0, 0.5, 0.25);
306 let b: HslaColorType = a.into();
307 assert_eq!(a, b.into());
308 }
309 fn error(c: RgbaColorType, d: RgbaColorType) -> f64 {
310 let e = c.r - d.r + c.g - d.g + c.b - d.b + c.a - d.a;
311 e / 4.0
312 }
313}