Coverage Report

Created: 2026-05-30 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/image/src/math/rect.rs
Line
Count
Source
1
use core::cmp;
2
use core::ops::Range;
3
4
use crate::{error, GenericImageView};
5
6
/// A Rectangle defined by its top left corner, width and height.
7
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
8
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9
pub struct Rect {
10
    /// The x coordinate of the top left corner.
11
    pub x: u32,
12
    /// The y coordinate of the top left corner.
13
    pub y: u32,
14
    /// The rectangle's width, going right toward larger x.
15
    pub width: u32,
16
    /// The rectangle's height, going down toward larger y.
17
    pub height: u32,
18
}
19
20
impl Rect {
21
    /// Construct a rectangle from the pixel range it covers.
22
    ///
23
    /// ```
24
    /// use image::math::Rect;
25
    ///
26
    /// let rect = Rect::from_xy_ranges(10..20, 30..50);
27
    /// assert_eq!(rect.width, 10);
28
    /// assert_eq!(rect.height, 20);
29
    /// ```
30
    ///
31
    /// # Panics
32
    ///
33
    /// Panics with debug assertions if the end of either range is less than the start. In release
34
    /// configurations that is treated as an empty range, the top-left coordinate is copied from
35
    /// the start and the width or height respectively is set to zero.
36
0
    pub fn from_xy_ranges(x: Range<u32>, y: Range<u32>) -> Self {
37
0
        debug_assert!(
38
0
            x.start <= x.end,
39
0
            "Range for x is incorrectly empty: {}..{}",
40
            x.start,
41
            x.end
42
        );
43
0
        debug_assert!(
44
0
            y.start <= y.end,
45
0
            "Range for y is incorrectly empty: {}..{}",
46
            x.start,
47
            x.end
48
        );
49
50
0
        Self {
51
0
            x: x.start,
52
0
            y: y.start,
53
0
            width: x.end.saturating_sub(x.start),
54
0
            height: y.end.saturating_sub(y.start),
55
0
        }
56
0
    }
57
58
    /// Construct a rectangle representing an image with its top-left corner.
59
0
    pub(crate) fn from_image_at(image: &(impl GenericImageView + ?Sized), x: u32, y: u32) -> Self {
60
0
        Self {
61
0
            x,
62
0
            y,
63
0
            width: image.width(),
64
0
            height: image.height(),
65
0
        }
66
0
    }
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[f32], image::color::Rgb<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[f32], image::color::Rgba<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u8], image::color::Rgb<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u8], image::color::Luma<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u8], image::color::Rgba<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u8], image::color::LumaA<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u16], image::color::Rgb<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u16], image::color::Luma<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u16], image::color::Rgba<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::flat::View<&[u16], image::color::LumaA<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::from_image_at::<image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>>>
67
68
0
    fn is_in_bounds(&self, (width, height): (u32, u32)) -> bool {
69
0
        u64::from(self.x) + u64::from(self.width) <= u64::from(width)
70
0
            && u64::from(self.y) + u64::from(self.height) <= u64::from(height)
71
0
    }
72
73
0
    pub(crate) fn test_in_bounds_of(
74
0
        &self,
75
0
        image: &(impl GenericImageView + ?Sized),
76
0
    ) -> Result<(), error::ImageError> {
77
0
        if self.is_in_bounds(image.dimensions()) {
78
0
            Ok(())
79
        } else {
80
0
            Err(error::ImageError::Parameter(
81
0
                error::ParameterError::from_kind(error::ParameterErrorKind::DimensionMismatch),
82
0
            ))
83
        }
84
0
    }
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [f32], image::color::Rgb<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [f32], image::color::Rgba<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u8], image::color::Rgb<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u8], image::color::Luma<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u8], image::color::Rgba<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u8], image::color::LumaA<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u16], image::color::Rgb<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u16], image::color::Luma<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u16], image::color::Rgba<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::flat::ViewMut<&mut [u16], image::color::LumaA<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::test_in_bounds_of::<image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>>>
85
86
    /// Check that the rectangle is contained in the image, panic otherwise.
87
    ///
88
    /// If exposed outside the library, add `#[inline]`.
89
    #[track_caller]
90
0
    pub(crate) fn assert_in_bounds_of(&self, image: &impl GenericImageView) {
91
0
        let dimensions = image.dimensions();
92
93
0
        if !self.is_in_bounds(dimensions) {
94
0
            panic_out_of_bounds(self, dimensions);
95
0
        }
96
0
    }
97
98
    /// Return the part of the rectangle that is in-bounds of the image.
99
0
    pub(crate) fn shrink_to_bounds_of(&self, image: &impl GenericImageView) -> Rect {
100
0
        let (width, height) = image.dimensions();
101
102
0
        let x = cmp::min(self.x, width);
103
0
        let y = cmp::min(self.y, height);
104
105
0
        let width = cmp::min(self.width, width - x);
106
0
        let height = cmp::min(self.height, height - y);
107
108
0
        Rect {
109
0
            x,
110
0
            y,
111
0
            width,
112
0
            height,
113
0
        }
114
0
    }
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgb<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgb<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgb<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Luma<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Luma<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgba<f32>, alloc::vec::Vec<f32>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgba<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::Rgba<u16>, alloc::vec::Vec<u16>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::LumaA<u8>, alloc::vec::Vec<u8>>>
Unexecuted instantiation: <image::math::rect::Rect>::shrink_to_bounds_of::<image::images::buffer::ImageBuffer<image::color::LumaA<u16>, alloc::vec::Vec<u16>>>
115
}
116
117
#[cold]
118
0
fn panic_out_of_bounds(rect: &Rect, dims: (u32, u32)) -> ! {
119
0
    panic!(
120
0
        "The rectangle {:?} is out of bounds for the image with dimensions {}×{}",
121
        rect, dims.0, dims.1
122
    );
123
}