fast image operations
enhance dynimage experience
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/cloner.rs | 2 | ||||
| -rw-r--r-- | src/dyn/mod.rs | 41 | ||||
| -rw-r--r-- | src/lib.rs | 15 | ||||
| -rw-r--r-- | src/overlay.rs | 120 |
5 files changed, 171 insertions, 9 deletions
@@ -1,6 +1,6 @@ [package] name = "fimg" -version = "0.4.46" +version = "0.4.47" authors = ["bend-n <[email protected]>"] license = "MIT" edition = "2024" diff --git a/src/cloner.rs b/src/cloner.rs index f110c1c..0d92db7 100644 --- a/src/cloner.rs +++ b/src/cloner.rs @@ -5,7 +5,7 @@ //! # let i = Image::<_, 1>::alloc(5, 5); //! unsafe { i.cloner().rot_270() }; //! ``` -use crate::{uninit, Image}; +use crate::{Image, uninit}; /// A neat way to clone a image. /// diff --git a/src/dyn/mod.rs b/src/dyn/mod.rs index ccf19f9..2688160 100644 --- a/src/dyn/mod.rs +++ b/src/dyn/mod.rs @@ -1,4 +1,4 @@ -use crate::{pixels::convert::PFrom, Image}; +use crate::{Image, pixels::convert::PFrom}; mod affine; mod convert; #[cfg(feature = "scale")] @@ -20,6 +20,30 @@ pub enum DynImage<T> { impl Copy for DynImage<&[u8]> {} +impl<T> const From<Image<T, 1>> for DynImage<T> { + fn from(x: Image<T, 1>) -> Self { + Self::Y(x) + } +} + +impl<T> const From<Image<T, 2>> for DynImage<T> { + fn from(x: Image<T, 2>) -> Self { + Self::Ya(x) + } +} + +impl<T> const From<Image<T, 3>> for DynImage<T> { + fn from(x: Image<T, 3>) -> Self { + Self::Rgb(x) + } +} + +impl<T> const From<Image<T, 4>> for DynImage<T> { + fn from(x: Image<T, 4>) -> Self { + Self::Rgba(x) + } +} + macro_rules! e { ($dyn:expr => |$image: pat_param| $do:expr) => { match $dyn { @@ -38,7 +62,7 @@ macro_rules! e { } }; } -use e; +pub(crate) use e; #[cfg(feature = "term")] impl<T: AsRef<[u8]>> std::fmt::Display for crate::term::Display<DynImage<T>> { @@ -72,6 +96,12 @@ impl<T> DynImage<T> { e!(self, |i| i.height()) } + #[doc(hidden)] + pub unsafe fn mapped<U, F: FnOnce(T) -> U>(self, f: F) -> DynImage<U> { + // SAFETY: we dont change anything, why check + unsafe { e!(self => |i| i.mapped(f)) } + } + /// Get the image buffer. pub const fn buffer(&self) -> &T { e!(self, |i| i.buffer()) @@ -83,6 +113,13 @@ impl<T> DynImage<T> { } } +impl DynImage<&[u8]> { + /// Copy this ref image + pub fn copy(&self) -> Self { + e!(self => |i| i.copy()) + } +} + impl<T: AsRef<[u8]>> DynImage<T> { /// Reference this image. pub fn as_ref(&self) -> DynImage<&[u8]> { @@ -58,12 +58,13 @@ generic_const_exprs, proc_macro_hygiene, iter_array_chunks, + const_trait_impl, core_intrinsics, rustc_private, portable_simd, array_windows, doc_auto_cfg, - iter_chain, + const_from, try_blocks, test )] @@ -162,7 +163,7 @@ impl At for (u32, u32) { } } -impl Image<&[u8], 3> { +impl<T: AsRef<[u8]>> Image<T, 3> { /// Tile self till it fills a new image of size x, y /// # Safety /// @@ -185,6 +186,7 @@ impl Image<&[u8], 3> { // SAFETY: get one row of pixels let from = unsafe { self.buffer + .as_ref() .get_unchecked(self.at(0, y)..self.at(0, y) + (self.width() as usize * 3)) }; debug_assert_eq!(from.len(), self.width() as usize * 3); @@ -253,6 +255,11 @@ impl<T: Clone, const CHANNELS: usize> Clone for Image<T, CHANNELS> { } impl<T, const CHANNELS: usize> Image<T, CHANNELS> { + #[doc(hidden)] + pub const fn channels(&self) -> usize { + CHANNELS + } + #[inline] /// get the height as a [`u32`] pub const fn height(&self) -> u32 { @@ -321,8 +328,8 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> { // SAFETY: we dont change anything, why check unsafe { self.with(f(self.buffer())) } } - - unsafe fn mapped<U, const N: usize, F: FnOnce(T) -> U>(self, f: F) -> Image<U, N> { + #[doc(hidden)] + pub unsafe fn mapped<U, const N: usize, F: FnOnce(T) -> U>(self, f: F) -> Image<U, N> { // SAFETY: we dont change anything, why check unsafe { Image::new(self.width, self.height, f(self.buffer)) } } diff --git a/src/overlay.rs b/src/overlay.rs index 08f3caf..3027808 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -1,6 +1,6 @@ //! Handles image overlay // TODO Y/YA -use crate::{cloner::ImageCloner, uninit}; +use crate::{DynImage, cloner::ImageCloner, uninit}; use super::{Image, assert_unchecked}; use crate::pixels::Blend; @@ -278,6 +278,95 @@ impl<U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for uninit::Image<u8, 3> { } } +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 1>> for Image<T, 3> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + /// this impl doesnt make much sense without a color. + unsafe fn overlay_at(&mut self, with: &Image<U, 1>, x: u32, y: u32) -> &mut Self { + for j in 0..with.height() { + for i in 0..with.width() { + // SAFETY: i, j is in bounds. + let &[their_px] = unsafe { &with.pixel(i, j) }; + let our_px = unsafe { self.pixel_mut(i + x, j + y) }; + our_px.copy_from_slice(&[their_px; 3]); + } + } + self + } +} + +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 2>> for Image<T, 3> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + /// this impl doesnt make much sense without a color. + unsafe fn overlay_at(&mut self, with: &Image<U, 2>, x: u32, y: u32) -> &mut Self { + for j in 0..with.height() { + for i in 0..with.width() { + // SAFETY: i, j is in bounds. + let &[their_px, a] = unsafe { &with.pixel(i, j) }; + if a >= 128 { + let our_px = unsafe { self.pixel_mut(i + x, j + y) }; + our_px.copy_from_slice(&[their_px; 3]); + } + } + } + self + } +} + +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 1>> for Image<T, 4> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + /// this impl doesnt make much sense without a color. + unsafe fn overlay_at(&mut self, with: &Image<U, 1>, x: u32, y: u32) -> &mut Self { + for j in 0..with.height() { + for i in 0..with.width() { + // SAFETY: i, j is in bounds. + let &[their_px] = unsafe { &with.pixel(i, j) }; + let our_px = unsafe { self.pixel_mut(i + x, j + y) }; + our_px.copy_from_slice(&[their_px; 4]); + } + } + self + } +} + +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 2>> for Image<T, 4> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + /// this impl doesnt make much sense without a color. + unsafe fn overlay_at(&mut self, with: &Image<U, 2>, x: u32, y: u32) -> &mut Self { + for j in 0..with.height() { + for i in 0..with.width() { + // SAFETY: i, j is in bounds. + let &[their_px, a] = unsafe { &with.pixel(i, j) }; + if a >= 128 { + let our_px = unsafe { self.pixel_mut(i + x, j + y) }; + our_px.copy_from_slice(&[their_px; 4]); + } + } + } + self + } +} + +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for Image<T, 4> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + /// its not a optimized impl + unsafe fn overlay_at(&mut self, with: &Image<U, 3>, x: u32, y: u32) -> &mut Self { + for j in 0..with.height() { + for i in 0..with.width() { + // SAFETY: i, j is in bounds. + let their_px = unsafe { &with.pixel(i, j) }; + let our_px = unsafe { self.pixel_mut(i + x, j + y) }; + our_px.copy_from_slice(their_px); + } + } + self + } +} + impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for Image<T, 3> { /// Overlay a RGB image(with) => self at coordinates x, y. /// As this is a `RGBxRGB` operation, blending is unnecessary, @@ -398,3 +487,32 @@ impl ClonerOverlayAt<4, 4> for ImageCloner<'_, 4> { out } } + +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<DynImage<U>> for Image<T, 3> { + unsafe fn overlay_at(&mut self, with: &DynImage<U>, x: u32, y: u32) -> &mut Self { + crate::r#dyn::e!(with, |with| unsafe { + self.overlay_at(with, x, y); + }); + self + } +} + +impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<DynImage<U>> for Image<T, 4> { + unsafe fn overlay_at(&mut self, with: &DynImage<U>, x: u32, y: u32) -> &mut Self { + crate::r#dyn::e!(with, |with| unsafe { + self.overlay_at(with, x, y); + }); + self + } +} + +impl<U: AsRef<[u8]>> OverlayAt<DynImage<U>> for uninit::Image<u8, 3> { + unsafe fn overlay_at(&mut self, with: &DynImage<U>, x: u32, y: u32) -> &mut Self { + match with { + DynImage::Rgb(with) => unsafe { self.overlay_at(with, x, y) }, + DynImage::Rgba(with) => unsafe { self.overlay_at(with, x, y) }, + _ => unimplemented!(), + }; + self + } +} |