1use crate::hdu::hdu::HDU;
2use crate::header::{BayerPattern, ImageType};
3use crate::image::{Group, Image};
4use image::{ImageBuffer, Luma, Primitive};
5use std::error::Error;
6use std::fmt;
7
8#[cfg(feature = "tokio")]
10pub type NormalisedImageStream<'a> = futures::stream::BoxStream<'a, (u32, u32, f64)>;
11
12pub trait ImageHDU: HDU + fmt::Debug + Send + Sync {
14 fn image_count(&self) -> usize;
16 fn images_width(&self) -> u32;
18 fn images_height(&self) -> u32;
20 fn images_bayer_pattern(&self) -> Option<BayerPattern>;
22 fn images_type(&self) -> Option<&ImageType>;
24 fn images_exposure_time(&self) -> Option<std::time::Duration>;
26 fn read_image(&self, index: usize) -> Result<Option<Image>, Box<dyn Error + Send + Sync>>;
28
29 fn group_count(&self) -> usize {
34 0
35 }
36
37 fn read_group(&self, index: usize) -> Result<Option<Group>, Box<dyn Error + Send + Sync>>;
39
40 fn set_images_u8(
42 &mut self,
43 images: &[&ImageBuffer<Luma<u8>, Vec<u8>>],
44 ) -> Result<(), Box<dyn Error + Send + Sync>> {
45 get_raw_data_from_image(self, images, Self::set_raw_images_u8)
46 }
47 fn set_images_i16(
49 &mut self,
50 images: &[&ImageBuffer<Luma<i16>, Vec<i16>>],
51 ) -> Result<(), Box<dyn Error + Send + Sync>> {
52 get_raw_data_from_image(self, images, Self::set_raw_images_i16)
53 }
54 fn set_images_i32(
56 &mut self,
57 images: &[&ImageBuffer<Luma<i32>, Vec<i32>>],
58 ) -> Result<(), Box<dyn Error + Send + Sync>> {
59 get_raw_data_from_image(self, images, Self::set_raw_images_i32)
60 }
61 fn set_images_f32(
63 &mut self,
64 images: &[&ImageBuffer<Luma<f32>, Vec<f32>>],
65 ) -> Result<(), Box<dyn Error + Send + Sync>> {
66 get_raw_data_from_image(self, images, Self::set_raw_images_f32)
67 }
68 fn set_images_f64(
70 &mut self,
71 images: &[&ImageBuffer<Luma<f64>, Vec<f64>>],
72 ) -> Result<(), Box<dyn Error + Send + Sync>> {
73 get_raw_data_from_image(self, images, Self::set_raw_images_f64)
74 }
75
76 fn clear_images(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
78
79 fn set_raw_array_u8(
90 &mut self,
91 shape: &[u32],
92 values: &[u8],
93 ) -> Result<(), Box<dyn Error + Send + Sync>>;
94
95 fn set_raw_array_i16(
98 &mut self,
99 shape: &[u32],
100 values: &[i16],
101 ) -> Result<(), Box<dyn Error + Send + Sync>>;
102
103 fn set_raw_array_i32(
106 &mut self,
107 shape: &[u32],
108 values: &[i32],
109 ) -> Result<(), Box<dyn Error + Send + Sync>>;
110
111 fn set_raw_array_f32(
114 &mut self,
115 shape: &[u32],
116 values: &[f32],
117 ) -> Result<(), Box<dyn Error + Send + Sync>>;
118
119 fn set_raw_array_f64(
122 &mut self,
123 shape: &[u32],
124 values: &[f64],
125 ) -> Result<(), Box<dyn Error + Send + Sync>>;
126
127 fn set_raw_images_u8(
131 &mut self,
132 width: u32,
133 height: u32,
134 images: &[&[u8]],
135 ) -> Result<(), Box<dyn Error + Send + Sync>> {
136 set_planes(self, width, height, images, Self::set_raw_array_u8)
137 }
138 fn set_raw_images_i16(
140 &mut self,
141 width: u32,
142 height: u32,
143 images: &[&[i16]],
144 ) -> Result<(), Box<dyn Error + Send + Sync>> {
145 set_planes(self, width, height, images, Self::set_raw_array_i16)
146 }
147 fn set_raw_images_i32(
149 &mut self,
150 width: u32,
151 height: u32,
152 images: &[&[i32]],
153 ) -> Result<(), Box<dyn Error + Send + Sync>> {
154 set_planes(self, width, height, images, Self::set_raw_array_i32)
155 }
156 fn set_raw_images_f32(
158 &mut self,
159 width: u32,
160 height: u32,
161 images: &[&[f32]],
162 ) -> Result<(), Box<dyn Error + Send + Sync>> {
163 set_planes(self, width, height, images, Self::set_raw_array_f32)
164 }
165 fn set_raw_images_f64(
167 &mut self,
168 width: u32,
169 height: u32,
170 images: &[&[f64]],
171 ) -> Result<(), Box<dyn Error + Send + Sync>> {
172 set_planes(self, width, height, images, Self::set_raw_array_f64)
173 }
174
175 #[cfg(feature = "tokio")]
177 fn stream_normalised_image(
178 &self,
179 index: usize,
180 ) -> Result<Option<NormalisedImageStream<'_>>, Box<dyn Error + Send + Sync>>;
181 fn image_data_size(&self) -> u64;
183
184 fn is_compressed(&self) -> bool {
186 self.header().is_compressed_image()
187 }
188
189 fn compress(
225 &mut self,
226 options: &crate::image::compression::CompressionOptions,
227 ) -> Result<(), Box<dyn Error + Send + Sync>>;
228
229 fn decompress(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
237}
238
239fn set_planes<T: Copy, S: ImageHDU + ?Sized>(
244 hdu: &mut S,
245 width: u32,
246 height: u32,
247 images: &[&[T]],
248 set: impl FnOnce(&mut S, &[u32], &[T]) -> Result<(), Box<dyn Error + Send + Sync>>,
249) -> Result<(), Box<dyn Error + Send + Sync>> {
250 if images.is_empty() {
251 return hdu.clear_images();
252 }
253
254 let pixels = (width as usize)
255 .checked_mul(height as usize)
256 .ok_or("Image dimensions overflow the address space")?;
257
258 for (index, image) in images.iter().enumerate() {
261 if image.len() != pixels {
262 return Err(format!(
263 "Image {} has {} pixels, but a {}x{} image has {}",
264 index,
265 image.len(),
266 width,
267 height,
268 pixels
269 )
270 .into());
271 }
272 }
273
274 let mut shape = vec![width, height];
275 if images.len() > 1 {
276 shape.push(images.len() as u32);
277 }
278
279 let values: Vec<T> = images
280 .iter()
281 .flat_map(|image| image.iter().copied())
282 .collect();
283
284 set(hdu, &shape, &values)
285}
286
287fn get_raw_data_from_image<
288 'a,
289 T: Primitive,
290 S: ImageHDU + ?Sized,
291 CB: FnOnce(&mut S, u32, u32, &[&[T]]) -> Result<(), Box<dyn Error + Send + Sync>>,
292>(
293 hdu: &mut S,
294 images: &'a [&'a ImageBuffer<Luma<T>, Vec<T>>],
295 callback: CB,
296) -> Result<(), Box<dyn Error + Send + Sync>> {
297 if images.is_empty() {
298 hdu.clear_images()?;
299 Ok(())
300 } else {
301 let width = images[0].width();
302 let height = images[0].height();
303
304 let data = images
305 .iter()
306 .map(|image| image.iter().as_slice())
307 .collect::<Vec<_>>();
308
309 callback(hdu, width, height, &data)
310 }
311}