machine_vision_formats/
owned.rs

1//! Implementation of an image type which owns its own image buffer
2
3#[cfg(not(feature = "std"))]
4use alloc::boxed::Box;
5#[cfg(not(feature = "std"))]
6use alloc::vec;
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9
10use crate::{
11    ImageBuffer, ImageBufferMutRef, ImageBufferRef, ImageData, ImageMutData, OwnedImageStride,
12    PixelFormat, Stride,
13};
14
15// -----
16
17/// An owned image buffer with strided pixel format `FMT`.
18#[derive(Clone)]
19pub struct OImage<FMT: PixelFormat> {
20    buf: Vec<u8>,
21    width: u32,
22    height: u32,
23    stride: usize,
24    fmt: std::marker::PhantomData<FMT>,
25}
26
27impl<FMT: PixelFormat> ImageData<FMT> for OImage<FMT> {
28    fn width(&self) -> u32 {
29        self.width
30    }
31    fn height(&self) -> u32 {
32        self.height
33    }
34    fn buffer_ref(&self) -> ImageBufferRef<'_, FMT> {
35        ImageBufferRef::new(&self.buf)
36    }
37    fn buffer(self) -> ImageBuffer<FMT> {
38        // move the data
39        ImageBuffer {
40            data: self.buf,
41            pixel_format: self.fmt,
42        }
43    }
44}
45
46impl<FMT: PixelFormat> ImageMutData<FMT> for OImage<FMT> {
47    fn buffer_mut_ref(&mut self) -> ImageBufferMutRef<'_, FMT> {
48        ImageBufferMutRef::new(&mut self.buf)
49    }
50}
51
52impl<FMT: PixelFormat> Stride for OImage<FMT> {
53    fn stride(&self) -> usize {
54        self.stride
55    }
56}
57
58impl<FMT: PixelFormat> OImage<FMT> {
59    /// Move a `Vec<u8>` buffer as the backing store for an ImageStruct for
60    /// image.
61    ///
62    /// Returns None if the buffer is not large enough to store an image of the
63    /// desired properties.
64    pub fn new(width: u32, height: u32, stride: usize, buf: Vec<u8>) -> Option<Self> {
65        let fmt = crate::pixel_format::pixfmt::<FMT>().unwrap();
66        let min_stride = fmt.bits_per_pixel() as usize * width as usize / 8;
67
68        if height > 0 {
69            // Check buffer size. (With height==0, we accept zero length
70            // buffer.)
71            let sz = stride * (height as usize - 1) + min_stride;
72            if buf.len() < sz {
73                return None;
74            }
75        }
76
77        Some(Self {
78            width,
79            height,
80            stride,
81            buf,
82            fmt: std::marker::PhantomData,
83        })
84    }
85
86    /// Allocate minimum size buffer for image and fill with zeros
87    pub fn zeros(width: u32, height: u32, stride: usize) -> Option<Self> {
88        let fmt = crate::pixel_format::pixfmt::<FMT>().unwrap();
89        let valid_stride = fmt.bits_per_pixel() as usize * width as usize / 8;
90
91        let sz = if height == 0 {
92            0
93        } else {
94            stride * (height as usize - 1) + valid_stride
95        };
96        let buf = vec![0u8; sz];
97        Some(Self {
98            width,
99            height,
100            stride,
101            buf,
102            fmt: std::marker::PhantomData,
103        })
104    }
105
106    pub fn from_owned(orig: impl OwnedImageStride<FMT>) -> Self {
107        let width = orig.width();
108        let height = orig.height();
109        let stride = orig.stride();
110        let buf: Vec<u8> = orig.into(); // move data
111        Self::new(width, height, stride, buf).unwrap()
112    }
113}
114
115/// Compile-time test to ensure ImageStruct implements Send.
116fn _test_owned_image_implements_send<F: PixelFormat + Send>() {
117    fn implements<T: Send>() {}
118    implements::<OImage<F>>();
119}
120
121/// Compile-time test to ensure ImageStruct implements Stride.
122fn _test_owned_image_implements_stride<F: PixelFormat>() {
123    fn implements<T: Stride, F>() {}
124    implements::<OImage<F>, F>();
125}
126
127/// Compile-time test to ensure ImageStruct implements Into<Vec<u8>>.
128fn _test_owned_image_implements_into_vec_u8<F: PixelFormat>() {
129    fn implements<T: Into<Vec<u8>>>() {}
130    implements::<OImage<F>>();
131}
132
133impl<F: PixelFormat> std::fmt::Debug for OImage<F> {
134    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
135        f.debug_struct("ImageStruct")
136            .field("fmt", &self.fmt)
137            .field("width", &self.width)
138            .field("height", &self.height)
139            .field("stride", &self.stride)
140            .finish_non_exhaustive()
141    }
142}
143
144impl<F: PixelFormat> OImage<F> {
145    pub fn copy_from<FRAME: crate::ImageStride<F>>(frame: &FRAME) -> OImage<F> {
146        let width = frame.width();
147        let height = frame.height();
148        let stride = frame.stride();
149        let buf = frame.image_data().to_vec(); // copy data
150
151        Self {
152            width,
153            height,
154            stride,
155            buf,
156            fmt: std::marker::PhantomData,
157        }
158    }
159}
160
161impl<F: PixelFormat> From<OImage<F>> for Vec<u8> {
162    fn from(orig: OImage<F>) -> Vec<u8> {
163        orig.buf
164    }
165}
166
167impl<F: PixelFormat> From<Box<OImage<F>>> for Vec<u8> {
168    fn from(orig: Box<OImage<F>>) -> Vec<u8> {
169        orig.buf
170    }
171}
172
173#[test]
174fn test_alloc() {
175    // test the key size of 0 and some other arbitrary size.
176    for width in [0, 640] {
177        for height in [0, 480] {
178            let min_stride = (width * 3) as usize; // RGB8 has 3 bytes per pixel
179            for stride in [min_stride, min_stride + 10] {
180                // Test zeros.
181                let img =
182                    OImage::<crate::pixel_format::RGB8>::zeros(width, height, stride).unwrap();
183                assert_eq!(img.width(), width);
184                assert_eq!(img.height(), height);
185                assert_eq!(img.stride(), stride);
186
187                // Test new.
188                let sz = height as usize * stride;
189                let buf = vec![0u8; sz]; // allocate buffer
190                let img =
191                    OImage::<crate::pixel_format::RGB8>::new(width, height, stride, buf).unwrap();
192                assert_eq!(img.width(), width);
193                assert_eq!(img.height(), height);
194                assert_eq!(img.stride(), stride);
195            }
196        }
197    }
198}