diff --git a/Cargo.toml b/Cargo.toml index dfa3cdf..14421ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fimg" -version = "0.4.20" +version = "0.4.21" authors = ["bend-n "] license = "MIT" edition = "2021" diff --git a/README.md b/README.md index bc312b3..7ad63a6 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,8 @@ quick simple image operations - [x] image tiling - [x] image scaling - [x] triangle drawing -- [x] simple line drawing +- [x] line drawing - [x] box drawing -- [x] thick box drawing -- [x] thick line drawing - [x] polygon drawing - [x] circle drawing - [x] text drawing \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 53ae5d7..e1c8249 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ pub mod pixels; #[cfg(feature = "scale")] pub mod scale; use cloner::ImageCloner; -pub use overlay::{ClonerOverlay, ClonerOverlayAt, Overlay, OverlayAt}; +pub use overlay::{BlendingOverlay, ClonerOverlay, ClonerOverlayAt, Overlay, OverlayAt}; /// like assert!(), but causes undefined behaviour at runtime when the condition is not met. /// 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: Sealed { /// Think `magick a b -layers flatten a` pub trait Overlay { /// 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 { + /// 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: Sealed { /// Overlay with => self (does not blend) @@ -116,6 +129,26 @@ impl + AsRef<[u8]>, U: AsRef<[u8]>> Overlay> for Imag } } +impl BlendingOverlay> 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 + AsRef<[u8]>, U: AsRef<[u8]>> Overlay> for Imag } } +impl + AsRef<[u8]>, U: AsRef<[u8]>> BlendingOverlay> for Image { + #[inline] + unsafe fn overlay_blended(&mut self, with: &Image) -> &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"]