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}