use crate::hdu::hdu::HDU;
use crate::header::{BayerPattern, ImageType};
use crate::image::{Group, Image};
use image::{ImageBuffer, Luma, Primitive};
use std::error::Error;
use std::fmt;
#[cfg(feature = "tokio")]
pub type NormalisedImageStream<'a> = futures::stream::BoxStream<'a, (u32, u32, f64)>;
pub trait ImageHDU: HDU + fmt::Debug + Send + Sync {
fn image_count(&self) -> usize;
fn images_width(&self) -> u32;
fn images_height(&self) -> u32;
fn images_bayer_pattern(&self) -> Option<BayerPattern>;
fn images_type(&self) -> Option<&ImageType>;
fn images_exposure_time(&self) -> Option<std::time::Duration>;
fn read_image(&self, index: usize) -> Result<Option<Image>, Box<dyn Error + Send + Sync>>;
fn group_count(&self) -> usize {
0
}
fn read_group(&self, index: usize) -> Result<Option<Group>, Box<dyn Error + Send + Sync>>;
fn set_images_u8(
&mut self,
images: &[&ImageBuffer<Luma<u8>, Vec<u8>>],
) -> Result<(), Box<dyn Error + Send + Sync>> {
get_raw_data_from_image(self, images, Self::set_raw_images_u8)
}
fn set_images_i16(
&mut self,
images: &[&ImageBuffer<Luma<i16>, Vec<i16>>],
) -> Result<(), Box<dyn Error + Send + Sync>> {
get_raw_data_from_image(self, images, Self::set_raw_images_i16)
}
fn set_images_i32(
&mut self,
images: &[&ImageBuffer<Luma<i32>, Vec<i32>>],
) -> Result<(), Box<dyn Error + Send + Sync>> {
get_raw_data_from_image(self, images, Self::set_raw_images_i32)
}
fn set_images_f32(
&mut self,
images: &[&ImageBuffer<Luma<f32>, Vec<f32>>],
) -> Result<(), Box<dyn Error + Send + Sync>> {
get_raw_data_from_image(self, images, Self::set_raw_images_f32)
}
fn set_images_f64(
&mut self,
images: &[&ImageBuffer<Luma<f64>, Vec<f64>>],
) -> Result<(), Box<dyn Error + Send + Sync>> {
get_raw_data_from_image(self, images, Self::set_raw_images_f64)
}
fn clear_images(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
fn set_raw_array_u8(
&mut self,
shape: &[u32],
values: &[u8],
) -> Result<(), Box<dyn Error + Send + Sync>>;
fn set_raw_array_i16(
&mut self,
shape: &[u32],
values: &[i16],
) -> Result<(), Box<dyn Error + Send + Sync>>;
fn set_raw_array_i32(
&mut self,
shape: &[u32],
values: &[i32],
) -> Result<(), Box<dyn Error + Send + Sync>>;
fn set_raw_array_f32(
&mut self,
shape: &[u32],
values: &[f32],
) -> Result<(), Box<dyn Error + Send + Sync>>;
fn set_raw_array_f64(
&mut self,
shape: &[u32],
values: &[f64],
) -> Result<(), Box<dyn Error + Send + Sync>>;
fn set_raw_images_u8(
&mut self,
width: u32,
height: u32,
images: &[&[u8]],
) -> Result<(), Box<dyn Error + Send + Sync>> {
set_planes(self, width, height, images, Self::set_raw_array_u8)
}
fn set_raw_images_i16(
&mut self,
width: u32,
height: u32,
images: &[&[i16]],
) -> Result<(), Box<dyn Error + Send + Sync>> {
set_planes(self, width, height, images, Self::set_raw_array_i16)
}
fn set_raw_images_i32(
&mut self,
width: u32,
height: u32,
images: &[&[i32]],
) -> Result<(), Box<dyn Error + Send + Sync>> {
set_planes(self, width, height, images, Self::set_raw_array_i32)
}
fn set_raw_images_f32(
&mut self,
width: u32,
height: u32,
images: &[&[f32]],
) -> Result<(), Box<dyn Error + Send + Sync>> {
set_planes(self, width, height, images, Self::set_raw_array_f32)
}
fn set_raw_images_f64(
&mut self,
width: u32,
height: u32,
images: &[&[f64]],
) -> Result<(), Box<dyn Error + Send + Sync>> {
set_planes(self, width, height, images, Self::set_raw_array_f64)
}
#[cfg(feature = "tokio")]
fn stream_normalised_image(
&self,
index: usize,
) -> Result<Option<NormalisedImageStream<'_>>, Box<dyn Error + Send + Sync>>;
fn image_data_size(&self) -> u64;
fn is_compressed(&self) -> bool {
self.header().is_compressed_image()
}
fn compress(
&mut self,
options: &crate::image::compression::CompressionOptions,
) -> Result<(), Box<dyn Error + Send + Sync>>;
fn decompress(&mut self) -> Result<(), Box<dyn Error + Send + Sync>>;
}
fn set_planes<T: Copy, S: ImageHDU + ?Sized>(
hdu: &mut S,
width: u32,
height: u32,
images: &[&[T]],
set: impl FnOnce(&mut S, &[u32], &[T]) -> Result<(), Box<dyn Error + Send + Sync>>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
if images.is_empty() {
return hdu.clear_images();
}
let pixels = (width as usize)
.checked_mul(height as usize)
.ok_or("Image dimensions overflow the address space")?;
for (index, image) in images.iter().enumerate() {
if image.len() != pixels {
return Err(format!(
"Image {} has {} pixels, but a {}x{} image has {}",
index,
image.len(),
width,
height,
pixels
)
.into());
}
}
let mut shape = vec![width, height];
if images.len() > 1 {
shape.push(images.len() as u32);
}
let values: Vec<T> = images
.iter()
.flat_map(|image| image.iter().copied())
.collect();
set(hdu, &shape, &values)
}
fn get_raw_data_from_image<
'a,
T: Primitive,
S: ImageHDU + ?Sized,
CB: FnOnce(&mut S, u32, u32, &[&[T]]) -> Result<(), Box<dyn Error + Send + Sync>>,
>(
hdu: &mut S,
images: &'a [&'a ImageBuffer<Luma<T>, Vec<T>>],
callback: CB,
) -> Result<(), Box<dyn Error + Send + Sync>> {
if images.is_empty() {
hdu.clear_images()?;
Ok(())
} else {
let width = images[0].width();
let height = images[0].height();
let data = images
.iter()
.map(|image| image.iter().as_slice())
.collect::<Vec<_>>();
callback(hdu, width, height, &data)
}
}