use std::collections::HashMap;
use std::time::{Duration, SystemTime};
use serde::Serialize;
use crate::imagetraits::ImageProps;
use crate::metadata::InsertValue;
use crate::{genericimageowned::GenericImageOwned, genericimageref::GenericImageRef};
use crate::{
BayerError, CalcOptExp, ColorSpace, Debayer, DemosaicMethod, GenericLineItem, OptimumExposure,
PixelType, ToLuma,
};
#[derive(Debug, PartialEq, Serialize)]
pub enum GenericImage<'a> {
Ref(GenericImageRef<'a>),
Own(GenericImageOwned),
}
impl Clone for GenericImage<'_> {
fn clone(&self) -> Self {
match self {
GenericImage::Ref(data) => {
let meta = data.metadata.clone();
GenericImage::Own(GenericImageOwned {
metadata: meta,
image: (&data.image).into(),
})
}
GenericImage::Own(data) => GenericImage::Own(data.clone()),
}
}
}
macro_rules! dynamic_map(
($dynimage: expr, $image: pat => $action: expr) => ({
use GenericImage::*;
match $dynimage {
Ref($image) => Ref($action),
Own($image) => Own($action),
}
});
($dynimage: expr, $image:pat_param, $action: expr) => (
match $dynimage {
GenericImage::Ref($image) => $action,
GenericImage::Own($image) => $action,
}
);
);
impl GenericImage<'_> {
pub fn get_timestamp(&self) -> SystemTime {
dynamic_map!(self, ref image, { image.get_timestamp() })
}
pub fn get_exposure(&self) -> Option<Duration> {
dynamic_map!(self, ref image, { image.get_exposure() })
}
pub fn insert_key<T: InsertValue>(&mut self, name: &str, value: T) -> Result<(), &'static str> {
dynamic_map!(self, ref mut image, { image.insert_key(name, value) })
}
pub fn remove_key(&mut self, name: &str) -> Result<(), &'static str> {
dynamic_map!(self, ref mut image, { image.remove_key(name) })
}
pub fn replace_key<T: InsertValue>(
&mut self,
name: &str,
value: T,
) -> Result<(), &'static str> {
dynamic_map!(self, ref mut image, { image.replace_key(name, value) })
}
pub fn get_metadata(&self) -> &HashMap<String, GenericLineItem> {
dynamic_map!(self, ref image, { image.get_metadata() })
}
pub fn get_key(&self, name: &str) -> Option<&GenericLineItem> {
dynamic_map!(self, ref image, { image.get_key(name) })
}
}
impl ImageProps for GenericImage<'_> {
type OutputU8 = GenericImageOwned;
fn width(&self) -> usize {
dynamic_map!(self, ref image, { image.image.width() })
}
fn height(&self) -> usize {
dynamic_map!(self, ref image, { image.image.height() })
}
fn channels(&self) -> u8 {
dynamic_map!(self, ref image, { image.image.channels() })
}
fn color_space(&self) -> ColorSpace {
dynamic_map!(self, ref image, { image.image.color_space() })
}
fn pixel_type(&self) -> PixelType {
dynamic_map!(self, ref image, { image.image.pixel_type() })
}
fn len(&self) -> usize {
dynamic_map!(self, ref image, { image.image.len() })
}
fn is_empty(&self) -> bool {
dynamic_map!(self, ref image, { image.image.is_empty() })
}
fn cast_u8(&self) -> Self::OutputU8 {
let meta = self.get_metadata().clone();
match self {
GenericImage::Ref(image) => GenericImageOwned {
metadata: meta,
image: image.image.into_u8(),
},
GenericImage::Own(image) => GenericImageOwned {
metadata: meta,
image: image.image.clone().into_u8(),
},
}
}
}
impl From<GenericImageOwned> for GenericImage<'_> {
fn from(img: GenericImageOwned) -> Self {
Self::Own(img)
}
}
impl<'a> From<GenericImageRef<'a>> for GenericImage<'a> {
fn from(img: GenericImageRef<'a>) -> Self {
Self::Ref(img)
}
}
impl From<GenericImage<'_>> for GenericImageOwned {
fn from(val: GenericImage<'_>) -> Self {
match val {
GenericImage::Own(data) => data,
GenericImage::Ref(data) => data.into(),
}
}
}
impl<'a> TryInto<GenericImageRef<'a>> for GenericImage<'a> {
type Error = &'static str;
fn try_into(self) -> Result<GenericImageRef<'a>, Self::Error> {
match self {
GenericImage::Ref(data) => Ok(data),
_ => Err("Image is not GenericImageRef."),
}
}
}
impl<'a: 'b, 'b> ToLuma<'a, 'b> for GenericImage<'b> {
type Output = GenericImageOwned;
fn to_luma(&'b self) -> Result<Self::Output, &'static str> {
match self {
GenericImage::Ref(image) => Ok(image.to_luma()?),
GenericImage::Own(image) => Ok(image.to_luma()?),
}
}
fn to_luma_alpha(&'b self) -> Result<Self::Output, &'static str> {
match self {
GenericImage::Ref(image) => Ok(image.to_luma_alpha()?),
GenericImage::Own(image) => Ok(image.to_luma_alpha()?),
}
}
fn to_luma_custom(&'b self, coeffs: [f64; 3]) -> Result<Self::Output, &'static str> {
match self {
GenericImage::Ref(image) => Ok(image.to_luma_custom(coeffs)?),
GenericImage::Own(image) => Ok(image.to_luma_custom(coeffs)?),
}
}
fn to_luma_alpha_custom(&'b self, coeffs: [f64; 3]) -> Result<Self::Output, &'static str> {
match self {
GenericImage::Ref(image) => Ok(image.to_luma_alpha_custom(coeffs)?),
GenericImage::Own(image) => Ok(image.to_luma_alpha_custom(coeffs)?),
}
}
}
macro_rules! impl_toluma {
($inp: ty, $mid: ty) => {
impl<'a: 'b, 'b> ToLuma<'a, 'b> for $inp {
type Output = GenericImageOwned;
fn to_luma(&'a self) -> Result<Self::Output, &'static str> {
let img = self.get_image().to_luma()?;
let meta = self.metadata.clone();
Ok(Self::Output {
metadata: meta,
image: img,
})
}
fn to_luma_alpha(&'a self) -> Result<Self::Output, &'static str> {
let img = self.get_image().to_luma_alpha()?;
let meta = self.metadata.clone();
Ok(Self::Output {
metadata: meta,
image: img,
})
}
fn to_luma_custom(&'a self, coeffs: [f64; 3]) -> Result<Self::Output, &'static str> {
let img = self.get_image().to_luma_custom(coeffs)?;
let meta = self.metadata.clone();
Ok(Self::Output {
metadata: meta,
image: img,
})
}
fn to_luma_alpha_custom(
&'a self,
coeffs: [f64; 3],
) -> Result<Self::Output, &'static str> {
let img = self.get_image().to_luma_alpha_custom(coeffs)?;
let meta = self.metadata.clone();
Ok(Self::Output {
metadata: meta,
image: img,
})
}
}
};
}
impl_toluma!(GenericImageRef<'_>, DynamicImageRef<'_>);
impl_toluma!(GenericImageOwned, DynamicImageOwned);
impl<'a: 'b, 'b> Debayer<'a, 'b> for GenericImage<'b> {
type Output = GenericImage<'a>;
fn debayer(&'b self, method: DemosaicMethod) -> Result<Self::Output, BayerError> {
match self {
GenericImage::Ref(image) => Ok(image.debayer(method)?.into()),
GenericImage::Own(image) => Ok(image.debayer(method)?.into()),
}
}
}
impl CalcOptExp for GenericImage<'_> {
fn calc_opt_exp(
self,
eval: &OptimumExposure,
exposure: Duration,
bin: u8,
) -> Result<(Duration, u16), &'static str> {
match self {
GenericImage::Ref(img) => img.calc_opt_exp(eval, exposure, bin),
GenericImage::Own(img) => img.calc_opt_exp(eval, exposure, bin),
}
}
}
impl GenericImage<'_> {
pub fn as_raw_u8(&self) -> &[u8] {
dynamic_map!(self, ref image, { image.image.as_raw_u8() })
}
pub fn as_raw_u8_checked(&self) -> Option<&[u8]> {
dynamic_map!(self, ref image, { image.image.as_raw_u8_checked() })
}
pub fn as_slice_u8(&self) -> Option<&[u8]> {
dynamic_map!(self, ref image, { image.image.as_slice_u8() })
}
pub fn as_mut_slice_u8(&mut self) -> Option<&mut [u8]> {
dynamic_map!(self, ref mut image, { image.image.as_mut_slice_u8() })
}
pub fn as_slice_u16(&self) -> Option<&[u16]> {
dynamic_map!(self, ref image, { image.image.as_slice_u16() })
}
pub fn as_mut_slice_u16(&mut self) -> Option<&mut [u16]> {
dynamic_map!(self, ref mut image, { image.image.as_mut_slice_u16() })
}
pub fn as_slice_f32(&self) -> Option<&[f32]> {
dynamic_map!(self, ref image, { image.image.as_slice_f32() })
}
pub fn as_mut_slice_f32(&mut self) -> Option<&mut [f32]> {
dynamic_map!(self, ref mut image, { image.image.as_mut_slice_f32() })
}
}