Skip to main content

ponsic_color/
lib.rs

1mod const_color;
2
3/// RGB 颜色类型
4#[repr(C, align(4))]
5#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct Color {
7    _ph: u8,
8    pub blue: u8,
9    pub green: u8,
10    pub red: u8,
11}
12
13/// HSV 颜色类型
14pub struct ColorHSV {
15    pub hue: f32,
16    pub saturation: f32,
17    pub value: f32,
18}
19
20/// HSL 颜色类型
21pub struct ColorHSL {
22    pub hue: f32,
23    pub saturation: f32,
24    pub lightness: f32,
25}
26
27impl Color {
28    /// 创建一个颜色
29    pub const fn new(red: u8, green: u8, blue: u8) -> Color {
30        Color {
31            _ph: 0,
32            blue,
33            green,
34            red,
35        }
36    }
37}
38
39impl Color {
40    /// 将 RGB 颜色转换为 HSV 颜色
41    pub const fn into_hsv(self) -> ColorHSV {
42        let r = self.red as f32 / 255.0;
43        let g = self.green as f32 / 255.0;
44        let b = self.blue as f32 / 255.0;
45
46        let max = r.max(g).max(b);
47        let min = r.min(g).min(b);
48        let delta = max - min;
49
50        let hue = if delta == 0.0 {
51            0.0
52        } else if max == r {
53            (g - b) / delta
54        } else if max == g {
55            (b - r) / delta + 2.0
56        } else {
57            (r - g) / delta + 4.0
58        };
59        let saturation = if max == 0.0 { 0.0 } else { delta / max };
60        let value = max;
61
62        let mut hue = hue * 60.0;
63        if hue < 0.0 {
64            hue += 360.0;
65        }
66
67        ColorHSV {
68            hue,
69            saturation,
70            value,
71        }
72    }
73
74    /// 将 RGB 颜色转换为 HSL 颜色
75    pub const fn into_hsl(self) -> ColorHSL {
76        let r = self.red as f32 / 255.0;
77        let g = self.green as f32 / 255.0;
78        let b = self.blue as f32 / 255.0;
79
80        let max = r.max(g).max(b);
81        let min = r.min(g).min(b);
82        let delta = max - min;
83
84        let lightness = (max + min) / 2.0;
85        let saturation = if lightness == 0.0 || lightness == 1.0 {
86            0.0
87        } else {
88            delta / (1.0 - (2.0 * lightness - 1.0).abs())
89        };
90
91        let hue = if delta == 0.0 {
92            0.0
93        } else if max == r {
94            (g - b) / delta
95        } else if max == g {
96            (b - r) / delta + 2.0
97        } else {
98            (r - g) / delta + 4.0
99        };
100
101        let mut hue = hue * 60.0;
102        if hue < 0.0 {
103            hue += 360.0;
104        }
105
106        ColorHSL {
107            hue,
108            saturation,
109            lightness,
110        }
111    }
112
113    /// 将 HSV 颜色转换为 RGB 颜色
114    pub const fn from_hsv(hsv: ColorHSV) -> Color {
115        let chroma = hsv.value * hsv.saturation;
116        let hue_prime = hsv.hue / 60.0;
117        let x = chroma * (1.0 - (hue_prime % 2.0 - 1.0).abs());
118
119        let (r, g, b) = if hue_prime < 1.0 {
120            (chroma, x, 0.0)
121        } else if hue_prime < 2.0 {
122            (x, chroma, 0.0)
123        } else if hue_prime < 3.0 {
124            (0.0, chroma, x)
125        } else if hue_prime < 4.0 {
126            (0.0, x, chroma)
127        } else if hue_prime < 5.0 {
128            (x, 0.0, chroma)
129        } else {
130            (chroma, 0.0, x)
131        };
132
133        let m = hsv.value - chroma;
134
135        Color::new(
136            ((r + m) * 255.0) as u8,
137            ((g + m) * 255.0) as u8,
138            ((b + m) * 255.0) as u8,
139        )
140    }
141
142    /// 将 HSL 颜色转换为 RGB 颜色
143    pub const fn from_hsl(hsl: ColorHSL) -> Color {
144        let chroma = (1.0 - (2.0 * hsl.lightness - 1.0).abs()) * hsl.saturation;
145        let hue_prime = hsl.hue / 60.0;
146        let x = chroma * (1.0 - (hue_prime % 2.0 - 1.0).abs());
147
148        let (r, g, b) = if hue_prime < 1.0 {
149            (chroma, x, 0.0)
150        } else if hue_prime < 2.0 {
151            (x, chroma, 0.0)
152        } else if hue_prime < 3.0 {
153            (0.0, chroma, x)
154        } else if hue_prime < 4.0 {
155            (0.0, x, chroma)
156        } else if hue_prime < 5.0 {
157            (x, 0.0, chroma)
158        } else {
159            (chroma, 0.0, x)
160        };
161
162        let m = hsl.lightness - chroma / 2.0;
163
164        Color::new(
165            ((r + m) * 255.0) as u8,
166            ((g + m) * 255.0) as u8,
167            ((b + m) * 255.0) as u8,
168        )
169    }
170}
171
172impl Into<u32> for Color {
173    fn into(self) -> u32 {
174        unsafe { std::mem::transmute(self) }
175    }
176}
177
178impl From<u32> for Color {
179    fn from(color: u32) -> Self {
180        unsafe { std::mem::transmute(color & 0x00ffffff) }
181    }
182}
183
184impl Into<ColorHSV> for Color {
185    fn into(self) -> ColorHSV {
186        self.into_hsv()
187    }
188}
189
190impl From<ColorHSV> for Color {
191    fn from(hsv: ColorHSV) -> Self {
192        Self::from_hsv(hsv)
193    }
194}
195
196impl Into<ColorHSL> for Color {
197    fn into(self) -> ColorHSL {
198        self.into_hsl()
199    }
200}
201
202impl From<ColorHSL> for Color {
203    fn from(hsl: ColorHSL) -> Self {
204        Self::from_hsl(hsl)
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    #[test]
213    fn test_color_hsv() {
214        let color = Color::new(255, 0, 0);
215        let hsv = color.into_hsv();
216        assert_eq!(hsv.hue, 0.0);
217        assert_eq!(hsv.saturation, 1.0);
218        assert_eq!(hsv.value, 1.0);
219
220        let color = Color::new(0, 255, 0);
221        let hsv = color.into_hsv();
222        assert_eq!(hsv.hue, 120.0);
223        assert_eq!(hsv.saturation, 1.0);
224        assert_eq!(hsv.value, 1.0);
225
226        let color = Color::new(0, 0, 255);
227        let hsv = color.into_hsv();
228        assert_eq!(hsv.hue, 240.0);
229        assert_eq!(hsv.saturation, 1.0);
230        assert_eq!(hsv.value, 1.0);
231
232        let color = Color::new(255, 255, 0);
233        let hsv = color.into_hsv();
234        assert_eq!(hsv.hue, 60.0);
235        assert_eq!(hsv.saturation, 1.0);
236        assert_eq!(hsv.value, 1.0);
237
238        let color = Color::new(0, 255, 255);
239        let hsv = color.into_hsv();
240        assert_eq!(hsv.hue, 180.0);
241        assert_eq!(hsv.saturation, 1.0);
242        assert_eq!(hsv.value, 1.0);
243
244        let color = Color::new(255, 0, 255);
245        let hsv = color.into_hsv();
246        assert_eq!(hsv.hue, 300.0);
247        assert_eq!(hsv.saturation, 1.0);
248        assert_eq!(hsv.value, 1.0);
249    }
250
251    #[test]
252    fn test_color_hsl() {
253        let color = Color::new(255, 0, 0);
254        let hsl = color.into_hsl();
255        assert_eq!(hsl.hue, 0.0);
256        assert_eq!(hsl.saturation, 1.0);
257        assert_eq!(hsl.lightness, 0.5);
258
259        let color = Color::new(0, 255, 0);
260        let hsl = color.into_hsl();
261        assert_eq!(hsl.hue, 120.0);
262        assert_eq!(hsl.saturation, 1.0);
263        assert_eq!(hsl.lightness, 0.5);
264
265        let color = Color::new(0, 0, 255);
266        let hsl = color.into_hsl();
267        assert_eq!(hsl.hue, 240.0);
268        assert_eq!(hsl.saturation, 1.0);
269        assert_eq!(hsl.lightness, 0.5);
270
271        let color = Color::new(255, 255, 0);
272        let hsl = color.into_hsl();
273        assert_eq!(hsl.hue, 60.0);
274        assert_eq!(hsl.saturation, 1.0);
275        assert_eq!(hsl.lightness, 0.5);
276        let color = Color::new(0, 255, 255);
277        let hsl = color.into_hsl();
278        assert_eq!(hsl.hue, 180.0);
279        assert_eq!(hsl.saturation, 1.0);
280        assert_eq!(hsl.lightness, 0.5);
281
282        let color = Color::new(255, 0, 255);
283        let hsl = color.into_hsl();
284        assert_eq!(hsl.hue, 300.0);
285        assert_eq!(hsl.saturation, 1.0);
286        assert_eq!(hsl.lightness, 0.5);
287    }
288
289    #[test]
290    fn test_color_from_hsv() {
291        let color = Color::from_hsv(ColorHSV {
292            hue: 0.0,
293            saturation: 1.0,
294            value: 1.0,
295        });
296        assert_eq!(color, Color::new(255, 0, 0));
297
298        let color = Color::from_hsv(ColorHSV {
299            hue: 120.0,
300            saturation: 1.0,
301            value: 1.0,
302        });
303        assert_eq!(color, Color::new(0, 255, 0));
304
305        let color = Color::from_hsv(ColorHSV {
306            hue: 240.0,
307            saturation: 1.0,
308            value: 1.0,
309        });
310        assert_eq!(color, Color::new(0, 0, 255));
311
312        let color = Color::from_hsv(ColorHSV {
313            hue: 60.0,
314            saturation: 1.0,
315            value: 1.0,
316        });
317        assert_eq!(color, Color::new(255, 255, 0));
318
319        let color = Color::from_hsv(ColorHSV {
320            hue: 180.0,
321            saturation: 1.0,
322            value: 1.0,
323        });
324        assert_eq!(color, Color::new(0, 255, 255));
325
326        let color = Color::from_hsv(ColorHSV {
327            hue: 300.0,
328            saturation: 1.0,
329            value: 1.0,
330        });
331        assert_eq!(color, Color::new(255, 0, 255));
332    }
333
334    #[test]
335    fn test_color_from_hsl() {
336        let color = Color::from_hsl(ColorHSL {
337            hue: 0.0,
338            saturation: 1.0,
339            lightness: 0.5,
340        });
341        assert_eq!(color, Color::new(255, 0, 0));
342
343        let color = Color::from_hsl(ColorHSL {
344            hue: 120.0,
345            saturation: 1.0,
346            lightness: 0.5,
347        });
348        assert_eq!(color, Color::new(0, 255, 0));
349
350        let color = Color::from_hsl(ColorHSL {
351            hue: 240.0,
352            saturation: 1.0,
353            lightness: 0.5,
354        });
355        assert_eq!(color, Color::new(0, 0, 255));
356
357        let color = Color::from_hsl(ColorHSL {
358            hue: 60.0,
359            saturation: 1.0,
360            lightness: 0.5,
361        });
362        assert_eq!(color, Color::new(255, 255, 0));
363
364        let color = Color::from_hsl(ColorHSL {
365            hue: 180.0,
366            saturation: 1.0,
367            lightness: 0.5,
368        });
369        assert_eq!(color, Color::new(0, 255, 255));
370
371        let color = Color::from_hsl(ColorHSL {
372            hue: 300.0,
373            saturation: 1.0,
374            lightness: 0.5,
375        });
376        assert_eq!(color, Color::new(255, 0, 255));
377    }
378}