diff --git a/crates/raw/src/dngwrite.rs b/crates/raw/src/dngwrite.rs index 3df8d706d..bd46a2c5b 100644 --- a/crates/raw/src/dngwrite.rs +++ b/crates/raw/src/dngwrite.rs @@ -177,6 +177,9 @@ pub fn write_dng(raw: &RawImage, opts: &DngWriteOptions) -> Result> { ifd.set(t::AS_SHOT_NEUTRAL, rat_vec(&v)); } else if let Some(xy) = c.as_shot_white_xy { ifd.set(t::AS_SHOT_WHITE_XY, rat_vec(&[xy.x, xy.y])); + } else if let Some(m) = raw.wb_multipliers.filter(|m| m.iter().all(|v| *v > 0.0 && v.is_finite())) { + // vendor raws (NEF, ARW…) carry white balance as multipliers: the DNG neutral is their reciprocal + ifd.set(t::AS_SHOT_NEUTRAL, rat_vec(&m.map(|v| 1.0 / v as f64))); } ifd.set(t::BASELINE_EXPOSURE, Value::SRational(vec![srational(c.baseline_exposure)])); // the source's own profile look travels with its data (conversions, smart previews, merges) diff --git a/crates/raw/tests/dng.rs b/crates/raw/tests/dng.rs index 5f0aad287..0d38ebb40 100644 --- a/crates/raw/tests/dng.rs +++ b/crates/raw/tests/dng.rs @@ -453,6 +453,22 @@ fn colour_transform_from_decoded_dng() { assert!(o.iter().all(|v| (v - 1.0).abs() < 1e-9)); } +/// Issue #212: a NEF converted to DNG came out dark and green. NEF white balance is vendor multipliers +/// (no colour matrix, no `AsShotNeutral`); the DNG must carry them as its as-shot neutral. +#[test] +fn vendor_white_balance_survives_dng_conversion() { + let mut raw = synthetic(16, 16, Some(Cfa::bayer("RGGB").unwrap()), 1); + raw.color = ColorData::default(); + raw.wb_multipliers = Some([2.25, 1.0, 1.7421875]); + let before = lightcraft_raw::color::camera_transform(&raw, lightcraft_raw::color::as_shot_white_xy(&raw)); + let back = decode(&write_dng(&raw, &DngWriteOptions::default()).unwrap()).unwrap(); + let after = lightcraft_raw::color::camera_transform(&back, lightcraft_raw::color::as_shot_white_xy(&back)); + for c in 0..3 { + assert!((before.wb[c] - after.wb[c]).abs() < 1e-3, "{:?} vs {:?}", before.wb, after.wb); + } + assert!((after.wb[0] - 2.25).abs() < 1e-3 && (after.wb[2] - 1.7421875).abs() < 1e-3, "{:?}", after.wb); +} + #[test] fn rejects_unsupported_and_broken() { let (w, h) = (8, 8);