1 | use core::fmt; |
2 | use crate::alt::*; |
3 | use crate::RGB; |
4 | use crate::RGBA; |
5 | use super::pixel::*; |
6 | |
7 | impl<T> RGBA<T> { |
8 | #[inline (always)] |
9 | /// Convenience function for creating a new pixel |
10 | /// The order of arguments is R,G,B,A |
11 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { |
12 | Self {r,g,b,a} |
13 | } |
14 | } |
15 | |
16 | impl<T, A> RGBA<T,A> { |
17 | #[inline (always)] |
18 | /// Convenience function for creating a new pixel |
19 | /// The order of arguments is R,G,B,A |
20 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { |
21 | Self {r,g,b,a} |
22 | } |
23 | } |
24 | |
25 | impl<T> BGRA<T> { |
26 | #[inline (always)] |
27 | /// Convenience function for creating a new pixel |
28 | /// Warning: The order of arguments is R,G,B,A |
29 | #[deprecated (note="This function has a misleading order of arguments. Use BGRA{} literal instead" )] |
30 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { |
31 | Self {r,g,b,a} |
32 | } |
33 | } |
34 | |
35 | impl<T, A> BGRA<T,A> { |
36 | #[inline (always)] |
37 | /// Convenience function for creating a new pixel |
38 | /// Warning: The order of arguments is R,G,B,A |
39 | #[deprecated (note="This function has a misleading order of arguments. Use BGRA{} literal instead" )] |
40 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { |
41 | Self {r,g,b,a} |
42 | } |
43 | } |
44 | |
45 | #[cfg (feature = "as-bytes" )] |
46 | unsafe impl<T, A> crate::Pod for RGBA<T, A> where T: crate::Pod, A: crate::Pod {} |
47 | #[cfg (feature = "as-bytes" )] |
48 | unsafe impl<T, A> crate::Pod for BGRA<T, A> where T: crate::Pod, A: crate::Pod {} |
49 | #[cfg (feature = "as-bytes" )] |
50 | unsafe impl<T, A> crate::Zeroable for RGBA<T, A> where T: crate::Zeroable, A: crate::Zeroable {} |
51 | #[cfg (feature = "as-bytes" )] |
52 | unsafe impl<T, A> crate::Zeroable for BGRA<T, A> where T: crate::Zeroable, A: crate::Zeroable {} |
53 | |
54 | #[cfg (feature = "argb" )] |
55 | impl<T> ARGB<T> { |
56 | #[inline (always)] |
57 | /// Convenience function for creating a new pixel |
58 | /// The order of arguments is R,G,B,A |
59 | #[deprecated (note="This function has a misleading order of arguments. Use ARGB{} literal instead" )] |
60 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { |
61 | Self {r,g,b,a} |
62 | } |
63 | } |
64 | |
65 | #[cfg (feature = "argb" )] |
66 | impl<T, A> ARGB<T,A> { |
67 | #[inline (always)] |
68 | /// Convenience function for creating a new pixel |
69 | /// The order of arguments is R,G,B,A |
70 | #[deprecated (note="This function has a misleading order of arguments. Use ARGB{} literal instead" )] |
71 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { |
72 | Self {r,g,b,a} |
73 | } |
74 | } |
75 | |
76 | #[cfg (feature = "argb" )] |
77 | impl<T> ABGR<T> { |
78 | #[inline (always)] |
79 | /// Convenience function for creating a new pixel |
80 | /// The order of arguments is R,G,B,A |
81 | #[deprecated (note="This function has a misleading order of arguments. Use ABGR{} literal instead" )] |
82 | pub const fn new(r: T, g: T, b: T, a: T) -> Self { |
83 | Self {r,g,b,a} |
84 | } |
85 | } |
86 | |
87 | #[cfg (feature = "argb" )] |
88 | impl<T, A> ABGR<T,A> { |
89 | #[inline (always)] |
90 | /// Convenience function for creating a new pixel |
91 | /// The order of arguments is R,G,B,A |
92 | #[deprecated (note="This function has a misleading order of arguments. Use ABGR{} literal instead" )] |
93 | pub const fn new_alpha(r: T, g: T, b: T, a: A) -> Self { |
94 | Self {r,g,b,a} |
95 | } |
96 | } |
97 | |
98 | #[cfg (all(feature = "as-bytes" , feature = "argb" ))] |
99 | unsafe impl<T, A> crate::Pod for ARGB<T, A> where T: crate::Pod, A: crate::Pod {} |
100 | #[cfg (all(feature = "as-bytes" , feature = "argb" ))] |
101 | unsafe impl<T, A> crate::Pod for ABGR<T, A> where T: crate::Pod, A: crate::Pod {} |
102 | #[cfg (all(feature = "as-bytes" , feature = "argb" ))] |
103 | unsafe impl<T, A> crate::Zeroable for ARGB<T, A> where T: crate::Zeroable, A: crate::Zeroable {} |
104 | #[cfg (all(feature = "as-bytes" , feature = "argb" ))] |
105 | unsafe impl<T, A> crate::Zeroable for ABGR<T, A> where T: crate::Zeroable, A: crate::Zeroable {} |
106 | |
107 | macro_rules! impl_rgba { |
108 | ($RGBA:ident) => { |
109 | impl<T: Clone> $RGBA<T> { |
110 | /// Iterate over all components (length=4) |
111 | #[inline(always)] |
112 | pub fn iter(&self) -> core::iter::Cloned<core::slice::Iter<'_, T>> { |
113 | self.as_slice().iter().cloned() |
114 | } |
115 | } |
116 | |
117 | impl<T: Clone, A> $RGBA<T, A> { |
118 | /// Copy RGB components out of the RGBA struct |
119 | /// |
120 | /// Note: you can use `.into()` to convert between other types |
121 | #[inline(always)] |
122 | pub fn bgr(&self) -> BGR<T> { |
123 | BGR {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()} |
124 | } |
125 | } |
126 | |
127 | impl<T: Copy, A: Clone> $RGBA<T, A> { |
128 | /// Create new RGBA with the same alpha value, but different RGB values |
129 | #[inline(always)] |
130 | pub fn map_rgb<F, U, B>(&self, mut f: F) -> $RGBA<U, B> |
131 | where F: FnMut(T) -> U, U: Clone, B: From<A> + Clone |
132 | { |
133 | $RGBA { |
134 | r: f(self.r), |
135 | g: f(self.g), |
136 | b: f(self.b), |
137 | a: self.a.clone().into(), |
138 | } |
139 | } |
140 | |
141 | #[inline(always)] |
142 | /// Create a new RGBA with the new alpha value, but same RGB values |
143 | pub fn alpha(&self, a: A) -> Self { |
144 | Self { |
145 | r: self.r, g: self.g, b: self.b, a, |
146 | } |
147 | } |
148 | |
149 | /// Create a new RGBA with a new alpha value created by the callback. |
150 | /// Allows changing of the type used for the alpha channel. |
151 | #[inline] |
152 | pub fn map_alpha<F, B>(&self, f: F) -> $RGBA<T, B> |
153 | where F: FnOnce(A) -> B { |
154 | $RGBA { |
155 | r: self.r, |
156 | g: self.g, |
157 | b: self.b, |
158 | a: f(self.a.clone()), |
159 | } |
160 | } |
161 | } |
162 | |
163 | impl<T: Copy, B> ComponentMap<$RGBA<B>, T, B> for $RGBA<T> { |
164 | #[inline(always)] |
165 | fn map<F>(&self, mut f: F) -> $RGBA<B> |
166 | where |
167 | F: FnMut(T) -> B, |
168 | { |
169 | $RGBA { |
170 | r: f(self.r), |
171 | g: f(self.g), |
172 | b: f(self.b), |
173 | a: f(self.a), |
174 | } |
175 | } |
176 | } |
177 | |
178 | impl<T: Copy, A: Copy, B> ColorComponentMap<$RGBA<B, A>, T, B> for $RGBA<T, A> { |
179 | #[inline(always)] |
180 | fn map_c<F>(&self, mut f: F) -> $RGBA<B, A> |
181 | where |
182 | F: FnMut(T) -> B, |
183 | { |
184 | $RGBA { |
185 | r: f(self.r), |
186 | g: f(self.g), |
187 | b: f(self.b), |
188 | a: self.a, |
189 | } |
190 | } |
191 | } |
192 | |
193 | impl<T> ComponentSlice<T> for $RGBA<T> { |
194 | #[inline(always)] |
195 | fn as_slice(&self) -> &[T] { |
196 | unsafe { |
197 | core::slice::from_raw_parts(self as *const Self as *const T, 4) |
198 | } |
199 | } |
200 | |
201 | #[inline(always)] |
202 | fn as_mut_slice(&mut self) -> &mut [T] { |
203 | unsafe { |
204 | core::slice::from_raw_parts_mut(self as *mut Self as *mut T, 4) |
205 | } |
206 | } |
207 | } |
208 | |
209 | impl<T> ComponentSlice<T> for [$RGBA<T>] { |
210 | #[inline] |
211 | fn as_slice(&self) -> &[T] { |
212 | unsafe { |
213 | core::slice::from_raw_parts(self.as_ptr() as *const _, self.len() * 4) |
214 | } |
215 | } |
216 | #[inline] |
217 | fn as_mut_slice(&mut self) -> &mut [T] { |
218 | unsafe { |
219 | core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut _, self.len() * 4) |
220 | } |
221 | } |
222 | } |
223 | |
224 | #[cfg(feature = "as-bytes" )] |
225 | impl<T: crate::Pod> ComponentBytes<T> for [$RGBA<T>] {} |
226 | } |
227 | } |
228 | |
229 | macro_rules! impl_alpha_conv { |
230 | ($RGB:ident, $RGBA:ident) => { |
231 | /// Assumes 255 is opaque |
232 | impl<T: Copy> From<$RGB<T>> for $RGBA<T, u8> { |
233 | #[inline(always)] |
234 | fn from(other: $RGB<T>) -> Self { |
235 | Self { |
236 | r: other.r, |
237 | g: other.g, |
238 | b: other.b, |
239 | a: 0xFF, |
240 | } |
241 | } |
242 | } |
243 | |
244 | /// Assumes 65535 is opaque |
245 | impl<T: Copy> From<$RGB<T>> for $RGBA<T, u16> { |
246 | #[inline(always)] |
247 | fn from(other: $RGB<T>) -> Self { |
248 | Self { |
249 | r: other.r, |
250 | g: other.g, |
251 | b: other.b, |
252 | a: 0xFFFF, |
253 | } |
254 | } |
255 | } |
256 | } |
257 | } |
258 | |
259 | impl<T, A> RGBA<T, A> { |
260 | /// Provide a mutable view of only RGB components (leaving out alpha). |
261 | /// Useful to change color without changing opacity. |
262 | #[inline (always)] |
263 | pub fn rgb_mut(&mut self) -> &mut RGB<T> { |
264 | unsafe { |
265 | &mut *(self as *mut _ as *mut RGB<T>) |
266 | } |
267 | } |
268 | } |
269 | |
270 | impl<T, A> BGRA<T, A> { |
271 | /// Provide a mutable view of only RGB components (leaving out alpha). |
272 | /// Useful to change color without changing opacity. |
273 | #[inline (always)] |
274 | #[deprecated (note = "This function will change. Use bgr_mut()" )] |
275 | pub fn rgb_mut(&mut self) -> &mut BGR<T> { |
276 | unsafe { |
277 | &mut *(self as *mut _ as *mut BGR<T>) |
278 | } |
279 | } |
280 | |
281 | /// Provide a mutable view of only RGB components (leaving out alpha). |
282 | /// Useful to change color without changing opacity. |
283 | #[inline (always)] |
284 | pub fn bgr_mut(&mut self) -> &mut BGR<T> { |
285 | unsafe { |
286 | &mut *(self as *mut _ as *mut BGR<T>) |
287 | } |
288 | } |
289 | } |
290 | |
291 | impl<T> core::iter::FromIterator<T> for RGBA<T> { |
292 | #[inline (always)] |
293 | /// Takes exactly 4 elements from the iterator and creates a new instance. |
294 | /// Panics if there are fewer elements in the iterator. |
295 | fn from_iter<I: IntoIterator<Item = T>>(into_iter: I) -> Self { |
296 | let mut iter: ::IntoIter = into_iter.into_iter(); |
297 | Self { |
298 | r: iter.next().unwrap(), |
299 | g: iter.next().unwrap(), |
300 | b: iter.next().unwrap(), |
301 | a: iter.next().unwrap(), |
302 | } |
303 | } |
304 | } |
305 | |
306 | impl<T: Clone, A> RGBA<T, A> { |
307 | /// Copy RGB components out of the RGBA struct |
308 | /// |
309 | /// Note: you can use `.into()` to convert between other types |
310 | #[inline (always)] |
311 | pub fn rgb(&self) -> RGB<T> { |
312 | RGB {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()} |
313 | } |
314 | } |
315 | |
316 | #[cfg (feature = "argb" )] |
317 | impl<T: Clone, A> ARGB<T, A> { |
318 | /// Copy RGB components out of the ARGB struct |
319 | /// |
320 | /// Note: you can use `.into()` to convert between other types |
321 | #[inline (always)] |
322 | pub fn rgb(&self) -> RGB<T> { |
323 | RGB {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()} |
324 | } |
325 | } |
326 | |
327 | impl<T: Clone, A> BGRA<T, A> { |
328 | /// Copy RGB components out of the RGBA struct |
329 | /// |
330 | /// Note: you can use `.into()` to convert between other types |
331 | #[inline (always)] |
332 | #[deprecated (note = "This function will change. Use bgr()" )] |
333 | pub fn rgb(&self) -> BGR<T> { |
334 | BGR {r:self.r.clone(), g:self.g.clone(), b:self.b.clone()} |
335 | } |
336 | } |
337 | |
338 | impl_rgba! {RGBA} |
339 | impl_rgba! {BGRA} |
340 | #[cfg (feature = "argb" )] |
341 | impl_rgba! {ARGB} |
342 | #[cfg (feature = "argb" )] |
343 | impl_rgba! {ABGR} |
344 | |
345 | impl_alpha_conv! {BGR, BGRA} |
346 | impl_alpha_conv! {RGB, BGRA} |
347 | impl_alpha_conv! {BGR, RGBA} |
348 | impl_alpha_conv! {RGB, RGBA} |
349 | #[cfg (feature = "argb" )] |
350 | impl_alpha_conv! {BGR, ABGR} |
351 | #[cfg (feature = "argb" )] |
352 | impl_alpha_conv! {RGB, ABGR} |
353 | #[cfg (feature = "argb" )] |
354 | impl_alpha_conv! {BGR, ARGB} |
355 | #[cfg (feature = "argb" )] |
356 | impl_alpha_conv! {RGB, ARGB} |
357 | |
358 | impl<T: fmt::Display, A: fmt::Display> fmt::Display for RGBA<T, A> { |
359 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
360 | write!(f, "rgba( {}, {}, {}, {})" , self.r, self.g, self.b, self.a) |
361 | } |
362 | } |
363 | |
364 | impl<T: fmt::Display, A: fmt::Display> fmt::Display for BGRA<T, A> { |
365 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
366 | write!(f, "bgra( {}, {}, {}, {})" , self.r, self.g, self.b, self.a) |
367 | } |
368 | } |
369 | |
370 | #[test ] |
371 | fn rgba_test() { |
372 | let neg = RGBA::new(1,2,3i32,1000).map(|x| -x); |
373 | assert_eq!(neg.r, -1); |
374 | assert_eq!(neg.rgb().r, -1); |
375 | assert_eq!(neg.g, -2); |
376 | assert_eq!(neg.rgb().g, -2); |
377 | assert_eq!(neg.b, -3); |
378 | assert_eq!(neg.rgb().b, -3); |
379 | assert_eq!(neg.a, -1000); |
380 | assert_eq!(neg.map_alpha(|x| x+1).a, -999); |
381 | assert_eq!(neg, neg.as_slice().iter().cloned().collect()); |
382 | assert!(neg < RGBA::new(0,0,0,0)); |
383 | |
384 | let neg = RGBA::new(1u8,2,3,4).map_rgb(|c| -(c as i16)); |
385 | assert_eq!(-1i16, neg.r); |
386 | assert_eq!(4i16, neg.a); |
387 | let neg = RGBA::new(1u8,2,3,4).map_c(|c| -(c as i16)); |
388 | assert_eq!(-1i16, neg.r); |
389 | assert_eq!(4u8, neg.a); |
390 | |
391 | let mut px = RGBA{r:1,g:2,b:3,a:4}; |
392 | px.as_mut_slice()[3] = 100; |
393 | assert_eq!(1, px.rgb_mut().r); |
394 | assert_eq!(2, px.rgb_mut().g); |
395 | px.rgb_mut().b = 4; |
396 | assert_eq!(4, px.rgb_mut().b); |
397 | assert_eq!(100, px.a); |
398 | |
399 | #[cfg (feature = "as-bytes" )] |
400 | { |
401 | let v = vec![RGBA::new(1u8,2,3,4), RGBA::new(5,6,7,8)]; |
402 | assert_eq!(&[1,2,3,4,5,6,7,8], v.as_bytes()); |
403 | } |
404 | } |
405 | |
406 | #[test ] |
407 | #[cfg (feature = "argb" )] |
408 | fn abgr_test() { |
409 | let abgr = ABGR {r:1,g:2,b:3,a:4}; |
410 | assert_eq!(4, abgr.as_slice()[0]); |
411 | use crate::AsPixels; |
412 | assert_eq!(abgr, [abgr].as_bytes().as_pixels()[0]); |
413 | } |
414 | |
415 | #[test ] |
416 | #[allow (deprecated)] |
417 | fn bgra_test() { |
418 | let neg = BGRA::new(1, 2, 3i32, 1000).map(|x| -x); |
419 | let _ = neg.as_slice(); |
420 | |
421 | #[cfg (feature = "as-bytes" )] |
422 | { |
423 | let _ = [neg].as_bytes(); |
424 | } |
425 | assert_eq!(neg.r, -1); |
426 | assert_eq!(neg.bgr().r, -1); |
427 | assert_eq!(neg.g, -2); |
428 | assert_eq!(neg.bgr().g, -2); |
429 | assert_eq!(neg.b, -3); |
430 | assert_eq!(neg.bgr().b, -3); |
431 | assert_eq!(neg.a, -1000); |
432 | assert_eq!(&[-3,-2,-1,-1000], neg.as_slice()); |
433 | assert!(neg < BGRA::new(0, 0, 0, 0)); |
434 | |
435 | let neg = BGRA::new(1u8, 2u8, 3u8, 4u8).map_rgb(|c| -(c as i16)); |
436 | assert_eq!(-1i16, neg.r); |
437 | assert_eq!(4i16, neg.a); |
438 | let neg = BGRA::new(1u8, 2u8, 3u8, 4u8).map_c(|c| -(c as i16)); |
439 | assert_eq!(-1i16, neg.r); |
440 | assert_eq!(4u8, neg.a); |
441 | |
442 | let mut px = BGRA{r:1,g:2,b:3,a:-9}.alpha(4); |
443 | px.as_mut_slice()[3] = 100; |
444 | assert_eq!(1, px.bgr_mut().r); |
445 | assert_eq!(2, px.bgr_mut().g); |
446 | px.bgr_mut().b = 4; |
447 | assert_eq!(4, px.bgr_mut().b); |
448 | assert_eq!(100, px.a); |
449 | |
450 | |
451 | #[cfg (feature = "as-bytes" )] |
452 | { |
453 | let v = vec![BGRA::new(3u8, 2, 1, 4), BGRA::new(7, 6, 5, 8)]; |
454 | assert_eq!(&[1,2,3,4,5,6,7,8], v.as_bytes()); |
455 | } |
456 | } |
457 | |