exiftool_vendored 12.68.0 → 12.70.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +63 -15
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +13 -13
- data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- data/bin/lib/Image/ExifTool/Canon.pm +68 -16
- data/bin/lib/Image/ExifTool/DJI.pm +3 -2
- data/bin/lib/Image/ExifTool/DNG.pm +25 -2
- data/bin/lib/Image/ExifTool/EXE.pm +54 -6
- data/bin/lib/Image/ExifTool/Exif.pm +175 -14
- data/bin/lib/Image/ExifTool/FujiFilm.pm +142 -20
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/ID3.pm +70 -7
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +58 -18
- data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
- data/bin/lib/Image/ExifTool/PNG.pm +8 -13
- data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +32 -5
- data/bin/lib/Image/ExifTool/README +14 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
- data/bin/lib/Image/ExifTool/Sony.pm +95 -34
- data/bin/lib/Image/ExifTool/TagLookup.pm +6937 -6714
- data/bin/lib/Image/ExifTool/TagNames.pod +812 -332
- data/bin/lib/Image/ExifTool/Text.pm +4 -5
- data/bin/lib/Image/ExifTool/Validate.pm +23 -20
- data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
- data/bin/lib/Image/ExifTool/WriteExif.pl +14 -4
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
- data/bin/lib/Image/ExifTool/Writer.pl +40 -14
- data/bin/lib/Image/ExifTool/XMP.pm +67 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
- data/bin/lib/Image/ExifTool.pm +79 -40
- data/bin/lib/Image/ExifTool.pod +9 -3
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
@@ -25,11 +25,10 @@ $VERSION = '1.04';
|
|
25
25
|
Although basic text files contain no metadata, the following tags are
|
26
26
|
determined from a simple analysis of the data in TXT and CSV files.
|
27
27
|
Statistics are generated only for 8-bit encodings, but the L<FastScan|../ExifTool.html#FastScan> (-fast)
|
28
|
-
option may be used to limit processing to the first 64
|
29
|
-
tags are not produced. To avoid long processing delays, ExifTool will
|
30
|
-
a minor warning and process only the first 64
|
31
|
-
|
32
|
-
option is used.
|
28
|
+
option may be used to limit processing to the first 64 KiB in which case
|
29
|
+
some tags are not produced. To avoid long processing delays, ExifTool will
|
30
|
+
issue a minor warning and process only the first 64 KiB of any file larger
|
31
|
+
than 20 MiB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m) option is used.
|
33
32
|
},
|
34
33
|
MIMEEncoding => { Groups => { 2 => 'Other' } },
|
35
34
|
Newlines => {
|
@@ -17,7 +17,7 @@ package Image::ExifTool::Validate;
|
|
17
17
|
use strict;
|
18
18
|
use vars qw($VERSION %exifSpec);
|
19
19
|
|
20
|
-
$VERSION = '1.
|
20
|
+
$VERSION = '1.23';
|
21
21
|
|
22
22
|
use Image::ExifTool qw(:Utils);
|
23
23
|
use Image::ExifTool::Exif;
|
@@ -86,7 +86,7 @@ my %verCheck = (
|
|
86
86
|
GPS => { GPSVersionID => \%gpsVer },
|
87
87
|
);
|
88
88
|
|
89
|
-
# tags standard in various RAW file formats
|
89
|
+
# tags standard in various RAW file formats or IFD's
|
90
90
|
my %otherSpec = (
|
91
91
|
CR2 => { 0xc5d8 => 1, 0xc5d9 => 1, 0xc5e0 => 1, 0xc640 => 1, 0xc6dc => 1, 0xc6dd => 1 },
|
92
92
|
NEF => { 0x9216 => 1, 0x9217 => 1 },
|
@@ -103,6 +103,7 @@ my %otherSpec = (
|
|
103
103
|
SRW => { 0xa010 => 1, 0xa011 => 1, 0xa101 => 1, 0xa102 => 1 },
|
104
104
|
NRW => { 0x9216 => 1, 0x9217 => 1 },
|
105
105
|
X3F => { 0xa500 => 1 },
|
106
|
+
CameraIFD => { All => 1 }, # (exists in JPG and DNG of Leica Q3 images)
|
106
107
|
);
|
107
108
|
|
108
109
|
# standard format for tags (not necessary for exifSpec or GPS tags where Writable is defined)
|
@@ -142,20 +143,22 @@ my %stdFormat = (
|
|
142
143
|
# GeoTiff tags:
|
143
144
|
0x830e => 'double', 0x8482 => 'double', 0x87af => 'int16u', 0x87b1 => 'string',
|
144
145
|
0x8480 => 'double', 0x85d8 => 'double', 0x87b0 => 'double',
|
145
|
-
# DNG tags:
|
146
|
-
0xc615 => '(string|int8u)',
|
147
|
-
0xc61a => '(int16u|int32u|rational64u)',
|
148
|
-
0xc61d => 'int(16|32)u',
|
149
|
-
0xc61f => '(int16u|int32u|rational64u)',
|
150
|
-
0xc620 => '(int16u|int32u|rational64u)',
|
151
|
-
0xc628 => '(int16u|rational64u)',
|
152
|
-
0xc634 => 'int8u',
|
153
|
-
0xc640 => '',
|
154
|
-
0xc660 => '',
|
155
|
-
0xc68b => '(string|int8u)',
|
156
|
-
0xc68d => 'int(16|32)u',
|
157
|
-
0xc68e => 'int(16|32)u',
|
158
|
-
0xc6d2 => '',
|
146
|
+
# DNG tags: (use '' for non-DNG tags in the range 0xc612-0xcd48)
|
147
|
+
0xc615 => '(string|int8u)', 0xc6f4 => '(string|int8u)',
|
148
|
+
0xc61a => '(int16u|int32u|rational64u)', 0xc6f6 => '(string|int8u)',
|
149
|
+
0xc61d => 'int(16|32)u', 0xc6f8 => '(string|int8u)',
|
150
|
+
0xc61f => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
|
151
|
+
0xc620 => '(int16u|int32u|rational64u)', 0xc716 => '(string|int8u)',
|
152
|
+
0xc628 => '(int16u|rational64u)', 0xc717 => '(string|int8u)',
|
153
|
+
0xc634 => 'int8u', 0xc718 => '(string|int8u)',
|
154
|
+
0xc640 => '', 0xc71e => 'int(16|32)u',
|
155
|
+
0xc660 => '', 0xc71f => 'int(16|32)u',
|
156
|
+
0xc68b => '(string|int8u)', 0xc791 => 'int(16|32)u',
|
157
|
+
0xc68d => 'int(16|32)u', 0xc792 => 'int(16|32)u',
|
158
|
+
0xc68e => 'int(16|32)u', 0xc793 => '(int16u|int32u|rational64u)',
|
159
|
+
0xc6d2 => '', 0xcd43 => 'int(16|32)u',
|
160
|
+
0xc6d3 => '', 0xcd48 => '(string|int8u)',
|
161
|
+
|
159
162
|
# Exif 3.0 spec
|
160
163
|
0x10e => 'string|utf8', 0xa430 => 'string|utf8', 0xa439 => 'string|utf8',
|
161
164
|
0x10f => 'string|utf8', 0xa433 => 'string|utf8', 0xa43a => 'string|utf8',
|
@@ -430,7 +433,7 @@ sub ValidateExif($$$$$$$$)
|
|
430
433
|
my $stdFmt = $stdFormat{$ifd} || $stdFormat{IFD};
|
431
434
|
if (defined $$stdFmt{All} or ($tagTablePtr eq \%Image::ExifTool::Exif::Main and
|
432
435
|
($exifSpec{$tag} or $$stdFmt{$tag} or
|
433
|
-
($tag >= 0xc612 and $tag <=
|
436
|
+
($tag >= 0xc612 and $tag <= 0xcd48 and not defined $$stdFmt{$tag}))) or # (DNG tags)
|
434
437
|
$$tagTablePtr{SHORT_NAME} eq 'GPS::Main')
|
435
438
|
{
|
436
439
|
my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP};
|
@@ -456,8 +459,8 @@ sub ValidateExif($$$$$$$$)
|
|
456
459
|
} elsif (not $otherSpec{$$et{FileType}} or
|
457
460
|
(not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
|
458
461
|
{
|
459
|
-
if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$
|
460
|
-
$et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1);
|
462
|
+
if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$ti{Unknown}) {
|
463
|
+
$et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1) unless $otherSpec{$ifd};
|
461
464
|
}
|
462
465
|
}
|
463
466
|
# change expected count from read Format to Writable size
|
@@ -478,7 +481,7 @@ sub ValidateExif($$$$$$$$)
|
|
478
481
|
} elsif (not $otherSpec{$$et{FileType}} or
|
479
482
|
(not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
|
480
483
|
{
|
481
|
-
$et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1);
|
484
|
+
$et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1) unless $otherSpec{$ifd};
|
482
485
|
}
|
483
486
|
}
|
484
487
|
|
@@ -142,7 +142,6 @@ sub SaveMakerNotes($)
|
|
142
142
|
}
|
143
143
|
# save position of maker notes for pointer fixups
|
144
144
|
$fixup->{Shift} += length($makerNotes);
|
145
|
-
$$et{MAKER_NOTE_FIXUP} = $fixup;
|
146
145
|
$$et{MAKER_NOTE_BYTE_ORDER} = GetByteOrder();
|
147
146
|
# add value data
|
148
147
|
$makerNotes .= $makerInfo->{ValBuff};
|
@@ -150,7 +149,8 @@ sub SaveMakerNotes($)
|
|
150
149
|
my $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::Exif::Main');
|
151
150
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, 0x927c, \$makerNotes);
|
152
151
|
# save the MakerNotes
|
153
|
-
$et->FoundTag($tagInfo, $makerNotes);
|
152
|
+
my $key = $et->FoundTag($tagInfo, $makerNotes);
|
153
|
+
$$et{TAG_EXTRA}{$key}{Fixup} = $fixup;
|
154
154
|
# save the garbage collection some work later
|
155
155
|
delete $makerInfo->{Entries};
|
156
156
|
delete $makerInfo->{ValBuff};
|
@@ -930,8 +930,16 @@ Entry: for (;;) {
|
|
930
930
|
}
|
931
931
|
}
|
932
932
|
unless ($success) {
|
933
|
-
|
934
|
-
|
933
|
+
my $wrn = sprintf("Error reading value for $name entry $index, ID 0x%.4x", $oldID);
|
934
|
+
my $truncOK;
|
935
|
+
if ($oldInfo and not $$oldInfo{Unknown}) {
|
936
|
+
$wrn .= " $$oldInfo{Name}";
|
937
|
+
$truncOK = $$oldInfo{TruncateOK};
|
938
|
+
}
|
939
|
+
return undef if $et->Error($wrn, $inMakerNotes || $truncOK);
|
940
|
+
unless ($truncOK) {
|
941
|
+
++$index; $oldID = $newID; next; # drop this tag
|
942
|
+
}
|
935
943
|
}
|
936
944
|
} elsif (not $invalidPreview) {
|
937
945
|
return undef if $et->Error("Bad $name offset for $tagStr", $inMakerNotes);
|
@@ -1094,6 +1102,8 @@ Entry: for (;;) {
|
|
1094
1102
|
# add, edit or delete this tag
|
1095
1103
|
shift @newTags; # remove from list
|
1096
1104
|
my $curInfo = $set{$newID};
|
1105
|
+
# don't allow MakerNotes to be added to ExifIFD of CR3 file
|
1106
|
+
next if $newID == 0x927c and $isNew > 0 and $$et{FileType} eq 'CR3';
|
1097
1107
|
unless ($curInfo or $$addDirs{$newID}) {
|
1098
1108
|
# we can finally get the specific tagInfo reference for this tag
|
1099
1109
|
# (because we can now evaluate the Condition statement since all
|
@@ -1429,8 +1439,8 @@ NoOverwrite: next if $isNew > 0;
|
|
1429
1439
|
if ($$et{DEL_GROUP}{MakerNotes} and
|
1430
1440
|
($$et{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0))
|
1431
1441
|
{
|
1432
|
-
if ($et->IsRawType()) {
|
1433
|
-
$et->
|
1442
|
+
if ($et->IsRawType() and not ($et->IsRawType() == 2 and $dirName eq 'ExifIFD')) {
|
1443
|
+
$et->Warn("Can't delete MakerNotes from $$et{FileType}",1);
|
1434
1444
|
} else {
|
1435
1445
|
if ($isNew <= 0) {
|
1436
1446
|
++$$et{CHANGED};
|
@@ -19,6 +19,8 @@ my %webpMap = (
|
|
19
19
|
'XMP ' => 'RIFF', # (the RIFF chunk name is 'XMP ')
|
20
20
|
EXIF => 'RIFF',
|
21
21
|
ICCP => 'RIFF',
|
22
|
+
C2PA => 'RIFF',
|
23
|
+
JUMBF => 'C2PA',
|
22
24
|
XMP => 'XMP ',
|
23
25
|
IFD0 => 'EXIF',
|
24
26
|
IFD1 => 'IFD0',
|
@@ -66,6 +68,7 @@ sub WriteRIFF($$)
|
|
66
68
|
$et->InitWriteDirs(\%webpMap);
|
67
69
|
my $addDirs = $$et{ADD_DIRS};
|
68
70
|
my $editDirs = $$et{EDIT_DIRS};
|
71
|
+
$$addDirs{IFD0} = 'EXIF' if $$addDirs{EXIF}; # set flag to add IFD0 if adding EXIF (don't ask)
|
69
72
|
my ($createVP8X, $deleteVP8X);
|
70
73
|
|
71
74
|
# write header
|
@@ -142,6 +145,17 @@ sub WriteRIFF($$)
|
|
142
145
|
}
|
143
146
|
# RIFF chunks are padded to an even number of bytes
|
144
147
|
my $len2 = $len + ($len & 0x01);
|
148
|
+
# handle incorrect "XMP\0" chunk ID written by Google software
|
149
|
+
if ($tag eq "XMP\0") {
|
150
|
+
if ($$et{DEL_GROUP}{XMP}) {
|
151
|
+
# just ignore this chunk if deleting XMP
|
152
|
+
$raf->Seek($len2, 1) or $et->Error('Seek error'), last;
|
153
|
+
++$$et{CHANGED};
|
154
|
+
next;
|
155
|
+
} else {
|
156
|
+
$et->Warn('Incorrect XMP tag ID',1) if $pass;
|
157
|
+
}
|
158
|
+
}
|
145
159
|
# edit/add/delete necessary metadata chunks (EXIF must come before XMP)
|
146
160
|
if ($$editDirs{$tag} or $tag eq '' or ($tag eq 'XMP ' and $$addDirs{EXIF})) {
|
147
161
|
my $handledTag;
|
@@ -156,13 +170,12 @@ sub WriteRIFF($$)
|
|
156
170
|
#
|
157
171
|
# add/edit/delete EXIF/XMP/ICCP (note: EXIF must come before XMP, and ICCP is written elsewhere)
|
158
172
|
#
|
159
|
-
my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
|
160
|
-
my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
|
173
|
+
my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'JUMBF' );
|
174
|
+
my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'Jpeg2000' );
|
161
175
|
my $dir;
|
162
|
-
foreach $dir ('EXIF', 'XMP ', 'ICCP' ) {
|
176
|
+
foreach $dir ('EXIF', 'XMP ', 'ICCP', 'C2PA' ) {
|
163
177
|
next unless $tag eq $dir or ($$addDirs{$dir} and
|
164
178
|
($tag eq '' or ($tag eq 'XMP ' and $dir eq 'EXIF')));
|
165
|
-
delete $$addDirs{$dir}; # (don't try to add again)
|
166
179
|
my $start;
|
167
180
|
unless ($pass) {
|
168
181
|
# write the EXIF and save the result for the next pass
|
@@ -170,8 +183,15 @@ sub WriteRIFF($$)
|
|
170
183
|
if ($tag eq 'EXIF') {
|
171
184
|
# (only need to set directory $start for EXIF)
|
172
185
|
if ($buff =~ /^Exif\0\0/) {
|
173
|
-
|
174
|
-
|
186
|
+
if ($$et{DEL_GROUP}{EXIF}) {
|
187
|
+
# remove incorrect header if rewriting anyway
|
188
|
+
$buff = substr($buff, 6);
|
189
|
+
$len -= 6;
|
190
|
+
$len2 -= 6;
|
191
|
+
} else {
|
192
|
+
$et->Warn('Improper EXIF header',1) unless $pass;
|
193
|
+
$start = 6;
|
194
|
+
}
|
175
195
|
} else {
|
176
196
|
$start = 0;
|
177
197
|
}
|
@@ -189,11 +209,16 @@ sub WriteRIFF($$)
|
|
189
209
|
Parent => $dir,
|
190
210
|
DirName => $dirName{$dir},
|
191
211
|
);
|
212
|
+
# must pass the TagInfo to enable deletion of C2PA information
|
213
|
+
if (ref $Image::ExifTool::RIFF::Main{$dir} eq 'HASH') {
|
214
|
+
$dirInfo{TagInfo} = $Image::ExifTool::RIFF::Main{$dir};
|
215
|
+
}
|
192
216
|
my $tagTablePtr = GetTagTable("Image::ExifTool::$tblName{$dir}::Main");
|
193
217
|
# (override writeProc for EXIF because it has the TIFF header)
|
194
218
|
my $writeProc = $dir eq 'EXIF' ? \&Image::ExifTool::WriteTIFF : undef;
|
195
219
|
$dirDat{$dir} = $et->WriteDirectory(\%dirInfo, $tagTablePtr, $writeProc);
|
196
220
|
}
|
221
|
+
delete $$addDirs{$dir}; # (don't try to add again)
|
197
222
|
if (defined $dirDat{$dir}) {
|
198
223
|
if ($dir eq $tag) {
|
199
224
|
$handledTag = 1; # set flag indicating we edited this tag
|
@@ -122,9 +122,9 @@ my %writableType = (
|
|
122
122
|
XMP => [ undef, 'WriteXMP' ],
|
123
123
|
);
|
124
124
|
|
125
|
-
# RAW file types
|
125
|
+
# RAW file types (2 = raw file where we can delete maker notes from ExifIFD)
|
126
126
|
my %rawType = (
|
127
|
-
'3FR'=> 1, CR3 =>
|
127
|
+
'3FR'=> 1, CR3 => 2, IIQ => 1, NEF => 1, RW2 => 1,
|
128
128
|
ARQ => 1, CRW => 1, K25 => 1, NRW => 1, RWL => 1,
|
129
129
|
ARW => 1, DCR => 1, KDC => 1, ORF => 1, SR2 => 1,
|
130
130
|
ARW => 1, ERF => 1, MEF => 1, PEF => 1, SRF => 1,
|
@@ -278,6 +278,7 @@ my %ignorePrintConv = map { $_ => 1 } qw(OTHER BITMASK Notes);
|
|
278
278
|
# ListOnly => [internal use] set only list or non-list tags
|
279
279
|
# SetTags => [internal use] hash ref to return tagInfo refs of set tags
|
280
280
|
# Sanitized => [internal use] set to avoid double-sanitizing the value
|
281
|
+
# Fixup => [internal use] fixup information when writing maker notes
|
281
282
|
# Returns: number of tags set (plus error string in list context)
|
282
283
|
# Notes: For tag lists (like Keywords), call repeatedly with the same tag name for
|
283
284
|
# each value in the list. Internally, the new information is stored in
|
@@ -1002,10 +1003,8 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
1002
1003
|
$$nvHash{NoReplace} = 1 if $$tagInfo{List} and not $options{Replace};
|
1003
1004
|
$$nvHash{WantGroup} = $wantGroup;
|
1004
1005
|
$$nvHash{EditOnly} = 1 if $editOnly;
|
1005
|
-
# save maker note information if writing maker notes
|
1006
|
-
if
|
1007
|
-
$$nvHash{MAKER_NOTE_FIXUP} = $$self{MAKER_NOTE_FIXUP};
|
1008
|
-
}
|
1006
|
+
# save maker note fixup information if writing maker notes
|
1007
|
+
$$nvHash{MAKER_NOTE_FIXUP} = $options{Fixup} if $$tagInfo{MakerNotes};
|
1009
1008
|
if ($createOnly) { # create only (never edit)
|
1010
1009
|
# empty item in DelValue list to never edit existing value
|
1011
1010
|
$$nvHash{DelValue} = [ '' ];
|
@@ -1272,6 +1271,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1272
1271
|
# +------------------------------------------+
|
1273
1272
|
$srcExifTool->Options(
|
1274
1273
|
Binary => 1,
|
1274
|
+
ByteUnit => $$options{ByteUnit},
|
1275
1275
|
Charset => $$options{Charset},
|
1276
1276
|
CharsetEXIF => $$options{CharsetEXIF},
|
1277
1277
|
CharsetFileName => $$options{CharsetFileName},
|
@@ -1372,8 +1372,8 @@ sub SetNewValuesFromFile($$;@)
|
|
1372
1372
|
#
|
1373
1373
|
unless (@setTags) {
|
1374
1374
|
# transfer maker note information to this object
|
1375
|
-
$$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
|
1376
1375
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
1376
|
+
my $tagExtra = $$srcExifTool{TAG_EXTRA};
|
1377
1377
|
foreach $tag (@tags) {
|
1378
1378
|
# don't try to set errors or warnings
|
1379
1379
|
next if $tag =~ /^(Error|Warning)\b/;
|
@@ -1381,10 +1381,13 @@ sub SetNewValuesFromFile($$;@)
|
|
1381
1381
|
if ($opts{SrcType} and $opts{SrcType} ne $srcType) {
|
1382
1382
|
$$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType});
|
1383
1383
|
}
|
1384
|
+
my $fixup = $$tagExtra{$tag}{Fixup};
|
1385
|
+
$opts{Fixup} = $fixup if $fixup;
|
1384
1386
|
# set value for this tag
|
1385
1387
|
my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts);
|
1386
1388
|
# delete this tag if we couldn't set it
|
1387
1389
|
$n or delete $$info{$tag};
|
1390
|
+
delete $opts{Fixup} if $fixup;
|
1388
1391
|
}
|
1389
1392
|
return $info;
|
1390
1393
|
}
|
@@ -1617,7 +1620,7 @@ SET: foreach $set (@setList) {
|
|
1617
1620
|
}
|
1618
1621
|
# transfer maker note information if setting this tag
|
1619
1622
|
if ($$srcExifTool{TAG_INFO}{$tag}{MakerNotes}) {
|
1620
|
-
$$
|
1623
|
+
$$opts{Fixup} = $$srcExifTool{TAG_EXTRA}{$tag}{Fixup};
|
1621
1624
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
1622
1625
|
}
|
1623
1626
|
if ($dstTag eq '*') {
|
@@ -1649,6 +1652,7 @@ SET: foreach $set (@setList) {
|
|
1649
1652
|
$rtnInfo{NextFreeTagKey(\%rtnInfo, 'Warning')} = $wrn;
|
1650
1653
|
$noWarn = 1;
|
1651
1654
|
}
|
1655
|
+
delete $$opts{Fixup};
|
1652
1656
|
$rtnInfo{$tag} = $val if $rtn; # tag was set successfully
|
1653
1657
|
}
|
1654
1658
|
}
|
@@ -4176,6 +4180,7 @@ sub WriteDirectory($$$;$)
|
|
4176
4180
|
$out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose};
|
4177
4181
|
# set directory name from default group0 name if not done already
|
4178
4182
|
my $dirName = $$dirInfo{DirName};
|
4183
|
+
my $parent = $$dirInfo{Parent} || '';
|
4179
4184
|
my $dataPt = $$dirInfo{DataPt};
|
4180
4185
|
my $grp0 = $$tagTablePtr{GROUPS}{0};
|
4181
4186
|
$dirName or $dirName = $$dirInfo{DirName} = $grp0;
|
@@ -4183,14 +4188,19 @@ sub WriteDirectory($$$;$)
|
|
4183
4188
|
my $delGroup = $$self{DEL_GROUP};
|
4184
4189
|
# delete entire directory if specified
|
4185
4190
|
my $grp1 = $dirName;
|
4186
|
-
$delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1})
|
4191
|
+
$delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1});
|
4192
|
+
if ($permanentDir{$grp0} and not ($$dirInfo{TagInfo} and $$dirInfo{TagInfo}{Deletable})) {
|
4193
|
+
undef $delFlag;
|
4194
|
+
}
|
4187
4195
|
# (never delete an entire QuickTime group)
|
4188
4196
|
if ($delFlag) {
|
4189
4197
|
if (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and
|
4190
4198
|
$self->IsRawType() and
|
4191
4199
|
# allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
|
4192
4200
|
(not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
|
4193
|
-
$$dirInfo{TagInfo}{Permanent})
|
4201
|
+
$$dirInfo{TagInfo}{Permanent}) and
|
4202
|
+
# allow MakerNotes to be deleted from ExifIFD of CR3 file
|
4203
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
4194
4204
|
{
|
4195
4205
|
$self->WarnOnce("Can't delete $1 from $$self{FileType}",1);
|
4196
4206
|
undef $grp1;
|
@@ -4226,7 +4236,6 @@ sub WriteDirectory($$$;$)
|
|
4226
4236
|
if ($delFlag == 2 and $right) {
|
4227
4237
|
# also check grandparent because some routines create 2 levels in 1
|
4228
4238
|
my $right2 = $$self{ADD_DIRS}{$right} || '';
|
4229
|
-
my $parent = $$dirInfo{Parent};
|
4230
4239
|
if (not $parent or $parent eq $right or $parent eq $right2) {
|
4231
4240
|
# prevent duplicate directories from being recreated at the same path
|
4232
4241
|
my $path = join '-', @{$$self{PATH}}, $dirName;
|
@@ -4284,10 +4293,27 @@ sub WriteDirectory($$$;$)
|
|
4284
4293
|
last unless $self->IsOverwriting($nvHash, $dataPt ? $$dataPt : '');
|
4285
4294
|
my $verb = 'Writing';
|
4286
4295
|
my $newVal = $self->GetNewValue($nvHash);
|
4287
|
-
|
4296
|
+
if (defined $newVal and length $newVal) {
|
4297
|
+
# hack to add back TIFF header when writing MakerNoteCanon to CMT3 in CR3 images
|
4298
|
+
if ($$tagInfo{Name} eq 'MakerNoteCanon') {
|
4299
|
+
require Image::ExifTool::Canon;
|
4300
|
+
if ($tagInfo eq $Image::ExifTool::Canon::uuid{CMT3}) {
|
4301
|
+
my $hdr;
|
4302
|
+
if (substr($newVal, 0, 1) eq "\0") {
|
4303
|
+
$hdr = "MM\0\x2a" . pack('N', 8);
|
4304
|
+
} else {
|
4305
|
+
$hdr = "II\x2a\0" . pack('V', 8);
|
4306
|
+
}
|
4307
|
+
$newVal = $hdr . $newVal;
|
4308
|
+
}
|
4309
|
+
}
|
4310
|
+
} else {
|
4288
4311
|
return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed
|
4289
4312
|
# don't allow MakerNotes to be removed from RAW files
|
4290
|
-
if ($blockName eq 'MakerNotes' and $
|
4313
|
+
if ($blockName eq 'MakerNotes' and $self->IsRawType() and
|
4314
|
+
# but allow MakerNotes to be deleted from ExifIFD of CR3 image (shouldn't be there)
|
4315
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
4316
|
+
{
|
4291
4317
|
$self->Warn("Can't delete MakerNotes from $$self{FileType}",1);
|
4292
4318
|
return undef;
|
4293
4319
|
}
|
@@ -7067,7 +7093,7 @@ sub WriteBinaryData($$$)
|
|
7067
7093
|
$newVal = length($data) if defined $data;
|
7068
7094
|
my $format = $$tagInfo{Format} || $$tagTablePtr{FORMAT} || 'int32u';
|
7069
7095
|
if ($format =~ /^int16/ and $newVal > 0xffff) {
|
7070
|
-
$self->Error("$$tagInfo{DataTag} is too large (64
|
7096
|
+
$self->Error("$$tagInfo{DataTag} is too large (64 KiB max. for this file)");
|
7071
7097
|
}
|
7072
7098
|
}
|
7073
7099
|
my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $entry);
|
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
|
|
50
50
|
use Image::ExifTool::GPS;
|
51
51
|
require Exporter;
|
52
52
|
|
53
|
-
$VERSION = '3.
|
53
|
+
$VERSION = '3.61';
|
54
54
|
@ISA = qw(Exporter);
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
56
56
|
|
@@ -201,6 +201,8 @@ my %xmpNS = (
|
|
201
201
|
nine => 'http://ns.nikon.com/nine/1.0/',
|
202
202
|
hdr_metadata => 'http://ns.adobe.com/hdr-metadata/1.0/',
|
203
203
|
hdrgm => 'http://ns.adobe.com/hdr-gain-map/1.0/',
|
204
|
+
# Note: Not included due to namespace prefix conflict with Device:Container
|
205
|
+
# Container => 'http://ns.google.com/photos/1.0/container/',
|
204
206
|
);
|
205
207
|
|
206
208
|
# build reverse namespace lookup
|
@@ -479,7 +481,7 @@ my %sCorrRangeMask = (
|
|
479
481
|
LuminanceDepthSampleInfo => { },
|
480
482
|
);
|
481
483
|
# new LR2 crs structures (PH)
|
482
|
-
my %sCorrectionMask;
|
484
|
+
my %sCorrectionMask; # (must define this before assigning because it is self-referential)
|
483
485
|
%sCorrectionMask = (
|
484
486
|
STRUCT_NAME => 'CorrectionMask',
|
485
487
|
NAMESPACE => 'crs',
|
@@ -919,6 +921,11 @@ my %sRangeMask = (
|
|
919
921
|
Name => 'hdrgm',
|
920
922
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::hdrgm' },
|
921
923
|
},
|
924
|
+
# Note: Note included due to namespace prefix conflict with Device:Container
|
925
|
+
# Container => {
|
926
|
+
# Name => 'Container',
|
927
|
+
# SubDirectory => { TagTable => 'Image::ExifTool::XMP::Container' },
|
928
|
+
# },
|
922
929
|
);
|
923
930
|
|
924
931
|
# hack to allow XML containing Dublin Core metadata to be handled like XMP (eg. EPUB - see ZIP.pm)
|
@@ -1699,6 +1706,8 @@ my %sPantryItem = (
|
|
1699
1706
|
ToneCurvePV2012Red => { List => 'Seq' },
|
1700
1707
|
ToneCurvePV2012Green => { List => 'Seq' },
|
1701
1708
|
ToneCurvePV2012Blue => { List => 'Seq' },
|
1709
|
+
Highlights2012 => { },
|
1710
|
+
Shadows2012 => { },
|
1702
1711
|
},
|
1703
1712
|
},
|
1704
1713
|
}
|
@@ -1760,6 +1769,62 @@ my %sPantryItem = (
|
|
1760
1769
|
SDRShadows => { Writable => 'real' },
|
1761
1770
|
SDRWhites => { Writable => 'real' },
|
1762
1771
|
SDRBlend => { Writable => 'real' },
|
1772
|
+
# new for ACR 16 (ref forum15305)
|
1773
|
+
LensBlur => {
|
1774
|
+
Struct => {
|
1775
|
+
STRUCT_NAME => 'LensBlur',
|
1776
|
+
NAMESPACE => 'crs',
|
1777
|
+
# (Note: all the following 'real' values could be limited to 'integer')
|
1778
|
+
Active => { Writable => 'boolean' },
|
1779
|
+
BlurAmount => { FlatName => 'Amount', Writable => 'real' },
|
1780
|
+
BokehAspect => { Writable => 'real' },
|
1781
|
+
BokehRotation => { Writable => 'real' },
|
1782
|
+
BokehShape => { Writable => 'real' },
|
1783
|
+
BokehShapeDetail => { Writable => 'real' },
|
1784
|
+
CatEyeAmount => { Writable => 'real' },
|
1785
|
+
CatEyeScale => { Writable => 'real' },
|
1786
|
+
FocalRange => { }, # (eg. "-48 32 64 144")
|
1787
|
+
FocalRangeSource => { Writable => 'real' },
|
1788
|
+
HighlightsBoost => { Writable => 'real' },
|
1789
|
+
HighlightsThreshold => { Writable => 'real' },
|
1790
|
+
SampledArea => { }, # (eg. "0.500000 0.500000 0.500000 0.500000")
|
1791
|
+
SampledRange => { }, # (eg. "0 0")
|
1792
|
+
SphericalAberration => { Writable => 'real' },
|
1793
|
+
SubjectRange => { }, # (eg. "0 57");
|
1794
|
+
Version => { },
|
1795
|
+
},
|
1796
|
+
},
|
1797
|
+
DepthMapInfo => {
|
1798
|
+
Struct => {
|
1799
|
+
STRUCT_NAME => 'DepthMapInfo',
|
1800
|
+
NAMESPACE => 'crs',
|
1801
|
+
BaseHighlightGuideInputDigest => { },
|
1802
|
+
BaseHighlightGuideTable => { },
|
1803
|
+
BaseHighlightGuideVersion => { },
|
1804
|
+
BaseLayeredDepthInputDigest => { },
|
1805
|
+
BaseLayeredDepthTable => { },
|
1806
|
+
BaseLayeredDepthVersion => { },
|
1807
|
+
BaseRawDepthInputDigest => { },
|
1808
|
+
BaseRawDepthTable => { },
|
1809
|
+
BaseRawDepthVersion => { },
|
1810
|
+
DepthSource => { },
|
1811
|
+
},
|
1812
|
+
},
|
1813
|
+
DepthBasedCorrections => {
|
1814
|
+
List => 'Seq',
|
1815
|
+
FlatName => 'DepthBasedCorr',
|
1816
|
+
Struct => {
|
1817
|
+
STRUCT_NAME => 'DepthBasedCorr',
|
1818
|
+
NAMESPACE => 'crs',
|
1819
|
+
CorrectionActive => { Writable => 'boolean' },
|
1820
|
+
CorrectionAmount => { Writable => 'real' },
|
1821
|
+
CorrectionMasks => { FlatName => 'Mask', List => 'Seq', Struct => \%sCorrectionMask },
|
1822
|
+
CorrectionSyncID => { },
|
1823
|
+
LocalCorrectedDepth => { Writable => 'real' },
|
1824
|
+
LocalCurveRefineSaturation => { Writable => 'real' },
|
1825
|
+
What => { },
|
1826
|
+
},
|
1827
|
+
},
|
1763
1828
|
);
|
1764
1829
|
|
1765
1830
|
# Tiff namespace properties (tiff)
|
@@ -1873,6 +1873,10 @@ my %sSubVersion = (
|
|
1873
1873
|
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
1874
1874
|
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
1875
1875
|
},
|
1876
|
+
HdrPlusMakernote => {
|
1877
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
1878
|
+
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
1879
|
+
},
|
1876
1880
|
);
|
1877
1881
|
|
1878
1882
|
# Google creations namespace (ref PH)
|
@@ -2037,6 +2041,37 @@ my %sSubVersion = (
|
|
2037
2041
|
},
|
2038
2042
|
);
|
2039
2043
|
|
2044
|
+
# Google container tags (ref https://developer.android.com/guide/topics/media/platform/hdr-image-format)
|
2045
|
+
# NOTE: Not included because these namespace prefixes conflict with Google's depth-map Device tags!
|
2046
|
+
# (see ../pics/GooglePixel8Pro.jpg sample image)
|
2047
|
+
# %Image::ExifTool::XMP::Container = (
|
2048
|
+
# %xmpTableDefaults,
|
2049
|
+
# GROUPS => { 1 => 'XMP-Container', 2 => 'Image' },
|
2050
|
+
# NAMESPACE => 'Container',
|
2051
|
+
# NOTES => 'Google Container namespace.',
|
2052
|
+
# Directory => {
|
2053
|
+
# Name => 'ContainerDirectory',
|
2054
|
+
# FlatName => 'Directory',
|
2055
|
+
# List => 'Seq',
|
2056
|
+
# Struct => {
|
2057
|
+
# STRUCT_NAME => 'Directory',
|
2058
|
+
# Item => {
|
2059
|
+
# Namespace => 'Container',
|
2060
|
+
# Struct => {
|
2061
|
+
# STRUCT_NAME => 'Item',
|
2062
|
+
# NAMESPACE => { Item => 'http://ns.google.com/photos/1.0/container/item/'},
|
2063
|
+
# Mime => { },
|
2064
|
+
# Semantic => { },
|
2065
|
+
# Length => { Writable => 'integer' },
|
2066
|
+
# Label => { },
|
2067
|
+
# Padding => { Writable => 'integer' },
|
2068
|
+
# URI => { },
|
2069
|
+
# },
|
2070
|
+
# },
|
2071
|
+
# },
|
2072
|
+
# },
|
2073
|
+
# );
|
2074
|
+
|
2040
2075
|
# Getty Images namespace (ref PH)
|
2041
2076
|
%Image::ExifTool::XMP::GettyImages = (
|
2042
2077
|
%xmpTableDefaults,
|