seamcarving/
carved.rs

1use image::{GenericImageView, ImageBuffer, Pixel};
2
3use crate::matrix::Matrix;
4use crate::pos::Pos;
5use crate::{image_view_to_buffer, max_pos};
6
7/// An image with some vertical seams carved.
8/// If you want to save this image or otherwise manipulate it,
9/// you can convert it to a [ImageBuffer](image::ImageBuffer).
10pub struct Carved<'a, IMG: GenericImageView> {
11    img: &'a IMG,
12    removed: u32,
13    // pos_aliases is a matrix such as img[x,y] = self[pos_aliases[x,y],y]
14    pos_aliases: Matrix<u32>,
15}
16
17impl<'a, IMG: GenericImageView> Carved<'a, IMG> {
18    pub(crate) fn new(img: &'a IMG) -> Self {
19        let size = max_pos(img);
20        let pos_aliases = Matrix::from_fn(size, |x, _y| x as u32);
21        Carved {
22            img,
23            removed: 0,
24            pos_aliases,
25        }
26    }
27    pub(crate) fn remove_seam(&mut self, seam: &[Pos]) {
28        self.pos_aliases.remove_seam(seam);
29        self.removed += 1;
30    }
31    /// Given a position in the carved image, return a position in the original
32    #[inline(always)]
33    fn transform_pos(&self, pos: Pos) -> Pos {
34        let mut pos = pos;
35        pos.0 = self.pos_aliases[pos];
36        pos
37    }
38}
39
40impl<'a, 'b, IMG: GenericImageView>
41    Into<ImageBuffer<IMG::Pixel, Vec<<<IMG as GenericImageView>::Pixel as Pixel>::Subpixel>>>
42    for &'b Carved<'a, IMG>
43where
44    <IMG as GenericImageView>::Pixel: 'static,
45{
46    /// Creates a buffer storing the image modified image contents.
47    ///
48    /// Creating the buffer is expensive, but accessing image data from a buffer is then
49    /// faster than from [Carved](Carved) instance.
50    fn into(
51        self,
52    ) -> ImageBuffer<IMG::Pixel, Vec<<<IMG as GenericImageView>::Pixel as Pixel>::Subpixel>> {
53        image_view_to_buffer(self)
54    }
55}
56
57impl<'a, IMG: GenericImageView> GenericImageView for Carved<'a, IMG>
58where
59    <IMG as GenericImageView>::Pixel: 'a,
60{
61    type Pixel = IMG::Pixel;
62    type InnerImageView = IMG::InnerImageView;
63
64    #[inline(always)]
65    fn dimensions(&self) -> (u32, u32) {
66        let (w, h) = self.img.dimensions();
67        (w - self.removed, h)
68    }
69
70    #[inline(always)]
71    fn bounds(&self) -> (u32, u32, u32, u32) {
72        let (w, h) = self.dimensions();
73        (0, 0, w, h)
74    }
75
76    #[inline(always)]
77    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
78        let Pos(u, v) = self.transform_pos(Pos(x, y));
79        self.img.get_pixel(u, v)
80    }
81
82    fn inner(&self) -> &Self::InnerImageView {
83        self.img.inner()
84    }
85}