use num::FromPrimitive;
use num_derive::{FromPrimitive, ToPrimitive};
use serde::Serialize;
use zerocopy::{BigEndian, FromBytes, Immutable, IntoBytes, KnownLayout, I32, U32};
use crate::tag::tagdata::MeasurementData;
#[derive(Serialize, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
#[repr(u32)]
pub enum Observer {
Unknown = 0x00000000,
Cie1931TwoDegrees = 0x00000001,
Cie1964TenDegrees = 0x00000002,
}
#[derive(Serialize, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
#[repr(u32)]
pub enum Geometry {
Unknown = 0x00000000,
FourtyFiveZero = 0x00000001, Diffuse = 0x00000002, }
#[derive(FromBytes, IntoBytes, KnownLayout, Immutable)]
#[repr(C, packed)]
struct Layout {
singature: [u8; 4],
_reserved: [u8; 4],
standard_observer: U32<BigEndian>,
xyz: [I32<BigEndian>; 3],
geometry: U32<BigEndian>,
flare: U32<BigEndian>,
illuminant: U32<BigEndian>,
}
#[derive(Serialize, Debug, Clone, PartialEq)]
pub struct MeasurementType {
pub observer: Observer,
pub xyz: Option<[f64; 3]>,
pub geometry: Option<Geometry>,
pub flare_pct: f64,
pub illuminant: super::Illuminant,
}
impl From<&MeasurementData> for MeasurementType {
fn from(measurement: &MeasurementData) -> Self {
let layout = Layout::ref_from_bytes(&measurement.0).unwrap();
let xyz =
if layout.xyz[0].get() == 0 && layout.xyz[1].get() == 0 && layout.xyz[2].get() == 0 {
None
} else {
Some([
layout.xyz[0].get() as f64 / 65536.0,
layout.xyz[1].get() as f64 / 65536.0,
layout.xyz[2].get() as f64 / 65536.0,
])
};
let geometry = if layout.geometry.get() == 0 {
None
} else {
let g: Geometry = FromPrimitive::from_u32(layout.geometry.get()).unwrap();
Some(g)
};
MeasurementType {
observer: FromPrimitive::from_u32(layout.standard_observer.get())
.unwrap_or(Observer::Unknown),
xyz,
geometry,
flare_pct: crate::round_to_precision(layout.flare.get() as f64 * 100.0 / 65536.0, 2),
illuminant: FromPrimitive::from_u32(layout.illuminant.get())
.unwrap_or(super::Illuminant::Unknown),
}
}
}