machine_vision_formats/lib.rs
1//! Types and traits for working with raw image data from machine vision
2//! cameras.
3//!
4//! This crate aims to be a lowest common denominator for working with images
5//! from machine vision cameras from companies such as Basler, FLIR, and AVT.
6//!
7//! - Can be compiled without standard library support (`no_std`).
8//! - Includes strongly-typed pixel formats in the [pixel_format] module (e.g.
9//! [pixel_format::RGB8] and [pixel_format::Mono8]) to ensure correct API use.
10//! - Includes types to efficiently iterate through images respecting strided
11//! layouts in the [iter] module.
12//! - Includes structs which reference image data in the [image_ref] module.
13//! - Includes struct which owns image data in the [owned] module.
14//!
15//! Additionally several traits are defined to describe image data:
16//!
17//! - [ImageData] defines the basics, such as image dimensions and the data
18//! buffer.
19//! - [ImageMutData] is implemented for images with mutable data.
20//! - [Stride] is implemented for images with strided data (i.e. each image row
21//! is encoded with exactly the same number of bytes, which may including
22//! padding).
23//! - Compound traits combine these basic traits. [ImageStride] implements both
24//! [ImageData] and [Stride]. [ImageMutStride] implements [ImageMutData] and
25//! [Stride]. [OwnedImage] implements [AsImageData], [ImageData], and
26//! [Into<Vec<`u8`>>]. [OwnedImageStride] implements [AsImageStride],
27//! [ImageStride], and [Into<Vec<`u8`>>].
28//! - Converter traits: [AsImageData] allows converting to `&dyn ImageData`,
29//! [AsImageStride] to `&dyn ImageStride`, and [AsImageMutStride] to `&dyn
30//! ImageMutStride`.
31//!
32//! This crate is used extensively in [Strand
33//! Camera](https://github.com/strawlab/strand-braid).
34#![cfg_attr(not(feature = "std"), no_std)]
35
36#[cfg(not(feature = "std"))]
37extern crate core as std;
38
39#[cfg(feature = "alloc")]
40extern crate alloc;
41
42#[cfg(feature = "alloc")]
43use alloc::vec::Vec;
44
45pub mod image_ref;
46pub mod iter;
47#[cfg(any(feature = "std", feature = "alloc"))]
48pub mod owned;
49
50#[cfg(any(feature = "std", feature = "alloc"))]
51pub mod cow;
52
53#[allow(non_camel_case_types)]
54pub mod pixel_format;
55
56// re-export
57pub use pixel_format::{PixFmt, PixelFormat};
58
59// ------------------------------- ImageBufferRef ----------------------
60
61/// A concrete type with view of image data with pixel format `F`.
62///
63/// This is a zero-size wrapper around a slice of bytes parameterized by the
64/// type `F`. It should cause no additional overhead above passing the raw byte
65/// slice but maintains a compile-time guarantee of the image format.
66#[derive(Clone)]
67pub struct ImageBufferRef<'a, F> {
68 /// The pixel format
69 pub pixel_format: std::marker::PhantomData<F>,
70 /// The raw bytes of the image buffer.
71 pub data: &'a [u8],
72}
73
74impl<F: PixelFormat> std::fmt::Debug for ImageBufferRef<'_, F> {
75 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76 f.debug_struct("ImageBufferRef").finish_non_exhaustive()
77 }
78}
79
80impl<'a, F> ImageBufferRef<'a, F> {
81 #[inline]
82 pub fn new(data: &'a [u8]) -> Self {
83 Self {
84 pixel_format: std::marker::PhantomData,
85 data,
86 }
87 }
88 /// Copy the data to make a new buffer.
89 #[cfg(any(feature = "std", feature = "alloc"))]
90 #[inline]
91 pub fn to_buffer(&self) -> ImageBuffer<F> {
92 ImageBuffer::new(self.data.to_vec())
93 }
94}
95
96// ------------------------------- ImageBufferMutRef ----------------------
97
98/// A concrete type with view of mutable image data with pixel format `F`.
99///
100/// This is a zero-size wrapper around a slice of bytes parameterized by the
101/// type `F`. It should cause no additional overhead above passing the raw byte
102/// slice but maintains a compile-time guarantee of the image format.
103pub struct ImageBufferMutRef<'a, F> {
104 /// The pixel format
105 pub pixel_format: std::marker::PhantomData<F>,
106 /// The raw bytes of the image buffer.
107 pub data: &'a mut [u8],
108}
109
110impl<F: PixelFormat> std::fmt::Debug for ImageBufferMutRef<'_, F> {
111 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
112 f.debug_struct("ImageBufferMutRef").finish_non_exhaustive()
113 }
114}
115
116impl<'a, F> ImageBufferMutRef<'a, F> {
117 #[inline]
118 pub fn new(data: &'a mut [u8]) -> Self {
119 Self {
120 pixel_format: std::marker::PhantomData,
121 data,
122 }
123 }
124 /// Copy the data to make a new buffer.
125 #[cfg(any(feature = "std", feature = "alloc"))]
126 #[inline]
127 pub fn to_buffer(&self) -> ImageBuffer<F> {
128 ImageBuffer::new(self.data.to_vec())
129 }
130}
131
132// ------------------------------- ImageBuffer ----------------------
133
134/// A concrete type which containing image data with pixel format `F`.
135///
136/// This is a zero-size wrapper around bytes parameterized by the type `F`. It
137/// should cause no additional overhead above passing the raw byte vector but
138/// maintains a compile-time guarantee of the image format.
139#[cfg(any(feature = "std", feature = "alloc"))]
140#[derive(Clone)]
141pub struct ImageBuffer<F> {
142 /// The pixel format
143 pub pixel_format: std::marker::PhantomData<F>,
144 /// The raw bytes of the image buffer.
145 pub data: Vec<u8>,
146}
147
148#[cfg(any(feature = "std", feature = "alloc"))]
149impl<F: PixelFormat> std::fmt::Debug for ImageBuffer<F> {
150 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
151 f.debug_struct("ImageBuffer").finish_non_exhaustive()
152 }
153}
154
155#[cfg(any(feature = "std", feature = "alloc"))]
156impl<F> ImageBuffer<F> {
157 #[inline]
158 pub fn new(data: Vec<u8>) -> Self {
159 Self {
160 pixel_format: std::marker::PhantomData,
161 data,
162 }
163 }
164}
165
166// ------------------------------- simple traits ----------------------
167
168/// An image.
169///
170/// The pixel format is specified as the type `F`.
171pub trait ImageData<F> {
172 /// Number of pixel columns in the image. Note: this is not the stride.
173 fn width(&self) -> u32;
174 /// Number of pixel rows in the image.
175 fn height(&self) -> u32;
176 /// Returns the raw image data as specified by pixel format `F`.
177 ///
178 /// This does not copy the data but returns a view of it.
179 ///
180 /// This method may be deprecated in factor of `buffer_ref`.
181 #[inline]
182 fn image_data(&self) -> &[u8] {
183 self.buffer_ref().data
184 }
185 /// Returns the image buffer specified by pixel format `F`.
186 ///
187 /// Ideally, prefer using this over `image_data()`.
188 ///
189 /// This does not copy the data but returns a view of it.
190 fn buffer_ref(&self) -> ImageBufferRef<'_, F>;
191 /// Returns the image buffer specified by pixel format `F`.
192 ///
193 /// Implementations should move the data without copying it if possible. The
194 /// implementation may copy the data if needed. To guarantee a move with no
195 /// copy, use the `Into<Vec<u8>>` trait required by the OwnedImage trait.
196 #[cfg(any(feature = "std", feature = "alloc"))]
197 fn buffer(self) -> ImageBuffer<F>;
198 // fn pixel_format(&self) -> std::marker::PhantomData<F> {
199 // std::marker::PhantomData
200 // }
201}
202
203/// A mutable image.
204///
205/// The pixel format is specified as the type `F`.
206pub trait ImageMutData<F>: ImageData<F> {
207 /// Returns the image mutable buffer specified by pixel format `F`.
208 ///
209 /// This does not copy the data but returns a mutable view of it.
210 fn buffer_mut_ref(&mut self) -> ImageBufferMutRef<'_, F>;
211}
212
213/// An image whose data is stored such that successive rows are a stride apart.
214///
215/// This is sometimes also called "pitch".
216pub trait Stride {
217 /// the width (in bytes) of each row of image data
218 ///
219 /// This is sometimes also called "pitch".
220 fn stride(&self) -> usize;
221}
222
223// ------------------------------- compound traits ----------------------
224
225/// Can be converted into `ImageData`.
226pub trait AsImageData<F>: ImageData<F> {
227 fn as_image_data(&self) -> &dyn ImageData<F>;
228}
229impl<S: ImageData<F>, F> AsImageData<F> for S {
230 fn as_image_data(&self) -> &dyn ImageData<F> {
231 self
232 }
233}
234
235#[cfg(any(feature = "std", feature = "alloc"))]
236/// An image which can be moved into `Vec<u8>`.
237// TODO: any breaking release should add Clone as a supertrait
238pub trait OwnedImage<F>: AsImageData<F> + ImageData<F> + Into<Vec<u8>> {}
239
240#[cfg(any(feature = "std", feature = "alloc"))]
241impl<S, F> OwnedImage<F> for S
242where
243 S: AsImageData<F> + ImageData<F>,
244 Vec<u8>: From<S>,
245{
246}
247
248/// An image with a stride.
249pub trait ImageStride<F>: ImageData<F> + Stride {}
250
251impl<S, F> ImageStride<F> for S where S: ImageData<F> + Stride {}
252
253/// Can be converted into `ImageStride`.
254pub trait AsImageStride<F>: ImageStride<F> {
255 fn as_image_stride(&self) -> &dyn ImageStride<F>;
256}
257impl<S: ImageStride<F>, F> AsImageStride<F> for S {
258 fn as_image_stride(&self) -> &dyn ImageStride<F> {
259 self
260 }
261}
262
263/// A mutable image with a stride.
264pub trait ImageMutStride<F>: ImageMutData<F> + Stride {}
265impl<S, F> ImageMutStride<F> for S where S: ImageMutData<F> + Stride {}
266
267/// Can be converted into `ImageMutStride`.
268pub trait AsImageMutStride<F>: ImageMutStride<F> {
269 fn as_image_mut_stride(&self) -> &dyn ImageMutStride<F>;
270}
271impl<S: ImageMutStride<F>, F> AsImageMutStride<F> for S {
272 fn as_image_mut_stride(&self) -> &dyn ImageMutStride<F> {
273 self
274 }
275}
276
277#[cfg(any(feature = "std", feature = "alloc"))]
278/// An image with a stride which can be moved into `Vec<u8>`.
279// TODO: any breaking release should add Clone as a supertrait
280pub trait OwnedImageStride<F>: AsImageStride<F> + ImageStride<F> + Into<Vec<u8>> {}
281#[cfg(any(feature = "std", feature = "alloc"))]
282impl<S, F> OwnedImageStride<F> for S
283where
284 S: AsImageStride<F> + ImageStride<F>,
285 Vec<u8>: From<S>,
286{
287}