diff --git a/src/color.rs b/src/color.rs index 2002a27f14..4c1b768879 100644 --- a/src/color.rs +++ b/src/color.rs @@ -364,6 +364,37 @@ impl Pixel for $ident { } } + fn map2_with_alpha(&self, other: &Self, f: F, g: G) -> $ident where F: FnMut(T, T) -> T, G: FnMut(T, T) -> T { + let mut this = (*self).clone(); + this.apply2_with_alpha(other, f, g); + this + } + + fn apply2_with_alpha(&mut self, other: &$ident, mut f: F, mut g: G) where F: FnMut(T, T) -> T, G: FnMut(T, T) -> T { + const ALPHA: usize = $channels - $alphas; + for (a, &b) in self.0[..ALPHA].iter_mut().zip(other.0[..ALPHA].iter()) { + *a = f(*a, b) + } + // The branch of this match is `const`. This way ensures that no subexpression fails the + // `const_err` lint (the expression `self.0[ALPHA]` would). + if let (Some(a), Some(b)) = (self.0.get_mut(ALPHA), other.0.get(ALPHA)) { + *a = g(*a, *b) + } + } + + fn map2_without_alpha(&self, other: &Self, f: F) -> $ident where F: FnMut(T, T) -> T { + let mut this = (*self).clone(); + this.apply2_without_alpha(other, f); + this + } + + fn apply2_without_alpha(&mut self, other: &$ident, mut f: F) where F: FnMut(T, T) -> T { + const ALPHA: usize = $channels - $alphas; + for (a, &b) in self.0[..ALPHA].iter_mut().zip(other.0[..ALPHA].iter()) { + *a = f(*a, b) + } + } + fn invert(&mut self) { Invert::invert(self) } @@ -924,6 +955,63 @@ mod tests { assert_eq!(rgb, Rgb([0, 0, 0])); } + #[test] + fn test_apply2_with_alpha_rgba() { + let mut rgba = Rgba([1, 2, 3, 64]); + rgba.apply2_with_alpha(&Rgba([4, 5, 6, 128]), |s, o| s + o, |s, o| (s + o) / 2); + assert_eq!(rgba, Rgba([5, 7, 9, 96])); + } + + #[test] + fn test_apply2_with_alpha_rgb() { + let mut rgb = Rgb([1, 2, 3]); + rgb.apply2_with_alpha(&Rgb([4, 5, 6]), |s, o| s + o, |_s, _o| panic!("bug")); + assert_eq!(rgb, Rgb([5, 7, 9])); + } + + #[test] + fn test_map2_with_alpha_rgba() { + let rgba = Rgba([1, 2, 3, 64]).map2_with_alpha( + &Rgba([4, 5, 6, 128]), + |s, o| s + o, + |s, o| (s + o) / 2, + ); + assert_eq!(rgba, Rgba([5, 7, 9, 96])); + } + + #[test] + fn test_map2_with_alpha_rgb() { + let rgb = + Rgb([1, 2, 3]).map2_with_alpha(&Rgb([4, 5, 6]), |s, o| s + o, |_s, _o| panic!("bug")); + assert_eq!(rgb, Rgb([5, 7, 9])); + } + + #[test] + fn test_apply2_without_alpha_rgba() { + let mut rgba = Rgba([1, 2, 3, 64]); + rgba.apply2_without_alpha(&Rgba([4, 5, 6, 128]), |s, o| s + o); + assert_eq!(rgba, Rgba([5, 7, 9, 64])); + } + + #[test] + fn test_apply2_without_alpha_rgb() { + let mut rgb = Rgb([1, 2, 3]); + rgb.apply2_without_alpha(&Rgb([4, 5, 6]), |s, o| s + o); + assert_eq!(rgb, Rgb([5, 7, 9])); + } + + #[test] + fn test_map2_without_alpha_rgba() { + let rgba = Rgba([1, 2, 3, 64]).map2_without_alpha(&Rgba([4, 5, 6, 128]), |s, o| s + o); + assert_eq!(rgba, Rgba([5, 7, 9, 64])); + } + + #[test] + fn test_map2_without_alpha_rgb() { + let rgb = Rgb([1, 2, 3]).map2_without_alpha(&Rgb([4, 5, 6]), |s, o| s + o); + assert_eq!(rgb, Rgb([5, 7, 9])); + } + #[test] fn test_blend_luma_alpha() { let a = &mut LumaA([255_u8, 255]); diff --git a/src/traits.rs b/src/traits.rs index a993a3350c..8b13602407 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -356,6 +356,35 @@ pub trait Pixel: Copy + Clone { where F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel; + /// Apply the function ```f``` to each channel except alpha channel. + /// Apply the function ```g``` to the alpha channel. + fn map2_with_alpha(&self, other: &Self, f: F, g: G) -> Self + where + F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel, + G: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel; + + /// Apply the function ```f``` to each channel (except alpha) of this + /// pixel and ```other``` pairwise. Then apply the function ```g``` to + /// the alpha channel of this pixel and ```other``` pairwise. + /// + /// Works in place. + fn apply2_with_alpha(&mut self, other: &Self, f: F, g: G) + where + F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel, + G: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel; + + /// Apply the function ```f``` to each channel except the alpha channel, + /// of this pixel and ```other``` pairwise. + fn map2_without_alpha(&self, other: &Self, f: F) -> Self + where + F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel; + + /// Apply the function ```f``` to each channel except the alpha channel, + /// of this pixel and ```other``` pairwise. Works in place. + fn apply2_without_alpha(&mut self, other: &Self, f: F) + where + F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel; + /// Invert this pixel fn invert(&mut self);