fast image operations
clipper
bendn 7 weeks ago
parent 6db604c · commit 2edce8d
-rw-r--r--Cargo.toml2
-rw-r--r--LICENSE2
-rw-r--r--src/dyn/mod.rs3
-rw-r--r--src/lib.rs5
-rw-r--r--src/overlay.rs63
5 files changed, 55 insertions, 20 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 10fedc0..4107be0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "fimg"
-version = "0.4.52"
+version = "0.4.53"
authors = ["bend-n <[email protected]>"]
license = "MIT"
edition = "2024"
diff --git a/LICENSE b/LICENSE
index 2f002a4..8c33164 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2024 bendn
+Copyright (c) 2026 bendn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/src/dyn/mod.rs b/src/dyn/mod.rs
index c36a7c1..5c93720 100644
--- a/src/dyn/mod.rs
+++ b/src/dyn/mod.rs
@@ -4,7 +4,8 @@ mod convert;
#[cfg(feature = "scale")]
mod scale;
-#[derive(Clone, Debug, PartialEq, Hash)]
+#[derive(Clone, Debug, Hash)]
+#[derive_const(PartialEq)]
/// Dynamic image.
/// Can be any of {`Y8`, `YA8`, `RGB8`, `RGB16`}.
pub enum DynImage<T> {
diff --git a/src/lib.rs b/src/lib.rs
index 447aea0..5668841 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -63,7 +63,9 @@
rustc_private,
portable_simd,
const_convert,
+ derive_const,
try_blocks,
+ const_cmp,
doc_cfg,
test
)]
@@ -214,7 +216,8 @@ impl<T: AsRef<[u8]>> Image<T, 3> {
}
/// A image with a variable number of channels, and a nonzero size.
-#[derive(Debug, PartialEq, Eq, Hash)]
+#[derive(Debug, Eq, Hash)]
+#[derive_const(PartialEq)]
#[repr(C)]
pub struct Image<T, const CHANNELS: usize> {
/// column order 2d slice/vec
diff --git a/src/overlay.rs b/src/overlay.rs
index 0725453..1823899 100644
--- a/src/overlay.rs
+++ b/src/overlay.rs
@@ -384,25 +384,44 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 2>> for Im
}
}
-impl<const N: usize, T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAtClipping<Image<U, N>>
- for Image<T, N>
-{
- #[inline]
- #[cfg_attr(debug_assertions, track_caller)]
- fn clipping_overlay_at(&mut self, with: &Image<U, N>, x: u32, y: u32) -> &mut Self {
- for j in 0..with.height() {
- for i in 0..with.width() {
- // SAFETY: i, j is in bounds.
- if let Some(their_px) = with.get_pixel(i, j)
- && let Some(our_px) = self.get_pixel_mut(i + x, j + y)
- {
- our_px.copy_from_slice(their_px);
+fn coerce<T, U, F: FnMut(T, U)>(f: F) -> F {
+ f
+}
+macro_rules! imp {
+ ($N1:literal => $N2:literal, $conv:expr) => {
+ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAtClipping<Image<U, $N1>>
+ for Image<T, $N2>
+ {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn clipping_overlay_at(&mut self, with: &Image<U, $N1>, x: u32, y: u32) -> &mut Self {
+ for j in 0..with.height() {
+ for i in 0..with.width() {
+ // SAFETY: i, j is in bounds.
+ if let Some(their_px) = with.get_pixel(i, j)
+ && let Some(our_px) = self.get_pixel_mut(i + x, j + y)
+ {
+ (coerce::<&mut [u8; $N2], &[u8; $N1], _>($conv))(our_px, their_px);
+ }
+ }
}
+ self
}
}
- self
- }
-}
+ };
+}
+imp!(1 => 1, |a, b| a.copy_from_slice(b));
+imp!(2 => 2, |a, b| a.copy_from_slice(b));
+imp!(3 => 3, |a, b| a.copy_from_slice(b));
+imp!(4 => 4, |a, b| a.copy_from_slice(b));
+imp!(4 => 3, |a, b| if b[3] > 128 { a.copy_from_slice(&b[..3]) });
+imp!(1 => 4, |a, [b]| a.copy_from_slice(&[*b;4]));
+imp!(1 => 3, |a, [b]| a.copy_from_slice(&[*b;3]));
+imp!(2 => 3, |a, [b, y]| if *y > 128 { a.copy_from_slice(&[*b;3]) });
+imp!(2 => 4, |a, [b, y]| if *y > 128 { a.copy_from_slice(&[*b;3].join(255)); });
+use atools::Join;
+imp!(3 => 4, |a, b| a.copy_from_slice(&(*b).join(255)));
+
impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for Image<T, 4> {
#[inline]
#[cfg_attr(debug_assertions, track_caller)]
@@ -549,6 +568,18 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<DynImage<U>> for Im
self
}
}
+impl<T: AsRef<[u8]>, U: AsRef<[u8]> + AsMut<[u8]>> OverlayAtClipping<DynImage<T>> for Image<U, 3> {
+ fn clipping_overlay_at(&mut self, with: &DynImage<T>, x: u32, y: u32) -> &mut Self {
+ crate::r#dyn::e!(with, |with| { self.clipping_overlay_at(with, x, y) });
+ self
+ }
+}
+impl<T: AsRef<[u8]>, U: AsRef<[u8]> + AsMut<[u8]>> OverlayAtClipping<DynImage<T>> for Image<U, 4> {
+ fn clipping_overlay_at(&mut self, with: &DynImage<T>, x: u32, y: u32) -> &mut Self {
+ crate::r#dyn::e!(with, |with| { self.clipping_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 {