image/images/
sub_image.rs

1use crate::{flat::ViewOfPixel, math::Rect, GenericImage, GenericImageView, ImageBuffer, Pixel};
2use std::ops::{Deref, DerefMut};
3
4/// A View into another image
5///
6/// Instances of this struct can be created using:
7///   - [`GenericImage::sub_image`] to create a mutable view,
8///   - [`GenericImageView::view`] to create an immutable view,
9///   - [`SubImage::new`] to instantiate the struct directly.
10///
11/// Note that this does _not_ implement `GenericImage`, but it dereferences to one which allows you
12/// to use it as if it did. See [Design Considerations](#Design-Considerations) below for details.
13///
14/// # Design Considerations
15///
16/// For reasons relating to coherence, this is not itself a `GenericImage` or a `GenericImageView`.
17/// In short, we want to reserve the ability of adding traits implemented for _all_ generic images
18/// but in a different manner for `SubImage`. This may be required to ensure that stacking
19/// sub-images comes at no double indirect cost.
20///
21/// If, ultimately, this is not needed then a directly implementation of `GenericImage` can and
22/// will get added. This inconvenience may alternatively get resolved if Rust allows some forms of
23/// specialization, which might make this trick unnecessary and thus also allows for a direct
24/// implementation.
25#[derive(Copy, Clone)]
26pub struct SubImage<I> {
27    inner: SubImageInner<I>,
28}
29
30/// The inner type of `SubImage` that implements `GenericImage{,View}`.
31///
32/// This type is _nominally_ `pub` but it is not exported from the crate. It should be regarded as
33/// an existential type in any case.
34#[derive(Copy, Clone)]
35pub struct SubImageInner<I> {
36    image: I,
37    xoffset: u32,
38    yoffset: u32,
39    xstride: u32,
40    ystride: u32,
41}
42
43/// Alias to access Pixel behind a reference
44type DerefPixel<I> = <<I as Deref>::Target as GenericImageView>::Pixel;
45
46/// Alias to access Subpixel behind a reference
47type DerefSubpixel<I> = <DerefPixel<I> as Pixel>::Subpixel;
48
49impl<I> SubImage<I> {
50    /// Construct a new subimage
51    /// The coordinates set the position of the top left corner of the `SubImage`.
52    pub fn new(image: I, x: u32, y: u32, width: u32, height: u32) -> SubImage<I> {
53        SubImage {
54            inner: SubImageInner {
55                image,
56                xoffset: x,
57                yoffset: y,
58                xstride: width,
59                ystride: height,
60            },
61        }
62    }
63
64    /// Change the coordinates of this subimage.
65    pub fn change_bounds(&mut self, x: u32, y: u32, width: u32, height: u32) {
66        self.inner.xoffset = x;
67        self.inner.yoffset = y;
68        self.inner.xstride = width;
69        self.inner.ystride = height;
70    }
71
72    /// The offsets of this subimage relative to the underlying image.
73    pub fn offsets(&self) -> (u32, u32) {
74        (self.inner.xoffset, self.inner.yoffset)
75    }
76
77    /// Convert this subimage to an `ImageBuffer`
78    pub fn to_image(&self) -> ImageBuffer<DerefPixel<I>, Vec<DerefSubpixel<I>>>
79    where
80        I: Deref,
81        I::Target: GenericImageView + 'static,
82    {
83        let borrowed = &*self.inner.image;
84        let mut out = borrowed.buffer_with_dimensions(self.inner.xstride, self.inner.ystride);
85
86        for y in 0..self.inner.ystride {
87            for x in 0..self.inner.xstride {
88                let p = borrowed.get_pixel(x + self.inner.xoffset, y + self.inner.yoffset);
89                out.put_pixel(x, y, p);
90            }
91        }
92
93        out
94    }
95}
96
97/// Methods for readable images.
98impl<I> SubImage<I>
99where
100    I: Deref,
101    I::Target: GenericImageView,
102{
103    /// Create a sub-view of the image.
104    ///
105    /// The coordinates given are relative to the current view on the underlying image.
106    ///
107    /// Note that this method is preferred to the one from `GenericImageView`. This is accessible
108    /// with the explicit method call syntax but it should rarely be needed due to causing an
109    /// extra level of indirection.
110    ///
111    /// ```
112    /// use image::{GenericImageView, RgbImage, SubImage};
113    /// let buffer = RgbImage::new(10, 10);
114    ///
115    /// let subimage: SubImage<&RgbImage> = buffer.view(0, 0, 10, 10);
116    /// let subview: SubImage<&RgbImage> = subimage.view(0, 0, 10, 10);
117    ///
118    /// // Less efficient and NOT &RgbImage
119    /// let _: SubImage<&_> = GenericImageView::view(&*subimage, 0, 0, 10, 10);
120    /// ```
121    pub fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&I::Target> {
122        use crate::GenericImageView as _;
123        assert!(u64::from(x) + u64::from(width) <= u64::from(self.inner.width()));
124        assert!(u64::from(y) + u64::from(height) <= u64::from(self.inner.height()));
125        let x = self.inner.xoffset.saturating_add(x);
126        let y = self.inner.yoffset.saturating_add(y);
127        SubImage::new(&*self.inner.image, x, y, width, height)
128    }
129
130    /// Get a reference to the underlying image.
131    pub fn inner(&self) -> &I::Target {
132        &self.inner.image
133    }
134}
135
136impl<I> SubImage<I>
137where
138    I: DerefMut,
139    I::Target: GenericImage,
140{
141    /// Create a mutable sub-view of the image.
142    ///
143    /// The coordinates given are relative to the current view on the underlying image.
144    pub fn sub_image(
145        &mut self,
146        x: u32,
147        y: u32,
148        width: u32,
149        height: u32,
150    ) -> SubImage<&mut I::Target> {
151        assert!(u64::from(x) + u64::from(width) <= u64::from(self.inner.width()));
152        assert!(u64::from(y) + u64::from(height) <= u64::from(self.inner.height()));
153        let x = self.inner.xoffset.saturating_add(x);
154        let y = self.inner.yoffset.saturating_add(y);
155        SubImage::new(&mut *self.inner.image, x, y, width, height)
156    }
157
158    /// Get a mutable reference to the underlying image.
159    pub fn inner_mut(&mut self) -> &mut I::Target {
160        &mut self.inner.image
161    }
162}
163
164impl<I> Deref for SubImage<I>
165where
166    I: Deref,
167{
168    type Target = SubImageInner<I>;
169
170    fn deref(&self) -> &Self::Target {
171        &self.inner
172    }
173}
174
175impl<I> DerefMut for SubImage<I>
176where
177    I: DerefMut,
178{
179    fn deref_mut(&mut self) -> &mut Self::Target {
180        &mut self.inner
181    }
182}
183
184#[allow(deprecated)]
185impl<I> GenericImageView for SubImageInner<I>
186where
187    I: Deref,
188    I::Target: GenericImageView,
189{
190    type Pixel = DerefPixel<I>;
191
192    fn dimensions(&self) -> (u32, u32) {
193        (self.xstride, self.ystride)
194    }
195
196    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
197        self.image.get_pixel(x + self.xoffset, y + self.yoffset)
198    }
199
200    /// Create a buffer with the (color) metadata of the underlying image.
201    fn buffer_with_dimensions(
202        &self,
203        width: u32,
204        height: u32,
205    ) -> ImageBuffer<
206        <I::Target as GenericImageView>::Pixel,
207        Vec<<<I::Target as GenericImageView>::Pixel as Pixel>::Subpixel>,
208    > {
209        self.image.buffer_with_dimensions(width, height)
210    }
211
212    fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
213        let inner = self.image.to_pixel_view()?;
214
215        // Now pivot the inner descriptor.
216        let mut descriptor = inner.into_inner();
217
218        let offset = descriptor.index(0, self.xoffset, self.yoffset)?;
219        descriptor.samples = descriptor.samples.get(offset..)?;
220        descriptor.layout.width = self.xstride;
221        descriptor.layout.height = self.ystride;
222
223        descriptor.into_view().ok()
224    }
225}
226
227#[allow(deprecated)]
228impl<I> GenericImage for SubImageInner<I>
229where
230    I: DerefMut,
231    I::Target: GenericImage + Sized,
232{
233    fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel {
234        self.image.get_pixel_mut(x + self.xoffset, y + self.yoffset)
235    }
236
237    fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
238        self.image
239            .put_pixel(x + self.xoffset, y + self.yoffset, pixel);
240    }
241
242    /// DEPRECATED: This method will be removed. Blend the pixel directly instead.
243    fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
244        self.image
245            .blend_pixel(x + self.xoffset, y + self.yoffset, pixel);
246    }
247
248    fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> Result<(), crate::ImageError>
249    where
250        O: GenericImageView<Pixel = Self::Pixel>,
251    {
252        Rect::from_image_at(other, x, y).test_in_bounds(self)?;
253        // Dispatch the inner images `copy_from` method with adjusted offsets. this ensures its
254        // potentially optimized implementation gets used.
255        self.image
256            .copy_from(other, x + self.xoffset, y + self.yoffset)
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use crate::{metadata::Cicp, GenericImageView, RgbaImage};
263
264    #[test]
265    fn preserves_color_space() {
266        let mut buffer = RgbaImage::new(16, 16);
267        buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
268        buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
269
270        let view = buffer.view(0, 0, 16, 16);
271        let result = view.buffer_like();
272
273        assert_eq!(buffer.color_space(), result.color_space());
274    }
275
276    #[test]
277    fn deep_preserves_color_space() {
278        let mut buffer = RgbaImage::new(16, 16);
279        buffer[(0, 0)] = crate::Rgba([0xff, 0, 0, 255]);
280        buffer.set_rgb_primaries(Cicp::DISPLAY_P3.primaries);
281
282        let view = buffer.view(0, 0, 16, 16);
283        let view = view.view(0, 0, 16, 16);
284        let result = view.buffer_like();
285
286        assert_eq!(buffer.color_space(), result.color_space());
287    }
288}