1use std::{default, fmt};
2
3use crate::prelude::color;
4
5use super::prelude::*;
6
7use super::*;
8
9#[derive(Clone, Copy, PartialEq, Debug)] #[repr(C)]
12pub struct Color {
13 pub red: Float,
15 pub green: Float,
17 pub blue: Float,
19 pub alpha: Float,
21}
22
23impl Color {
24 pub fn new(red: Float, green: Float, blue: Float, alpha: Float) -> Self {
26 Color {
27 red,
28 green,
29 blue,
30 alpha,
31 }
32 }
33
34 pub fn rgb(red: u8, green: u8, blue: u8) -> Self {
36 Self::new(
37 red as Float / 255.,
38 green as Float / 255.,
39 blue as Float / 255.,
40 1.,
41 )
42 }
43
44 pub fn rgba(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
46 Self::new(
47 red as Float / 255.,
48 green as Float / 255.,
49 blue as Float / 255.,
50 alpha as Float / 255.,
51 )
52 }
53
54 pub fn hsl(hue: Float, saturation: Float, lightness: Float) -> Self {
56 Self::from_color(HslColor::new(hue, saturation, lightness))
57 }
58
59 pub fn hsla(hue: Float, saturation: Float, lightness: Float, alpha: Float) -> Self {
61 let mut color = Self::from_color(HslColor::new(hue, saturation, lightness));
62 color.alpha = alpha;
63 color
64 }
65
66 pub fn hsv(hue: Float, saturation: Float, value: Float) -> Self {
68 Self::from_color(HslColor::new(hue, saturation, value))
69 }
70
71 pub fn hsva(hue: Float, saturation: Float, value: Float, alpha: Float) -> Self {
73 let mut color = Self::from_color(HslColor::new(hue, saturation, value));
74 color.alpha = alpha;
75 color
76 }
77
78 pub fn cmyk(cyan: Float, magenta: Float, yellow: Float, key: Float) -> Self {
80 Self::from_color(CmykColor::new(cyan, magenta, yellow, key))
81 }
82
83 pub fn cmyka(cyan: Float, magenta: Float, yellow: Float, key: Float, alpha: Float) -> Self {
85 let mut color = Self::from_color(CmykColor::new(cyan, magenta, yellow, key));
86 color.alpha = alpha;
87 color
88 }
89
90 pub fn cmy(cyan: Float, magenta: Float, yellow: Float) -> Self {
92 Self::from_color(CmyColor::new(cyan, magenta, yellow))
93 }
94
95 pub fn cmya(cyan: Float, magenta: Float, yellow: Float, alpha: Float) -> Self {
97 let mut color = Self::from_color(CmyColor::new(cyan, magenta, yellow));
98 color.alpha = alpha;
99 color
100 }
101
102 #[cfg(feature = "experimental")]
104 pub fn xyz(x: Float, y: Float, z: Float) -> Self {
105 Self::from_color(XyzColor::new(x, y, z))
106 }
107
108 #[cfg(feature = "experimental")]
110 pub fn xyza(x: Float, y: Float, z: Float, alpha: Float) -> Self {
111 let mut color = Self::from_color(XyzColor::new(x, y, z));
112 color.alpha = alpha;
113 color
114 }
115
116 #[cfg(feature = "experimental")]
118 pub fn lab(l: Float, a: Float, b: Float) -> Self {
119 Self::from_color(XyzColor::new(l, a, b))
120 }
121
122 #[cfg(feature = "experimental")]
124 pub fn laba(l: Float, a: Float, b: Float, alpha: Float) -> Self {
125 let mut color = Self::from_color(XyzColor::new(l, a, b));
126 color.alpha = alpha;
127 color
128 }
129
130 #[allow(non_snake_case)]
134 #[deprecated]
135 pub fn RGB(red: u8, green: u8, blue: u8) -> Self {
136 Self::rgb(red, green, blue)
137 }
138
139 #[allow(non_snake_case)]
141 #[deprecated]
142 pub fn RGBA(red: u8, green: u8, blue: u8, alpha: u8) -> Self {
143 Self::rgba(red, green, blue, alpha)
144 }
145
146 #[allow(non_snake_case)]
148 #[deprecated]
149 pub fn HSL(hue: Float, saturation: Float, lightness: Float) -> Self {
150 Self::hsl(hue, saturation, lightness)
151 }
152
153 #[allow(non_snake_case)]
155 #[deprecated]
156 pub fn HSV(hue: Float, saturation: Float, value: Float) -> Self {
157 Self::hsv(hue, saturation, value)
158 }
159
160 #[allow(non_snake_case)]
162 #[deprecated]
163 pub fn CMYK(cyan: Float, magenta: Float, yellow: Float, key: Float) -> Self {
164 Self::cmyk(cyan, magenta, yellow, key)
165 }
166
167 #[allow(non_snake_case)]
169 #[deprecated]
170 pub fn CMY(cyan: Float, magenta: Float, yellow: Float) -> Self {
171 Self::cmy(cyan, magenta, yellow)
172 }
173
174 #[cfg(feature = "experimental")]
176 #[allow(non_snake_case)]
177 #[deprecated]
178 pub fn XYZ(x: Float, y: Float, z: Float) -> Self {
179 Self::xyz(x, y, z)
180 }
181
182 #[cfg(feature = "experimental")]
184 #[allow(non_snake_case)]
185 #[deprecated]
186 pub fn LAB(l: Float, a: Float, b: Float) -> Self {
187 Self::lab(l, a, b)
188 }
189}
190
191impl fmt::Display for Color {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 write!(f, "rgb({}, {}, {})", self.red, self.green, self.blue)
194 }
195}
196
197impl default::Default for Color {
198 fn default() -> Self {
199 color::BLACK
200 }
201}
202
203
204#[derive(Debug)]
206pub enum ColorError {
207 PercentageOverflow,
209 DegreeOverflow,
211 Unimplemented,
213}
214
215impl fmt::Display for ColorError {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 match self {
218 Self::PercentageOverflow => write!(
219 f,
220 "Overflow of Color percentage value (can't be greater than 100%)"
221 ),
222 Self::DegreeOverflow => write!(
223 f,
224 "Overflow of Hue in hsl(v) color space (can't be greater than 360 deg"
225 ),
226 Self::Unimplemented => write!(f, "Unimplemented color conversion"),
227 }
228 }
229}
230
231#[cfg(any(feature = "color_quantization", test))]
232impl Color {
233 pub fn distance(&self, other: Self) -> f64 {
234 let RgbColor {
235 red: s_red,
236 green: s_green,
237 blue: s_blue,
238 } = (*self).into();
239 let RgbColor {
240 red: p_red,
241 green: p_green,
242 blue: p_blue,
243 } = other.into();
244 (((p_red as i32 - s_red as i32).pow(2)
245 + (p_green as i32 - s_green as i32).pow(2)
246 + (p_blue as i32 - s_blue as i32).pow(2)) as f64)
247 .sqrt()
248 .abs()
249 }
250
251 pub fn quantize(&self) -> Self {
252 let mut min_color_distance =
253 ((0xFF_u32.pow(2) + 0xFF_u32.pow(2) + 0xFF_u32.pow(2)) as f64).sqrt();
254 let mut min_distance_color: Option<&Color> = None;
255 for color in color::PALETTE.iter() {
256 let color_distance = self.distance(*color);
257 if color_distance < min_color_distance {
258 min_color_distance = color_distance;
259 min_distance_color = Some(color);
260 }
261 }
262 *min_distance_color.expect("In this palette not found color which distance is smaller than distance from black to white")
263 }
264}
265
266#[cfg(test)]
267pub mod test {
268 use super::super::RgbColor;
269 use super::*;
270 use math::round::stochastic;
271
272 #[test]
273 fn calc_distance() {
274 assert_eq!(
276 stochastic(color::YELLOW_0.distance(color::LIME_0), 12),
277 13.928388277184
278 );
279
280 let stochastic_scale = 10;
281 for delta in [2u8, 3u8, 4u8].iter() {
282 let delta = *delta;
283 for src_color in [
284 color::TEAL_1,
285 color::TEAL_2,
286 color::TEAL_3,
287 color::TEAL_4,
288 color::TEAL_5,
289 color::TEAL_6,
290 color::TEAL_7,
291 color::TEAL_8,
292 ]
293 .iter()
294 {
295 let RgbColor {
296 red: s_red,
297 green: s_green,
298 blue: s_blue,
299 } = (*src_color).into();
300 let dst_color = Color::rgb(s_red + delta, s_green + delta, s_blue + delta);
301 assert_eq!(
302 stochastic(src_color.distance(dst_color), stochastic_scale),
303 stochastic(
304 (((delta as i32).pow(2) + (delta as i32).pow(2) + (delta as i32).pow(2))
305 as f64)
306 .sqrt(),
307 stochastic_scale
308 )
309 )
310 }
311 }
312 }
313
314 #[test]
315 fn quantization() {
316 for delta in [2u8, 3u8, 4u8].iter() {
317 let delta = *delta;
318 for palette_color in [
319 color::CYAN_2,
320 color::CYAN_3,
321 color::CYAN_4,
322 color::CYAN_5,
323 color::CYAN_6,
324 color::CYAN_7,
325 ]
326 .iter()
327 {
328 let RgbColor {
329 red: p_red,
330 green: p_green,
331 blue: p_blue,
332 } = (*palette_color).into();
333 let test_color = Color::rgb(p_red + delta, p_green + delta, p_blue + delta);
334 let found_color = test_color.quantize();
336 let RgbColor {
341 red: f_red,
342 green: f_green,
343 blue: f_blue,
344 } = found_color.into();
345 assert_eq!(f_red, p_red);
346 assert_eq!(f_green, p_green);
347 assert_eq!(f_blue, p_blue);
348 }
349 }
350 }
351}