use std::time::Duration;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::{
genericimageref::GenericImageRef, metadata::InsertValue, CalcOptExp, DynamicImageOwned,
ExposureResult, GenericLineItem, ImageProps, Metadata, OptimumExposure, OptimumExposureResult,
PixelData,
};
#[allow(unused_imports)]
use crate::{ColorSpace, DynamicImageRef};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GenericImageOwned {
pub(crate) metadata: Metadata,
pub(crate) image: DynamicImageOwned,
}
impl GenericImageOwned {
pub fn new(
timestamp: DateTime<Utc>,
exposure: Duration,
image: impl Into<DynamicImageOwned>,
) -> Self {
Self {
metadata: Metadata::new(timestamp, exposure),
image: image.into(),
}
}
pub fn with_metadata(metadata: Metadata, image: impl Into<DynamicImageOwned>) -> Self {
Self {
metadata,
image: image.into(),
}
}
pub fn timestamp(&self) -> DateTime<Utc> {
self.metadata.timestamp()
}
pub fn exposure(&self) -> Duration {
self.metadata.exposure()
}
pub fn set_exposure(&mut self, exposure: Duration) {
self.metadata.set_exposure(exposure);
}
pub fn frame_id(&self) -> Option<u32> {
self.metadata.frame_id()
}
pub fn set_frame_id(&mut self, frame_id: u32) {
self.metadata.set_frame_id(frame_id);
}
pub fn insert_key<T: InsertValue>(
&mut self,
name: &str,
value: T,
) -> Result<(), crate::MetadataError> {
self.metadata.insert(name, value)
}
pub fn remove_key(&mut self, name: &str) -> Result<GenericLineItem, crate::MetadataError> {
self.metadata.remove(name)
}
pub fn replace_key<T: InsertValue>(
&mut self,
name: &str,
value: T,
) -> Result<GenericLineItem, crate::MetadataError> {
self.metadata.replace(name, value)
}
pub fn image(&self) -> &DynamicImageOwned {
&self.image
}
pub fn image_mut(&mut self) -> &mut DynamicImageOwned {
&mut self.image
}
pub fn metadata(&self) -> &Metadata {
&self.metadata
}
pub fn metadata_mut(&mut self) -> &mut Metadata {
&mut self.metadata
}
pub fn key(&self, name: &str) -> Option<&GenericLineItem> {
self.metadata.get(name)
}
}
impl ImageProps for 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()
}
}
impl<'a> From<GenericImageRef<'a>> for GenericImageOwned {
fn from(img: GenericImageRef<'a>) -> Self {
Self {
metadata: img.metadata,
image: (&img.image).into(),
}
}
}
impl CalcOptExp for GenericImageOwned {
fn calc_opt_exp(
&mut self,
eval: &OptimumExposure,
exposure: Duration,
bin: u16,
) -> ExposureResult<OptimumExposureResult> {
self.image.calc_opt_exp(eval, exposure, bin)
}
}
impl GenericImageOwned {
pub fn optimum_exposure(
&mut self,
eval: &OptimumExposure,
bin: u16,
) -> ExposureResult<OptimumExposureResult> {
let exposure = self.exposure();
self.image.calc_opt_exp(eval, exposure, bin)
}
}
impl PixelData for GenericImageOwned {
fn as_raw_u8(&self) -> &[u8] {
self.image.as_raw_u8()
}
fn as_raw_u8_checked(&self) -> Option<&[u8]> {
self.image.as_raw_u8_checked()
}
fn as_slice_u8(&self) -> Option<&[u8]> {
self.image.as_slice_u8()
}
fn as_mut_slice_u8(&mut self) -> Option<&mut [u8]> {
self.image.as_mut_slice_u8()
}
fn as_slice_u16(&self) -> Option<&[u16]> {
self.image.as_slice_u16()
}
fn as_mut_slice_u16(&mut self) -> Option<&mut [u16]> {
self.image.as_mut_slice_u16()
}
fn as_slice_f32(&self) -> Option<&[f32]> {
self.image.as_slice_f32()
}
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 img = vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let img = crate::ImageOwned::from_owned(img, 5, 2, crate::ColorSpace::Gray)
.expect("Failed to create ImageOwned");
let img = crate::DynamicImageOwned::from(img);
let ts = chrono::DateTime::from_timestamp(1_700_000_000, 0).unwrap();
let mut img = crate::GenericImageOwned::new(ts, std::time::Duration::from_secs(2), img);
let res = img
.calc_opt_exp(&opt_exp, std::time::Duration::from_secs(10), 1)
.unwrap();
assert_eq!(res.exposure, std::time::Duration::from_secs(10));
assert_eq!(res.bin, 1);
let res2 = img.optimum_exposure(&opt_exp, 1).unwrap();
assert!(res2.exposure <= std::time::Duration::from_secs(10));
}
}