Files
DarkRoom/core/dr-decode/examples/rawinfo.rs
T
dtourolle 6b0d29cc15 Read a DNG's NoiseProfile
The converter's measured noise for the body at that ISO, (S, O) per CFA
plane: the learned denoise's best source for a body with no table of its
own (denoise.md §3.3). Read from the header beside the colour tags, and
printed by rawinfo. Checked against tifffile on a 6D DNG at ISO 5000: all
six values agree.
2026-10-03 10:39:15 -04:00

66 lines
2.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Print what `decode` extracts from a RAW file.
//!
//! A sanity check on the pipeline's inputs: black and white levels, the CFA
//! pattern after re-phasing, as-shot white balance, and the camera→sRGB
//! matrix. Wrong values here produce a wrong image no shader can fix, so it
//! is worth being able to see them directly.
//!
//! ```sh
//! cargo run -p dr-decode --example rawinfo -- IMG.CR2
//! ```
fn main() {
let Some(path) = std::env::args().nth(1) else {
eprintln!("usage: rawinfo <file.cr2>");
std::process::exit(2);
};
let bytes = std::fs::read(&path).expect("read file");
let raw = dr_decode::decode(&bytes).expect("decode");
println!("file {path}");
println!("readout {} × {}", raw.width, raw.height);
println!(
"crop {} × {} at ({}, {})",
raw.crop.width, raw.crop.height, raw.crop.x, raw.crop.y
);
let (dx, dy) = raw.crop.shifts_cfa_phase();
println!(
"cfa {:?} (rephased: {dx}, {dy})",
raw.cfa_pattern
);
println!("black {:?}", raw.black_level);
println!("white {}", raw.white_level);
println!("wb_coeffs {:?}", raw.wb_coeffs);
match dr_decode::noise_profile(&bytes) {
Some(p) => println!("noise profile {p:?} ((S, O) per plane)"),
None => println!("noise profile none"),
}
match raw.color_matrix {
Some(m) => {
println!("cam→srgb");
for row in m.chunks(3) {
println!(
" [{:>8.4} {:>8.4} {:>8.4}]",
row[0], row[1], row[2]
);
}
// Each row should sum to roughly 1: a neutral camera-space colour
// must stay neutral in sRGB. Far from 1 means the normalisation
// or the matrix composition is wrong.
let sums: Vec<f32> = m.chunks(3).map(|r| r.iter().sum()).collect();
println!("row sums {sums:.4?} (≈1.0 each if correct)");
}
None => println!("cam→srgb none — uncalibrated body"),
}
// Sample the actual data range, which reveals a black-level or bit-depth
// mistake faster than any amount of staring at metadata.
let (min, max) = raw
.data
.iter()
.fold((u16::MAX, 0u16), |(lo, hi), &v| (lo.min(v), hi.max(v)));
println!("sample range {min} … {max}");
}