ruby_math/color/
rgb24.rs

1#![allow(dead_code)]
2
3use std::{
4    fmt::Display,
5    ops::{Index, IndexMut},
6};
7
8use super::{RGBAf, RGBf, RGB, RGBA, RGBA32};
9
10fn convert_f64_to_u8(v: f64) -> u8 {
11    let v = (v * 255.0 + 0.5) as i32;
12    v.max(0).min(255) as u8
13}
14
15#[derive(Clone, Copy, PartialEq, Debug)]
16pub struct RGB24 {
17    r: u8,
18    g: u8,
19    b: u8,
20}
21
22impl Display for RGB24 {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        write!(f, "RGB24(r: {}, g: {}, b: {})", self.r, self.g, self.b)
25    }
26}
27
28impl Default for RGB24 {
29    fn default() -> Self {
30        Self { r: 0, g: 0, b: 0 }
31    }
32}
33
34impl Index<usize> for RGB24 {
35    type Output = u8;
36
37    fn index(&self, index: usize) -> &Self::Output {
38        match index {
39            0 => &self.r,
40            1 => &self.g,
41            2 => &self.b,
42            _ => panic!("`rmath::color::RGB24::index`: index out of bounds."),
43        }
44    }
45}
46
47impl IndexMut<usize> for RGB24 {
48    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
49        match index {
50            0 => &mut self.r,
51            1 => &mut self.g,
52            2 => &mut self.b,
53            _ => panic!("`rmath::color::RGB24::index_mut`: index out of bounds."),
54        }
55    }
56}
57
58impl From<f64> for RGB24 {
59    fn from(rgb: f64) -> Self {
60        let rgb = convert_f64_to_u8(rgb);
61        Self::new(rgb, rgb, rgb)
62    }
63}
64
65impl From<(f64, f64, f64)> for RGB24 {
66    fn from(rgb: (f64, f64, f64)) -> Self {
67        let (r, g, b) = rgb;
68        let r = convert_f64_to_u8(r);
69        let g = convert_f64_to_u8(g);
70        let b = convert_f64_to_u8(b);
71        Self::new(r, g, b)
72    }
73}
74
75impl From<[f64; 3]> for RGB24 {
76    fn from(rgb: [f64; 3]) -> Self {
77        let r = convert_f64_to_u8(rgb[0]);
78        let g = convert_f64_to_u8(rgb[1]);
79        let b = convert_f64_to_u8(rgb[2]);
80        Self::new(r, g, b)
81    }
82}
83
84impl From<u32> for RGB24 {
85    fn from(rgb_: u32) -> Self {
86        let r = ((rgb_ >> 16) & 0xff) as u8;
87        let g = ((rgb_ >> 8) & 0xff) as u8;
88        let b = (rgb_ & 0xff) as u8;
89        Self::new(r, g, b)
90    }
91}
92
93impl From<u8> for RGB24 {
94    fn from(rgb: u8) -> Self {
95        Self::new(rgb, rgb, rgb)
96    }
97}
98
99impl From<(u8, u8, u8)> for RGB24 {
100    fn from(rgb: (u8, u8, u8)) -> Self {
101        let (r, g, b) = rgb;
102        Self::new(r, g, b)
103    }
104}
105
106impl From<[u8; 3]> for RGB24 {
107    fn from(rgb: [u8; 3]) -> Self {
108        Self::new(rgb[0], rgb[1], rgb[2])
109    }
110}
111
112impl From<RGB> for RGB24 {
113    fn from(color: RGB) -> Self {
114        color.to_rgb24()
115    }
116}
117
118impl From<RGBf> for RGB24 {
119    fn from(color: RGBf) -> Self {
120        color.to_rgb24()
121    }
122}
123
124impl From<RGBA> for RGB24 {
125    fn from(color: RGBA) -> Self {
126        color.to_rgb24()
127    }
128}
129
130impl From<RGBAf> for RGB24 {
131    fn from(color: RGBAf) -> Self {
132        color.to_rgb24()
133    }
134}
135
136impl From<RGBA32> for RGB24 {
137    fn from(color: RGBA32) -> Self {
138        color.to_rgb24()
139    }
140}
141
142impl RGB24 {
143    pub fn new(r: u8, g: u8, b: u8) -> Self {
144        Self { r, g, b }
145    }
146
147    pub fn black() -> Self {
148        Self::new(0, 0, 0)
149    }
150
151    pub fn white() -> Self {
152        Self::new(255, 255, 255)
153    }
154
155    pub fn red() -> Self {
156        Self::new(255, 0, 0)
157    }
158
159    pub fn green() -> Self {
160        Self::new(0, 255, 0)
161    }
162
163    pub fn blue() -> Self {
164        Self::new(0, 0, 255)
165    }
166
167    pub fn r(self) -> u8 {
168        self.r
169    }
170
171    pub fn g(self) -> u8 {
172        self.g
173    }
174
175    pub fn b(self) -> u8 {
176        self.b
177    }
178}
179
180impl RGB24 {
181    pub fn sum(self) -> i32 {
182        self.r as i32 + self.g as i32 + self.b as i32
183    }
184
185    pub fn gray(self) -> u8 {
186        (self.sum() / 3) as u8
187    }
188
189    pub fn min_element(self) -> u8 {
190        self.r.min(self.g).min(self.b)
191    }
192
193    pub fn max_element(self) -> u8 {
194        self.r.max(self.g).max(self.b)
195    }
196
197    pub fn clamp(self, min: Self, max: Self) -> Self {
198        ruby_assert!(min.r <= max.r);
199        ruby_assert!(min.g <= max.g);
200        ruby_assert!(min.b <= max.b);
201
202        self.min(max).max(min)
203    }
204
205    pub fn min(self, rhs: Self) -> Self {
206        Self::new(self.r.min(rhs.r), self.g.min(rhs.g), self.b.min(rhs.b))
207    }
208
209    pub fn max(self, rhs: Self) -> Self {
210        Self::new(self.r.max(rhs.r), self.g.max(rhs.g), self.b.max(rhs.b))
211    }
212
213    pub fn saturate(self) -> Self {
214        self.clamp(Self::black(), Self::white())
215    }
216}
217
218impl RGB24 {
219    pub fn to_array(self) -> [u8; 3] {
220        [self.r, self.g, self.b]
221    }
222
223    pub fn to_tuple(self) -> (u8, u8, u8) {
224        (self.r, self.g, self.b)
225    }
226
227    pub fn to_rgb(self) -> RGB {
228        RGB::new(
229            self.r as f64 / 255.0,
230            self.g as f64 / 255.0,
231            self.b as f64 / 255.0,
232        )
233    }
234
235    pub fn to_rgbf(self) -> RGBf {
236        RGBf::new(
237            self.r as f32 / 255.0,
238            self.g as f32 / 255.0,
239            self.b as f32 / 255.0,
240        )
241    }
242
243    pub fn to_rgba(self) -> RGBA {
244        RGBA::new(
245            self.r as f64 / 255.0,
246            self.g as f64 / 255.0,
247            self.b as f64 / 255.0,
248            1.0,
249        )
250    }
251
252    pub fn to_rgba_alpha(self, alpha: f64) -> RGBA {
253        RGBA::new(
254            self.r as f64 / 255.0,
255            self.g as f64 / 255.0,
256            self.b as f64 / 255.0,
257            alpha,
258        )
259    }
260
261    pub fn to_rgbaf(self) -> RGBAf {
262        RGBAf::new(
263            self.r as f32 / 255.0,
264            self.g as f32 / 255.0,
265            self.b as f32 / 255.0,
266            1.0,
267        )
268    }
269
270    pub fn to_rgbaf_alpha(self, alpha: f32) -> RGBAf {
271        RGBAf::new(
272            self.r as f32 / 255.0,
273            self.g as f32 / 255.0,
274            self.b as f32 / 255.0,
275            alpha,
276        )
277    }
278
279    pub fn to_rgba32(self) -> RGBA32 {
280        RGBA32::new(self.r, self.g, self.b, 255)
281    }
282
283    pub fn to_rgba32_alpha(self, alpha: u8) -> RGBA32 {
284        RGBA32::new(self.r, self.g, self.b, alpha)
285    }
286}