Files
DarkRoom/core/dr-decode/examples/defects.rs
T
dtourolle ecd6df686c
Build and test / Desktop (Linux) (push) Failing after 54s
Build and test / Layer separation (push) Successful in 22s
Traceability / Requirement traces (push) Failing after 59s
🐳 Android image / Build and push (push) Successful in 12m59s
Build and test / android-image (push) Successful in 13m1s
Build and test / Android (aarch64) (push) Failing after 9m42s
Read the defect map a raw file carries
First step of dead pixel removal, and the one that decides whether the
rest is worth building: where the map comes from.

`rawler` is no help. It knows `OpcodeList1/2/3` exist — it copies them
through when *writing* a DNG — but it never decodes them, and the
`dng_tags` map it exposes is only ever filled by callers, never by a
decoder. So the bytes are read from the IFD directly, which this module
was already walking for previews, including the SubIFDs where a DNG keeps
its raw IFD.

`OpcodeList1` specifically: lists 2 and 3 run after demosaic and after the
colour transform, so neither can carry a correction that has to happen on
the mosaic. Two opcodes describe defects — `FixBadPixelsList`, which is
explicit coordinates plus whole dead rows and columns, and
`FixBadPixelsConstant`, which names a sentinel value rather than any
coordinates and is left unimplemented until there is a stage to consume
it. A half-implementation that guessed at coordinates would be worse than
the absence, because it would look like it worked.

Two things the tests pin down because both are silent when wrong: a point
is stored (row, column) and reading it the other way round lands the
correction on the wrong photosite — invisibly, on a square crop — and
opcode payloads are big-endian whatever the container's byte order is, so
a little-endian TIFF still writes these the other way round.

An unknown opcode is stepped over using its declared length rather than
abandoning the list, because a camera that corrected its lens as well as
its sensor writes both, and losing the map whenever a warp is present
would be losing it on most files that have one.

Includes `--example defects`, because whether any of this fires is a
question about a particular library rather than about the specification.
2026-08-21 23:00:10 +02:00

53 lines
1.7 KiB
Rust

//! Report the defect map a raw file carries, if it carries one.
//!
//! ```text
//! cargo run -p dr-decode --example defects -- IMG_6320.dng photo.cr2
//! ```
//!
//! Exists because whether this is worth building a correction stage for is a
//! question about *your files*, not about the specification: DNGs written by
//! cameras that map their own sensors carry `OpcodeList1`, conversions from a
//! proprietary raw usually do not, and no CR2 or scanner TIFF ever does.
//! Rather than guess, point this at the library and see.
fn main() {
let files: Vec<String> = std::env::args().skip(1).collect();
if files.is_empty() {
eprintln!("usage: defects <raw file>...");
std::process::exit(2);
}
for path in &files {
let bytes = match std::fs::read(path) {
Ok(b) => b,
Err(e) => {
println!("{path}: unreadable — {e}");
continue;
}
};
let found = dr_decode::defects(&bytes);
if found.is_empty() {
println!("{path}: no defect map");
continue;
}
println!(
"{path}: {} bad pixel(s), {} bad line(s)",
found.pixels.len(),
found.lines.len()
);
// A handful, so the output stays readable on a sensor reporting
// hundreds — the count above is the number that matters.
for p in found.pixels.iter().take(8) {
println!(" pixel at {},{}", p.x, p.y);
}
for l in found.lines.iter().take(8) {
match l {
dr_decode::BadLine::Column(x) => println!(" dead column {x}"),
dr_decode::BadLine::Row(y) => println!(" dead row {y}"),
}
}
}
}