From 1e55d36e36a0ba447374c40cfe9538c4c70342ed Mon Sep 17 00:00:00 2001 From: dev-null-undefined Date: Wed, 14 Oct 2026 15:58:37 +0200 Subject: [PATCH] =?UTF-8?q?Perf:=20DNG=20Deflate=20tiles=20at=20level=201,?= =?UTF-8?q?=204.8=E2=80=937=C3=97=20faster=20writes=20for=203=E2=80=9312?= =?UTF-8?q?=20%=20more=20bytes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deflate-compressed DNG tiles are written at zlib level 1 instead of 6. Measured on Sony A7R VI files (67 MP), 4 threads, best of 3: - Photo Merge DNG (half floats, 3 channels): 3.88 → 0.55 s, 265.7 → 274.8 MB (+3.4 %) - raw export with Deflate (16-bit CFA): 0.89 → 0.18 s, 96.7 → 103.0 MB (+6.5 %) - rendered DNG: 4.60 → 0.69 s, 239.0 → 267.1 MB (+11.8 %) Lossless either way; both written files decode back bit-exactly. Lossless-JPEG DNGs (the default for convert/import) are unchanged. Co-Authored-By: Claude Opus 5.5 --- crates/raw/src/dngwrite.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/raw/src/dngwrite.rs b/crates/raw/src/dngwrite.rs index 379267c87..08281bf38 100644 --- a/crates/raw/src/dngwrite.rs +++ b/crates/raw/src/dngwrite.rs @@ -29,6 +29,10 @@ pub enum DngCompression { /// the sensor origin instead of the ActiveArea (the reader keeps their original reading). pub const SOFTWARE: &str = "LightCraft DNG 2"; +/// zlib level of Deflate tiles. On a 67 MP focus-stack merge (half floats) level 6 took 7× as long as level 1 +/// (3.9 s vs 0.55 s on 4 cores) to save 3 % of the file (266 vs 275 MB); 5–12 % on raw and rendered DNGs. +const DEFLATE_LEVEL: u8 = 1; + /// IEEE 754 binary32 → binary16 (round to nearest even; overflow → ±inf, NaN kept). pub fn f32_to_f16(v: f32) -> u16 { let b = v.to_bits(); @@ -274,7 +278,7 @@ pub fn write_dng(raw: &RawImage, opts: &DngWriteOptions) -> Result> { } buf.extend_from_slice(&float_predict(&row, tile * cpp, bp, cpp)); } - miniz_oxide::deflate::compress_to_vec_zlib(&buf, 6) + miniz_oxide::deflate::compress_to_vec_zlib(&buf, DEFLATE_LEVEL) }) .collect(); ifd.set_image(ImageData::Tiles { tile_width: tile as u32, tile_height: tile as u32, tiles }); @@ -337,7 +341,7 @@ pub fn write_dng(raw: &RawImage, opts: &DngWriteOptions) -> Result> { } row.iter().for_each(|&x| opts.order.put_u16(&mut buf, x)); } - miniz_oxide::deflate::compress_to_vec_zlib(&buf, 6) + miniz_oxide::deflate::compress_to_vec_zlib(&buf, DEFLATE_LEVEL) }) .collect(); ifd.set_image(ImageData::Tiles { tile_width: tile as u32, tile_height: tile as u32, tiles });