use std::ops::Sub;
use zune_core::bit_depth::BitType;
use zune_core::colorspace::ColorSpace;
use zune_image::errors::ImageErrors;
use zune_image::image::Image;
use zune_image::traits::OperationsTrait;
use crate::traits::NumOps;
#[derive(Default)]
pub struct Invert;
impl Invert {
#[must_use]
pub fn new() -> Invert {
Self
}
}
impl OperationsTrait for Invert {
fn name(&self) -> &'static str {
"Invert"
}
fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors> {
let depth = image.depth().bit_type();
for channel in image.channels_mut(true) {
match depth {
BitType::U8 => invert(channel.reinterpret_as_mut::<u8>().unwrap()),
BitType::U16 => invert(channel.reinterpret_as_mut::<u16>().unwrap()),
BitType::F32 => invert(channel.reinterpret_as_mut::<f32>().unwrap()),
d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d))
}
}
Ok(())
}
fn supported_colorspaces(&self) -> &'static [ColorSpace] {
&[
ColorSpace::RGB,
ColorSpace::RGBA,
ColorSpace::LumaA,
ColorSpace::Luma
]
}
fn supported_types(&self) -> &'static [BitType] {
&[BitType::U8, BitType::U16, BitType::F32]
}
}
pub fn invert<T>(in_image: &mut [T])
where
T: NumOps<T> + Sub<Output = T> + Copy
{
for pixel in in_image.iter_mut() {
*pixel = T::max_val() - *pixel;
}
}
#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod benchmarks {
extern crate test;
use crate::invert::invert;
#[bench]
fn invert_u8(b: &mut test::Bencher) {
let mut in_out = vec![0_u8; 800 * 800];
b.iter(|| {
invert(&mut in_out);
});
}
#[bench]
fn invert_u16(b: &mut test::Bencher) {
let mut in_out = vec![0_u8; 800 * 800];
b.iter(|| {
invert(&mut in_out);
});
}
}