File exiftool-minolta_A1-byte-exact-copy.v11.patch of Package perl-Image-ExifTool-minolta_A1-byte-exact.openSUSE_Tumbleweed
exiftool-minolta_A1-byte-exact-copy.v11.patch
This patch allows to make byte exact copies of the Minolta Dimage A1
camera original from a copy edited by exiftool >= 7.34.
This version is ported for Image-ExifTool-9.70.
If you set environment variable MINOLTA_BYTE_EXACT=4 and then remove all
tags you added, you will get a copy, that is equal to the original file
as it came from the camera.
Note: Patch still needs testing for images with edited ExifIFD/UserComment.
Author: Stanislav Brabec <utx@penguin.cz>
Variable MINOLTA_BYTE_EXACT meanings:
0 or undefined: default exiftool behavior
1: organize tags exactly as camera does
4: 1 + pad items exactly as camera does
Notes:
- To get byte-exact copy of original, you have to strip custom tags and
revert existing tags manually, as levels 2 and 3 are not yet
implemented.
- For exiftool >= 7.34 you can get byte exact copy of original even
from files, that were written by with the default exiftool behavior.
- exiftool <= 7.34 has an one obsolete pad byte in the MakerNotes, which
causes a different result after reverting of all tags.
History:
2008-08-08: v1: initial version for Image-ExifTool-7.37
2009-11-23: v2: ported to Image-ExifTool-7.82
2010-07-11: v3: ported to Image-ExifTool-8.15
2010-08-27: v4: fixed byte exact padding with embedded ICC profile
2010-11-01: v5: fixed exact padding for exif size % 512 equal to 392 (support for negative padding)
2011-03-13: v6: ported to Image-ExifTool-8.40
2012-06-06: v7: fixed byte exact padding with Adobe RGB images without embedded ICC profile
2012-09-23: v8: ported to Image-ExifTool-8.65 (v8 was broken)
2013-03-24: v9: ported to Image-ExifTool-9.01
2014-12-08: v10: ported to Image-ExifTool-9.70
2015-03-21: v11: fixed compilation error
Index: Image-ExifTool-9.70/lib/Image/ExifTool/WriteExif.pl
===================================================================
--- Image-ExifTool-9.70.orig/lib/Image/ExifTool/WriteExif.pl
+++ Image-ExifTool-9.70/lib/Image/ExifTool/WriteExif.pl
@@ -1743,6 +1743,25 @@ sub WriteExif($$$)
# set encoding for strings
$strEnc = $et->Options('CharsetEXIF') if $$tagTablePtr{GROUPS}{0} eq 'EXIF';
+# Variable MINOLTA_BYTE_EXACT meanings:
+# 0 or undefined: default exiftool behavior
+# 1: organize tags exactly as camera does
+# 2: 1 + write only tags generated by the camera (not yet implemented)
+# 3: 2 + revert tag to values that camera can generate (not yet implemented)
+# 4: 3 + pad items exactly as camera does
+# Notes:
+# - To get byte-exact copy of original, you have to strip custom tags and
+# revert existing tags manually, as levels 2 and 3 are not yet
+# implemented.
+# - For exiftool >= 7.34 you can get byte exact copy of original even
+# from files, that were written by with the default exiftool behavior.
+ my $minolta_byte_exact;
+ if (defined($ENV{MINOLTA_BYTE_EXACT})) {
+ $minolta_byte_exact = int($ENV{MINOLTA_BYTE_EXACT});
+ } else {
+ $minolta_byte_exact = 0;
+ }
+
# allow multiple IFD's in IFD0-IFD1-IFD2... chain
$$dirInfo{Multi} = 1 if $dirName =~ /^(IFD0|SubIFD)$/ and not defined $$dirInfo{Multi};
$inMakerNotes = 1 if $$tagTablePtr{GROUPS}{0} eq 'MakerNotes';
@@ -1957,6 +1976,7 @@ sub WriteExif($$$)
}
my $dirBuff = ''; # buffer for directory data
my $valBuff = ''; # buffer for value data
+ my $offsetValBuff = 0; # current offset to $valBuff
my @valFixups; # list of fixups for offsets in valBuff
# fixup for offsets in dirBuff
my $dirFixup = new Image::ExifTool::Fixup;
@@ -1968,6 +1988,23 @@ sub WriteExif($$$)
my ($offList, $offHash, $ignoreCount, $fixCount);
my $oldID = -1;
my $newID = -1;
+ my $sizeUserComment = 0;
+
+ if (($minolta_byte_exact > 0) and ($dirName eq 'ExifIFD')) {
+ $index = 0;
+ EntryUserComment:
+ for (;$index < $numEntries;++$index) {
+ $entry = $dirStart + 2 + 12 * $index;
+ $oldID = Get16u($dataPt, $entry);
+ $readCount = Get32u($dataPt, $entry+4);
+ # UserComment
+ if ($oldID == 37510) {
+ $sizeUserComment=$readCount;
+ }
+ }
+ $index = 0;
+ $oldID = -1;
+ }
# patch for Canon EOS 40D firmware 1.0.4 bug (incorrect directory counts)
if ($inMakerNotes and $$et{Model} eq 'Canon EOS 40D') {
@@ -3068,10 +3105,42 @@ NoOverwrite: next if $isNew >
my $entryBased;
if ($$dirInfo{EntryBased} or ($newInfo and $$newInfo{EntryBased})) {
$entryBased = 1;
- $offsetVal = Set32u(length($valBuff) - length($dirBuff));
+ $offsetValBuff = length($valBuff) - length($dirBuff);
} else {
- $offsetVal = Set32u(length $valBuff);
+ if (($minolta_byte_exact > 0) and ($dirName eq 'ExifIFD')) {
+ CASE:{
+ # DateTimeOriginal
+ $newID == 36867 and do{$offsetValBuff = 0; last CASE;};
+ # CreateDate
+ $newID == 36868 and do{$offsetValBuff = 20; last CASE;};
+ # ExposureTime
+ $newID == 33434 and do{$offsetValBuff = 40; last CASE;};
+ # FNumber
+ $newID == 33437 and do{$offsetValBuff = 48; last CASE;};
+ # ExposureCompensation
+ $newID == 37380 and do{$offsetValBuff = 56; last CASE;};
+ # MaxApertureValue
+ $newID == 37381 and do{$offsetValBuff = 64; last CASE;};
+ # FocalLength
+ $newID == 37386 and do{$offsetValBuff = 72; last CASE;};
+ # DigitalZoomRatio
+ $newID == 41988 and do{$offsetValBuff = 80; last CASE;};
+ # BrightnessValue
+ $newID == 37379 and do{$offsetValBuff = 88; last CASE;};
+ # SubjectLocation
+ $newID == 37396 and do{$offsetValBuff = 96; last CASE;};
+ # These two have defined position as well, but editing UserComment, MakerNoteMinolta will change.
+ # As MakerNote is processed first, we must add UserComment size
+ # UserComment
+ $newID == 37510 and do{$offsetValBuff = 104; last CASE;};
+ # MakerNote 37500
+ $newID == 37500 and do{$offsetValBuff = 104 + $sizeUserComment; last CASE;};
+ # Unknown entries
+ do{$offsetValBuff = length $valBuff;};
+ }
+ } else {$offsetValBuff = length $valBuff;};
}
+ $offsetVal = Set32u($offsetValBuff);
my ($dataTag, $putFirst);
($dataTag, $putFirst) = @$newInfo{'DataTag','PutFirst'} if $newInfo;
if ($dataTag) {
@@ -3100,7 +3169,11 @@ NoOverwrite: next if $isNew >
$offsetVal = Set32u(length $$hdrPtr);
$$hdrPtr .= $$newValuePt;
} else {
- $valBuff .= $$newValuePt; # add value data to buffer
+ # pad $valBuff if value starts after current buffer end (in byte exact mode)
+ if ($offsetValBuff > length $valBuff) {
+ $valBuff .= "\0" x ($offsetValBuff - length $valBuff);
+ }
+ (substr $valBuff, $offsetValBuff, length $$newValuePt) = $$newValuePt; # add value data to buffer
# must save a fixup pointer for every pointer in the directory
if ($entryBased) {
$entryBasedFixup or $entryBasedFixup = new Image::ExifTool::Fixup;
@@ -3250,6 +3323,10 @@ NoOverwrite: next if $isNew >
my $valFixup;
foreach $valFixup (@valFixups) {
$$valFixup{Start} += $valPos;
+ if (($minolta_byte_exact > 0) and ($dirName eq 'ExifIFD')) {
+ # Fix MakerNotes fixups to refer to a known fixed position
+ $valFixup->{Start} += $sizeUserComment;
+ }
$fixup->AddFixup($valFixup);
}
# stop if no next IFD pointer
@@ -3652,9 +3729,10 @@ NoOverwrite: next if $isNew >
my $pt = \$$previewInfo{Data}; # image data or 'LOAD_PREVIEW' flag
# now that we know the size of the EXIF data, first test to see if our new image fits
# inside the EXIF segment (remember about the TIFF and EXIF headers: 8+6 bytes)
- if (($$pt ne 'LOAD_PREVIEW' and length($$pt) + length($newData) + 14 <= 0xfffd and
+ if (($minolta_byte_exact == 0) and
+ (($$pt ne 'LOAD_PREVIEW' and length($$pt) + length($newData) + 14 <= 0xfffd and
not $$previewInfo{IsTrailer}) or
- $$previewInfo{IsShort}) # must fit in this segment if using short pointers
+ $$previewInfo{IsShort})) # must fit in this segment if using short pointers
{
# It fits! (or must exist in EXIF segment), so fixup the
# PreviewImage pointers and stuff the preview image in here
@@ -3702,6 +3780,23 @@ NoOverwrite: next if $isNew >
# (could be up to 10 bytes and still be empty)
$newData = '' if defined $newData and length($newData) < 12;
+ if (($minolta_byte_exact > 3) and ($dirName eq 'IFD1')) {
+ my $padSize;
+ # is ICC profile included?
+ # In this time we have no better hint than file extension:
+ # FIXME: Use of RAF would be better.
+ if ($$et{FILE_EXT} eq "JPE") {
+ $padSize = 510 - ((length($newData) + 119) % 512);
+ } else {
+ $padSize = 511 - ((length($newData) + 94) % 512);
+ }
+ if ($padSize == -1) {
+ $newData = substr($newData, 0, length($newData) - 1);
+ } else {
+ $newData .= "\0" x $padSize;
+ }
+ }
+
return $newData; # return our directory data
}