use zune_core::bit_depth::BitType;
use zune_image::errors::ImageErrors;
use zune_image::image::Image;
use zune_image::traits::OperationsTrait;
#[derive(Default)]
pub struct Flip;
impl Flip {
#[must_use]
pub fn new() -> Flip {
Self
}
}
impl OperationsTrait for Flip {
fn name(&self) -> &'static str {
"Flip"
}
fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors> {
let depth = image.depth();
for inp in image.channels_mut(false) {
match depth.bit_type() {
BitType::U8 => {
flip(inp.reinterpret_as_mut::<u8>()?);
}
BitType::U16 => {
flip(inp.reinterpret_as_mut::<u16>()?);
}
BitType::F32 => {
flip(inp.reinterpret_as_mut::<f32>()?);
}
d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)),
}
}
Ok(())
}
fn supported_types(&self) -> &'static [BitType] {
&[BitType::U8, BitType::U16, BitType::F32]
}
}
#[derive(Default)]
pub struct VerticalFlip;
impl VerticalFlip {
#[must_use]
pub fn new() -> VerticalFlip {
Self
}
}
impl OperationsTrait for VerticalFlip {
fn name(&self) -> &'static str {
"Vertical Flip"
}
fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors> {
let depth = image.depth();
let width = image.dimensions().0;
for inp in image.channels_mut(false) {
match depth.bit_type() {
BitType::U8 => {
vertical_flip(inp.reinterpret_as_mut::<u8>()?, width);
}
BitType::U16 => {
vertical_flip(inp.reinterpret_as_mut::<u16>()?, width);
}
BitType::F32 => {
vertical_flip(inp.reinterpret_as_mut::<f32>()?, width);
}
d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)),
}
}
Ok(())
}
fn supported_types(&self) -> &'static [BitType] {
&[BitType::U8, BitType::U16, BitType::F32]
}
}
pub fn flip<T: Copy>(in_out_image: &mut [T]) {
let length = in_out_image.len() / 2;
let (in_img_top, in_img_bottom) = in_out_image.split_at_mut(length);
for (in_dim, out_dim) in in_img_top.iter_mut().zip(in_img_bottom.iter_mut().rev()) {
std::mem::swap(in_dim, out_dim);
}
}
pub fn vertical_flip<T: Copy + Default>(channel: &mut [T], width: usize) {
let len = channel.len();
let (top, bottom) = channel.split_at_mut(len / 2);
let mut stride = vec![T::default(); width];
for (t, b) in top
.chunks_exact_mut(width)
.zip(bottom.rchunks_exact_mut(width))
{
stride.copy_from_slice(t);
t.copy_from_slice(b);
b.copy_from_slice(&stride);
}
}
#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod benchmarks {
extern crate test;
use crate::flip::flip;
#[bench]
fn flip_scalar(b: &mut test::Bencher) {
let width = 800;
let height = 800;
let dimensions = width * height;
let mut c1 = vec![0_u16; dimensions];
b.iter(|| {
flip(&mut c1);
});
}
}