fast image operations
Diffstat (limited to 'src/overlay.rs')
| -rw-r--r-- | src/overlay.rs | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/src/overlay.rs b/src/overlay.rs index fca17bb..d364a76 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -1,7 +1,9 @@ //! Handles image overlay +// TODO Y/YA use crate::cloner::ImageCloner; use super::{assert_unchecked, Image}; +use crate::pixels::Blend; use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd}; /// Trait for layering a image ontop of another, with a offset to the second image. @@ -34,12 +36,23 @@ pub trait ClonerOverlayAt<const W: usize, const C: usize>: Sealed { /// Think `magick a b -layers flatten a` pub trait Overlay<W> { /// Overlay with => self (does not blend) + /// /// # Safety /// /// UB if a.width != b.width || a.height != b.height unsafe fn overlay(&mut self, with: &W) -> &mut Self; } +/// This blends the images together, like [`imageops::overlay`](https://docs.rs/image/latest/image/imageops/fn.overlay.html). +pub trait BlendingOverlay<W> { + /// Overlay with => self, blending. You probably do not need this, unless your images make much usage of alpha. + /// If you only have 2 alpha states, `0` | `255` (transparent | opaque), please use [`Overlay`], as it is much faster. + /// # Safety + /// + /// UB if a.width != b.width || a.height != b.height + unsafe fn overlay_blended(&mut self, with: &W) -> &mut Self; +} + /// [`Overlay`] but owned pub trait ClonerOverlay<const W: usize, const C: usize>: Sealed { /// Overlay with => self (does not blend) @@ -116,6 +129,26 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Imag } } +impl BlendingOverlay<Image<&[u8], 4>> for Image<&mut [u8], 4> { + #[inline] + unsafe fn overlay_blended(&mut self, with: &Image<&[u8], 4>) -> &mut Self { + debug_assert!(self.width() == with.width()); + debug_assert!(self.height() == with.height()); + for (i, other_pixels) in with.chunked().enumerate() { + // SAFETY: caller assures us, all is well. + let own_pixels = unsafe { + &mut *(self + .buffer + .as_mut() + .get_unchecked_mut(i * 4..i * 4 + 4) + .as_mut_ptr() as *mut [u8; 4]) + }; + own_pixels.blend(*other_pixels); + } + self + } +} + impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> { #[inline] #[must_use = "function does not modify the original image"] @@ -226,6 +259,28 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Imag } } +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> BlendingOverlay<Image<U, 4>> for Image<T, 3> { + #[inline] + unsafe fn overlay_blended(&mut self, with: &Image<U, 4>) -> &mut Self { + debug_assert!(self.width() == with.width()); + debug_assert!(self.height() == with.height()); + for (i, other_pixels) in with.chunked().enumerate() { + // SAFETY: caller assures us, all is well. + let [r, g, b] = unsafe { + &mut *(self + .buffer + .as_mut() + .get_unchecked_mut(i * 3..i * 3 + 3) + .as_mut_ptr() as *mut [u8; 3]) + }; + let mut us = [*r, *g, *b, 255]; + us.blend(*other_pixels); + (*r, *g, *b) = (us[0], us[1], us[2]); + } + self + } +} + impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> { #[inline] #[must_use = "function does not modify the original image"] |