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> From<ImageRef<'a, F>> for CowImage<'a, F> {
44 /// Creates a [`CowImage::Borrowed`] from an [`ImageRef`].
45 ///
46 /// # Examples
47 /// ```rust
48 /// # use machine_vision_formats::{cow::CowImage, image_ref::ImageRef, pixel_format::RGB8};
49 /// let data = [0u8; 300]; // 10x10 RGB image
50 /// let image_ref = ImageRef::<RGB8>::new(10, 10, 30, &data).unwrap();
51 /// let cow_image = CowImage::from(image_ref);
52 /// ```
53 fn from(frame: ImageRef<'a, F>) -> CowImage<'a, F> {
54 CowImage::Borrowed(frame)
55 }
56}
57
58impl<'a, F: PixelFormat> From<OImage<F>> for CowImage<'a, F> {
59 /// Creates a [`CowImage::Owned`] from an [`OImage`].
60 ///
61 /// # Examples
62 /// ```rust
63 /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8};
64 /// let owned_image = OImage::<Mono8>::new(20, 15, 20, vec![128u8; 300]).unwrap();
65 /// let cow_image = CowImage::from(owned_image);
66 /// ```
67 fn from(frame: OImage<F>) -> CowImage<'a, F> {
68 CowImage::Owned(frame)
69 }
70}
71
72impl<F: PixelFormat> Stride for CowImage<'_, F> {
73 /// Returns the stride (bytes per row) of the image.
74 ///
75 /// # Examples
76 /// ```rust
77 /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, Stride};
78 /// let owned_image = OImage::<Mono8>::new(10, 10, 12, vec![0u8; 120]).unwrap();
79 /// let cow_image = CowImage::from(owned_image);
80 /// assert_eq!(cow_image.stride(), 12);
81 /// ```
82 fn stride(&self) -> usize {
83 match self {
84 CowImage::Borrowed(im) => im.stride(),
85 CowImage::Owned(im) => im.stride(),
86 }
87 }
88}
89
90impl<F: PixelFormat> ImageData<F> for CowImage<'_, F> {
91 /// Returns the width of the image in pixels.
92 ///
93 /// # Examples
94 /// ```rust
95 /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::RGB8, ImageData};
96 /// let owned_image = OImage::<RGB8>::new(25, 20, 75, vec![0u8; 1500]).unwrap();
97 /// let cow_image = CowImage::from(owned_image);
98 /// assert_eq!(cow_image.width(), 25);
99 /// ```
100 fn width(&self) -> u32 {
101 match self {
102 CowImage::Borrowed(im) => im.width(),
103 CowImage::Owned(im) => im.width(),
104 }
105 }
106
107 /// Returns the height of the image in pixels.
108 ///
109 /// # Examples
110 /// ```rust
111 /// # use machine_vision_formats::{cow::CowImage, image_ref::ImageRef, pixel_format::Mono8, ImageData};
112 /// let data = [0u8; 200];
113 /// let image_ref = ImageRef::<Mono8>::new(10, 20, 10, &data).unwrap();
114 /// let cow_image = CowImage::from(image_ref);
115 /// assert_eq!(cow_image.height(), 20);
116 /// ```
117 fn height(&self) -> u32 {
118 match self {
119 CowImage::Borrowed(im) => im.height(),
120 CowImage::Owned(im) => im.height(),
121 }
122 }
123
124 /// Returns a reference to the image buffer.
125 ///
126 /// This provides access to the pixel data regardless of whether the image
127 /// is borrowed or owned.
128 ///
129 /// # Examples
130 /// ```rust
131 /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
132 /// let owned_image = OImage::<Mono8>::new(5, 5, 5, vec![42u8; 25]).unwrap();
133 /// let cow_image = CowImage::from(owned_image);
134 /// let buffer_ref = cow_image.buffer_ref();
135 /// ```
136 fn buffer_ref(&self) -> ImageBufferRef<'_, F> {
137 let image_data = match self {
138 CowImage::Borrowed(im) => im.image_data(),
139 CowImage::Owned(im) => im.image_data(),
140 };
141 ImageBufferRef::new(image_data)
142 }
143
144 /// Consumes the image and returns the pixel data as an owned buffer.
145 ///
146 /// For borrowed images, this copies the data into a new vector.
147 /// For owned images, this moves the existing data without copying.
148 ///
149 /// # Examples
150 /// ```rust
151 /// # use machine_vision_formats::{cow::CowImage, owned::OImage, pixel_format::Mono8, ImageData};
152 /// let owned_image = OImage::<Mono8>::new(4, 4, 4, vec![255u8; 16]).unwrap();
153 /// let cow_image = CowImage::from(owned_image);
154 /// let buffer = cow_image.buffer();
155 /// ```
156 fn buffer(self) -> ImageBuffer<F> {
157 match self {
158 CowImage::Borrowed(im) => ImageBuffer::new(im.image_data().to_vec()),
159 CowImage::Owned(im) => ImageBuffer::new(im.into()),
160 }
161 }
162}