1use crate::rgb::Rgb;
8
9#[repr(C)]
10#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
11pub struct Hsl {
13 pub h: f32,
15 pub s: f32,
17 pub l: f32,
19}
20
21impl Hsl {
22 #[inline]
23 pub fn new(h: u16, s: u16, l: u16) -> Hsl {
24 Hsl {
25 h: h as f32,
26 s: s as f32 * (1f32 / 100f32),
27 l: l as f32 * (1f32 / 100f32),
28 }
29 }
30
31 #[inline]
32 pub fn from_components(h: f32, s: f32, l: f32) -> Hsl {
33 Hsl { h, s, l }
34 }
35
36 #[inline]
37 pub fn from_rgb(rgb: Rgb<u8>) -> Hsl {
38 rgb2hsl(rgb.r, rgb.g, rgb.b)
39 }
40
41 #[inline]
42 pub fn to_rgb8(&self) -> Rgb<u8> {
43 let c = (1f32 - (2f32 * self.l - 1f32).abs()) * self.s;
44 let x = c * (1f32 - ((self.h / 60f32) % 2f32 - 1f32).abs());
45 let m = self.l - c / 2f32;
46
47 let (r, g, b) = if self.h >= 0f32 && self.h < 60f32 {
48 (c, x, 0f32)
49 } else if self.h >= 60f32 && self.h < 120f32 {
50 (x, c, 0f32)
51 } else if self.h >= 120f32 && self.h < 180f32 {
52 (0f32, c, x)
53 } else if self.h >= 180f32 && self.h < 240f32 {
54 (0f32, x, c)
55 } else if self.h >= 240f32 && self.h < 300f32 {
56 (x, 0f32, c)
57 } else {
58 (c, 0f32, x)
59 };
60
61 Rgb::<u8> {
62 r: ((r + m) * 255f32).round() as u8,
63 g: ((g + m) * 255f32).round() as u8,
64 b: ((b + m) * 255f32).round() as u8,
65 }
66 }
67
68 #[inline]
69 pub fn to_rgb(&self) -> Rgb<u8> {
70 self.to_rgb8()
71 }
72
73 #[inline]
74 pub fn get_saturation(&self) -> u16 {
75 ((self.s * 100f32) as u16).min(100u16)
76 }
77
78 #[inline]
79 pub fn get_lightness(&self) -> u16 {
80 ((self.l * 100f32) as u16).min(100u16)
81 }
82
83 #[inline]
84 pub fn get_hue(&self) -> u16 {
85 (self.h as u16).min(360)
86 }
87}
88
89#[inline]
90fn rgb2hsl(o_r: u8, o_g: u8, o_b: u8) -> Hsl {
91 let r = o_r as f32 / 255f32;
92 let g = o_g as f32 / 255f32;
93 let b = o_b as f32 / 255f32;
94
95 let c_max = r.max(g).max(b);
96 let c_min = r.min(g).min(b);
97 let delta = c_max - c_min;
98
99 let mut h = if delta == 0f32 {
100 0f32
101 } else if c_max == r {
102 60f32 * (((g - b) / delta) % 6f32)
103 } else if c_max == g {
104 60f32 * (((b - r) / delta) + 2f32)
105 } else {
106 60f32 * (((r - g) / delta) + 4f32)
107 };
108
109 if h < 0f32 {
110 h += 360f32;
111 }
112
113 let l = 0.5f32 * (c_max + c_min);
114 let s = delta / (1f32 - (2f32 * l - 1f32).abs());
115
116 Hsl { h, s, l }
117}