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 "] 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 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, 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> Image { } } +/// Reverse columns of square image +/// # Safety +/// +/// UB if supplied image not square +unsafe fn crev>(mut img: Image) { + 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, const CHANNELS: usize> Image &[[u8; CHANNELS]] { + pub fn flatten(&self) -> &[[u8; CHANNELS]] { // SAFETY: buffer cannot have half pixels unsafe { self.buffer.as_chunks_unchecked::() } }