use std::borrow::Cow;
use image::{ImageBuffer, Pixel, imageops::crop_imm};
#[derive(Debug, Clone, Default)]
pub struct ImageCrop {
pub top: u32,
pub bottom: u32,
pub left: u32,
pub right: u32,
}
impl ImageCrop {
pub fn reverse(self) -> Self {
Self {
top: self.bottom,
bottom: self.top,
left: self.right,
right: self.left,
}
}
pub fn crop_image<'a, P>(
&self,
image: &'a ImageBuffer<P, Vec<P::Subpixel>>,
) -> Cow<'a, ImageBuffer<P, Vec<P::Subpixel>>>
where
P: Pixel + 'static,
{
if self.left | self.top | self.bottom | self.right == 0 {
return Cow::Borrowed(image);
}
let width = image.width().saturating_sub(self.left + self.right);
let height = image.height().saturating_sub(self.top + self.bottom);
Cow::Owned(crop_imm(image, self.left, self.top, width, height).to_image())
}
}
#[cfg(test)]
mod tests {
use super::*;
use image::{Rgba, RgbaImage};
#[test]
fn reverse_mirrors_all_sides() {
let crop = ImageCrop {
top: 1,
bottom: 2,
left: 3,
right: 4,
};
let reversed = crop.reverse();
assert_eq!(
(reversed.top, reversed.bottom, reversed.left, reversed.right),
(2, 1, 4, 3)
);
}
#[test]
fn crop_image_removes_both_margins() {
let image = RgbaImage::from_fn(10, 8, |x, y| Rgba([x as u8, y as u8, 0, 255]));
let crop = ImageCrop {
top: 1,
bottom: 2,
left: 3,
right: 4,
};
let cropped = crop.crop_image(&image);
assert_eq!((cropped.width(), cropped.height()), (3, 5));
assert_eq!(cropped.get_pixel(0, 0), image.get_pixel(3, 1));
assert_eq!(cropped.get_pixel(2, 4), image.get_pixel(5, 5));
}
#[test]
fn crop_image_zero_is_borrowed() {
let image = RgbaImage::new(4, 4);
let cropped = ImageCrop::default().crop_image(&image);
assert!(matches!(cropped, Cow::Borrowed(_)));
}
}