wonfy-tools 0.2.0

Collection of tools for personal use, provides library and CLI.
Documentation
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(_)));
    }
}