From e82b5089f7dc50bafb911930360041307f139413 Mon Sep 17 00:00:00 2001 From: radialmonster Date: Tue, 13 Oct 2026 02:36:28 -0400 Subject: [PATCH] LR-RAW-DNG: DNGs written by older LightCraft keep their sensor-anchored CFAPattern reading; the writer now marks its spec-anchored files 'LightCraft DNG 2' --- crates/raw/src/dng.rs | 6 +++++- crates/raw/src/dngwrite.rs | 6 +++++- crates/raw/tests/dng.rs | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/raw/src/dng.rs b/crates/raw/src/dng.rs index 3c7ece61b..b75f4c61a 100644 --- a/crates/raw/src/dng.rs +++ b/crates/raw/src/dng.rs @@ -303,7 +303,11 @@ pub(crate) fn decode_as(bytes: &[u8], mode: Mode, format: RawFormat) -> Result u16 { let b = v.to_bits(); @@ -119,7 +123,7 @@ pub fn write_dng(raw: &RawImage, opts: &DngWriteOptions) -> Result> { let unique = format!("{make} {model}").trim().to_string(); ifd.set(t::UNIQUE_CAMERA_MODEL, Value::Ascii(if unique.is_empty() { "LightCraft".into() } else { unique })); ifd.set(t::ORIENTATION, Value::Short(vec![raw.orientation.to_exif()])); - ifd.set(t::SOFTWARE, Value::Ascii("LightCraft".into())); + ifd.set(t::SOFTWARE, Value::Ascii(SOFTWARE.into())); let xmp = opts.xmp.clone().unwrap_or_else(|| lightcraft_meta::write_xmp(&raw.metadata, None)); ifd.set(t::XMP, Value::Byte(xmp.into_bytes())); diff --git a/crates/raw/tests/dng.rs b/crates/raw/tests/dng.rs index 9876e349e..a26a4375c 100644 --- a/crates/raw/tests/dng.rs +++ b/crates/raw/tests/dng.rs @@ -1047,3 +1047,21 @@ fn cfa_pattern_is_relative_to_the_active_area() { assert_eq!(back.normalized().unwrap().cfa.unwrap().name(), "GRBG"); } } + +/// DNGs LightCraft wrote before the writer anchored the pattern at the ActiveArea carry a bare "LightCraft" Software +/// tag and a sensor-origin pattern; they keep that reading, while the current writer marks its files differently. +#[test] +fn legacy_lightcraft_dng_keeps_the_sensor_anchored_pattern() { + let (w, h) = (20, 12); + let build = |software: &str| { + let mut raw = base_ifd(w, h, 16, 1, true); + raw.set_image(ImageData::Strips { rows_per_strip: h as u32, strips: vec![u16_bytes(&pattern(w, h, 1, 16), ByteOrder::Little)] }); + raw.set(t::WHITE_LEVEL, Value::Short(vec![65535])); + raw.set(t::ACTIVE_AREA, Value::Long(vec![1, 0, h as u32 - 1, w as u32 - 1])); + raw.set(t::SOFTWARE, Value::Ascii(software.into())); + decode(&dng(raw, ByteOrder::Little)).unwrap() + }; + assert_eq!(build("LightCraft").cfa.unwrap().name(), "GRBG"); + assert_eq!(build("Adobe Photoshop Lightroom").cfa.unwrap().name(), "BGGR"); + assert_ne!(lightcraft_raw::dngwrite::SOFTWARE, "LightCraft"); +}