Skip to main content

image/images/
generic_image.rs

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