Skip to main content

cu_sensor_payloads/
image.rs

1use 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    /// Builds an ImageBuffer from the image crate backed by the CuImage's pixel data.
149    #[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            // SAFETY: The buffer is contiguous, aligned for P::Subpixel (typically u8), and large enough.
160            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            // SAFETY: The buffer is aligned for T, its length is a multiple of T, and it lives long enough.
185            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        // SAFETY: raw_pixels points to size elements laid out for the requested shape.
195        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}