Merge pull request #235 from Gremiger/fix/issue-212-nef-dng-white-balance

Issue #212: Raw: keep vendor white balance when writing DNG
This commit is contained in:
Brandon Thomas
2026-10-07 20:15:37 -04:00
committed by GitHub
2 changed files with 19 additions and 0 deletions
+3
View File
@@ -177,6 +177,9 @@ pub fn write_dng(raw: &RawImage, opts: &DngWriteOptions) -> Result<Vec<u8>> {
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)
+16
View File
@@ -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);