cu_sensor_payloads/
image.rs1use alloc::vec::Vec;
2use bincode::de::Decoder;
3use bincode::error::DecodeError;
4use bincode::{Decode, Encode};
5use core::fmt::Debug;
6use cu29::prelude::*;
7
8#[cfg(feature = "image")]
9use image::{ImageBuffer, Pixel};
10#[cfg(feature = "kornia")]
11use kornia_image::Image;
12#[cfg(feature = "kornia")]
13use kornia_image::allocator::ImageAllocator;
14use serde::{Deserialize, Serialize, Serializer};
15
16#[derive(Default, Debug, Encode, Decode, Clone, Copy, Serialize, Deserialize, Reflect)]
17pub struct CuImageBufferFormat {
18 pub width: u32,
19 pub height: u32,
20 pub stride: u32,
21 pub pixel_format: [u8; 4],
22}
23
24impl CuImageBufferFormat {
25 pub fn byte_size(&self) -> usize {
26 self.stride as usize * self.height as usize
27 }
28}
29
30#[derive(Debug, Default, Clone, Encode, Reflect)]
31#[reflect(from_reflect = false, no_field_bounds, type_path = false)]
32pub struct CuImage<A>
33where
34 A: ArrayLike<Element = u8> + Send + Sync + 'static,
35{
36 pub seq: u64,
37 pub format: CuImageBufferFormat,
38 #[reflect(ignore)]
39 pub buffer_handle: CuHandle<A>,
40}
41
42impl<A> TypePath for CuImage<A>
43where
44 A: ArrayLike<Element = u8> + Send + Sync + 'static,
45{
46 fn type_path() -> &'static str {
47 "cu_sensor_payloads::CuImage"
48 }
49
50 fn short_type_path() -> &'static str {
51 "CuImage"
52 }
53
54 fn type_ident() -> Option<&'static str> {
55 Some("CuImage")
56 }
57
58 fn crate_name() -> Option<&'static str> {
59 Some("cu_sensor_payloads")
60 }
61
62 fn module_path() -> Option<&'static str> {
63 Some("cu_sensor_payloads")
64 }
65}
66
67impl Decode<()> for CuImage<Vec<u8>> {
68 fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
69 let seq: u64 = Decode::decode(decoder)?;
70 let format: CuImageBufferFormat = Decode::decode(decoder)?;
71 let buffer: Vec<u8> = Decode::decode(decoder)?;
72 let buffer_handle = CuHandle::new_detached(buffer);
73
74 Ok(Self {
75 seq,
76 format,
77 buffer_handle,
78 })
79 }
80}
81
82impl<'de> Deserialize<'de> for CuImage<Vec<u8>> {
83 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84 where
85 D: serde::Deserializer<'de>,
86 {
87 #[derive(Deserialize)]
88 struct CuImageWire {
89 seq: u64,
90 format: CuImageBufferFormat,
91 handle: Vec<u8>,
92 }
93
94 let wire = CuImageWire::deserialize(deserializer)?;
95 Ok(Self {
96 seq: wire.seq,
97 format: wire.format,
98 buffer_handle: CuHandle::new_detached(wire.handle),
99 })
100 }
101}
102
103impl<A> Serialize for CuImage<A>
104where
105 A: ArrayLike<Element = u8> + Send + Sync + 'static,
106{
107 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
108 where
109 S: Serializer,
110 {
111 use serde::ser::SerializeStruct;
112 let mut struct_ = serializer.serialize_struct("CuImage", 3)?;
113 struct_.serialize_field("seq", &self.seq)?;
114 struct_.serialize_field("format", &self.format)?;
115 let placeholder_buffer: Vec<u8> = Vec::new();
117 struct_.serialize_field("handle", &placeholder_buffer)?;
118 struct_.end()
119 }
120}
121
122impl<A> CuImage<A>
123where
124 A: ArrayLike<Element = u8> + Send + Sync + 'static,
125{
126 pub fn new(format: CuImageBufferFormat, buffer_handle: CuHandle<A>) -> Self {
127 assert!(
128 format.byte_size() <= buffer_handle.with_inner(|i| i.len()),
129 "Buffer size must at least match the format."
130 );
131 CuImage {
132 seq: 0,
133 format,
134 buffer_handle,
135 }
136 }
137}
138
139impl<A> CuImage<A>
140where
141 A: ArrayLike<Element = u8> + Send + Sync + 'static,
142{
143 #[cfg(feature = "image")]
145 pub fn as_image_buffer<P: Pixel>(&self) -> CuResult<ImageBuffer<P, &[P::Subpixel]>> {
146 let width = self.format.width;
147 let height = self.format.height;
148 assert_eq!(
149 width, self.format.stride,
150 "STRIDE must equal WIDTH for ImageBuffer compatibility."
151 );
152
153 let raw_pixels: &[P::Subpixel] = self.buffer_handle.with_inner(|inner| {
154 unsafe {
156 let data: &[u8] = inner;
157 core::slice::from_raw_parts(data.as_ptr() as *const P::Subpixel, data.len())
158 }
159 });
160 ImageBuffer::from_raw(width, height, raw_pixels)
161 .ok_or("Could not create the image:: buffer".into())
162 }
163
164 #[cfg(feature = "kornia")]
165 pub fn as_kornia_image<T: Clone, const C: usize, K: ImageAllocator>(
166 &self,
167 k: K,
168 ) -> CuResult<Image<T, C, K>> {
169 let width = self.format.width as usize;
170 let height = self.format.height as usize;
171
172 assert_eq!(
173 width, self.format.stride as usize,
174 "stride must equal width for Kornia compatibility."
175 );
176
177 let size = width * height * C;
178 let raw_pixels: &[T] = self.buffer_handle.with_inner(|inner| {
179 unsafe {
181 let data: &[u8] = inner;
182 core::slice::from_raw_parts(
183 data.as_ptr() as *const T,
184 data.len() / core::mem::size_of::<T>(),
185 )
186 }
187 });
188
189 unsafe { Image::from_raw_parts([height, width].into(), raw_pixels.as_ptr(), size, k) }
191 .map_err(|e| CuError::new_with_cause("Could not create a Kornia Image", e))
192 }
193}