1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
//! Type definitions for working with machine vision cameras.
//!
//! This crate aims to be a lowest common denominator for working with images
//! from machine vision cameras from companies such as Basler, FLIR, and AVT.
//!
//! - Can be compiled without standard library support (`no_std`).
//! - Includes strongly-typed pixel formats in the [pixel_format] module (e.g.
//!   [pixel_format::RGB8] and [pixel_format::Mono8]) to ensure correct API use.
//!
//! Additionally several traits are defined to describe image data:
//!
//! - [ImageData] defines the basics, such as image dimensions and the data
//!   buffer.
//! - [ImageMutData] is implemented for images with mutable data.
//! - [Stride] is implemented for images with strided data (i.e. each image row
//!    is encoded with exactly the same number of bytes, which may including
//!    padding).
//!
//! This crate is used extensively in [Strand
//! Camera](https://github.com/strawlab/strand-braid).
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
extern crate core as std;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "alloc")]
use alloc::vec::Vec;

// TODO: Should we move module `pixel_format` to own crate?
#[allow(non_camel_case_types)]
pub mod pixel_format;

// re-export
pub use pixel_format::{PixFmt, PixelFormat};

// ------------------------------- ImageBufferRef ----------------------

/// A concrete type with view of image data with pixel format `F`.
///
/// This is a zero-size wrapper around a slice of bytes parameterized by the
/// type `F`. It should cause no additional overhead above passing the raw byte
/// slice but maintains a compile-time guarantee of the image format.
#[derive(Clone)]
pub struct ImageBufferRef<'a, F> {
    /// The pixel format
    pub pixel_format: std::marker::PhantomData<F>,
    /// The raw bytes of the image buffer.
    pub data: &'a [u8],
}

impl<'a, F> ImageBufferRef<'a, F> {
    #[inline]
    pub fn new(data: &'a [u8]) -> Self {
        Self {
            pixel_format: std::marker::PhantomData,
            data,
        }
    }
    /// Copy the data to make a new buffer.
    #[cfg(any(feature = "std", feature = "alloc"))]
    #[inline]
    pub fn to_buffer(&self) -> ImageBuffer<F> {
        ImageBuffer::new(self.data.to_vec())
    }
}

// ------------------------------- ImageBufferMutRef ----------------------

/// A concrete type with view of mutable image data with pixel format `F`.
///
/// This is a zero-size wrapper around a slice of bytes parameterized by the
/// type `F`. It should cause no additional overhead above passing the raw byte
/// slice but maintains a compile-time guarantee of the image format.
pub struct ImageBufferMutRef<'a, F> {
    /// The pixel format
    pub pixel_format: std::marker::PhantomData<F>,
    /// The raw bytes of the image buffer.
    pub data: &'a mut [u8],
}

impl<'a, F> ImageBufferMutRef<'a, F> {
    #[inline]
    pub fn new(data: &'a mut [u8]) -> Self {
        Self {
            pixel_format: std::marker::PhantomData,
            data,
        }
    }
    /// Copy the data to make a new buffer.
    #[cfg(any(feature = "std", feature = "alloc"))]
    #[inline]
    pub fn to_buffer(&self) -> ImageBuffer<F> {
        ImageBuffer::new(self.data.to_vec())
    }
}

// ------------------------------- ImageBuffer ----------------------

/// A concrete type which containing image data with pixel format `F`.
///
/// This is a zero-size wrapper around bytes parameterized by the type `F`. It
/// should cause no additional overhead above passing the raw byte vector but
/// maintains a compile-time guarantee of the image format.
#[cfg(any(feature = "std", feature = "alloc"))]
#[derive(Clone)]
pub struct ImageBuffer<F> {
    /// The pixel format
    pub pixel_format: std::marker::PhantomData<F>,
    /// The raw bytes of the image buffer.
    pub data: Vec<u8>,
}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<F> ImageBuffer<F> {
    #[inline]
    pub fn new(data: Vec<u8>) -> Self {
        Self {
            pixel_format: std::marker::PhantomData,
            data,
        }
    }
}

// ------------------------------- simple traits ----------------------

/// An image.
///
/// The pixel format is specified as the type `F`.
pub trait ImageData<F> {
    /// Number of pixel columns in the image. Note: this is not the stride.
    fn width(&self) -> u32;
    /// Number of pixel rows in the image.
    fn height(&self) -> u32;
    /// Returns the raw image data as specified by pixel format `F`.
    ///
    /// This does not copy the data but returns a view of it.
    ///
    /// This method may be deprecated in factor of `buffer_ref`.
    #[inline]
    fn image_data(&self) -> &[u8] {
        &self.buffer_ref().data
    }
    /// Returns the image buffer specified by pixel format `F`.
    ///
    /// Ideally, prefer using this over `image_data()`.
    ///
    /// This does not copy the data but returns a view of it.
    fn buffer_ref(&self) -> ImageBufferRef<'_, F>;
    /// Returns the image buffer specified by pixel format `F`.
    ///
    /// Implementations should move the data without copying it if possible. The
    /// implementation may copy the data if needed. To guarantee a move with no
    /// copy, use the `Into<Vec<u8>>` trait required by the OwnedImage trait.
    #[cfg(any(feature = "std", feature = "alloc"))]
    fn buffer(self) -> ImageBuffer<F>;
}

/// A mutable image.
///
/// The pixel format is specified as the type `F`.
pub trait ImageMutData<F>: ImageData<F> {
    /// Returns the image mutable buffer specified by pixel format `F`.
    ///
    /// This does not copy the data but returns a mutable view of it.
    fn buffer_mut_ref(&mut self) -> ImageBufferMutRef<'_, F>;
}

/// An image whose data is stored such that successive rows are a stride apart.
///
/// This is sometimes also called "pitch".
pub trait Stride {
    /// the width (in bytes) of each row of image data
    ///
    /// This is sometimes also called "pitch".
    fn stride(&self) -> usize;
}

// ------------------------------- compound traits ----------------------

/// Can be converted into `ImageData`.
pub trait AsImageData<F>: ImageData<F> {
    fn as_image_data(&self) -> &dyn ImageData<F>;
}
impl<S: ImageData<F>, F> AsImageData<F> for S {
    fn as_image_data(&self) -> &dyn ImageData<F> {
        self
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
/// An image which can be moved into `Vec<u8>`.
pub trait OwnedImage<F>: AsImageData<F> + ImageData<F> + Into<Vec<u8>> {}

#[cfg(any(feature = "std", feature = "alloc"))]
impl<S, F> OwnedImage<F> for S
where
    S: AsImageData<F> + ImageData<F>,
    Vec<u8>: From<S>,
{
}

/// An image with a stride.
pub trait ImageStride<F>: ImageData<F> + Stride {}
impl<S: ImageData<F> + Stride, F> ImageStride<F> for S {}

/// Can be converted into `ImageStride`.
pub trait AsImageStride<F>: ImageStride<F> {
    fn as_image_stride(&self) -> &dyn ImageStride<F>;
}
impl<S: ImageStride<F>, F> AsImageStride<F> for S {
    fn as_image_stride(&self) -> &dyn ImageStride<F> {
        self
    }
}

#[cfg(any(feature = "std", feature = "alloc"))]
/// An image with a stride which can be moved into `Vec<u8>`.
pub trait OwnedImageStride<F>: AsImageStride<F> + ImageStride<F> + Into<Vec<u8>> {}
#[cfg(any(feature = "std", feature = "alloc"))]
impl<S, F> OwnedImageStride<F> for S
where
    S: AsImageStride<F> + ImageStride<F>,
    Vec<u8>: From<S>,
{
}