use serde::Serialize;
use zerocopy::I32;
use zerocopy::{BigEndian, Immutable, KnownLayout, TryFromBytes, Unaligned};
use crate::tag::tagdata::Lut8Data;
#[derive(TryFromBytes, KnownLayout, Unaligned, Immutable)]
#[repr(C, packed)]
struct Lut8HeaderLayout {
signature: [u8; 4], _reserved: [u8; 4], n: u8, m: u8, g: u8,
_padding: u8, e_mat: [I32<BigEndian>; 9], }
#[derive(Serialize)]
pub struct Lut8Type {
g: usize, e_mat: [f64; 9], input_luts: Vec<Vec<u8>>, output_luts: Vec<Vec<u8>>, multi_lut: Vec<Vec<u8>>, }
fn reshape_by_grid_points(multi_lut: &[u8], m: usize) -> Vec<Vec<u8>> {
multi_lut.chunks(m).map(|chunk| chunk.to_vec()).collect()
}
impl From<&Lut8Data> for Lut8Type {
fn from(lut8: &Lut8Data) -> Self {
let (layout, _) = Lut8HeaderLayout::try_ref_from_prefix(&lut8.0)
.expect("lut8Type: data too short to contain header");
let n = layout.n as usize;
let m = layout.m as usize;
let g = layout.g as usize;
let e_mat: [f64; 9] = layout
.e_mat
.iter()
.map(|&v| v.get() as f64 / 65536.0)
.collect::<Vec<f64>>()
.try_into()
.unwrap();
let header_size = std::mem::size_of::<Lut8HeaderLayout>();
let input_luts_size = n * 256;
let clut_size = g
.checked_pow(n as u32)
.and_then(|v| v.checked_mul(m))
.expect("lut8Type: CLUT size overflow");
let output_luts_size = m * 256;
let total_size = header_size
.checked_add(input_luts_size)
.and_then(|v| v.checked_add(clut_size))
.and_then(|v| v.checked_add(output_luts_size))
.expect("lut8Type: total size overflow");
assert!(
lut8.0.len() >= total_size,
"lut8Type: truncated data (have {}, need >= {})",
lut8.0.len(),
total_size
);
let input_luts_offset = header_size;
let clut_offset = input_luts_offset + input_luts_size;
let output_luts_offset = clut_offset + clut_size;
let input_luts: Vec<Vec<u8>> = lut8.0
[input_luts_offset..input_luts_offset + input_luts_size]
.chunks(256)
.map(|chunk| chunk.to_vec())
.collect();
let multi_lut = lut8.0[clut_offset..clut_offset + clut_size].to_vec();
let output_luts: Vec<Vec<u8>> = lut8.0
[output_luts_offset..output_luts_offset + output_luts_size]
.chunks(256)
.map(|chunk| chunk.to_vec())
.collect();
Lut8Type {
g,
e_mat,
input_luts,
output_luts,
multi_lut: reshape_by_grid_points(&multi_lut, m),
}
}
}