farbraum/spaces/
hsl.rs

1use crate::spaces::{util, Hsl, Srgb};
2use crate::{Color, Into};
3
4impl Into<Srgb> for Color<Hsl> {
5    fn into(self, _: Srgb) -> Color<Srgb> {
6        let (h, s, l) = self.tuple();
7
8        let h = util::normalize_hue(h);
9        let m1 = l + s * (if l < 0.5 { l } else { 1.0 - l });
10        let m2 = m1 - (m1 - l) * 2.0 * (((h / 60.0) % 2.0) - 1.0).abs();
11
12        match (h / 60.0).floor() as i32 {
13            0 => Color::of(m1, m2, 2.0 * l - m1),
14            1 => Color::of(m2, m1, 2.0 * l - m1),
15            2 => Color::of(2.0 * l - m1, m1, m2),
16            3 => Color::of(2.0 * l - m1, m2, m1),
17            4 => Color::of(m2, 2.0 * l - m1, m1),
18            5 => Color::of(m1, 2.0 * l - m1, m2),
19            _ => Color::of(2.0 * l - m1, 2.0 * l - m1, 2.0 * l - m1),
20        }
21    }
22}
23
24impl Into<Hsl> for Color<Srgb> {
25    fn into(self, _: Hsl) -> Color<Hsl> {
26        let (r, g, b) = self.tuple();
27
28        let (min, max) = util::min_max(r, g, b);
29        let s = if max == min {
30            0.0
31        } else {
32            (max - min) / (1.0 - (max + min - 1.0).abs())
33        };
34        let l = 0.5 * (max + min);
35        let h = util::calculate_hsl_hue(r, g, b, max, min);
36
37        Color::of(h, s, l)
38    }
39}
40
41#[cfg(test)]
42mod tests {
43
44    use crate::spaces::{Hsl, Srgb};
45    use crate::test_util::round_trips_srgb;
46    use crate::{Color, Float};
47
48    fn rgb(r: Float, g: Float, b: Float) -> Color<Srgb> {
49        Color::of(r, g, b)
50    }
51
52    fn hsl(l: Float, a: Float, b: Float) -> Color<Hsl> {
53        Color::of(l, a, b)
54    }
55
56    #[test]
57    fn test_hsl_to_rgb() {
58        assert_eq!(hsl(0.0, 0.0, 0.0).into(Srgb), rgb(0.0, 0.0, 0.0));
59        assert_eq!(hsl(60.0, 0.25, 0.0).into(Srgb), rgb(0.0, 0.0, 0.0));
60        assert_eq!(hsl(0.0, 0.0, 0.5).into(Srgb), rgb(0.5, 0.5, 0.5));
61        assert_eq!(hsl(60.0, 0.0, 0.25).into(Srgb), rgb(0.25, 0.25, 0.25));
62        assert_eq!(hsl(100.0, 0.0, 0.5).into(Srgb), rgb(0.5, 0.5, 0.5));
63    }
64
65    #[test]
66    fn test_rgb_to_hsl() {
67        assert_eq!(hsl(0.0, 0.0, 0.0), rgb(0.0, 0.0, 0.0).into(Hsl));
68        assert_eq!(hsl(0.0, 0.0, 0.25), rgb(0.25, 0.25, 0.25).into(Hsl));
69
70        // red, yellow, green, cyan, blue, magenta
71        assert_eq!(hsl(0.0, 1.0, 0.5), rgb(1.0, 0.0, 0.0).into(Hsl));
72        assert_eq!(hsl(60.0, 1.0, 0.5), rgb(1.0, 1.0, 0.0).into(Hsl));
73        assert_eq!(hsl(120.0, 1.0, 0.5), rgb(0.0, 1.0, 0.0).into(Hsl));
74        assert_eq!(hsl(180.0, 1.0, 0.5), rgb(0.0, 1.0, 1.0).into(Hsl));
75        assert_eq!(hsl(240.0, 1.0, 0.5), rgb(0.0, 0.0, 1.0).into(Hsl));
76        assert_eq!(hsl(300.0, 1.0, 0.5), rgb(1.0, 0.0, 1.0).into(Hsl));
77    }
78
79    #[test]
80    fn test_hsl_roundtrips() {
81        round_trips_srgb::<Hsl>();
82    }
83}