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    #[must_use]
38    pub fn bytes_per_pixel(self) -> u8 {
39        match self {
40            ColorType::L8 => 1,
41            ColorType::L16 | ColorType::La8 => 2,
42            ColorType::Rgb8 => 3,
43            ColorType::Rgba8 | ColorType::La16 => 4,
44            ColorType::Rgb16 => 6,
45            ColorType::Rgba16 => 8,
46            ColorType::Rgb32F => 3 * 4,
47            ColorType::Rgba32F => 4 * 4,
48        }
49    }
50
51    #[must_use]
53    pub fn has_alpha(self) -> bool {
54        use ColorType::*;
55        match self {
56            L8 | L16 | Rgb8 | Rgb16 | Rgb32F => false,
57            La8 | Rgba8 | La16 | Rgba16 | Rgba32F => true,
58        }
59    }
60
61    #[must_use]
63    pub fn has_color(self) -> bool {
64        use ColorType::*;
65        match self {
66            L8 | L16 | La8 | La16 => false,
67            Rgb8 | Rgb16 | Rgba8 | Rgba16 | Rgb32F | Rgba32F => true,
68        }
69    }
70
71    #[must_use]
74    pub fn bits_per_pixel(self) -> u16 {
75        <u16 as From<u8>>::from(self.bytes_per_pixel()) * 8
76    }
77
78    #[must_use]
80    pub fn channel_count(self) -> u8 {
81        let e: ExtendedColorType = self.into();
82        e.channel_count()
83    }
84}
85
86#[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)]
95#[non_exhaustive]
96pub enum ExtendedColorType {
97    A8,
99    L1,
101    La1,
103    Rgb1,
105    Rgba1,
107    L2,
109    La2,
111    Rgb2,
113    Rgba2,
115    L4,
117    La4,
119    Rgb4,
121    Rgba4,
123    L8,
125    La8,
127    Rgb8,
129    Rgba8,
131    L16,
133    La16,
135    Rgb16,
137    Rgba16,
139    Bgr8,
141    Bgra8,
143
144    Rgb32F,
147    Rgba32F,
149
150    Cmyk8,
152
153    Unknown(u8),
157}
158
159impl ExtendedColorType {
160    #[must_use]
165    pub fn channel_count(self) -> u8 {
166        match self {
167            ExtendedColorType::A8
168            | ExtendedColorType::L1
169            | ExtendedColorType::L2
170            | ExtendedColorType::L4
171            | ExtendedColorType::L8
172            | ExtendedColorType::L16
173            | ExtendedColorType::Unknown(_) => 1,
174            ExtendedColorType::La1
175            | ExtendedColorType::La2
176            | ExtendedColorType::La4
177            | ExtendedColorType::La8
178            | ExtendedColorType::La16 => 2,
179            ExtendedColorType::Rgb1
180            | ExtendedColorType::Rgb2
181            | ExtendedColorType::Rgb4
182            | ExtendedColorType::Rgb8
183            | ExtendedColorType::Rgb16
184            | ExtendedColorType::Rgb32F
185            | ExtendedColorType::Bgr8 => 3,
186            ExtendedColorType::Rgba1
187            | ExtendedColorType::Rgba2
188            | ExtendedColorType::Rgba4
189            | ExtendedColorType::Rgba8
190            | ExtendedColorType::Rgba16
191            | ExtendedColorType::Rgba32F
192            | ExtendedColorType::Bgra8
193            | ExtendedColorType::Cmyk8 => 4,
194        }
195    }
196
197    #[must_use]
199    pub fn bits_per_pixel(&self) -> u16 {
200        match *self {
201            ExtendedColorType::A8 => 8,
202            ExtendedColorType::L1 => 1,
203            ExtendedColorType::La1 => 2,
204            ExtendedColorType::Rgb1 => 3,
205            ExtendedColorType::Rgba1 => 4,
206            ExtendedColorType::L2 => 2,
207            ExtendedColorType::La2 => 4,
208            ExtendedColorType::Rgb2 => 6,
209            ExtendedColorType::Rgba2 => 8,
210            ExtendedColorType::L4 => 4,
211            ExtendedColorType::La4 => 8,
212            ExtendedColorType::Rgb4 => 12,
213            ExtendedColorType::Rgba4 => 16,
214            ExtendedColorType::L8 => 8,
215            ExtendedColorType::La8 => 16,
216            ExtendedColorType::Rgb8 => 24,
217            ExtendedColorType::Rgba8 => 32,
218            ExtendedColorType::L16 => 16,
219            ExtendedColorType::La16 => 32,
220            ExtendedColorType::Rgb16 => 48,
221            ExtendedColorType::Rgba16 => 64,
222            ExtendedColorType::Rgb32F => 96,
223            ExtendedColorType::Rgba32F => 128,
224            ExtendedColorType::Bgr8 => 24,
225            ExtendedColorType::Bgra8 => 32,
226            ExtendedColorType::Cmyk8 => 32,
227            ExtendedColorType::Unknown(bpp) => bpp as u16,
228        }
229    }
230
231    pub(crate) fn buffer_size(self, width: u32, height: u32) -> u64 {
233        let bpp = self.bits_per_pixel() as u64;
234        let row_pitch = (width as u64 * bpp + 7) / 8;
235        row_pitch.saturating_mul(height as u64)
236    }
237}
238impl From<ColorType> for ExtendedColorType {
239    fn from(c: ColorType) -> Self {
240        match c {
241            ColorType::L8 => ExtendedColorType::L8,
242            ColorType::La8 => ExtendedColorType::La8,
243            ColorType::Rgb8 => ExtendedColorType::Rgb8,
244            ColorType::Rgba8 => ExtendedColorType::Rgba8,
245            ColorType::L16 => ExtendedColorType::L16,
246            ColorType::La16 => ExtendedColorType::La16,
247            ColorType::Rgb16 => ExtendedColorType::Rgb16,
248            ColorType::Rgba16 => ExtendedColorType::Rgba16,
249            ColorType::Rgb32F => ExtendedColorType::Rgb32F,
250            ColorType::Rgba32F => ExtendedColorType::Rgba32F,
251        }
252    }
253}
254
255macro_rules! define_colors {
256    {$(
257        $(#[$doc:meta])*
258        pub struct $ident:ident<T: $($bound:ident)*>([T; $channels:expr, $alphas:expr])
259            = $interpretation:literal;
260    )*} => {
261
262$( $(#[$doc])*
265#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)]
266#[repr(transparent)]
267#[allow(missing_docs)]
268pub struct $ident<T> (pub [T; $channels]);
269
270impl<T: $($bound+)*> Pixel for $ident<T> {
271    type Subpixel = T;
272
273    const CHANNEL_COUNT: u8 = $channels;
274
275    #[inline(always)]
276    fn channels(&self) -> &[T] {
277        &self.0
278    }
279
280    #[inline(always)]
281    fn channels_mut(&mut self) -> &mut [T] {
282        &mut self.0
283    }
284
285    const COLOR_MODEL: &'static str = $interpretation;
286
287    fn channels4(&self) -> (T, T, T, T) {
288        const CHANNELS: usize = $channels;
289        let mut channels = [T::DEFAULT_MAX_VALUE; 4];
290        channels[0..CHANNELS].copy_from_slice(&self.0);
291        (channels[0], channels[1], channels[2], channels[3])
292    }
293
294    fn from_channels(a: T, b: T, c: T, d: T,) -> $ident<T> {
295        const CHANNELS: usize = $channels;
296        *<$ident<T> as Pixel>::from_slice(&[a, b, c, d][..CHANNELS])
297    }
298
299    fn from_slice(slice: &[T]) -> &$ident<T> {
300        assert_eq!(slice.len(), $channels);
301        unsafe { &*(slice.as_ptr() as *const $ident<T>) }
302    }
303    fn from_slice_mut(slice: &mut [T]) -> &mut $ident<T> {
304        assert_eq!(slice.len(), $channels);
305        unsafe { &mut *(slice.as_mut_ptr() as *mut $ident<T>) }
306    }
307
308    fn to_rgb(&self) -> Rgb<T> {
309        let mut pix = Rgb([Zero::zero(), Zero::zero(), Zero::zero()]);
310        pix.from_color(self);
311        pix
312    }
313
314    fn to_rgba(&self) -> Rgba<T> {
315        let mut pix = Rgba([Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero()]);
316        pix.from_color(self);
317        pix
318    }
319
320    fn to_luma(&self) -> Luma<T> {
321        let mut pix = Luma([Zero::zero()]);
322        pix.from_color(self);
323        pix
324    }
325
326    fn to_luma_alpha(&self) -> LumaA<T> {
327        let mut pix = LumaA([Zero::zero(), Zero::zero()]);
328        pix.from_color(self);
329        pix
330    }
331
332    fn map<F>(& self, f: F) -> $ident<T> where F: FnMut(T) -> T {
333        let mut this = (*self).clone();
334        this.apply(f);
335        this
336    }
337
338    fn apply<F>(&mut self, mut f: F) where F: FnMut(T) -> T {
339        for v in &mut self.0 {
340            *v = f(*v)
341        }
342    }
343
344    fn map_with_alpha<F, G>(&self, f: F, g: G) -> $ident<T> where F: FnMut(T) -> T, G: FnMut(T) -> T {
345        let mut this = (*self).clone();
346        this.apply_with_alpha(f, g);
347        this
348    }
349
350    fn apply_with_alpha<F, G>(&mut self, mut f: F, mut g: G) where F: FnMut(T) -> T, G: FnMut(T) -> T {
351        const ALPHA: usize = $channels - $alphas;
352        for v in self.0[..ALPHA].iter_mut() {
353            *v = f(*v)
354        }
355        if let Some(v) = self.0.get_mut(ALPHA) {
358            *v = g(*v)
359        }
360    }
361
362    fn map2<F>(&self, other: &Self, f: F) -> $ident<T> where F: FnMut(T, T) -> T {
363        let mut this = (*self).clone();
364        this.apply2(other, f);
365        this
366    }
367
368    fn apply2<F>(&mut self, other: &$ident<T>, mut f: F) where F: FnMut(T, T) -> T {
369        for (a, &b) in self.0.iter_mut().zip(other.0.iter()) {
370            *a = f(*a, b)
371        }
372    }
373
374    fn invert(&mut self) {
375        Invert::invert(self)
376    }
377
378    fn blend(&mut self, other: &$ident<T>) {
379        Blend::blend(self, other)
380    }
381}
382
383impl<T> Index<usize> for $ident<T> {
384    type Output = T;
385    #[inline(always)]
386    fn index(&self, _index: usize) -> &T {
387        &self.0[_index]
388    }
389}
390
391impl<T> IndexMut<usize> for $ident<T> {
392    #[inline(always)]
393    fn index_mut(&mut self, _index: usize) -> &mut T {
394        &mut self.0[_index]
395    }
396}
397
398impl<T> From<[T; $channels]> for $ident<T> {
399    fn from(c: [T; $channels]) -> Self {
400        Self(c)
401    }
402}
403
404)* }
407}
408
409define_colors! {
410    pub struct Rgb<T: Primitive Enlargeable>([T; 3, 0]) = "RGB";
415    pub struct Luma<T: Primitive>([T; 1, 0]) = "Y";
417    pub struct Rgba<T: Primitive Enlargeable>([T; 4, 1]) = "RGBA";
419    pub struct LumaA<T: Primitive>([T; 2, 1]) = "YA";
421}
422
423pub trait FromPrimitive<Component> {
425    fn from_primitive(component: Component) -> Self;
427}
428
429impl<T: Primitive> FromPrimitive<T> for T {
430    fn from_primitive(sample: T) -> Self {
431        sample
432    }
433}
434
435#[inline]
443fn normalize_float(float: f32, max: f32) -> f32 {
444    #[allow(clippy::neg_cmp_op_on_partial_ord)]
445    let clamped = if !(float < 1.0) { 1.0 } else { float.max(0.0) };
446    (clamped * max).round()
447}
448
449impl FromPrimitive<f32> for u8 {
450    fn from_primitive(float: f32) -> Self {
451        NumCast::from(normalize_float(float, u8::MAX as f32)).unwrap()
452    }
453}
454
455impl FromPrimitive<f32> for u16 {
456    fn from_primitive(float: f32) -> Self {
457        NumCast::from(normalize_float(float, u16::MAX as f32)).unwrap()
458    }
459}
460
461impl FromPrimitive<u16> for u8 {
464    fn from_primitive(c16: u16) -> Self {
465        fn from(c: impl Into<u32>) -> u32 {
466            c.into()
467        }
468        NumCast::from((from(c16) + 128) / 257).unwrap()
475    }
476}
477
478impl FromPrimitive<u16> for f32 {
479    fn from_primitive(int: u16) -> Self {
480        (int as f32 / u16::MAX as f32).clamp(0.0, 1.0)
481    }
482}
483
484impl FromPrimitive<u8> for f32 {
487    fn from_primitive(int: u8) -> Self {
488        (int as f32 / u8::MAX as f32).clamp(0.0, 1.0)
489    }
490}
491
492impl FromPrimitive<u8> for u16 {
493    fn from_primitive(c8: u8) -> Self {
494        let x = c8.to_u64().unwrap();
495        NumCast::from((x << 8) | x).unwrap()
496    }
497}
498
499pub trait FromColor<Other> {
501    #[allow(clippy::wrong_self_convention)]
503    fn from_color(&mut self, _: &Other);
504}
505
506pub(crate) trait IntoColor<Other> {
510    #[allow(clippy::wrong_self_convention)]
512    fn into_color(&self) -> Other;
513}
514
515impl<O, S> IntoColor<O> for S
516where
517    O: Pixel + FromColor<S>,
518{
519    #[allow(clippy::wrong_self_convention)]
520    fn into_color(&self) -> O {
521        #[allow(deprecated)]
524        let mut pix = O::from_channels(Zero::zero(), Zero::zero(), Zero::zero(), Zero::zero());
525        pix.from_color(self);
526        pix
527    }
528}
529
530const SRGB_LUMA: [u32; 3] = [2126, 7152, 722];
532const SRGB_LUMA_DIV: u32 = 10000;
533
534#[inline]
535fn rgb_to_luma<T: Primitive + Enlargeable>(rgb: &[T]) -> T {
536    let l = <T::Larger as NumCast>::from(SRGB_LUMA[0]).unwrap() * rgb[0].to_larger()
537        + <T::Larger as NumCast>::from(SRGB_LUMA[1]).unwrap() * rgb[1].to_larger()
538        + <T::Larger as NumCast>::from(SRGB_LUMA[2]).unwrap() * rgb[2].to_larger();
539    T::clamp_from(l / <T::Larger as NumCast>::from(SRGB_LUMA_DIV).unwrap())
540}
541
542impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Luma<T>
544where
545    T: FromPrimitive<S>,
546{
547    fn from_color(&mut self, other: &Luma<S>) {
548        let own = self.channels_mut();
549        let other = other.channels();
550        own[0] = T::from_primitive(other[0]);
551    }
552}
553
554impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Luma<T>
555where
556    T: FromPrimitive<S>,
557{
558    fn from_color(&mut self, other: &LumaA<S>) {
559        self.channels_mut()[0] = T::from_primitive(other.channels()[0]);
560    }
561}
562
563impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for Luma<T>
564where
565    T: FromPrimitive<S>,
566{
567    fn from_color(&mut self, other: &Rgb<S>) {
568        let gray = self.channels_mut();
569        let rgb = other.channels();
570        gray[0] = T::from_primitive(rgb_to_luma(rgb));
571    }
572}
573
574impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for Luma<T>
575where
576    T: FromPrimitive<S>,
577{
578    fn from_color(&mut self, other: &Rgba<S>) {
579        let gray = self.channels_mut();
580        let rgb = other.channels();
581        let l = rgb_to_luma(rgb);
582        gray[0] = T::from_primitive(l);
583    }
584}
585
586impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for LumaA<T>
589where
590    T: FromPrimitive<S>,
591{
592    fn from_color(&mut self, other: &LumaA<S>) {
593        let own = self.channels_mut();
594        let other = other.channels();
595        own[0] = T::from_primitive(other[0]);
596        own[1] = T::from_primitive(other[1]);
597    }
598}
599
600impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgb<S>> for LumaA<T>
601where
602    T: FromPrimitive<S>,
603{
604    fn from_color(&mut self, other: &Rgb<S>) {
605        let gray_a = self.channels_mut();
606        let rgb = other.channels();
607        gray_a[0] = T::from_primitive(rgb_to_luma(rgb));
608        gray_a[1] = T::DEFAULT_MAX_VALUE;
609    }
610}
611
612impl<S: Primitive + Enlargeable, T: Primitive> FromColor<Rgba<S>> for LumaA<T>
613where
614    T: FromPrimitive<S>,
615{
616    fn from_color(&mut self, other: &Rgba<S>) {
617        let gray_a = self.channels_mut();
618        let rgba = other.channels();
619        gray_a[0] = T::from_primitive(rgb_to_luma(rgba));
620        gray_a[1] = T::from_primitive(rgba[3]);
621    }
622}
623
624impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for LumaA<T>
625where
626    T: FromPrimitive<S>,
627{
628    fn from_color(&mut self, other: &Luma<S>) {
629        let gray_a = self.channels_mut();
630        gray_a[0] = T::from_primitive(other.channels()[0]);
631        gray_a[1] = T::DEFAULT_MAX_VALUE;
632    }
633}
634
635impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgba<T>
638where
639    T: FromPrimitive<S>,
640{
641    fn from_color(&mut self, other: &Rgba<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        own[3] = T::from_primitive(other[3]);
648    }
649}
650
651impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgba<T>
652where
653    T: FromPrimitive<S>,
654{
655    fn from_color(&mut self, other: &Rgb<S>) {
656        let rgba = &mut self.0;
657        let rgb = &other.0;
658        rgba[0] = T::from_primitive(rgb[0]);
659        rgba[1] = T::from_primitive(rgb[1]);
660        rgba[2] = T::from_primitive(rgb[2]);
661        rgba[3] = T::DEFAULT_MAX_VALUE;
662    }
663}
664
665impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgba<T>
666where
667    T: FromPrimitive<S>,
668{
669    fn from_color(&mut self, gray: &LumaA<S>) {
670        let rgba = &mut self.0;
671        let gray = &gray.0;
672        rgba[0] = T::from_primitive(gray[0]);
673        rgba[1] = T::from_primitive(gray[0]);
674        rgba[2] = T::from_primitive(gray[0]);
675        rgba[3] = T::from_primitive(gray[1]);
676    }
677}
678
679impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgba<T>
680where
681    T: FromPrimitive<S>,
682{
683    fn from_color(&mut self, gray: &Luma<S>) {
684        let rgba = &mut self.0;
685        let gray = gray.0[0];
686        rgba[0] = T::from_primitive(gray);
687        rgba[1] = T::from_primitive(gray);
688        rgba[2] = T::from_primitive(gray);
689        rgba[3] = T::DEFAULT_MAX_VALUE;
690    }
691}
692
693impl<S: Primitive, T: Primitive> FromColor<Rgb<S>> for Rgb<T>
696where
697    T: FromPrimitive<S>,
698{
699    fn from_color(&mut self, other: &Rgb<S>) {
700        let own = &mut self.0;
701        let other = &other.0;
702        own[0] = T::from_primitive(other[0]);
703        own[1] = T::from_primitive(other[1]);
704        own[2] = T::from_primitive(other[2]);
705    }
706}
707
708impl<S: Primitive, T: Primitive> FromColor<Rgba<S>> for Rgb<T>
709where
710    T: FromPrimitive<S>,
711{
712    fn from_color(&mut self, other: &Rgba<S>) {
713        let rgb = &mut self.0;
714        let rgba = &other.0;
715        rgb[0] = T::from_primitive(rgba[0]);
716        rgb[1] = T::from_primitive(rgba[1]);
717        rgb[2] = T::from_primitive(rgba[2]);
718    }
719}
720
721impl<S: Primitive, T: Primitive> FromColor<LumaA<S>> for Rgb<T>
722where
723    T: FromPrimitive<S>,
724{
725    fn from_color(&mut self, other: &LumaA<S>) {
726        let rgb = &mut self.0;
727        let gray = other.0[0];
728        rgb[0] = T::from_primitive(gray);
729        rgb[1] = T::from_primitive(gray);
730        rgb[2] = T::from_primitive(gray);
731    }
732}
733
734impl<S: Primitive, T: Primitive> FromColor<Luma<S>> for Rgb<T>
735where
736    T: FromPrimitive<S>,
737{
738    fn from_color(&mut self, other: &Luma<S>) {
739        let rgb = &mut self.0;
740        let gray = other.0[0];
741        rgb[0] = T::from_primitive(gray);
742        rgb[1] = T::from_primitive(gray);
743        rgb[2] = T::from_primitive(gray);
744    }
745}
746
747pub(crate) trait Blend {
749    fn blend(&mut self, other: &Self);
751}
752
753impl<T: Primitive> Blend for LumaA<T> {
754    fn blend(&mut self, other: &LumaA<T>) {
755        let max_t = T::DEFAULT_MAX_VALUE;
756        let max_t = max_t.to_f32().unwrap();
757        let (bg_luma, bg_a) = (self.0[0], self.0[1]);
758        let (fg_luma, fg_a) = (other.0[0], other.0[1]);
759
760        let (bg_luma, bg_a) = (
761            bg_luma.to_f32().unwrap() / max_t,
762            bg_a.to_f32().unwrap() / max_t,
763        );
764        let (fg_luma, fg_a) = (
765            fg_luma.to_f32().unwrap() / max_t,
766            fg_a.to_f32().unwrap() / max_t,
767        );
768
769        let alpha_final = bg_a + fg_a - bg_a * fg_a;
770        if alpha_final == 0.0 {
771            return;
772        };
773        let bg_luma_a = bg_luma * bg_a;
774        let fg_luma_a = fg_luma * fg_a;
775
776        let out_luma_a = fg_luma_a + bg_luma_a * (1.0 - fg_a);
777        let out_luma = out_luma_a / alpha_final;
778
779        *self = LumaA([
780            NumCast::from(max_t * out_luma).unwrap(),
781            NumCast::from(max_t * alpha_final).unwrap(),
782        ]);
783    }
784}
785
786impl<T: Primitive> Blend for Luma<T> {
787    fn blend(&mut self, other: &Luma<T>) {
788        *self = *other;
789    }
790}
791
792impl<T: Primitive> Blend for Rgba<T> {
793    fn blend(&mut self, other: &Rgba<T>) {
794        if other.0[3].is_zero() {
797            return;
798        }
799        if other.0[3] == T::DEFAULT_MAX_VALUE {
800            *self = *other;
801            return;
802        }
803
804        let max_t = T::DEFAULT_MAX_VALUE;
806        let max_t = max_t.to_f32().unwrap();
807        let (bg_r, bg_g, bg_b, bg_a) = (self.0[0], self.0[1], self.0[2], self.0[3]);
808        let (fg_r, fg_g, fg_b, fg_a) = (other.0[0], other.0[1], other.0[2], other.0[3]);
809        let (bg_r, bg_g, bg_b, bg_a) = (
810            bg_r.to_f32().unwrap() / max_t,
811            bg_g.to_f32().unwrap() / max_t,
812            bg_b.to_f32().unwrap() / max_t,
813            bg_a.to_f32().unwrap() / max_t,
814        );
815        let (fg_r, fg_g, fg_b, fg_a) = (
816            fg_r.to_f32().unwrap() / max_t,
817            fg_g.to_f32().unwrap() / max_t,
818            fg_b.to_f32().unwrap() / max_t,
819            fg_a.to_f32().unwrap() / max_t,
820        );
821
822        let alpha_final = bg_a + fg_a - bg_a * fg_a;
824        if alpha_final == 0.0 {
825            return;
826        };
827
828        let (bg_r_a, bg_g_a, bg_b_a) = (bg_r * bg_a, bg_g * bg_a, bg_b * bg_a);
830        let (fg_r_a, fg_g_a, fg_b_a) = (fg_r * fg_a, fg_g * fg_a, fg_b * fg_a);
831
832        let (out_r_a, out_g_a, out_b_a) = (
834            fg_r_a + bg_r_a * (1.0 - fg_a),
835            fg_g_a + bg_g_a * (1.0 - fg_a),
836            fg_b_a + bg_b_a * (1.0 - fg_a),
837        );
838
839        let (out_r, out_g, out_b) = (
841            out_r_a / alpha_final,
842            out_g_a / alpha_final,
843            out_b_a / alpha_final,
844        );
845
846        *self = Rgba([
848            NumCast::from(max_t * out_r).unwrap(),
849            NumCast::from(max_t * out_g).unwrap(),
850            NumCast::from(max_t * out_b).unwrap(),
851            NumCast::from(max_t * alpha_final).unwrap(),
852        ]);
853    }
854}
855
856impl<T: Primitive> Blend for Rgb<T> {
857    fn blend(&mut self, other: &Rgb<T>) {
858        *self = *other;
859    }
860}
861
862pub(crate) trait Invert {
864    fn invert(&mut self);
866}
867
868impl<T: Primitive> Invert for LumaA<T> {
869    fn invert(&mut self) {
870        let l = self.0;
871        let max = T::DEFAULT_MAX_VALUE;
872
873        *self = LumaA([max - l[0], l[1]]);
874    }
875}
876
877impl<T: Primitive> Invert for Luma<T> {
878    fn invert(&mut self) {
879        let l = self.0;
880
881        let max = T::DEFAULT_MAX_VALUE;
882        let l1 = max - l[0];
883
884        *self = Luma([l1]);
885    }
886}
887
888impl<T: Primitive> Invert for Rgba<T> {
889    fn invert(&mut self) {
890        let rgba = self.0;
891
892        let max = T::DEFAULT_MAX_VALUE;
893
894        *self = Rgba([max - rgba[0], max - rgba[1], max - rgba[2], rgba[3]]);
895    }
896}
897
898impl<T: Primitive> Invert for Rgb<T> {
899    fn invert(&mut self) {
900        let rgb = self.0;
901
902        let max = T::DEFAULT_MAX_VALUE;
903
904        let r1 = max - rgb[0];
905        let g1 = max - rgb[1];
906        let b1 = max - rgb[2];
907
908        *self = Rgb([r1, g1, b1]);
909    }
910}
911
912#[cfg(test)]
913mod tests {
914    use super::{Luma, LumaA, Pixel, Rgb, Rgba};
915
916    #[test]
917    fn test_apply_with_alpha_rgba() {
918        let mut rgba = Rgba([0, 0, 0, 0]);
919        rgba.apply_with_alpha(|s| s, |_| 0xFF);
920        assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
921    }
922
923    #[test]
924    fn test_apply_with_alpha_rgb() {
925        let mut rgb = Rgb([0, 0, 0]);
926        rgb.apply_with_alpha(|s| s, |_| panic!("bug"));
927        assert_eq!(rgb, Rgb([0, 0, 0]));
928    }
929
930    #[test]
931    fn test_map_with_alpha_rgba() {
932        let rgba = Rgba([0, 0, 0, 0]).map_with_alpha(|s| s, |_| 0xFF);
933        assert_eq!(rgba, Rgba([0, 0, 0, 0xFF]));
934    }
935
936    #[test]
937    fn test_map_with_alpha_rgb() {
938        let rgb = Rgb([0, 0, 0]).map_with_alpha(|s| s, |_| panic!("bug"));
939        assert_eq!(rgb, Rgb([0, 0, 0]));
940    }
941
942    #[test]
943    fn test_blend_luma_alpha() {
944        let a = &mut LumaA([255_u8, 255]);
945        let b = LumaA([255_u8, 255]);
946        a.blend(&b);
947        assert_eq!(a.0[0], 255);
948        assert_eq!(a.0[1], 255);
949
950        let a = &mut LumaA([255_u8, 0]);
951        let b = LumaA([255_u8, 255]);
952        a.blend(&b);
953        assert_eq!(a.0[0], 255);
954        assert_eq!(a.0[1], 255);
955
956        let a = &mut LumaA([255_u8, 255]);
957        let b = LumaA([255_u8, 0]);
958        a.blend(&b);
959        assert_eq!(a.0[0], 255);
960        assert_eq!(a.0[1], 255);
961
962        let a = &mut LumaA([255_u8, 0]);
963        let b = LumaA([255_u8, 0]);
964        a.blend(&b);
965        assert_eq!(a.0[0], 255);
966        assert_eq!(a.0[1], 0);
967    }
968
969    #[test]
970    fn test_blend_rgba() {
971        let a = &mut Rgba([255_u8, 255, 255, 255]);
972        let b = Rgba([255_u8, 255, 255, 255]);
973        a.blend(&b);
974        assert_eq!(a.0, [255, 255, 255, 255]);
975
976        let a = &mut Rgba([255_u8, 255, 255, 0]);
977        let b = Rgba([255_u8, 255, 255, 255]);
978        a.blend(&b);
979        assert_eq!(a.0, [255, 255, 255, 255]);
980
981        let a = &mut Rgba([255_u8, 255, 255, 255]);
982        let b = Rgba([255_u8, 255, 255, 0]);
983        a.blend(&b);
984        assert_eq!(a.0, [255, 255, 255, 255]);
985
986        let a = &mut Rgba([255_u8, 255, 255, 0]);
987        let b = Rgba([255_u8, 255, 255, 0]);
988        a.blend(&b);
989        assert_eq!(a.0, [255, 255, 255, 0]);
990    }
991
992    #[test]
993    fn test_apply_without_alpha_rgba() {
994        let mut rgba = Rgba([0, 0, 0, 0]);
995        rgba.apply_without_alpha(|s| s + 1);
996        assert_eq!(rgba, Rgba([1, 1, 1, 0]));
997    }
998
999    #[test]
1000    fn test_apply_without_alpha_rgb() {
1001        let mut rgb = Rgb([0, 0, 0]);
1002        rgb.apply_without_alpha(|s| s + 1);
1003        assert_eq!(rgb, Rgb([1, 1, 1]));
1004    }
1005
1006    #[test]
1007    fn test_map_without_alpha_rgba() {
1008        let rgba = Rgba([0, 0, 0, 0]).map_without_alpha(|s| s + 1);
1009        assert_eq!(rgba, Rgba([1, 1, 1, 0]));
1010    }
1011
1012    #[test]
1013    fn test_map_without_alpha_rgb() {
1014        let rgb = Rgb([0, 0, 0]).map_without_alpha(|s| s + 1);
1015        assert_eq!(rgb, Rgb([1, 1, 1]));
1016    }
1017
1018    macro_rules! test_lossless_conversion {
1019        ($a:ty, $b:ty, $c:ty) => {
1020            let a: $a = [<$a as Pixel>::Subpixel::DEFAULT_MAX_VALUE >> 2;
1021                <$a as Pixel>::CHANNEL_COUNT as usize]
1022                .into();
1023            let b: $b = a.into_color();
1024            let c: $c = b.into_color();
1025            assert_eq!(a.channels(), c.channels());
1026        };
1027    }
1028
1029    #[test]
1030    fn test_lossless_conversions() {
1031        use super::IntoColor;
1032        use crate::traits::Primitive;
1033
1034        test_lossless_conversion!(Luma<u8>, Luma<u16>, Luma<u8>);
1035        test_lossless_conversion!(LumaA<u8>, LumaA<u16>, LumaA<u8>);
1036        test_lossless_conversion!(Rgb<u8>, Rgb<u16>, Rgb<u8>);
1037        test_lossless_conversion!(Rgba<u8>, Rgba<u16>, Rgba<u8>);
1038    }
1039
1040    #[test]
1041    fn accuracy_conversion() {
1042        use super::{Luma, Pixel, Rgb};
1043        let pixel = Rgb::from([13, 13, 13]);
1044        let Luma([luma]) = pixel.to_luma();
1045        assert_eq!(luma, 13);
1046    }
1047}