Skip to main content

colori/
rgb.rs

1use crate::hsl::HslColor;
2
3#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
4pub struct RgbColor(pub u8, pub u8, pub u8);
5
6impl RgbColor {
7    pub const SCALE: f32 = 255.0;
8
9    pub fn red(self) -> u8 {
10        self.0
11    }
12
13    pub fn green(self) -> u8 {
14        self.1
15    }
16
17    pub fn blue(self) -> u8 {
18        self.2
19    }
20
21    pub fn into_hsl(self) -> HslColor {
22        self.into()
23    }
24}
25
26impl From<HslColor> for RgbColor {
27    fn from(hsl: HslColor) -> Self {
28        let (r, g, b) = match hsl.1 {
29            s if s == 0.0 => (hsl.2, hsl.2, hsl.2),
30            _ => {
31                let q = if hsl.2 < 0.5 {
32                    hsl.2 * (1.0 + hsl.1)
33                } else {
34                    hsl.2 + hsl.1 - hsl.2 * hsl.1
35                };
36                let p = 2.0 * hsl.2 - q;
37                (
38                    get_rgb_from_hue(p, q, hsl.0 + 1.0 / 3.0),
39                    get_rgb_from_hue(p, q, hsl.0), 
40                    get_rgb_from_hue(p, q, hsl.0 - 1.0 / 3.0)
41                )
42            }
43        };
44
45        Self(
46            (r * RgbColor::SCALE).ceil() as u8,
47            (g * RgbColor::SCALE).ceil() as u8,
48            (b * RgbColor::SCALE).ceil() as u8,
49        )
50    }
51}
52
53fn get_rgb_from_hue(p: f32, q: f32, t: f32) -> f32 {
54    let nt = if t < 0.0 { t + 1.0 } else if t > 1.0 { t - 1.0 } else { t };
55
56    match nt {
57        nt if nt < 1.0 / 6.0 => p + (q - p) * 6.0 * nt,
58        nt if nt < 1.0 / 2.0 => q,
59        nt if nt < 2.0 / 3.0 => p + (q - p) * (2.0 / 3.0 - nt) * 6.0,
60        _ => p,
61    }
62}
63
64
65#[test]
66fn test_hsl_to_rgb() {
67    let cases = vec![
68        // Input,                             Expected
69        (HslColor(0.0, 0.0, 0.0),             RgbColor(0, 0, 0)),
70        (HslColor(0.0, 0.0, 0.5),             RgbColor(128, 128, 128)),
71        (HslColor(180.0 / 360.0, 1.0, 0.5),   RgbColor(0, 255, 255)),
72        (HslColor(30.0 / 360.0, 0.5, 0.5),    RgbColor(192, 128, 64)),
73        (HslColor(90.0 / 360.0, 0.2, 0.8),    RgbColor(204, 215, 194)),
74    ];
75
76    for (hsl, rgb) in cases.into_iter() {
77        assert_eq!(hsl.into_rgb(), rgb);
78    }
79}