Coverage Report

Created: 2026-01-19 07:25

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