Skip to main content

box_image_pyramid/
imageview.rs

1/// A borrowed, non-owning view into a row-major u8 grayscale image.
2///
3/// `ImageView` does not allocate or copy; it is a lightweight wrapper
4/// around an existing byte slice. Use it to pass image data into
5/// `build_pyramid` without transferring ownership.
6///
7/// Invariant: `data.len() == width * height`. The constructor
8/// [`ImageView::new`] enforces this and returns `None` on mismatch.
9#[derive(Copy, Clone, Debug)]
10pub struct ImageView<'a> {
11    /// Pixel data in row-major order. Row `y` starts at byte
12    /// `y * width`.
13    pub data: &'a [u8],
14    /// Image width in pixels.
15    pub width: usize,
16    /// Image height in pixels.
17    pub height: usize,
18}
19
20impl<'a> ImageView<'a> {
21    /// Create a view from a raw u8 slice.
22    ///
23    /// Returns `None` if `data.len() != width * height`.
24    pub fn new(width: usize, height: usize, data: &'a [u8]) -> Option<Self> {
25        if width.checked_mul(height)? != data.len() {
26            return None;
27        }
28        Some(Self {
29            data,
30            width,
31            height,
32        })
33    }
34}
35
36/// An owned, heap-allocated grayscale image buffer (u8, row-major).
37///
38/// `ImageBuffer` is the owning counterpart of [`ImageView`]. It is used
39/// internally by `PyramidBuffers` to hold the downsampled pyramid
40/// levels and can be borrowed as an [`ImageView`] via
41/// [`ImageBuffer::as_view`].
42#[derive(Clone, Debug)]
43pub struct ImageBuffer {
44    /// Image width in pixels.
45    pub width: usize,
46    /// Image height in pixels.
47    pub height: usize,
48    /// Pixel data in row-major order, zero-initialized at construction.
49    /// Row `y` starts at byte `y * width`.
50    pub data: Vec<u8>,
51}
52
53impl ImageBuffer {
54    /// Allocate a zero-filled buffer with the given dimensions.
55    ///
56    /// Uses [`usize::saturating_mul`], so multiplication never wraps.
57    /// Extremely large dimensions may still request an impractically
58    /// large allocation.
59    pub fn new(width: usize, height: usize) -> Self {
60        Self {
61            width,
62            height,
63            data: vec![0; width.saturating_mul(height)],
64        }
65    }
66
67    /// Borrow this buffer as a non-owning [`ImageView`].
68    ///
69    /// Panics if the internal invariant `data.len() == width * height`
70    /// is violated, which cannot happen through the public API.
71    pub fn as_view(&self) -> ImageView<'_> {
72        ImageView::new(self.width, self.height, &self.data).unwrap()
73    }
74}