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