Date a DNG whose IFDs follow its pixels: read the head and the tail
The scan reads the first 256 KB of a file for its metadata. A camera writes its IFDs at the front, so that is the whole structure; the linear DNG a merge writes puts its first IFD after the pixels, and rawler, given the head alone, finds no decoder in it. The composite was catalogued without a date and sorted to the very end of the grid, after every dated photograph — which is where a panorama merged on the tablet went unfound. dr-decode's own TIFF reader now reads through a head and a tail at a known offset; trailing_ifd says where the tail starts and metadata_split reads the two together. The scan, when the head fails and points beyond itself, fetches from the IFD to the end — kilobytes — and dates the file from both. Tested against the writer's own output.
This commit is contained in:
@@ -241,6 +241,8 @@ mod tests {
|
||||
let source = SourceMetadata {
|
||||
make: Some("Canon".into()),
|
||||
model: Some("Canon EOS 6D".into()),
|
||||
captured_at: Some(1_754_398_664),
|
||||
captured_offset: Some(120),
|
||||
..Default::default()
|
||||
};
|
||||
write_linear_dng(
|
||||
@@ -301,6 +303,32 @@ mod tests {
|
||||
assert_eq!((crop.p.x, crop.p.y, crop.d.w, crop.d.h), (2, 1, 15, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_catalog_reads_the_date_from_a_head_and_a_tail() {
|
||||
// TRACES: FR-CAT-5
|
||||
// The IFDs follow the pixels, so a scan that has the first bytes of
|
||||
// the file has a pointer into nothing; rawler finds no decoder in
|
||||
// that, and the composite would sit undated at the end of the grid.
|
||||
// The scan's second range — from the first IFD to the end — with
|
||||
// the head is enough to date it, and to name the camera.
|
||||
let bytes = write(640, 400, 64);
|
||||
let head = &bytes[..4096];
|
||||
assert!(
|
||||
dr_decode::metadata(head).is_err(),
|
||||
"the head alone must not read"
|
||||
);
|
||||
let at = dr_decode::trailing_ifd(head).expect("the IFD is beyond the head");
|
||||
assert!(at as usize > head.len());
|
||||
let tail = &bytes[at as usize..];
|
||||
assert!(tail.len() < 4096, "the tail is the IFD, not the pixels");
|
||||
let md = dr_decode::metadata_split(head, tail, at).expect("read from two ranges");
|
||||
assert_eq!(md.captured_at, Some(1_754_398_664));
|
||||
assert_eq!(md.captured_offset, Some(120));
|
||||
assert_eq!(md.model.as_deref(), Some("Canon EOS 6D"));
|
||||
// A head that holds everything is not a trailing-IFD file.
|
||||
assert_eq!(dr_decode::trailing_ifd(&bytes), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_strip_of_the_wrong_length_is_refused() {
|
||||
let mut bytes = std::io::Cursor::new(Vec::new());
|
||||
|
||||
Reference in New Issue
Block a user