use std::{
collections::HashMap,
time::{Duration, SystemTime},
};
use serde::Serialize;
use crate::{
genericimageowned::GenericImageOwned,
metadata::{name_check, InsertValue},
BayerError, CalcOptExp, Debayer, DemosaicMethod, DynamicImageRef, GenericLineItem, ImageProps,
OptimumExposure, EXPOSURE_KEY, TIMESTAMP_KEY,
};
#[allow(unused_imports)]
use crate::ColorSpace;
#[derive(Debug, PartialEq, Serialize)]
pub struct GenericImageRef<'a> {
pub(crate) metadata: HashMap<String, GenericLineItem>,
#[serde(borrow)]
pub(crate) image: DynamicImageRef<'a>,
}
impl<'a> GenericImageRef<'a> {
pub fn new(tstamp: SystemTime, image: DynamicImageRef<'a>) -> Self {
let mut metadata = HashMap::new();
metadata.insert(
TIMESTAMP_KEY.to_string(),
GenericLineItem {
value: tstamp.into(),
comment: Some("Timestamp of the image".to_owned()),
},
);
Self { metadata, image }
}
pub fn get_timestamp(&self) -> SystemTime {
self.metadata
.get(TIMESTAMP_KEY)
.and_then(|x| x.get_value().clone().try_into().ok())
.unwrap() }
pub fn get_exposure(&self) -> Option<Duration> {
self.metadata
.get(EXPOSURE_KEY)
.and_then(|x| x.get_value().clone().try_into().ok())
}
pub fn insert_key<T: InsertValue>(&mut self, name: &str, value: T) -> Result<(), &'static str> {
if name.to_uppercase() == TIMESTAMP_KEY {
return Err("Cannot re-insert timestamp key");
}
T::insert_key_gi(self, name, value)
}
pub fn remove_key(&mut self, name: &str) -> Result<(), &'static str> {
if name.to_uppercase() == TIMESTAMP_KEY {
return Err("Cannot remove timestamp key");
}
name_check(name)?;
self.metadata.remove(name).ok_or("Key not found")?;
Ok(())
}
pub fn replace_key<T: InsertValue>(
&mut self,
name: &str,
value: T,
) -> Result<(), &'static str> {
T::replace_gi(self, name, value)
}
pub fn get_image(&self) -> &DynamicImageRef<'a> {
&self.image
}
pub fn get_image_mut(&mut self) -> &mut DynamicImageRef<'a> {
&mut self.image
}
pub fn get_metadata(&self) -> &HashMap<String, GenericLineItem> {
&self.metadata
}
pub fn get_key(&self, name: &str) -> Option<&GenericLineItem> {
name_check(name).ok()?;
self.metadata.get(name)
}
pub fn into_u8(self) -> GenericImageOwned {
let img = self.image.into_u8();
GenericImageOwned {
metadata: self.metadata,
image: img,
}
}
}
impl Debayer for GenericImageRef<'_> {
type Output = GenericImageOwned;
fn debayer(&self, method: DemosaicMethod) -> Result<Self::Output, BayerError> {
let img = self.image.debayer(method)?;
let meta = self.metadata.clone();
Ok(Self::Output {
metadata: meta,
image: img,
})
}
}
impl CalcOptExp for GenericImageRef<'_> {
fn calc_opt_exp(
mut self,
eval: &OptimumExposure,
exposure: Duration,
bin: u8,
) -> Result<(Duration, u16), &'static str> {
match &mut self.image {
DynamicImageRef::U8(img) => {let len = img.len(); eval.calculate(img.as_mut_slice(), len, exposure, bin)},
DynamicImageRef::U16(img) => {let len = img.len(); eval.calculate(img.as_mut_slice(), len, exposure, bin)},
DynamicImageRef::F32(_) => Err("Floating point images are not supported for this operation, since Ord is not implemented for floating point types."),
}
}
}
impl ImageProps for GenericImageRef<'_> {
type OutputU8 = GenericImageOwned;
fn width(&self) -> usize {
self.image.width()
}
fn height(&self) -> usize {
self.image.height()
}
fn channels(&self) -> u8 {
self.image.channels()
}
fn color_space(&self) -> crate::ColorSpace {
self.image.color_space()
}
fn pixel_type(&self) -> crate::PixelType {
self.image.pixel_type()
}
fn len(&self) -> usize {
self.image.len()
}
fn is_empty(&self) -> bool {
self.image.is_empty()
}
fn cast_u8(&self) -> Self::OutputU8 {
Self::OutputU8 {
metadata: self.metadata.clone(),
image: self.image.into_u8(),
}
}
}
impl GenericImageRef<'_> {
pub fn as_raw_u8(&self) -> &[u8] {
self.image.as_raw_u8()
}
pub fn as_raw_u8_checked(&self) -> Option<&[u8]> {
self.image.as_raw_u8_checked()
}
pub fn as_slice_u8(&self) -> Option<&[u8]> {
self.image.as_slice_u8()
}
pub fn as_mut_slice_u8(&mut self) -> Option<&mut [u8]> {
self.image.as_mut_slice_u8()
}
pub fn as_slice_u16(&self) -> Option<&[u16]> {
self.image.as_slice_u16()
}
pub fn as_mut_slice_u16(&mut self) -> Option<&mut [u16]> {
self.image.as_mut_slice_u16()
}
pub fn as_slice_f32(&self) -> Option<&[f32]> {
self.image.as_slice_f32()
}
pub fn as_mut_slice_f32(&mut self) -> Option<&mut [f32]> {
self.image.as_mut_slice_f32()
}
}
mod test {
#[test]
fn test_optimum_exposure() {
use crate::CalcOptExp;
let opt_exp = crate::OptimumExposureBuilder::default()
.pixel_exclusion(1)
.build()
.unwrap();
let mut img = vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let img = crate::ImageRef::new(img.as_mut_slice(), 5, 2, crate::ColorSpace::Gray)
.expect("Failed to create ImageOwned");
let img = crate::DynamicImageRef::from(img);
let img = crate::GenericImageRef::new(std::time::SystemTime::now(), img);
let exp = std::time::Duration::from_secs(10); let bin = 1; let res = img.calc_opt_exp(&opt_exp, exp, bin).unwrap();
assert_eq!(res, (exp, bin as u16));
}
}