machine_vision_formats/
cow.rs

1//! Copy-on-Write (CoW) image that can either borrow or own its pixel data.
2
3use crate::{
4    image_ref::ImageRef, owned::OImage, ImageBuffer, ImageBufferRef, ImageData, PixelFormat, Stride,
5};
6
7/// A Copy-on-Write (CoW) image that can either borrow or own its pixel data.
8///
9/// `CowImage` provides a flexible way to work with image data that may be either
10/// borrowed from an existing source or owned by the container. This is particularly
11/// useful in scenarios where you want to avoid unnecessary copying when possible,
12/// but still provide owned data when needed.
13///
14/// The enum has two variants:
15/// - `Borrowed`: Contains an [`ImageRef`] that borrows data from elsewhere
16/// - `Owned`: Contains an [`OImage`] that owns its pixel data
17///
18/// Both variants implement the same image traits, allowing them to be used
19/// interchangeably in most contexts.
20///
21/// # Type Parameters
22/// * `F` - The pixel format type that implements [`PixelFormat`]
23///
24/// # Examples
25/// ```rust
26/// # use machine_vision_formats::{cow::CowImage, owned::OImage, image_ref::ImageRef, pixel_format::Mono8};
27/// // Create from borrowed data
28/// let data = [128u8; 100];
29/// let borrowed_ref = ImageRef::<Mono8>::new(10, 10, 10, &data).unwrap();
30/// let cow_borrowed = CowImage::from(borrowed_ref);
31///
32/// // Create from owned data
33/// let owned_image = OImage::<Mono8>::new(10, 10, 10, vec![64u8; 100]).unwrap();
34/// let cow_owned = CowImage::from(owned_image);
35/// ```
36pub enum CowImage<'a, F: PixelFormat> {
37    /// Borrowed image data with a lifetime tied to the source
38    Borrowed(ImageRef<'a, F>),
39    /// Owned image data that manages its own memory
40    Owned(OImage<F>),
41}
42
43impl<'a, F: PixelFormat> CowImage<'a, F> {
44    /// Consumes the image and returns an owned image.
45    ///
46    /// For borrowed images, this copies the data into a new image.
47    /// For owned images, this moves the existing data without copying.
48    ///
49    /// # Examples
50    /// ```rust
51    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
52    /// let owned_image = OImage::<Mono8>::new(4, 4, 4, vec![255u8; 16]).unwrap();
53    /// let cow_image = CowImage::from(owned_image);
54    /// let owned = cow_image.owned();
55    /// ```
56    pub fn owned(self) -> OImage<F> {
57        match self {
58            CowImage::Borrowed(im) => {
59                let w = im.width();
60                let h = im.height();
61                let s = im.stride();
62                let buf = im.buffer();
63                crate::owned::OImage::new(w, h, s, buf.data).unwrap()
64            }
65            CowImage::Owned(im) => im,
66        }
67    }
68}
69
70impl<'a, F: PixelFormat> From<ImageRef<'a, F>> for CowImage<'a, F> {
71    /// Creates a [`CowImage::Borrowed`] from an [`ImageRef`].
72    ///
73    /// # Examples
74    /// ```rust
75    /// # use machine_vision_formats::{cow::CowImage, image_ref::ImageRef, pixel_format::RGB8};
76    /// let data = [0u8; 300]; // 10x10 RGB image
77    /// let image_ref = ImageRef::<RGB8>::new(10, 10, 30, &data).unwrap();
78    /// let cow_image = CowImage::from(image_ref);
79    /// ```
80    fn from(frame: ImageRef<'a, F>) -> CowImage<'a, F> {
81        CowImage::Borrowed(frame)
82    }
83}
84
85impl<'a, F: PixelFormat> From<OImage<F>> for CowImage<'a, F> {
86    /// Creates a [`CowImage::Owned`] from an [`OImage`].
87    ///
88    /// # Examples
89    /// ```rust
90    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8};
91    /// let owned_image = OImage::<Mono8>::new(20, 15, 20, vec![128u8; 300]).unwrap();
92    /// let cow_image = CowImage::from(owned_image);
93    /// ```
94    fn from(frame: OImage<F>) -> CowImage<'a, F> {
95        CowImage::Owned(frame)
96    }
97}
98
99impl<F: PixelFormat> Stride for CowImage<'_, F> {
100    /// Returns the stride (bytes per row) of the image.
101    ///
102    /// # Examples
103    /// ```rust
104    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, Stride};
105    /// let owned_image = OImage::<Mono8>::new(10, 10, 12, vec![0u8; 120]).unwrap();
106    /// let cow_image = CowImage::from(owned_image);
107    /// assert_eq!(cow_image.stride(), 12);
108    /// ```
109    fn stride(&self) -> usize {
110        match self {
111            CowImage::Borrowed(im) => im.stride(),
112            CowImage::Owned(im) => im.stride(),
113        }
114    }
115}
116
117impl<F: PixelFormat> ImageData<F> for CowImage<'_, F> {
118    /// Returns the width of the image in pixels.
119    ///
120    /// # Examples
121    /// ```rust
122    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::RGB8, ImageData};
123    /// let owned_image = OImage::<RGB8>::new(25, 20, 75, vec![0u8; 1500]).unwrap();
124    /// let cow_image = CowImage::from(owned_image);
125    /// assert_eq!(cow_image.width(), 25);
126    /// ```
127    fn width(&self) -> u32 {
128        match self {
129            CowImage::Borrowed(im) => im.width(),
130            CowImage::Owned(im) => im.width(),
131        }
132    }
133
134    /// Returns the height of the image in pixels.
135    ///
136    /// # Examples
137    /// ```rust
138    /// # use machine_vision_formats::{cow::CowImage, image_ref::ImageRef, pixel_format::Mono8, ImageData};
139    /// let data = [0u8; 200];
140    /// let image_ref = ImageRef::<Mono8>::new(10, 20, 10, &data).unwrap();
141    /// let cow_image = CowImage::from(image_ref);
142    /// assert_eq!(cow_image.height(), 20);
143    /// ```
144    fn height(&self) -> u32 {
145        match self {
146            CowImage::Borrowed(im) => im.height(),
147            CowImage::Owned(im) => im.height(),
148        }
149    }
150
151    /// Returns a reference to the image buffer.
152    ///
153    /// This provides access to the pixel data regardless of whether the image
154    /// is borrowed or owned.
155    ///
156    /// # Examples
157    /// ```rust
158    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
159    /// let owned_image = OImage::<Mono8>::new(5, 5, 5, vec![42u8; 25]).unwrap();
160    /// let cow_image = CowImage::from(owned_image);
161    /// let buffer_ref = cow_image.buffer_ref();
162    /// ```
163    fn buffer_ref(&self) -> ImageBufferRef<'_, F> {
164        let image_data = match self {
165            CowImage::Borrowed(im) => im.image_data(),
166            CowImage::Owned(im) => im.image_data(),
167        };
168        ImageBufferRef::new(image_data)
169    }
170
171    /// Consumes the image and returns the pixel data as an owned buffer.
172    ///
173    /// For borrowed images, this copies the data into a new vector.
174    /// For owned images, this moves the existing data without copying.
175    ///
176    /// # Examples
177    /// ```rust
178    /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
179    /// let owned_image = OImage::<Mono8>::new(4, 4, 4, vec![255u8; 16]).unwrap();
180    /// let cow_image = CowImage::from(owned_image);
181    /// let buffer = cow_image.buffer();
182    /// ```
183    fn buffer(self) -> ImageBuffer<F> {
184        match self {
185            CowImage::Borrowed(im) => ImageBuffer::new(im.image_data().to_vec()),
186            CowImage::Owned(im) => ImageBuffer::new(im.into()),
187        }
188    }
189}