rawspeed
rawspeed copied to clipboard
Exif data from Silverfast DNG causes rawspeed to fail
This is a follow up issue from the darktable issue (https://github.com/darktable-org/darktable/issues/9447).
tldr of 9447:
- Silverfast (filmscanner) may produce DNG files with additional exif data (IFD1 + PreviewTiff) which causes rawspeed to report the image as corrupt.
- sample images found here
First thought, as shared within the 9447, was that because of the IFD1 Block rawspeed may fail. So I tried to remove it.
I ran exiftool -all= <file>
and magically rawspeed (accessed via darktable) could read the image and all went well. Hurray!
Now I tried to find out whats different within the files.
I made a diff of the exiftool -v
output (see attached) and the IFD1 and PreviewTiff Blocks are still present, but what was removed was:
- IFD0:ApplicationNotes
- IFD0:ExifOffset
I tried removing those by hand. IFD0:ApplicationNotes could be removed, but didn't change anything. The image was then still reported as corrupt. IFD0:ExifOffset could not be removed by hand with exiftool (it says "not writeable"). Does anyone has a tip how to remove it?
But as ExifOffset remains, I guess its whats causing the error and I guess its the content of the MakerNoteUnknownBinary.
Any Ideas how to check that?
Here are the exiftool -v
outputs and diffs.
exif_meta_vs_no_meta_diff.log
exif_w_meta.log
exif_wo_app_note.log
exif_wo_meta.log
Don't think it's metadata per se, more the file structure itself.
rawspeed fails here when parsing the additional IFD1 which does not exist in the lower resolution variant, but I don't think the file is really "corrupt" (exiftools manages to follow and parse the interleaved IFDs and SubIFDs ok), but the layout is a bit unusual...
Ah, there is indeed an erroneous overlap detected. There is an extra (non-existent and invalid) IFD parsed after the Exif subIFD. It is incidentally stating at the 0x927c makernote buffer offset right after the Exif tag entries, I guess coming from here.
The makernote is only 130 bytes of some unknown binary data in this case (correctly stored in the 0x927c tag value count), but rawspeed tries to parse it as an IFD of bogus 234474 bytes (19539 tags), hence the overlap.
This also happens in the lower resolution case, but does not create the problem because there is no attempt to parse/insert any IFDs after it.
I guess only valid makernote IFDs should be added to the 'ifds' list, but not sure how to best detect this...
I guess its the content of the MakerNoteUnknownBinary
@0x10 It was a good hunch after all, but unfortunately I also wasn't able to remove just this tag using exiftool... But if you zero out those 130 bytes in a hex editor then it works out. (The first 6 bytes should suffice actually; maybe even 2...).
BTW, I've looked into makernotes (0x927c) parsing code. I see completely broken logic here:
- makernotes tag data is analysed for known prefixes (e.g. OLYMP or Nikon)
- if nothing known found then entire tag data is passed to TIFF IFD parser
Then, in TIFF IFD parser:
- numEntries is read as 16bit int. For non-TIFF (binary) makernotes block this reads some random unsigned 16-bit number
- IFDFullSize is calculated as 6 + 12 * numEntries (this is some random number based on previous read)
- IFDFullSize is not compared to makernotes tag size (makernotes size is not passed here, so no value to compare), so some random-size file section will be parsed.
- Buffer(offset, IFDFullSize) is inserted into ifds set: this buffer is random size so next IFD may overlap with it, resulting in (false) file refusal
- and this Buffer get parsed via parseIFDEntry calls for numEntries items.
- Again, we're parsing some binary (non TIFF-like) data, so wrong tag data types (this is just some binary bytes) may result into TIFFParserException and so in (correct) file refusal.
The easiest way to improve it is to add 'LSI1\0' as known binary-makernotes prefix and do not parse such sections.
This does not negate the need to correct the entire makernotes parsing logic to not fail on non-tiff makernotes (as noted by @kmilos above):
- IFD parser should compare 0x927c tag size with IFDFullSize calculated and stop makernotes parsing (but do not refuse the file) if calculated size is larger than tag size (opposite case is OK).
- IFD overlap check should be fixed for that case: passed tag size (+offset) should not overlap with other ifds, not calculated size.
- TIFF tag parser should not stop/throw exception if makernotes section being parsed: makernotes are, by definition, vendor specific. It is possible that non-vendor parser does not know some vendor specific. In such case parser should skip unknowns, not raise fatal error.
Dixi
Thanks, much better summary of the problem than what I described.
I guess the same logic can be equally applied to 0xc634 (DNGPrivateData): if parsing as simple IFD (or other known vendor MakerNote variant) is unsuccessful, then fall back to adding it as binary blob as it is currently.
Actually we're discussing raw data decoder, not general-purpose metadata parser (like exiftool or exiv2). I'm not sure at all if it makes sense to parse unknown makernotes blocks: known blocks contains known data (e.g. black/white level) that may be used for raw processing. But what is supposed to be done with unknown data from unknown blocks?
Of course, changing the logic will require additional checks: from such a vendor we parse only such a block (with fixed known prefix list) and these tables will have to be maintained, which is a lot of work. But this is better than rejecting the correct dng
Thanks for both of your summaries (sorry for the late reply, holiday-season...). I'm though a bit confused about the status of the issue now. Do you have a possible solution and its only pending on implementation? Or is this a "won't fix" because its a vendor thingy?
Or is this a "won't fix" because its a vendor thingy?
No, the file is perfectly valid.
I'm though a bit confused about the status of the issue now. Do you have a possible solution and its only pending on implementation?
Yep, pending until someone comes up with a proposed fix for rawspeed.
Okay thank you!