Read the defect map a raw file carries
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
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
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.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
//! 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}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user