1use std::ops::{Index, IndexMut};
2
3use num_traits::{NumCast, ToPrimitive, Zero};
4
5use crate::traits::{Enlargeable, Pixel, Primitive};
6
7#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
9#[non_exhaustive]
10pub enum ColorType {
11 L8,
13 La8,
15 Rgb8,
17 Rgba8,
19
20 L16,
22 La16,
24 Rgb16,
26 Rgba16,
28
29 Rgb32F,
31 Rgba32F,
33}
34
35impl ColorType {
36 pub fn bytes_per_pixel(self) -> u8 {
38 match self {
39 ColorType::L8 => 1,
40 ColorType::L16 | ColorType::La8 => 2,
41 ColorType::Rgb8 => 3,
42 ColorType::Rgba8 | ColorType::La16 => 4,
43 ColorType::Rgb16 => 6,
44 ColorType::Rgba16 => 8,
45 ColorType::Rgb32F => 3 * 4,
46 ColorType::Rgba32F => 4 * 4,
47 }
48 }
49
50 pub fn has_alpha(self) -> bool {
52 use ColorType::*;
53 match self {
54 L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
55 La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
56 }
57 }
58
59 pub fn has_color(self) -> bool {
61 use ColorType::*;
62 match self {
63 L8 | L16 | La8 | La16 => false,
64 Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
65 }
66 }
67
68 pub fn bits_per_pixel(self) -> u16 {
71 <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
72 }
73
74 pub fn channel_count(self) -> u8 {
76 let e: ExtendedColorType = self.into();
77 e.channel_count()
78 }
79}
80
81#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
90#[non_exhaustive]
91pub enum ExtendedColorType {
92 A8,
94 L1,
96 La1,
98 Rgb1,
100 Rgba1,
102 L2,
104 La2,
106 Rgb2,
108 Rgba2,
110 L4,
112 La4,
114 Rgb4,
116 Rgba4,
118 L8,
120 La8,
122 Rgb8,
124 Rgba8,
126 L16,
128 La16,
130 Rgb16,
132 Rgba16,
134 Bgr8,
136 Bgra8,
138
139 Rgb32F,
142 Rgba32F,
144
145 Cmyk8,
147
148 Unknown(u8),
152}
153
154impl ExtendedColorType {
155 pub fn channel_count(self) -> u8 {
160 match self {
161 ExtendedColorType::A8
162 | ExtendedColorType::L1
163 | ExtendedColorType::L2
164 | ExtendedColorType::L4
165 | ExtendedColorType::L8
166 | ExtendedColorType::L16
167 | ExtendedColorType::Unknown(_) => 1,
168 ExtendedColorType::La1
169 | ExtendedColorType::La2
170 | ExtendedColorType::La4
171 | ExtendedColorType::La8
172 | ExtendedColorType::La16 => 2,
173 ExtendedColorType::Rgb1
174 | ExtendedColorType::Rgb2
175 | ExtendedColorType::Rgb4
176 | ExtendedColorType::Rgb8
177 | ExtendedColorType::Rgb16
178 | ExtendedColorType::Rgb32F
179 | ExtendedColorType::Bgr8 => 3,
180 ExtendedColorType::Rgba1
181 | ExtendedColorType::Rgba2
182 | ExtendedColorType::Rgba4
183 | ExtendedColorType::Rgba8
184 | ExtendedColorType::Rgba16
185 | ExtendedColorType::Rgba32F
186 | ExtendedColorType::Bgra8
187 | ExtendedColorType::Cmyk8 => 4,
188 }
189 }
190}
191impl From<ColorType> for ExtendedColorType {
192 fn from(c: ColorType) -> Self {
193 match c {
194 ColorType::L8 => ExtendedColorType::L8,
195 ColorType::La8 => ExtendedColorType::La8,
196 ColorType::Rgb8 => ExtendedColorType::Rgb8,
197 ColorType::Rgba8 => ExtendedColorType::Rgba8,
198 ColorType::L16 => ExtendedColorType::L16,
199 ColorType::La16 => ExtendedColorType::La16,
200 ColorType::Rgb16 => ExtendedColorType::Rgb16,
201 ColorType::Rgba16 => ExtendedColorType::Rgba16,
202 ColorType::Rgb32F => ExtendedColorType::Rgb32F,
203 ColorType::Rgba32F => ExtendedColorType::Rgba32F,
204 }
205 }
206}
207
208macro_rules! define_colors {
209 {$(
210 $(#[$doc:meta])*
211 pub struct $ident:ident<T: $($bound:ident)*>([T; $channels:expr, $alphas:expr])
212 = $interpretation:literal;
213 )*} => {
214
215$( $(#[$doc])*
218#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
219#[repr(C)]
220#[allow(missing_docs)]
221pub struct $ident<T> (pub [T; $channels]);
222
223impl<T: $($bound+)*> Pixel for $ident<T> {
224 type Subpixel = T;
225
226 const CHANNEL_COUNT: u8 = $channels;
227
228 #[inline(always)]
229 fn channels(&self) -> &[T] {
230 &self.0
231 }
232
233 #[inline(always)]
234 fn channels_mut(&mut self) -> &mut [T] {
235 &mut self.0
236 }
237
238 const COLOR_MODEL: &'static str = $interpretation;
239
240 fn channels4(&self) -> (T, T, T, T) {
241 const CHANNELS: usize = $channels;
242 let mut channels = [T::DEFAULT_MAX_VALUE; 4];
243 channels[0..CHANNELS].copy_from_slice(&self.0);
244 (channels[0], channels[1], channels[2], channels[3])
245 }
246
247 fn from_channels(a: T, b: T, c: T, d: T,) -> $ident<T> {
248 const CHANNELS: usize = $channels;
249 *<$ident<T> as Pixel>::from_slice(&[a, b, c, d][..CHANNELS])
250 }
251
252 fn from_slice(slice: &[T]) -> &$ident<T> {
253 assert_eq!(slice.len(), $channels);
254 unsafe { &*(slice.as_ptr() as *const $ident<T>) }
255 }
256 fn from_slice_mut(slice: &mut [T]) -> &mut $ident<T> {
257 assert_eq!(slice.len(), $channels);
258 unsafe { &mut *(slice.as_mut_ptr() as *mut $ident<T>) }
259 }
260
261 fn to_rgb(&self) -> Rgb<T> {
262 let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]);
263 pix.from_color(self);
264 pix
265 }
266
267 fn to_rgba(&self) -> Rgba<T> {
268 let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]);
269 pix.from_color(self);
270 pix
271 }
272
273 fn to_luma(&self) -> Luma<T> {
274 let mut pix = Luma([Zero::zero()]);
275 pix.from_color(self);
276 pix
277 }
278
279 fn to_luma_alpha(&self) -> LumaA<T> {
280 let mut pix = LumaA([Zero::zero(), Zero::zero()]);
281 pix.from_color(self);
282 pix
283 }
284
285 fn map<F>(& self, f: F) -> $ident<T> where F: FnMut(T) -> T {
286 let mut this = (*self).clone();
287 this.apply(f);
288 this
289 }
290
291 fn apply<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
292 for v in &mut self.0 {
293 *v = f(*v)
294 }
295 }
296
297 fn map_with_alpha<F, G>(&self, f: F, g: G) -> $ident<T> where F: FnMut(T) -> T, G: FnMut(T) -> T {
298 let mut this = (*self).clone();
299 this.apply_with_alpha(f, g);
300 this
301 }
302
303 fn apply_with_alpha<F, G>(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T {
304 const ALPHA: usize = $channels - $alphas;
305 for v in self.0[..ALPHA].iter_mut() {
306 *v = f(*v)
307 }
308 if let Some(v) = self.0.get_mut(ALPHA) {
311 *v = g(*v)
312 }
313 }
314
315 fn map2<F>(&self, other: &Self, f: F) -> $ident<T> where F: FnMut(T, T) -> T {
316 let mut this = (*self).clone();
317 this.apply2(other, f);
318 this
319 }
320
321 fn apply2<F>(&mut self, other: &$ident<T>, mut f: F) where F: FnMut(T, T) -> T {
322 for (a, &b) in self.0.iter_mut().zip(other.0.iter()) {
323 *a = f(*a, b)
324 }
325 }
326
327 fn invert(&mut self) {
328 Invert::invert(self)
329 }
330
331 fn blend(&mut self, other: &$ident<T>) {
332 Blend::blend(self, other)
333 }
334}
335
336impl<T> Index<usize> for $ident<T> {
337 type Output = T;
338 #[inline(always)]
339 fn index(&self, _index: usize) -> &T {
340 &self.0[_index]
341 }
342}
343
344impl<T> IndexMut<usize> for $ident<T> {
345 #[inline(always)]
346 fn index_mut(&mut self, _index: usize) -> &mut T {
347 &mut self.0[_index]
348 }
349}
350
351impl<T> From<[T; $channels]> for $ident<T> {
352 fn from(c: [T; $channels]) -> Self {
353 Self(c)
354 }
355}
356
357)* }
360}
361
362define_colors! {
363 pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
368 pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
370 pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
372 pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
374}
375
376pub trait FromPrimitive<Component> {
378 fn from_primitive(component: Component) -> Self;
380}
381
382impl<T: Primitive> FromPrimitive<T> for T {
383 fn from_primitive(sample: T) -> Self {
384 sample
385 }
386}
387
388impl FromPrimitive<f32> for u8 {
393 fn from_primitive(float: f32) -> Self {
394 let inner = (float.clamp(0.0, 1.0) * u8::MAX as f32).round();
395 NumCast::from(inner).unwrap()
396 }
397}
398
399impl FromPrimitive<f32> for u16 {
400 fn from_primitive(float: f32) -> Self {
401 let inner = (float.clamp(0.0, 1.0) * u16::MAX as f32).round();
402 NumCast::from(inner).unwrap()
403 }
404}
405
406impl FromPrimitive<u16> for u8 {
409 fn from_primitive(c16: u16) -> Self {
410 fn from(c: impl Into<u32>) -> u32 {
411 c.into()
412 }
413 NumCast::from((from(c16) + 128) / 257).unwrap()
420 }
421}
422
423impl FromPrimitive<u16> for f32 {
424 fn from_primitive(int: u16) -> Self {
425 (int as f32 / u16::MAX as f32).clamp(0.0, 1.0)
426 }
427}
428
429impl FromPrimitive<u8> for f32 {
432 fn from_primitive(int: u8) -> Self {
433 (int as f32 / u8::MAX as f32).clamp(0.0, 1.0)
434 }
435}
436
437impl FromPrimitive<u8> for u16 {
438 fn from_primitive(c8: u8) -> Self {
439 let x = c8.to_u64().unwrap();
440 NumCast::from((x << 8) | x).unwrap()
441 }
442}
443
444pub trait FromColor<Other> {
446 fn from_color(&mut self, _: &Other);
448}
449
450pub(crate) trait IntoColor<Other> {
454 fn into_color(&self) -> Other;
456}
457
458impl<O, S> IntoColor<O> for S
459where
460 O: Pixel + FromColor<S>,
461{
462 fn into_color(&self) -> O {
463 #[allow(deprecated)]
466 let mut pix = O::from_channels(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
467 pix.from_color(self);
468 pix
469 }
470}
471
472const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
474const SRGB_LUMA_DIV: u32 = 10000;
475
476#[inline]
477fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
478 let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
479 + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
480 + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
481 T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
482}
483
484impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
486where
487 T: FromPrimitive<S>,
488{
489 fn from_color(&mut self, other: &Luma<S>) {
490 let own = self.channels_mut();
491 let other = other.channels();
492 own[0] = T::from_primitive(other[0]);
493 }
494}
495
496impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
497where
498 T: FromPrimitive<S>,
499{
500 fn from_color(&mut self, other: &LumaA<S>) {
501 self.channels_mut()[0] = T::from_primitive(other.channels()[0])
502 }
503}
504
505impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
506where
507 T: FromPrimitive<S>,
508{
509 fn from_color(&mut self, other: &Rgb<S>) {
510 let gray = self.channels_mut();
511 let rgb = other.channels();
512 gray[0] = T::from_primitive(rgb_to_luma(rgb));
513 }
514}
515
516impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
517where
518 T: FromPrimitive<S>,
519{
520 fn from_color(&mut self, other: &Rgba<S>) {
521 let gray = self.channels_mut();
522 let rgb = other.channels();
523 let l = rgb_to_luma(rgb);
524 gray[0] = T::from_primitive(l);
525 }
526}
527
528impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
531where
532 T: FromPrimitive<S>,
533{
534 fn from_color(&mut self, other: &LumaA<S>) {
535 let own = self.channels_mut();
536 let other = other.channels();
537 own[0] = T::from_primitive(other[0]);
538 own[1] = T::from_primitive(other[1]);
539 }
540}
541
542impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
543where
544 T: FromPrimitive<S>,
545{
546 fn from_color(&mut self, other: &Rgb<S>) {
547 let gray_a = self.channels_mut();
548 let rgb = other.channels();
549 gray_a[0] = T::from_primitive(rgb_to_luma(rgb));
550 gray_a[1] = T::DEFAULT_MAX_VALUE;
551 }
552}
553
554impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
555where
556 T: FromPrimitive<S>,
557{
558 fn from_color(&mut self, other: &Rgba<S>) {
559 let gray_a = self.channels_mut();
560 let rgba = other.channels();
561 gray_a[0] = T::from_primitive(rgb_to_luma(rgba));
562 gray_a[1] = T::from_primitive(rgba[3]);
563 }
564}
565
566impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
567where
568 T: FromPrimitive<S>,
569{
570 fn from_color(&mut self, other: &Luma<S>) {
571 let gray_a = self.channels_mut();
572 gray_a[0] = T::from_primitive(other.channels()[0]);
573 gray_a[1] = T::DEFAULT_MAX_VALUE;
574 }
575}
576
577impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
580where
581 T: FromPrimitive<S>,
582{
583 fn from_color(&mut self, other: &Rgba<S>) {
584 let own = &mut self.0;
585 let other = &other.0;
586 own[0] = T::from_primitive(other[0]);
587 own[1] = T::from_primitive(other[1]);
588 own[2] = T::from_primitive(other[2]);
589 own[3] = T::from_primitive(other[3]);
590 }
591}
592
593impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
594where
595 T: FromPrimitive<S>,
596{
597 fn from_color(&mut self, other: &Rgb<S>) {
598 let rgba = &mut self.0;
599 let rgb = &other.0;
600 rgba[0] = T::from_primitive(rgb[0]);
601 rgba[1] = T::from_primitive(rgb[1]);
602 rgba[2] = T::from_primitive(rgb[2]);
603 rgba[3] = T::DEFAULT_MAX_VALUE;
604 }
605}
606
607impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
608where
609 T: FromPrimitive<S>,
610{
611 fn from_color(&mut self, gray: &LumaA<S>) {
612 let rgba = &mut self.0;
613 let gray = &gray.0;
614 rgba[0] = T::from_primitive(gray[0]);
615 rgba[1] = T::from_primitive(gray[0]);
616 rgba[2] = T::from_primitive(gray[0]);
617 rgba[3] = T::from_primitive(gray[1]);
618 }
619}
620
621impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
622where
623 T: FromPrimitive<S>,
624{
625 fn from_color(&mut self, gray: &Luma<S>) {
626 let rgba = &mut self.0;
627 let gray = gray.0[0];
628 rgba[0] = T::from_primitive(gray);
629 rgba[1] = T::from_primitive(gray);
630 rgba[2] = T::from_primitive(gray);
631 rgba[3] = T::DEFAULT_MAX_VALUE;
632 }
633}
634
635impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
638where
639 T: FromPrimitive<S>,
640{
641 fn from_color(&mut self, other: &Rgb<S>) {
642 let own = &mut self.0;
643 let other = &other.0;
644 own[0] = T::from_primitive(other[0]);
645 own[1] = T::from_primitive(other[1]);
646 own[2] = T::from_primitive(other[2]);
647 }
648}
649
650impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
651where
652 T: FromPrimitive<S>,
653{
654 fn from_color(&mut self, other: &Rgba<S>) {
655 let rgb = &mut self.0;
656 let rgba = &other.0;
657 rgb[0] = T::from_primitive(rgba[0]);
658 rgb[1] = T::from_primitive(rgba[1]);
659 rgb[2] = T::from_primitive(rgba[2]);
660 }
661}
662
663impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
664where
665 T: FromPrimitive<S>,
666{
667 fn from_color(&mut self, other: &LumaA<S>) {
668 let rgb = &mut self.0;
669 let gray = other.0[0];
670 rgb[0] = T::from_primitive(gray);
671 rgb[1] = T::from_primitive(gray);
672 rgb[2] = T::from_primitive(gray);
673 }
674}
675
676impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
677where
678 T: FromPrimitive<S>,
679{
680 fn from_color(&mut self, other: &Luma<S>) {
681 let rgb = &mut self.0;
682 let gray = other.0[0];
683 rgb[0] = T::from_primitive(gray);
684 rgb[1] = T::from_primitive(gray);
685 rgb[2] = T::from_primitive(gray);
686 }
687}
688
689pub(crate) trait Blend {
691 fn blend(&mut self, other: &Self);
693}
694
695impl<T: Primitive> Blend for LumaA<T> {
696 fn blend(&mut self, other: &LumaA<T>) {
697 let max_t = T::DEFAULT_MAX_VALUE;
698 let max_t = max_t.to_f32().unwrap();
699 let (bg_luma, bg_a) = (self.0[0], self.0[1]);
700 let (fg_luma, fg_a) = (other.0[0], other.0[1]);
701
702 let (bg_luma, bg_a) = (
703 bg_luma.to_f32().unwrap() / max_t,
704 bg_a.to_f32().unwrap() / max_t,
705 );
706 let (fg_luma, fg_a) = (
707 fg_luma.to_f32().unwrap() / max_t,
708 fg_a.to_f32().unwrap() / max_t,
709 );
710
711 let alpha_final = bg_a + fg_a - bg_a * fg_a;
712 if alpha_final == 0.0 {
713 return;
714 };
715 let bg_luma_a = bg_luma * bg_a;
716 let fg_luma_a = fg_luma * fg_a;
717
718 let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
719 let out_luma = out_luma_a / alpha_final;
720
721 *self = LumaA([
722 NumCast::from(max_t * out_luma).unwrap(),
723 NumCast::from(max_t * alpha_final).unwrap(),
724 ])
725 }
726}
727
728impl<T: Primitive> Blend for Luma<T> {
729 fn blend(&mut self, other: &Luma<T>) {
730 *self = *other
731 }
732}
733
734impl<T: Primitive> Blend for Rgba<T> {
735 fn blend(&mut self, other: &Rgba<T>) {
736 if other.0[3].is_zero() {
739 return;
740 }
741 if other.0[3] == T::DEFAULT_MAX_VALUE {
742 *self = *other;
743 return;
744 }
745
746 let max_t = T::DEFAULT_MAX_VALUE;
748 let max_t = max_t.to_f32().unwrap();
749 let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
750 let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
751 let (bg_r, bg_g, bg_b, bg_a) = (
752 bg_r.to_f32().unwrap() / max_t,
753 bg_g.to_f32().unwrap() / max_t,
754 bg_b.to_f32().unwrap() / max_t,
755 bg_a.to_f32().unwrap() / max_t,
756 );
757 let (fg_r, fg_g, fg_b, fg_a) = (
758 fg_r.to_f32().unwrap() / max_t,
759 fg_g.to_f32().unwrap() / max_t,
760 fg_b.to_f32().unwrap() / max_t,
761 fg_a.to_f32().unwrap() / max_t,
762 );
763
764 let alpha_final = bg_a + fg_a - bg_a * fg_a;
766 if alpha_final == 0.0 {
767 return;
768 };
769
770 let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
772 let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
773
774 let (out_r_a, out_g_a, out_b_a) = (
776 fg_r_a + bg_r_a * (1.0 - fg_a),
777 fg_g_a + bg_g_a * (1.0 - fg_a),
778 fg_b_a + bg_b_a * (1.0 - fg_a),
779 );
780
781 let (out_r, out_g, out_b) = (
783 out_r_a / alpha_final,
784 out_g_a / alpha_final,
785 out_b_a / alpha_final,
786 );
787
788 *self = Rgba([
790 NumCast::from(max_t * out_r).unwrap(),
791 NumCast::from(max_t * out_g).unwrap(),
792 NumCast::from(max_t * out_b).unwrap(),
793 NumCast::from(max_t * alpha_final).unwrap(),
794 ])
795 }
796}
797
798impl<T: Primitive> Blend for Rgb<T> {
799 fn blend(&mut self, other: &Rgb<T>) {
800 *self = *other
801 }
802}
803
804pub(crate) trait Invert {
806 fn invert(&mut self);
808}
809
810impl<T: Primitive> Invert for LumaA<T> {
811 fn invert(&mut self) {
812 let l = self.0;
813 let max = T::DEFAULT_MAX_VALUE;
814
815 *self = LumaA([max - l[0], l[1]])
816 }
817}
818
819impl<T: Primitive> Invert for Luma<T> {
820 fn invert(&mut self) {
821 let l = self.0;
822
823 let max = T::DEFAULT_MAX_VALUE;
824 let l1 = max - l[0];
825
826 *self = Luma([l1])
827 }
828}
829
830impl<T: Primitive> Invert for Rgba<T> {
831 fn invert(&mut self) {
832 let rgba = self.0;
833
834 let max = T::DEFAULT_MAX_VALUE;
835
836 *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]])
837 }
838}
839
840impl<T: Primitive> Invert for Rgb<T> {
841 fn invert(&mut self) {
842 let rgb = self.0;
843
844 let max = T::DEFAULT_MAX_VALUE;
845
846 let r1 = max - rgb[0];
847 let g1 = max - rgb[1];
848 let b1 = max - rgb[2];
849
850 *self = Rgb([r1, g1, b1])
851 }
852}
853
854#[cfg(test)]
855mod tests {
856 use super::{Luma, LumaA, Pixel, Rgb, Rgba};
857
858 #[test]
859 fn test_apply_with_alpha_rgba() {
860 let mut rgba = Rgba([0, 0, 0, 0]);
861 rgba.apply_with_alpha(|s| s, |_| 0xFF);
862 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
863 }
864
865 #[test]
866 fn test_apply_with_alpha_rgb() {
867 let mut rgb = Rgb([0, 0, 0]);
868 rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
869 assert_eq!(rgb, Rgb([0, 0, 0]));
870 }
871
872 #[test]
873 fn test_map_with_alpha_rgba() {
874 let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
875 assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
876 }
877
878 #[test]
879 fn test_map_with_alpha_rgb() {
880 let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
881 assert_eq!(rgb, Rgb([0, 0, 0]));
882 }
883
884 #[test]
885 fn test_blend_luma_alpha() {
886 let a = &mut LumaA([255_u8, 255]);
887 let b = LumaA([255_u8, 255]);
888 a.blend(&b);
889 assert_eq!(a.0[0], 255);
890 assert_eq!(a.0[1], 255);
891
892 let a = &mut LumaA([255_u8, 0]);
893 let b = LumaA([255_u8, 255]);
894 a.blend(&b);
895 assert_eq!(a.0[0], 255);
896 assert_eq!(a.0[1], 255);
897
898 let a = &mut LumaA([255_u8, 255]);
899 let b = LumaA([255_u8, 0]);
900 a.blend(&b);
901 assert_eq!(a.0[0], 255);
902 assert_eq!(a.0[1], 255);
903
904 let a = &mut LumaA([255_u8, 0]);
905 let b = LumaA([255_u8, 0]);
906 a.blend(&b);
907 assert_eq!(a.0[0], 255);
908 assert_eq!(a.0[1], 0);
909 }
910
911 #[test]
912 fn test_blend_rgba() {
913 let a = &mut Rgba([255_u8, 255, 255, 255]);
914 let b = Rgba([255_u8, 255, 255, 255]);
915 a.blend(&b);
916 assert_eq!(a.0, [255, 255, 255, 255]);
917
918 let a = &mut Rgba([255_u8, 255, 255, 0]);
919 let b = Rgba([255_u8, 255, 255, 255]);
920 a.blend(&b);
921 assert_eq!(a.0, [255, 255, 255, 255]);
922
923 let a = &mut Rgba([255_u8, 255, 255, 255]);
924 let b = Rgba([255_u8, 255, 255, 0]);
925 a.blend(&b);
926 assert_eq!(a.0, [255, 255, 255, 255]);
927
928 let a = &mut Rgba([255_u8, 255, 255, 0]);
929 let b = Rgba([255_u8, 255, 255, 0]);
930 a.blend(&b);
931 assert_eq!(a.0, [255, 255, 255, 0]);
932 }
933
934 #[test]
935 fn test_apply_without_alpha_rgba() {
936 let mut rgba = Rgba([0, 0, 0, 0]);
937 rgba.apply_without_alpha(|s| s + 1);
938 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
939 }
940
941 #[test]
942 fn test_apply_without_alpha_rgb() {
943 let mut rgb = Rgb([0, 0, 0]);
944 rgb.apply_without_alpha(|s| s + 1);
945 assert_eq!(rgb, Rgb([1, 1, 1]));
946 }
947
948 #[test]
949 fn test_map_without_alpha_rgba() {
950 let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
951 assert_eq!(rgba, Rgba([1, 1, 1, 0]));
952 }
953
954 #[test]
955 fn test_map_without_alpha_rgb() {
956 let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
957 assert_eq!(rgb, Rgb([1, 1, 1]));
958 }
959
960 macro_rules! test_lossless_conversion {
961 ($a:ty, $b:ty, $c:ty) => {
962 let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
963 <$a as Pixel>::CHANNEL_COUNT as usize]
964 .into();
965 let b: $b = a.into_color();
966 let c: $c = b.into_color();
967 assert_eq!(a.channels(), c.channels());
968 };
969 }
970
971 #[test]
972 fn test_lossless_conversions() {
973 use super::IntoColor;
974 use crate::traits::Primitive;
975
976 test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
977 test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
978 test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
979 test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
980 }
981
982 #[test]
983 fn accuracy_conversion() {
984 use super::{Luma, Pixel, Rgb};
985 let pixel = Rgb::from([13, 13, 13]);
986 let Luma([luma]) = pixel.to_luma();
987 assert_eq!(luma, 13);
988 }
989}