fast image operations
transpose out of place for rot_90 cloner
bendn 2023-10-02
parent ed92acb · commit f863d29
-rw-r--r--Cargo.toml3
-rw-r--r--benches/affine_transformations.rs26
-rw-r--r--src/affine.rs33
-rw-r--r--src/lib.rs5
4 files changed, 54 insertions, 13 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 3ade076..eaf4649 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "fimg"
-version = "0.4.12"
+version = "0.4.13"
authors = ["bend-n <[email protected]>"]
license = "MIT"
edition = "2021"
@@ -9,6 +9,7 @@ repository = "https://github.com/bend-n/fimg"
exclude = ["tdata", "benches/", ".gitignore"]
[dependencies]
+mattr = "0.0.2"
png = { version = "0.17", features = ["unstable"], optional = true }
[dev-dependencies]
diff --git a/benches/affine_transformations.rs b/benches/affine_transformations.rs
index 74742e1..0899900 100644
--- a/benches/affine_transformations.rs
+++ b/benches/affine_transformations.rs
@@ -1,7 +1,7 @@
use fimg::*;
macro_rules! bench {
- (fn $name: ident() { run $fn: ident() }) => {
+ (fn $name: ident() { run $fn: ident() } $($namec:ident)?) => {
fn $name() {
let mut img: Image<_, 4> =
Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf").to_vec());
@@ -12,12 +12,24 @@ macro_rules! bench {
};
}
}
+
+ $(fn $namec() {
+ let img: Image<&[u8], 4> =
+ Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf"));
+ #[allow(unused_unsafe)]
+ unsafe {
+ std::hint::black_box(img.cloner().$fn())
+ };
+ })?
};
}
-bench!(fn flip_h() { run flip_h() });
-bench!(fn flip_v() { run flip_v() });
-bench!(fn rotate_90() { run rot_90() });
-bench!(fn rotate_180() { run rot_180() });
-bench!(fn rotate_270() { run rot_270() });
-iai::main!(flip_h, flip_v, rotate_90, rotate_180, rotate_270);
+bench!(fn flip_h() { run flip_h() } flip_hc);
+bench!(fn flip_v() { run flip_v() } flip_vc);
+bench!(fn rotate_90() { run rot_90() } rot_90c);
+bench!(fn rotate_180() { run rot_180() } rot_180c);
+bench!(fn rotate_270() { run rot_270() } rot_280c);
+iai::main!(
+ flip_h, flip_v, rotate_90, rotate_180, rotate_270, flip_hc, flip_vc, rot_90c, rot_180c,
+ rot_280c
+);
diff --git a/src/affine.rs b/src/affine.rs
index f4c311e..b03dbba 100644
--- a/src/affine.rs
+++ b/src/affine.rs
@@ -107,9 +107,18 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
/// UB if the image is not square
#[must_use = "function does not modify the original image"]
pub unsafe fn rot_90(&self) -> Image<Vec<u8>, CHANNELS> {
- let mut out = self.flip_v();
+ let mut out = self.alloc();
+ // SAFETY: yep
+ unsafe {
+ mattr::transpose(
+ self.flatten(),
+ out.flatten_mut(),
+ self.height() as usize,
+ self.width() as usize,
+ )
+ };
// SAFETY: sqar
- unsafe { transpose(&mut out.as_mut()) };
+ unsafe { crev(out.as_mut()) };
out
}
@@ -157,6 +166,26 @@ impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> {
}
}
+/// Reverse columns of square image
+/// # Safety
+///
+/// UB if supplied image not square
+unsafe fn crev<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(mut img: Image<T, CHANNELS>) {
+ debug_assert_eq!(img.width(), img.height());
+ let size = img.width() as usize;
+ let b = img.flatten_mut();
+ for i in 0..size {
+ let mut start = 0;
+ let mut end = size - 1;
+ while start < end {
+ // SAFETY: hmm
+ unsafe { b.swap_unchecked(i * size + start, i * size + end) };
+ start += 1;
+ end -= 1;
+ }
+ }
+}
+
/// Transpose a square image
/// # Safety
///
diff --git a/src/lib.rs b/src/lib.rs
index 74469db..8049973 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,8 +10,7 @@
portable_simd,
array_windows,
const_option,
- array_chunks,
- test
+ array_chunks
)]
#![warn(
clippy::missing_docs_in_private_items,
@@ -300,7 +299,7 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
#[inline]
/// Flatten the chunks of this image into a slice of slices.
- pub fn flatten(&mut self) -> &[[u8; CHANNELS]] {
+ pub fn flatten(&self) -> &[[u8; CHANNELS]] {
// SAFETY: buffer cannot have half pixels
unsafe { self.buffer.as_chunks_unchecked::<CHANNELS>() }
}