fast image operations
-rw-r--r--Cargo.toml2
-rw-r--r--src/cloner.rs2
-rw-r--r--src/dyn/mod.rs41
-rw-r--r--src/lib.rs15
-rw-r--r--src/overlay.rs120
5 files changed, 171 insertions, 9 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 59e208d..8d6372a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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]> {
diff --git a/src/lib.rs b/src/lib.rs
index 4083126..2da59cc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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
+ }
+}