1 | use super::pixel::*; |
2 | use crate::alt::GRB; |
3 | use crate::alt::{BGR, BGRA}; |
4 | use crate::{RGB, RGBA}; |
5 | use core::fmt; |
6 | |
7 | impl<T> BGR<T> { |
8 | /// Convenience function for creating a new pixel |
9 | /// Warning: The order of arguments is R,G,B |
10 | #[deprecated (note = "This function has a misleading order of arguments. Use BGR{} literal instead" )] |
11 | pub const fn new(r: T, g: T, b: T) -> Self { |
12 | Self { b, g, r } |
13 | } |
14 | } |
15 | |
16 | macro_rules! impl_rgb { |
17 | ($RGB:ident) => { |
18 | impl<T: Clone> $RGB<T> { |
19 | /// Iterate over color components (R, G, and B) |
20 | #[inline(always)] |
21 | pub fn iter(&self) -> core::iter::Cloned<core::slice::Iter<'_, T>> { |
22 | self.as_slice().iter().cloned() |
23 | } |
24 | } |
25 | |
26 | impl<T: Copy, B> ComponentMap<$RGB<B>, T, B> for $RGB<T> { |
27 | #[inline(always)] |
28 | fn map<F>(&self, mut f: F) -> $RGB<B> |
29 | where F: FnMut(T) -> B { |
30 | $RGB { |
31 | r:f(self.r), |
32 | g:f(self.g), |
33 | b:f(self.b), |
34 | } |
35 | } |
36 | } |
37 | |
38 | impl<T: Copy, B> ColorComponentMap<$RGB<B>, T, B> for $RGB<T> { |
39 | #[inline(always)] |
40 | fn map_colors<F>(&self, mut f: F) -> $RGB<B> |
41 | where F: FnMut(T) -> B { |
42 | $RGB { |
43 | r:f(self.r), |
44 | g:f(self.g), |
45 | b:f(self.b), |
46 | } |
47 | } |
48 | } |
49 | |
50 | impl<T> ComponentSlice<T> for $RGB<T> { |
51 | #[inline(always)] |
52 | fn as_slice(&self) -> &[T] { |
53 | unsafe { |
54 | core::slice::from_raw_parts(self as *const Self as *const T, 3) |
55 | } |
56 | } |
57 | |
58 | #[inline(always)] |
59 | fn as_mut_slice(&mut self) -> &mut [T] { |
60 | unsafe { |
61 | core::slice::from_raw_parts_mut(self as *mut Self as *mut T, 3) |
62 | } |
63 | } |
64 | } |
65 | |
66 | impl<T> ComponentSlice<T> for [$RGB<T>] { |
67 | #[inline] |
68 | fn as_slice(&self) -> &[T] { |
69 | unsafe { |
70 | core::slice::from_raw_parts(self.as_ptr() as *const _, self.len() * 3) |
71 | } |
72 | } |
73 | |
74 | #[inline] |
75 | fn as_mut_slice(&mut self) -> &mut [T] { |
76 | unsafe { |
77 | core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() * 3) |
78 | } |
79 | } |
80 | } |
81 | |
82 | #[cfg(feature = "as-bytes" )] |
83 | impl<T: crate::Pod> ComponentBytes<T> for [$RGB<T>] {} |
84 | }; |
85 | } |
86 | |
87 | macro_rules! impl_rgb_to_alpha { |
88 | ($RGB:ident, $RGBA:ident) => { |
89 | impl<T: Clone> $RGB<T> { |
90 | /// Convenience function for converting to RGBA |
91 | #[doc(hidden)] |
92 | #[deprecated(note = "use .with_alpha(a) instead; this will become a getter in the future" )] |
93 | pub fn alpha(&self, a: T) -> $RGBA<T> { |
94 | self.with_alpha(a) |
95 | } |
96 | |
97 | /// Convenience function for converting to RGBA |
98 | #[inline(always)] |
99 | #[doc(alias = "alpha" )] |
100 | pub fn with_alpha(&self, a: T) -> $RGBA<T> { |
101 | $RGBA { |
102 | r: self.r.clone(), |
103 | g: self.g.clone(), |
104 | b: self.b.clone(), |
105 | a, |
106 | } |
107 | } |
108 | |
109 | /// Convenience function for converting to RGBA with alpha channel of a different type than type of the pixels |
110 | #[inline(never)] |
111 | #[deprecated(note = "use .with_alpha(a) instead" )] |
112 | pub fn new_alpha<A>(&self, a: A) -> $RGBA<T, A> { |
113 | $RGBA { |
114 | r: self.r.clone(), |
115 | g: self.g.clone(), |
116 | b: self.b.clone(), |
117 | a, |
118 | } |
119 | } |
120 | } |
121 | }; |
122 | } |
123 | |
124 | impl<T> core::iter::FromIterator<T> for RGB<T> { |
125 | /// Takes exactly 3 elements from the iterator and creates a new instance. |
126 | /// Panics if there are fewer elements in the iterator. |
127 | #[inline (always)] |
128 | fn from_iter<I: IntoIterator<Item = T>>(into_iter: I) -> Self { |
129 | let mut iter: ::IntoIter = into_iter.into_iter(); |
130 | Self { |
131 | r: iter.next().unwrap(), |
132 | g: iter.next().unwrap(), |
133 | b: iter.next().unwrap(), |
134 | } |
135 | } |
136 | } |
137 | |
138 | impl_rgb! {RGB} |
139 | impl_rgb_to_alpha! {RGB, RGBA} |
140 | impl_rgb! {BGR} |
141 | impl_rgb_to_alpha! {BGR, BGRA} |
142 | impl_rgb! {GRB} |
143 | |
144 | impl<T: fmt::Display> fmt::Display for RGB<T> { |
145 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
146 | write!(f, "rgb( {}, {}, {})" , self.r, self.g, self.b) |
147 | } |
148 | } |
149 | |
150 | impl<T: fmt::UpperHex> fmt::UpperHex for RGB<T> { |
151 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
152 | write!(f, "RGB {{ # {:02X}{:02X}{:02X} }}" , self.r, self.g, self.b) |
153 | } |
154 | } |
155 | |
156 | impl<T: fmt::LowerHex> fmt::LowerHex for RGB<T> { |
157 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
158 | write!(f, "RGB {{ # {:02x}{:02x}{:02x} }}" , self.r, self.g, self.b) |
159 | } |
160 | } |
161 | |
162 | impl<T: fmt::Display> fmt::Display for BGR<T> { |
163 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
164 | write!(f, "bgr( {}, {}, {})" , self.b, self.g, self.r) |
165 | } |
166 | } |
167 | |
168 | impl<T: fmt::UpperHex> fmt::UpperHex for BGR<T> { |
169 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
170 | write!(f, "BGR {{ # {:02X}{:02X}{:02X} }}" , self.b, self.g, self.r) |
171 | } |
172 | } |
173 | |
174 | impl<T: fmt::LowerHex> fmt::LowerHex for BGR<T> { |
175 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
176 | write!(f, "BGR {{ # {:02x}{:02x}{:02x} }}" , self.b, self.g, self.r) |
177 | } |
178 | } |
179 | |
180 | #[cfg (test)] |
181 | mod rgb_test { |
182 | use super::*; |
183 | |
184 | #[test ] |
185 | fn grb_test() { |
186 | let grb = GRB {g:1,r:2,b:3}.map(|c| c * 2) + 1; |
187 | let rgb: crate::RGB8 = grb.into(); |
188 | assert_eq!(rgb, RGB::new(5,3,7)); |
189 | } |
190 | |
191 | #[test ] |
192 | fn sanity_check() { |
193 | let neg = RGB::new(1,2,3i32).map(|x| -x); |
194 | assert_eq!(neg.r, -1); |
195 | assert_eq!(neg.g, -2); |
196 | assert_eq!(neg.b, -3); |
197 | |
198 | let mut px = RGB::new(3,4,5); |
199 | px.as_mut_slice()[1] = 111; |
200 | assert_eq!(111, px.g); |
201 | |
202 | assert_eq!(RGBA::new(250,251,252,253), RGB::new(250,251,252).with_alpha(253)); |
203 | |
204 | assert_eq!(RGB{r:1u8,g:2,b:3}, RGB::new(1u8,2,3)); |
205 | assert!(RGB{r:1u8,g:1,b:2} < RGB::new(2,1,1)); |
206 | |
207 | let mut h = std::collections::HashSet::new(); |
208 | h.insert(px); |
209 | assert!(h.contains(&RGB::new(3,111,5))); |
210 | assert!(!h.contains(&RGB::new(111,5,3))); |
211 | |
212 | |
213 | #[cfg (feature = "as-bytes" )] |
214 | { |
215 | let v = vec![RGB::new(1u8,2,3), RGB::new(4,5,6)]; |
216 | assert_eq!(&[1,2,3,4,5,6], v.as_bytes()); |
217 | } |
218 | |
219 | assert_eq!(RGB::new(0u8,0,0), Default::default()); |
220 | } |
221 | |
222 | #[test ] |
223 | #[allow (deprecated)] |
224 | fn test_fmt() { |
225 | let red_rgb = RGB::new(255, 0, 0); |
226 | let red_bgr = BGR::new(255, 0, 0); |
227 | assert_eq!("RGB { #FF0000 }" , &format!("{:X}" , red_rgb)); |
228 | assert_eq!("BGR { #0000FF }" , &format!("{:X}" , red_bgr)); |
229 | |
230 | assert_eq!("RGB { #ff0000 }" , &format!("{:x}" , red_rgb)); |
231 | assert_eq!("BGR { #0000ff }" , &format!("{:x}" , red_bgr)); |
232 | |
233 | assert_eq!("rgb(255,0,0)" , &format!("{}" , red_rgb)); |
234 | assert_eq!("bgr(0,0,255)" , &format!("{}" , red_bgr)); |
235 | } |
236 | } |
237 | |