image/images/
generic_image.rs

1use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind};
2use crate::math::Rect;
3use crate::traits::Pixel;
4use crate::{ImageBuffer, SubImage};
5
6/// Trait to inspect an image.
7///
8/// ```
9/// use image::{GenericImageView, Rgb, RgbImage};
10///
11/// let buffer = RgbImage::new(10, 10);
12/// let image: &dyn GenericImageView<Pixel = Rgb<u8>> = &buffer;
13/// ```
14pub trait GenericImageView {
15    /// The type of pixel.
16    type Pixel: Pixel;
17
18    /// The width and height of this image.
19    fn dimensions(&self) -> (u32, u32);
20
21    /// The width of this image.
22    fn width(&self) -> u32 {
23        let (w, _) = self.dimensions();
24        w
25    }
26
27    /// The height of this image.
28    fn height(&self) -> u32 {
29        let (_, h) = self.dimensions();
30        h
31    }
32
33    /// Returns true if this x, y coordinate is contained inside the image.
34    fn in_bounds(&self, x: u32, y: u32) -> bool {
35        let (width, height) = self.dimensions();
36        x < width && y < height
37    }
38
39    /// Returns the pixel located at (x, y). Indexed from top left.
40    ///
41    /// # Panics
42    ///
43    /// Panics if `(x, y)` is out of bounds.
44    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel;
45
46    /// Returns the pixel located at (x, y). Indexed from top left.
47    ///
48    /// This function can be implemented in a way that ignores bounds checking.
49    /// # Safety
50    ///
51    /// The coordinates must be [`in_bounds`] of the image.
52    ///
53    /// [`in_bounds`]: #method.in_bounds
54    unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
55        self.get_pixel(x, y)
56    }
57
58    /// Returns an Iterator over the pixels of this image.
59    /// The iterator yields the coordinates of each pixel
60    /// along with their value
61    fn pixels(&self) -> Pixels<'_, Self>
62    where
63        Self: Sized,
64    {
65        let (width, height) = self.dimensions();
66
67        Pixels {
68            image: self,
69            x: 0,
70            y: 0,
71            width,
72            height,
73        }
74    }
75
76    /// Returns a subimage that is an immutable view into this image.
77    /// You can use [`GenericImage::sub_image`] if you need a mutable view instead.
78    /// The coordinates set the position of the top left corner of the view.
79    ///
80    ///  # Panics
81    ///
82    /// Panics if the dimensions provided fall out of bounds.
83    fn view(&self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&Self>
84    where
85        Self: Sized,
86    {
87        assert!(u64::from(x) + u64::from(width) <= u64::from(self.width()));
88        assert!(u64::from(y) + u64::from(height) <= u64::from(self.height()));
89        SubImage::new(self, x, y, width, height)
90    }
91
92    /// Returns a subimage that is an immutable view into this image so long as
93    /// the provided coordinates and dimensions are within the bounds of this Image.
94    fn try_view(
95        &self,
96        x: u32,
97        y: u32,
98        width: u32,
99        height: u32,
100    ) -> Result<SubImage<&Self>, ImageError>
101    where
102        Self: Sized,
103    {
104        if u64::from(x) + u64::from(width) > u64::from(self.width())
105            || u64::from(y) + u64::from(height) > u64::from(self.height())
106        {
107            Err(ImageError::Parameter(ParameterError::from_kind(
108                ParameterErrorKind::DimensionMismatch,
109            )))
110        } else {
111            Ok(SubImage::new(self, x, y, width, height))
112        }
113    }
114
115    /// Create an empty [`ImageBuffer`] with the same pixel type as this image.
116    ///
117    /// This should ensure metadata such as the color space are transferred without copying any of
118    /// the pixel data. The idea is to prepare a buffer ready to be filled with a filtered or
119    /// portion of the channel data from the current image without performing the work of copying
120    /// the data into that buffer twice.
121    ///
122    /// The default implementation defers to [`GenericImageView::buffer_like`].
123    fn buffer_like(&self) -> ImageBuffer<Self::Pixel, Vec<<Self::Pixel as Pixel>::Subpixel>> {
124        let (w, h) = self.dimensions();
125        self.buffer_with_dimensions(w, h)
126    }
127
128    /// Create an empty [`ImageBuffer`] with different dimensions.
129    ///
130    /// See [`GenericImageView::buffer_like`].
131    ///
132    /// Uses for this are for instances preparing a buffer for only a portion of the image, or
133    /// extracting the metadata to prepare a buffer of a different pixel type.
134    fn buffer_with_dimensions(
135        &self,
136        width: u32,
137        height: u32,
138    ) -> ImageBuffer<Self::Pixel, Vec<<Self::Pixel as Pixel>::Subpixel>> {
139        ImageBuffer::new(width, height)
140    }
141}
142
143/// Immutable pixel iterator
144#[derive(Debug)]
145pub struct Pixels<'a, I: ?Sized + 'a> {
146    image: &'a I,
147    x: u32,
148    y: u32,
149    width: u32,
150    height: u32,
151}
152
153impl<I: GenericImageView> Iterator for Pixels<'_, I> {
154    type Item = (u32, u32, I::Pixel);
155
156    fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
157        if self.x >= self.width {
158            self.x = 0;
159            self.y += 1;
160        }
161
162        if self.y >= self.height {
163            None
164        } else {
165            let pixel = self.image.get_pixel(self.x, self.y);
166            let p = (self.x, self.y, pixel);
167
168            self.x += 1;
169
170            Some(p)
171        }
172    }
173}
174
175impl<I: ?Sized> Clone for Pixels<'_, I> {
176    fn clone(&self) -> Self {
177        Pixels { ..*self }
178    }
179}
180
181/// A trait for manipulating images.
182pub trait GenericImage: GenericImageView {
183    /// Gets a reference to the mutable pixel at location `(x, y)`. Indexed from top left.
184    ///
185    /// # Panics
186    ///
187    /// Panics if `(x, y)` is out of bounds.
188    ///
189    /// Panics for dynamic images (this method is deprecated and will be removed).
190    ///
191    /// ## Known issues
192    ///
193    /// This requires the buffer to contain a unique set of continuous channels in the exact order
194    /// and byte representation that the pixel type requires. This is somewhat restrictive.
195    ///
196    /// TODO: Maybe use some kind of entry API? this would allow pixel type conversion on the fly
197    /// while still doing only one array lookup:
198    ///
199    /// ```ignore
200    /// let px = image.pixel_entry_at(x,y);
201    /// px.set_from_rgba(rgba)
202    /// ```
203    #[deprecated(since = "0.24.0", note = "Use `get_pixel` and `put_pixel` instead.")]
204    fn get_pixel_mut(&mut self, x: u32, y: u32) -> &mut Self::Pixel;
205
206    /// Put a pixel at location (x, y). Indexed from top left.
207    ///
208    /// # Panics
209    ///
210    /// Panics if `(x, y)` is out of bounds.
211    fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
212
213    /// Puts a pixel at location (x, y). Indexed from top left.
214    ///
215    /// This function can be implemented in a way that ignores bounds checking.
216    /// # Safety
217    ///
218    /// The coordinates must be [`in_bounds`] of the image.
219    ///
220    /// [`in_bounds`]: traits.GenericImageView.html#method.in_bounds
221    unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
222        self.put_pixel(x, y, pixel);
223    }
224
225    /// Put a pixel at location (x, y), taking into account alpha channels
226    #[deprecated(
227        since = "0.24.0",
228        note = "Use iterator `pixels_mut` to blend the pixels directly"
229    )]
230    fn blend_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
231
232    /// Copies all of the pixels from another image into this image.
233    ///
234    /// The other image is copied with the top-left corner of the
235    /// other image placed at (x, y).
236    ///
237    /// In order to copy only a piece of the other image, use [`GenericImageView::view`].
238    ///
239    /// You can use [`FlatSamples`] to source pixels from an arbitrary regular raster of channel
240    /// values, for example from a foreign interface or a fixed image.
241    ///
242    /// # Returns
243    /// Returns an error if the image is too large to be copied at the given position
244    ///
245    /// [`GenericImageView::view`]: trait.GenericImageView.html#method.view
246    /// [`FlatSamples`]: flat/struct.FlatSamples.html
247    fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> ImageResult<()>
248    where
249        O: GenericImageView<Pixel = Self::Pixel>,
250    {
251        // Do bounds checking here so we can use the non-bounds-checking
252        // functions to copy pixels.
253        if self.width() < other.width() + x || self.height() < other.height() + y {
254            return Err(ImageError::Parameter(ParameterError::from_kind(
255                ParameterErrorKind::DimensionMismatch,
256            )));
257        }
258
259        for k in 0..other.height() {
260            for i in 0..other.width() {
261                let p = other.get_pixel(i, k);
262                self.put_pixel(i + x, k + y, p);
263            }
264        }
265        Ok(())
266    }
267
268    /// Copies all of the pixels from one part of this image to another part of this image.
269    ///
270    /// The destination rectangle of the copy is specified with the top-left corner placed at (x, y).
271    ///
272    /// # Returns
273    /// `true` if the copy was successful, `false` if the image could not
274    /// be copied due to size constraints.
275    fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
276        let Rect {
277            x: sx,
278            y: sy,
279            width,
280            height,
281        } = source;
282        let dx = x;
283        let dy = y;
284        assert!(sx < self.width() && dx < self.width());
285        assert!(sy < self.height() && dy < self.height());
286        if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
287            return false;
288        }
289        // since `.rev()` creates a new dype we would either have to go with dynamic dispatch for the ranges
290        // or have quite a lot of code bloat. A macro gives us static dispatch with less visible bloat.
291        macro_rules! copy_within_impl_ {
292            ($xiter:expr, $yiter:expr) => {
293                for y in $yiter {
294                    let sy = sy + y;
295                    let dy = dy + y;
296                    for x in $xiter {
297                        let sx = sx + x;
298                        let dx = dx + x;
299                        let pixel = self.get_pixel(sx, sy);
300                        self.put_pixel(dx, dy, pixel);
301                    }
302                }
303            };
304        }
305        // check how target and source rectangles relate to each other so we dont overwrite data before we copied it.
306        match (sx < dx, sy < dy) {
307            (true, true) => copy_within_impl_!((0..width).rev(), (0..height).rev()),
308            (true, false) => copy_within_impl_!((0..width).rev(), 0..height),
309            (false, true) => copy_within_impl_!(0..width, (0..height).rev()),
310            (false, false) => copy_within_impl_!(0..width, 0..height),
311        }
312        true
313    }
314
315    /// Returns a mutable subimage that is a view into this image.
316    /// If you want an immutable subimage instead, use [`GenericImageView::view`]
317    /// The coordinates set the position of the top left corner of the `SubImage`.
318    fn sub_image(&mut self, x: u32, y: u32, width: u32, height: u32) -> SubImage<&mut Self>
319    where
320        Self: Sized,
321    {
322        assert!(u64::from(x) + u64::from(width) <= u64::from(self.width()));
323        assert!(u64::from(y) + u64::from(height) <= u64::from(self.height()));
324        SubImage::new(self, x, y, width, height)
325    }
326}
327
328#[cfg(test)]
329mod tests {
330    use super::{GenericImage, GenericImageView};
331
332    use crate::color::Rgba;
333    use crate::math::Rect;
334    use crate::{GrayImage, ImageBuffer};
335
336    #[test]
337    #[allow(deprecated)]
338    /// Test that alpha blending works as expected
339    fn test_image_alpha_blending() {
340        let mut target = ImageBuffer::new(1, 1);
341        target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
342        assert!(*target.get_pixel(0, 0) == Rgba([255, 0, 0, 255]));
343        target.blend_pixel(0, 0, Rgba([0, 255, 0, 255]));
344        assert!(*target.get_pixel(0, 0) == Rgba([0, 255, 0, 255]));
345
346        // Blending an alpha channel onto a solid background
347        target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
348        assert!(*target.get_pixel(0, 0) == Rgba([127, 127, 0, 255]));
349
350        // Blending two alpha channels
351        target.put_pixel(0, 0, Rgba([0, 255, 0, 127]));
352        target.blend_pixel(0, 0, Rgba([255, 0, 0, 127]));
353        assert!(*target.get_pixel(0, 0) == Rgba([169, 85, 0, 190]));
354    }
355
356    #[test]
357    fn test_in_bounds() {
358        let mut target = ImageBuffer::new(2, 2);
359        target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
360
361        assert!(target.in_bounds(0, 0));
362        assert!(target.in_bounds(1, 0));
363        assert!(target.in_bounds(0, 1));
364        assert!(target.in_bounds(1, 1));
365
366        assert!(!target.in_bounds(2, 0));
367        assert!(!target.in_bounds(0, 2));
368        assert!(!target.in_bounds(2, 2));
369    }
370
371    #[test]
372    fn test_can_subimage_clone_nonmut() {
373        let mut source = ImageBuffer::new(3, 3);
374        source.put_pixel(1, 1, Rgba([255u8, 0, 0, 255]));
375
376        // A non-mutable copy of the source image
377        let source = source.clone();
378
379        // Clone a view into non-mutable to a separate buffer
380        let cloned = source.view(1, 1, 1, 1).to_image();
381
382        assert!(cloned.get_pixel(0, 0) == source.get_pixel(1, 1));
383    }
384
385    #[test]
386    fn test_can_nest_views() {
387        let mut source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
388
389        {
390            let mut sub1 = source.sub_image(0, 0, 2, 2);
391            let mut sub2 = sub1.sub_image(1, 1, 1, 1);
392            sub2.put_pixel(0, 0, Rgba([0, 0, 0, 0]));
393        }
394
395        assert_eq!(*source.get_pixel(1, 1), Rgba([0, 0, 0, 0]));
396
397        let view1 = source.view(0, 0, 2, 2);
398        assert_eq!(*source.get_pixel(1, 1), view1.get_pixel(1, 1));
399
400        let view2 = view1.view(1, 1, 1, 1);
401        assert_eq!(*source.get_pixel(1, 1), view2.get_pixel(0, 0));
402    }
403
404    #[test]
405    #[should_panic]
406    fn test_view_out_of_bounds() {
407        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
408        source.view(1, 1, 3, 3);
409    }
410
411    #[test]
412    #[should_panic]
413    fn test_view_coordinates_out_of_bounds() {
414        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
415        source.view(3, 3, 3, 3);
416    }
417
418    #[test]
419    #[should_panic]
420    fn test_view_width_out_of_bounds() {
421        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
422        source.view(1, 1, 3, 2);
423    }
424
425    #[test]
426    #[should_panic]
427    fn test_view_height_out_of_bounds() {
428        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
429        source.view(1, 1, 2, 3);
430    }
431
432    #[test]
433    #[should_panic]
434    fn test_view_x_out_of_bounds() {
435        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
436        source.view(3, 1, 3, 3);
437    }
438
439    #[test]
440    #[should_panic]
441    fn test_view_y_out_of_bounds() {
442        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
443        source.view(1, 3, 3, 3);
444    }
445
446    #[test]
447    fn test_view_in_bounds() {
448        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
449        source.view(0, 0, 3, 3);
450        source.view(1, 1, 2, 2);
451        source.view(2, 2, 0, 0);
452    }
453
454    #[test]
455    fn test_copy_sub_image() {
456        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
457        let view = source.view(0, 0, 3, 3);
458        let _view2 = view;
459        view.to_image();
460    }
461
462    #[test]
463    fn test_generic_image_copy_within_oob() {
464        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
465        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
466            Rect {
467                x: 0,
468                y: 0,
469                width: 5,
470                height: 4
471            },
472            0,
473            0
474        ));
475        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
476            Rect {
477                x: 0,
478                y: 0,
479                width: 4,
480                height: 5
481            },
482            0,
483            0
484        ));
485        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
486            Rect {
487                x: 1,
488                y: 0,
489                width: 4,
490                height: 4
491            },
492            0,
493            0
494        ));
495        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
496            Rect {
497                x: 0,
498                y: 0,
499                width: 4,
500                height: 4
501            },
502            1,
503            0
504        ));
505        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
506            Rect {
507                x: 0,
508                y: 1,
509                width: 4,
510                height: 4
511            },
512            0,
513            0
514        ));
515        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
516            Rect {
517                x: 0,
518                y: 0,
519                width: 4,
520                height: 4
521            },
522            0,
523            1
524        ));
525        assert!(!image.sub_image(0, 0, 4, 4).copy_within(
526            Rect {
527                x: 1,
528                y: 1,
529                width: 4,
530                height: 4
531            },
532            0,
533            0
534        ));
535    }
536
537    #[test]
538    fn test_generic_image_copy_within_tl() {
539        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
540        let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10];
541        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
542        assert!(image.sub_image(0, 0, 4, 4).copy_within(
543            Rect {
544                x: 0,
545                y: 0,
546                width: 3,
547                height: 3
548            },
549            1,
550            1
551        ));
552        assert_eq!(&image.into_raw(), &expected);
553    }
554
555    #[test]
556    fn test_generic_image_copy_within_tr() {
557        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
558        let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15];
559        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
560        assert!(image.sub_image(0, 0, 4, 4).copy_within(
561            Rect {
562                x: 1,
563                y: 0,
564                width: 3,
565                height: 3
566            },
567            0,
568            1
569        ));
570        assert_eq!(&image.into_raw(), &expected);
571    }
572
573    #[test]
574    fn test_generic_image_copy_within_bl() {
575        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
576        let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15];
577        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
578        assert!(image.sub_image(0, 0, 4, 4).copy_within(
579            Rect {
580                x: 0,
581                y: 1,
582                width: 3,
583                height: 3
584            },
585            1,
586            0
587        ));
588        assert_eq!(&image.into_raw(), &expected);
589    }
590
591    #[test]
592    fn test_generic_image_copy_within_br() {
593        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
594        let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15];
595        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
596        assert!(image.sub_image(0, 0, 4, 4).copy_within(
597            Rect {
598                x: 1,
599                y: 1,
600                width: 3,
601                height: 3
602            },
603            0,
604            0
605        ));
606        assert_eq!(&image.into_raw(), &expected);
607    }
608}