blended overlay

This commit is contained in:
bendn 2023-10-30 12:54:04 +07:00
parent 7c0e8a66c7
commit 47a299d9ae
No known key found for this signature in database
GPG key ID: 0D9D3A2A3B2A93D6
4 changed files with 58 additions and 5 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "fimg" name = "fimg"
version = "0.4.20" version = "0.4.21"
authors = ["bend-n <bend.n@outlook.com>"] authors = ["bend-n <bend.n@outlook.com>"]
license = "MIT" license = "MIT"
edition = "2021" edition = "2021"

View file

@ -10,10 +10,8 @@ quick simple image operations
- [x] image tiling - [x] image tiling
- [x] image scaling - [x] image scaling
- [x] triangle drawing - [x] triangle drawing
- [x] simple line drawing - [x] line drawing
- [x] box drawing - [x] box drawing
- [x] thick box drawing
- [x] thick line drawing
- [x] polygon drawing - [x] polygon drawing
- [x] circle drawing - [x] circle drawing
- [x] text drawing - [x] text drawing

View file

@ -36,7 +36,7 @@ pub mod pixels;
#[cfg(feature = "scale")] #[cfg(feature = "scale")]
pub mod scale; pub mod scale;
use cloner::ImageCloner; 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. /// like assert!(), but causes undefined behaviour at runtime when the condition is not met.
/// ///

View file

@ -1,7 +1,9 @@
//! Handles image overlay //! Handles image overlay
// TODO Y/YA
use crate::cloner::ImageCloner; use crate::cloner::ImageCloner;
use super::{assert_unchecked, Image}; use super::{assert_unchecked, Image};
use crate::pixels::Blend;
use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd}; use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd};
/// Trait for layering a image ontop of another, with a offset to the second image. /// 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` /// Think `magick a b -layers flatten a`
pub trait Overlay<W> { pub trait Overlay<W> {
/// Overlay with => self (does not blend) /// Overlay with => self (does not blend)
///
/// # Safety /// # Safety
/// ///
/// UB if a.width != b.width || a.height != b.height /// UB if a.width != b.width || a.height != b.height
unsafe fn overlay(&mut self, with: &W) -> &mut Self; 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 /// [`Overlay`] but owned
pub trait ClonerOverlay<const W: usize, const C: usize>: Sealed { pub trait ClonerOverlay<const W: usize, const C: usize>: Sealed {
/// Overlay with => self (does not blend) /// 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> { impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> {
#[inline] #[inline]
#[must_use = "function does not modify the original image"] #[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> { impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> {
#[inline] #[inline]
#[must_use = "function does not modify the original image"] #[must_use = "function does not modify the original image"]