use std::io::{BufRead, Write};
use super::filter_non_finite;
use crate::lut::{Lut1D, Lut3D};
pub fn write<W: Write>(
mut writer: W,
lut_1d: Option<(f32, f32, [&[f32]; 3])>,
lut_3d: Option<(f32, f32, usize, [&[f32]; 3])>,
) -> std::io::Result<()> {
assert!(!(lut_1d.is_none() && lut_3d.is_none()));
if let Some((range_min, range_max, tables)) = lut_1d {
assert!(tables[0].len() == tables[1].len() && tables[1].len() == tables[2].len());
writer.write_all(format!("LUT_1D_SIZE {}\n", tables[0].len()).as_bytes())?;
writer.write_all(
format!(
"LUT_1D_INPUT_RANGE {} {}\n",
filter_non_finite(range_min),
filter_non_finite(range_max),
)
.as_bytes(),
)?;
}
if let Some((range_min, range_max, res, tables)) = lut_3d {
assert!(tables[0].len() == (res * res * res));
assert!(tables[0].len() == tables[1].len() && tables[1].len() == tables[2].len());
writer.write_all(format!("LUT_3D_SIZE {}\n", res).as_bytes())?;
writer.write_all(
format!(
"LUT_3D_INPUT_RANGE {} {}\n",
filter_non_finite(range_min),
filter_non_finite(range_max),
)
.as_bytes(),
)?;
}
if let Some((_, _, tables)) = lut_1d {
for ((r, g), b) in tables[0]
.iter()
.copied()
.zip(tables[1].iter().copied())
.zip(tables[2].iter().copied())
{
writer.write_all(
format!(
"{} {} {}\n",
filter_non_finite(r),
filter_non_finite(g),
filter_non_finite(b),
)
.as_bytes(),
)?;
}
}
if let Some((_, _, _, tables)) = lut_3d {
for ((r, g), b) in tables[0]
.iter()
.copied()
.zip(tables[1].iter().copied())
.zip(tables[2].iter().copied())
{
writer.write_all(
format!(
"{} {} {}\n",
filter_non_finite(r),
filter_non_finite(g),
filter_non_finite(b),
)
.as_bytes(),
)?;
}
}
Ok(())
}
pub fn read<R: BufRead>(reader: R) -> Result<(Option<Lut1D>, Option<Lut3D>), super::ReadError> {
let mut range_1d = (0.0f32, 1.0f32);
let mut length_1d = 0;
let mut tables_1d = [Vec::new(), Vec::new(), Vec::new()];
let mut range_3d = (0.0f32, 1.0f32);
let mut size_3d = 0;
let mut tables_3d = [Vec::new(), Vec::new(), Vec::new()];
let mut lines = reader.lines().peekable();
while let Some(line) = lines.peek() {
let line = match line {
&Ok(ref s) => s,
&Err(_) => break, };
let parts: Vec<_> = line.split_whitespace().collect();
if parts.is_empty() || parts[0].starts_with("#") {
} else if parts[0] == "TITLE" && parts.len() > 1 {
let name_parts: Vec<_> = line.trim().split("\"").collect();
if name_parts.len() != 3 || !name_parts[2].is_empty() {
return Err(super::ReadError::FormatErr);
}
} else if parts[0] == "LUT_1D_SIZE" && parts.len() == 2 {
length_1d = parts[1].parse::<usize>()?;
} else if parts[0] == "LUT_1D_INPUT_RANGE" && parts.len() == 3 {
range_1d.0 = parts[1].parse::<f32>()?;
range_1d.1 = parts[2].parse::<f32>()?;
} else if parts[0] == "LUT_3D_SIZE" && parts.len() == 2 {
size_3d = parts[1].parse::<usize>()?;
} else if parts[0] == "LUT_3D_INPUT_RANGE" && parts.len() == 3 {
range_3d.0 = parts[1].parse::<f32>()?;
range_3d.1 = parts[2].parse::<f32>()?;
} else {
break;
}
lines.next();
}
if length_1d == 0 && size_3d == 0 {
return Err(super::ReadError::FormatErr);
}
let mut length_3d = size_3d * size_3d * size_3d;
for line in lines {
let line = line?;
let parts: Vec<_> = line.split_whitespace().collect();
if parts.is_empty() || parts[0].starts_with("#") {
} else if parts.len() == 3 {
if length_1d > 0 {
tables_1d[0].push(parts[0].parse::<f32>()?);
tables_1d[1].push(parts[1].parse::<f32>()?);
tables_1d[2].push(parts[2].parse::<f32>()?);
length_1d -= 1;
} else if length_3d > 0 {
tables_3d[0].push(parts[0].parse::<f32>()?);
tables_3d[1].push(parts[1].parse::<f32>()?);
tables_3d[2].push(parts[2].parse::<f32>()?);
length_3d -= 1;
} else {
return Err(super::ReadError::FormatErr);
}
} else {
return Err(super::ReadError::FormatErr);
}
}
if length_1d > 0 || length_3d > 0 {
return Err(super::ReadError::FormatErr);
}
if !tables_1d.iter().flatten().all(|n| n.is_finite())
|| !tables_3d.iter().flatten().all(|n| n.is_finite())
|| !range_1d.0.is_finite()
|| !range_1d.1.is_finite()
|| !range_3d.0.is_finite()
|| !range_3d.1.is_finite()
{
return Err(super::ReadError::FormatErr);
}
let lut_1d = if !tables_1d[0].is_empty() {
let [table_r, table_g, table_b] = tables_1d;
Some(Lut1D {
ranges: vec![range_1d],
tables: vec![table_r, table_g, table_b],
})
} else {
None
};
let lut_3d = if !tables_3d[0].is_empty() {
let [table_r, table_g, table_b] = tables_3d;
Some(Lut3D {
range: [range_3d, range_3d, range_3d],
resolution: [size_3d, size_3d, size_3d],
tables: vec![table_r, table_g, table_b],
})
} else {
None
};
Ok((lut_1d, lut_3d))
}