Coverage Report

Created: 2026-03-20 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/image/src/images/generic_image.rs
Line
Count
Source
1
use crate::error::{ImageError, ImageResult};
2
use crate::flat::ViewOfPixel;
3
use crate::math::Rect;
4
use crate::traits::Pixel;
5
use 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
/// ```
15
pub 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
0
    fn width(&self) -> u32 {
24
0
        let (w, _) = self.dimensions();
25
0
        w
26
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::width
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::width
27
28
    /// The height of this image.
29
0
    fn height(&self) -> u32 {
30
0
        let (_, h) = self.dimensions();
31
0
        h
32
0
    }
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgb<f32>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[f32], image::color::Rgba<f32>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgb<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Luma<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::Rgba<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u8], image::color::LumaA<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgb<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Luma<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::Rgba<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::flat::View<&[u16], image::color::LumaA<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::height
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::height
33
34
    /// Returns true if this x, y coordinate is contained inside the image.
35
0
    fn in_bounds(&self, x: u32, y: u32) -> bool {
36
0
        let (width, height) = self.dimensions();
37
0
        x < width && y < height
38
0
    }
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
0
    unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
56
0
        self.get_pixel(x, y)
57
0
    }
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
0
    fn pixels(&self) -> Pixels<'_, Self>
63
0
    where
64
0
        Self: Sized,
65
    {
66
0
        let (width, height) = self.dimensions();
67
68
0
        Pixels {
69
0
            image: self,
70
0
            x: 0,
71
0
            y: 0,
72
0
            width,
73
0
            height,
74
0
        }
75
0
    }
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::pixels
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::pixels
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
0
    fn view(&self, rect: Rect) -> SubImage<&Self>
85
0
    where
86
0
        Self: Sized,
87
    {
88
0
        rect.assert_in_bounds_of(self);
89
0
        SubImage::new(self, rect)
90
0
    }
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
0
    fn try_view(&self, rect: Rect) -> Result<SubImage<&Self>, ImageError>
95
0
    where
96
0
        Self: Sized,
97
    {
98
0
        rect.test_in_bounds(self)?;
99
0
        Ok(SubImage::new(self, rect))
100
0
    }
101
102
    /// Create an empty [`ImageBuffer`] with the same pixel type as this image.
103
    ///
104
    /// This should ensure metadata such as the color space are transferred without copying any of
105
    /// the pixel data. The idea is to prepare a buffer ready to be filled with a filtered or
106
    /// portion of the channel data from the current image without performing the work of copying
107
    /// the data into that buffer twice.
108
    ///
109
    /// The default implementation defers to [`GenericImageView::buffer_like`].
110
0
    fn buffer_like(&self) -> ImageBuffer<Self::Pixel, Vec<<Self::Pixel as Pixel>::Subpixel>> {
111
0
        let (w, h) = self.dimensions();
112
0
        self.buffer_with_dimensions(w, h)
113
0
    }
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImageView>::buffer_like
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImageView>::buffer_like
114
115
    /// Create an empty [`ImageBuffer`] with different dimensions.
116
    ///
117
    /// See [`GenericImageView::buffer_like`].
118
    ///
119
    /// Uses for this are for instances preparing a buffer for only a portion of the image, or
120
    /// extracting the metadata to prepare a buffer of a different pixel type.
121
0
    fn buffer_with_dimensions(
122
0
        &self,
123
0
        width: u32,
124
0
        height: u32,
125
0
    ) -> ImageBuffer<Self::Pixel, Vec<<Self::Pixel as Pixel>::Subpixel>> {
126
0
        ImageBuffer::new(width, height)
127
0
    }
128
129
    /// If the buffer has a fitting layout, return a canonical view of the samples.
130
    ///
131
    /// This is the basis of optimization and by default return `None`. It lets consumers of
132
    /// generic images access the sample data through a canonical descriptor of its layout directly
133
    /// instead of pixel-by-pixel. This provides more efficient forms of access that the
134
    /// [`GenericImageView`] trait itself does not demand from all its implementations.
135
    ///
136
    /// Implementation of this method should be cheap to call.
137
    ///
138
    /// If implemented, a [`SubImage`] proxy of this image will provide a sample view as well.
139
0
    fn to_pixel_view(&self) -> Option<ViewOfPixel<'_, Self::Pixel>> {
140
0
        None
141
0
    }
142
}
143
144
/// Immutable pixel iterator
145
#[derive(Debug)]
146
pub struct Pixels<'a, I: ?Sized + 'a> {
147
    image: &'a I,
148
    x: u32,
149
    y: u32,
150
    width: u32,
151
    height: u32,
152
}
153
154
impl<I: GenericImageView> Iterator for Pixels<'_, I> {
155
    type Item = (u32, u32, I::Pixel);
156
157
0
    fn next(&mut self) -> Option<(u32, u32, I::Pixel)> {
158
0
        if self.x >= self.width {
159
0
            self.x = 0;
160
0
            self.y += 1;
161
0
        }
162
163
0
        if self.y >= self.height {
164
0
            None
165
        } else {
166
0
            let pixel = self.image.get_pixel(self.x, self.y);
167
0
            let p = (self.x, self.y, pixel);
168
169
0
            self.x += 1;
170
171
0
            Some(p)
172
        }
173
0
    }
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>>> as core::iter::traits::iterator::Iterator>::next
Unexecuted instantiation: <image::images::generic_image::Pixels<image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>>> as core::iter::traits::iterator::Iterator>::next
174
}
175
176
impl<I: ?Sized> Clone for Pixels<'_, I> {
177
0
    fn clone(&self) -> Self {
178
0
        Pixels { ..*self }
179
0
    }
180
}
181
182
/// A trait for manipulating images.
183
pub trait GenericImage: GenericImageView {
184
    /// Put a pixel at location (x, y). Indexed from top left.
185
    ///
186
    /// # Panics
187
    ///
188
    /// Panics if `(x, y)` is out of bounds.
189
    fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel);
190
191
    /// Puts a pixel at location (x, y). Indexed from top left.
192
    ///
193
    /// This function can be implemented in a way that ignores bounds checking.
194
    /// # Safety
195
    ///
196
    /// The coordinates must be [`in_bounds`] of the image.
197
    ///
198
    /// [`in_bounds`]: traits.GenericImageView.html#method.in_bounds
199
0
    unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) {
200
0
        self.put_pixel(x, y, pixel);
201
0
    }
202
203
    /// Copies all of the pixels from another image into this image.
204
    ///
205
    /// The other image is copied with the top-left corner of the
206
    /// other image placed at (x, y).
207
    ///
208
    /// In order to copy only a piece of the other image, use [`GenericImageView::view`].
209
    ///
210
    /// You can use [`FlatSamples`] to source pixels from an arbitrary regular raster of channel
211
    /// values, for example from a foreign interface or a fixed image.
212
    ///
213
    /// # Returns
214
    /// Returns an error if the image is too large to be copied at the given position
215
    ///
216
    /// [`GenericImageView::view`]: trait.GenericImageView.html#method.view
217
    /// [`FlatSamples`]: flat/struct.FlatSamples.html
218
0
    fn copy_from<O>(&mut self, other: &O, x: u32, y: u32) -> ImageResult<()>
219
0
    where
220
0
        O: GenericImageView<Pixel = Self::Pixel>,
221
    {
222
0
        if let Some(flat) = other.to_pixel_view() {
223
0
            return self.copy_from_samples(flat, x, y);
224
0
        }
225
226
        // Do bounds checking here so we can use the non-bounds-checking
227
        // functions to copy pixels.
228
0
        Rect::from_image_at(other, x, y).test_in_bounds(self)?;
229
230
0
        for k in 0..other.height() {
231
0
            for i in 0..other.width() {
232
0
                let p = other.get_pixel(i, k);
233
0
                self.put_pixel(i + x, k + y, p);
234
0
            }
235
        }
236
237
0
        Ok(())
238
0
    }
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>> as image::images::generic_image::GenericImage>::copy_from::<image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>>>
239
240
    /// Copy pixels from a regular strided matrix of pixels.
241
0
    fn copy_from_samples(
242
0
        &mut self,
243
0
        samples: ViewOfPixel<'_, Self::Pixel>,
244
0
        x: u32,
245
0
        y: u32,
246
0
    ) -> ImageResult<()> {
247
        // Even though the implementation is the same, do not just call `Self::copy_from` here to
248
        // avoid circular dependencies in careless implementations.
249
0
        Rect::from_image_at(&samples, x, y).test_in_bounds(self)?;
250
251
0
        for k in 0..samples.height() {
252
0
            for i in 0..samples.width() {
253
0
                let p = samples.get_pixel(i, k);
254
0
                self.put_pixel(i + x, k + y, p);
255
0
            }
256
        }
257
258
0
        Ok(())
259
0
    }
260
261
    /// Copies all of the pixels from one part of this image to another part of this image.
262
    ///
263
    /// The destination rectangle of the copy is specified with the top-left corner placed at (x, y).
264
    ///
265
    /// # Returns
266
    /// `true` if the copy was successful, `false` if the image could not
267
    /// be copied due to size constraints.
268
0
    fn copy_within(&mut self, source: Rect, x: u32, y: u32) -> bool {
269
        let Rect {
270
0
            x: sx,
271
0
            y: sy,
272
0
            width,
273
0
            height,
274
0
        } = source;
275
0
        let dx = x;
276
0
        let dy = y;
277
0
        assert!(sx < self.width() && dx < self.width());
278
0
        assert!(sy < self.height() && dy < self.height());
279
0
        if self.width() - dx.max(sx) < width || self.height() - dy.max(sy) < height {
280
0
            return false;
281
0
        }
282
        // since `.rev()` creates a new dype we would either have to go with dynamic dispatch for the ranges
283
        // or have quite a lot of code bloat. A macro gives us static dispatch with less visible bloat.
284
        macro_rules! copy_within_impl_ {
285
            ($xiter:expr, $yiter:expr) => {
286
                for y in $yiter {
287
                    let sy = sy + y;
288
                    let dy = dy + y;
289
                    for x in $xiter {
290
                        let sx = sx + x;
291
                        let dx = dx + x;
292
                        let pixel = self.get_pixel(sx, sy);
293
                        self.put_pixel(dx, dy, pixel);
294
                    }
295
                }
296
            };
297
        }
298
        // check how target and source rectangles relate to each other so we dont overwrite data before we copied it.
299
0
        match (sx < dx, sy < dy) {
300
0
            (true, true) => copy_within_impl_!((0..width).rev(), (0..height).rev()),
301
0
            (true, false) => copy_within_impl_!((0..width).rev(), 0..height),
302
0
            (false, true) => copy_within_impl_!(0..width, (0..height).rev()),
303
0
            (false, false) => copy_within_impl_!(0..width, 0..height),
304
        }
305
0
        true
306
0
    }
307
308
    /// Returns a mutable subimage that is a view into this image.
309
    /// If you want an immutable subimage instead, use [`GenericImageView::view`]
310
    /// The coordinates set the position of the top left corner of the `SubImage`.
311
0
    fn sub_image(&mut self, rect: Rect) -> SubImage<&mut Self>
312
0
    where
313
0
        Self: Sized,
314
    {
315
0
        rect.assert_in_bounds_of(self);
316
0
        SubImage::new(self, rect)
317
0
    }
318
}
319
320
#[cfg(test)]
321
mod tests {
322
    use super::{GenericImage, GenericImageView};
323
324
    use crate::color::Rgba;
325
    use crate::math::Rect;
326
    use crate::{GrayImage, ImageBuffer};
327
328
    #[test]
329
    fn test_image_put_pixel() {
330
        let mut target = ImageBuffer::new(1, 1);
331
        let pixel: Rgba<u8> = Rgba([255, 0, 0, 255]);
332
        target.put_pixel(0, 0, pixel);
333
        assert_eq!(*target.get_pixel(0, 0), pixel);
334
    }
335
336
    #[test]
337
    fn test_in_bounds() {
338
        let mut target = ImageBuffer::new(2, 2);
339
        target.put_pixel(0, 0, Rgba([255u8, 0, 0, 255]));
340
341
        assert!(target.in_bounds(0, 0));
342
        assert!(target.in_bounds(1, 0));
343
        assert!(target.in_bounds(0, 1));
344
        assert!(target.in_bounds(1, 1));
345
346
        assert!(!target.in_bounds(2, 0));
347
        assert!(!target.in_bounds(0, 2));
348
        assert!(!target.in_bounds(2, 2));
349
    }
350
351
    #[test]
352
    fn test_can_subimage_clone_nonmut() {
353
        let mut source = ImageBuffer::new(3, 3);
354
        source.put_pixel(1, 1, Rgba([255u8, 0, 0, 255]));
355
356
        // A non-mutable copy of the source image
357
        let source = source.clone();
358
359
        // Clone a view into non-mutable to a separate buffer
360
        let cloned = source.view(Rect::from_xy_ranges(1..2, 1..2)).to_image();
361
362
        assert!(cloned.get_pixel(0, 0) == source.get_pixel(1, 1));
363
    }
364
365
    #[test]
366
    fn test_can_nest_views() {
367
        let mut source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
368
369
        {
370
            let mut sub1 = source.sub_image(Rect::from_xy_ranges(0..2, 0..2));
371
            let mut sub2 = sub1.sub_image(Rect::from_xy_ranges(1..2, 1..2));
372
            sub2.put_pixel(0, 0, Rgba([0, 0, 0, 0]));
373
        }
374
375
        assert_eq!(*source.get_pixel(1, 1), Rgba([0, 0, 0, 0]));
376
377
        let view1 = source.view(Rect::from_xy_ranges(0..2, 0..2));
378
        assert_eq!(*source.get_pixel(1, 1), view1.get_pixel(1, 1));
379
380
        let view2 = view1.view(Rect::from_xy_ranges(1..2, 1..2));
381
        assert_eq!(*source.get_pixel(1, 1), view2.get_pixel(0, 0));
382
    }
383
384
    #[test]
385
    #[should_panic]
386
    fn test_view_out_of_bounds() {
387
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
388
        source.view(Rect::from_xy_ranges(1..4, 1..4));
389
    }
390
391
    #[test]
392
    #[should_panic]
393
    fn test_view_coordinates_out_of_bounds() {
394
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
395
        source.view(Rect::from_xy_ranges(3..6, 3..6));
396
    }
397
398
    #[test]
399
    #[should_panic]
400
    fn test_view_width_out_of_bounds() {
401
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
402
        source.view(Rect::from_xy_ranges(1..4, 1..3));
403
    }
404
405
    #[test]
406
    #[should_panic]
407
    fn test_view_height_out_of_bounds() {
408
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
409
        source.view(Rect::from_xy_ranges(1..3, 1..4));
410
    }
411
412
    #[test]
413
    #[should_panic]
414
    fn test_view_x_out_of_bounds() {
415
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
416
        source.view(Rect::from_xy_ranges(3..6, 1..3));
417
    }
418
419
    #[test]
420
    #[should_panic]
421
    fn test_view_y_out_of_bounds() {
422
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
423
        source.view(Rect::from_xy_ranges(1..3, 3..6));
424
    }
425
426
    #[test]
427
    fn test_view_in_bounds() {
428
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
429
        source.view(Rect::from_xy_ranges(0..3, 0..3));
430
        source.view(Rect::from_xy_ranges(1..3, 1..3));
431
        source.view(Rect::from_xy_ranges(2..2, 2..2));
432
    }
433
434
    #[test]
435
    fn test_copy_sub_image() {
436
        let source = ImageBuffer::from_pixel(3, 3, Rgba([255u8, 0, 0, 255]));
437
        let view = source.view(Rect::from_xy_ranges(0..3, 0..3));
438
        let _view2 = view;
439
        view.to_image();
440
    }
441
442
    #[test]
443
    fn test_generic_image_copy_within_oob() {
444
        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, vec![0u8; 16]).unwrap();
445
        assert!(!image
446
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
447
            .copy_within(Rect::from_xy_ranges(0..5, 0..4), 0, 0));
448
        assert!(!image
449
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
450
            .copy_within(Rect::from_xy_ranges(0..4, 0..5), 0, 0));
451
        assert!(!image
452
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
453
            .copy_within(Rect::from_xy_ranges(1..5, 0..4), 0, 0));
454
        assert!(!image
455
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
456
            .copy_within(Rect::from_xy_ranges(0..4, 0..4), 1, 0));
457
        assert!(!image
458
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
459
            .copy_within(Rect::from_xy_ranges(0..4, 1..5), 0, 0));
460
        assert!(!image
461
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
462
            .copy_within(Rect::from_xy_ranges(0..4, 0..4), 0, 1));
463
        assert!(!image
464
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
465
            .copy_within(Rect::from_xy_ranges(1..5, 0..4), 0, 0));
466
    }
467
468
    #[test]
469
    fn test_generic_image_copy_within_tl() {
470
        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
471
        let expected = [0, 1, 2, 3, 4, 0, 1, 2, 8, 4, 5, 6, 12, 8, 9, 10];
472
        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
473
        assert!(image
474
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
475
            .copy_within(Rect::from_xy_ranges(0..3, 0..3), 1, 1));
476
        assert_eq!(&image.into_raw(), &expected);
477
    }
478
479
    #[test]
480
    fn test_generic_image_copy_within_tr() {
481
        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
482
        let expected = [0, 1, 2, 3, 1, 2, 3, 7, 5, 6, 7, 11, 9, 10, 11, 15];
483
        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
484
        assert!(image
485
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
486
            .copy_within(Rect::from_xy_ranges(1..4, 0..3), 0, 1));
487
        assert_eq!(&image.into_raw(), &expected);
488
    }
489
490
    #[test]
491
    fn test_generic_image_copy_within_bl() {
492
        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
493
        let expected = [0, 4, 5, 6, 4, 8, 9, 10, 8, 12, 13, 14, 12, 13, 14, 15];
494
        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
495
        assert!(image
496
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
497
            .copy_within(Rect::from_xy_ranges(0..3, 1..4), 1, 0));
498
        assert_eq!(&image.into_raw(), &expected);
499
    }
500
501
    #[test]
502
    fn test_generic_image_copy_within_br() {
503
        let data = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
504
        let expected = [5, 6, 7, 3, 9, 10, 11, 7, 13, 14, 15, 11, 12, 13, 14, 15];
505
        let mut image: GrayImage = ImageBuffer::from_raw(4, 4, Vec::from(&data[..])).unwrap();
506
        assert!(image
507
            .sub_image(Rect::from_xy_ranges(0..4, 0..4))
508
            .copy_within(Rect::from_xy_ranges(1..4, 1..4), 0, 0));
509
        assert_eq!(&image.into_raw(), &expected);
510
    }
511
}