From e9f4a9ff6b65fb03bfe57258cae2a9bc8a3fa500 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Mon, 19 Oct 2026 10:42:03 +0000 Subject: [PATCH] Preserve per-channel shaper domain in .cube round trip Found while testing crates/color/src/lut.rs:290 (Lut::to_cube, the `both` branch) Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/color/src/lut.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/color/src/lut.rs b/crates/color/src/lut.rs index 67590eb12..73879a5b0 100644 --- a/crates/color/src/lut.rs +++ b/crates/color/src/lut.rs @@ -308,7 +308,11 @@ impl Lut { if let Some(sh) = &self.shaper { let _ = writeln!(s, "LUT_1D_SIZE {}", sh.size()); if both { - if sh.domain_min != [0.0; 3] || sh.domain_max != [1.0; 3] { + let uniform = sh.domain_min.iter().all(|v| *v == sh.domain_min[0]) && sh.domain_max.iter().all(|v| *v == sh.domain_max[0]); + if !uniform { + // with both tables, DOMAIN_MIN/DOMAIN_MAX belong to the shaper + write_domain(&mut s, sh.domain_min, sh.domain_max); + } else if sh.domain_min != [0.0; 3] || sh.domain_max != [1.0; 3] { let _ = writeln!(s, "LUT_1D_INPUT_RANGE {} {}", sh.domain_min[0], sh.domain_max[0]); } } else { @@ -650,4 +654,16 @@ mod tests { let mesh257 = (0..257).map(|i| i.to_string()).collect::>().join(" ") + "\n"; assert!(Lut::parse_3dl(&mesh257).is_err()); } + + #[test] + fn cube_shaper_per_channel_domain_round_trips() { + let mut text = String::from("LUT_1D_SIZE 2\nLUT_3D_SIZE 2\nDOMAIN_MAX 1 2 3\n"); + for _ in 0..10 { + text.push_str("0 0 0\n"); + } + let a = Lut::parse_cube(&text).unwrap(); + assert_eq!(a.shaper.as_ref().unwrap().domain_max, [1.0, 2.0, 3.0]); + let b = Lut::parse_cube(&a.to_cube()).unwrap(); + assert_eq!(b.shaper.unwrap().domain_max, [1.0, 2.0, 3.0]); + } }