exiftool-vendored.pl 12.65.0 → 12.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/Changes +60 -2
- package/bin/MANIFEST +5 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +7 -7
- package/bin/exiftool +30 -21
- package/bin/lib/Image/ExifTool/Apple.pm +6 -2
- package/bin/lib/Image/ExifTool/Canon.pm +55 -13
- package/bin/lib/Image/ExifTool/DNG.pm +25 -2
- package/bin/lib/Image/ExifTool/Exif.pm +95 -13
- package/bin/lib/Image/ExifTool/FujiFilm.pm +20 -1
- package/bin/lib/Image/ExifTool/Geotag.pm +17 -12
- package/bin/lib/Image/ExifTool/Nikon.pm +47 -11
- package/bin/lib/Image/ExifTool/PLUS.pm +19 -4
- package/bin/lib/Image/ExifTool/PNG.pm +14 -7
- package/bin/lib/Image/ExifTool/Panasonic.pm +13 -9
- package/bin/lib/Image/ExifTool/Pentax.pm +8 -1
- package/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -1
- package/bin/lib/Image/ExifTool/QuickTime.pm +62 -52
- package/bin/lib/Image/ExifTool/README +7 -3
- package/bin/lib/Image/ExifTool/RIFF.pm +8 -2
- package/bin/lib/Image/ExifTool/Sony.pm +66 -21
- package/bin/lib/Image/ExifTool/TagLookup.pm +6881 -6709
- package/bin/lib/Image/ExifTool/TagNames.pod +454 -37
- package/bin/lib/Image/ExifTool/Validate.pm +18 -16
- package/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
- package/bin/lib/Image/ExifTool/WriteExif.pl +14 -4
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +2 -0
- package/bin/lib/Image/ExifTool/WriteRIFF.pl +22 -3
- package/bin/lib/Image/ExifTool/Writer.pl +53 -11
- package/bin/lib/Image/ExifTool/XISF.pm +185 -0
- package/bin/lib/Image/ExifTool/XMP.pm +67 -2
- package/bin/lib/Image/ExifTool/XMP2.pl +36 -1
- package/bin/lib/Image/ExifTool.pm +45 -20
- package/bin/lib/Image/ExifTool.pod +20 -10
- package/bin/perl-Image-ExifTool.spec +6 -6
- package/bin/pp_build_exe.args +5 -4
- package/package.json +2 -2
|
@@ -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.22';
|
|
21
21
|
|
|
22
22
|
use Image::ExifTool qw(:Utils);
|
|
23
23
|
use Image::ExifTool::Exif;
|
|
@@ -142,20 +142,22 @@ my %stdFormat = (
|
|
|
142
142
|
# GeoTiff tags:
|
|
143
143
|
0x830e => 'double', 0x8482 => 'double', 0x87af => 'int16u', 0x87b1 => 'string',
|
|
144
144
|
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 => '',
|
|
145
|
+
# DNG tags: (use '' for non-DNG tags in the range 0xc612-0xcd48)
|
|
146
|
+
0xc615 => '(string|int8u)', 0xc6f4 => '(string|int8u)',
|
|
147
|
+
0xc61a => '(int16u|int32u|rational64u)', 0xc6f6 => '(string|int8u)',
|
|
148
|
+
0xc61d => 'int(16|32)u', 0xc6f8 => '(string|int8u)',
|
|
149
|
+
0xc61f => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
|
|
150
|
+
0xc620 => '(int16u|int32u|rational64u)', 0xc716 => '(string|int8u)',
|
|
151
|
+
0xc628 => '(int16u|rational64u)', 0xc717 => '(string|int8u)',
|
|
152
|
+
0xc634 => 'int8u', 0xc718 => '(string|int8u)',
|
|
153
|
+
0xc640 => '', 0xc71e => 'int(16|32)u',
|
|
154
|
+
0xc660 => '', 0xc71f => 'int(16|32)u',
|
|
155
|
+
0xc68b => '(string|int8u)', 0xc791 => 'int(16|32)u',
|
|
156
|
+
0xc68d => 'int(16|32)u', 0xc792 => 'int(16|32)u',
|
|
157
|
+
0xc68e => 'int(16|32)u', 0xc793 => '(int16u|int32u|rational64u)',
|
|
158
|
+
0xc6d2 => '', 0xcd43 => 'int(16|32)u',
|
|
159
|
+
0xc6d3 => '', 0xcd48 => '(string|int8u)',
|
|
160
|
+
|
|
159
161
|
# Exif 3.0 spec
|
|
160
162
|
0x10e => 'string|utf8', 0xa430 => 'string|utf8', 0xa439 => 'string|utf8',
|
|
161
163
|
0x10f => 'string|utf8', 0xa433 => 'string|utf8', 0xa43a => 'string|utf8',
|
|
@@ -430,7 +432,7 @@ sub ValidateExif($$$$$$$$)
|
|
|
430
432
|
my $stdFmt = $stdFormat{$ifd} || $stdFormat{IFD};
|
|
431
433
|
if (defined $$stdFmt{All} or ($tagTablePtr eq \%Image::ExifTool::Exif::Main and
|
|
432
434
|
($exifSpec{$tag} or $$stdFmt{$tag} or
|
|
433
|
-
($tag >= 0xc612 and $tag <=
|
|
435
|
+
($tag >= 0xc612 and $tag <= 0xcd48 and not defined $$stdFmt{$tag}))) or # (DNG tags)
|
|
434
436
|
$$tagTablePtr{SHORT_NAME} eq 'GPS::Main')
|
|
435
437
|
{
|
|
436
438
|
my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP};
|
|
@@ -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};
|
|
@@ -96,6 +96,8 @@ my %ctboID = (
|
|
|
96
96
|
"\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac" => 1, # XMP
|
|
97
97
|
"\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16" => 2, # PreviewImage
|
|
98
98
|
# ID 3 is used for 'mdat' atom (not a uuid)
|
|
99
|
+
# (haven't seen ID 4 yet)
|
|
100
|
+
"\x57\x66\xb8\x29\xbb\x6a\x47\xc5\xbc\xfb\x8b\x9f\x22\x60\xd0\x6d" => 5, # something to do with burst-roll image
|
|
99
101
|
);
|
|
100
102
|
|
|
101
103
|
# mark UserData tags that don't have ItemList counterparts as Preferred
|
|
@@ -66,6 +66,7 @@ sub WriteRIFF($$)
|
|
|
66
66
|
$et->InitWriteDirs(\%webpMap);
|
|
67
67
|
my $addDirs = $$et{ADD_DIRS};
|
|
68
68
|
my $editDirs = $$et{EDIT_DIRS};
|
|
69
|
+
$$addDirs{IFD0} = 'EXIF' if $$addDirs{EXIF}; # set flag to add IFD0 if adding EXIF (don't ask)
|
|
69
70
|
my ($createVP8X, $deleteVP8X);
|
|
70
71
|
|
|
71
72
|
# write header
|
|
@@ -142,6 +143,17 @@ sub WriteRIFF($$)
|
|
|
142
143
|
}
|
|
143
144
|
# RIFF chunks are padded to an even number of bytes
|
|
144
145
|
my $len2 = $len + ($len & 0x01);
|
|
146
|
+
# handle incorrect "XMP\0" chunk ID written by Google software
|
|
147
|
+
if ($tag eq "XMP\0") {
|
|
148
|
+
if ($$et{DEL_GROUP}{XMP}) {
|
|
149
|
+
# just ignore this chunk if deleting XMP
|
|
150
|
+
$raf->Seek($len2, 1) or $et->Error('Seek error'), last;
|
|
151
|
+
++$$et{CHANGED};
|
|
152
|
+
next;
|
|
153
|
+
} else {
|
|
154
|
+
$et->Warn('Incorrect XMP tag ID',1) if $pass;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
145
157
|
# edit/add/delete necessary metadata chunks (EXIF must come before XMP)
|
|
146
158
|
if ($$editDirs{$tag} or $tag eq '' or ($tag eq 'XMP ' and $$addDirs{EXIF})) {
|
|
147
159
|
my $handledTag;
|
|
@@ -162,7 +174,6 @@ sub WriteRIFF($$)
|
|
|
162
174
|
foreach $dir ('EXIF', 'XMP ', 'ICCP' ) {
|
|
163
175
|
next unless $tag eq $dir or ($$addDirs{$dir} and
|
|
164
176
|
($tag eq '' or ($tag eq 'XMP ' and $dir eq 'EXIF')));
|
|
165
|
-
delete $$addDirs{$dir}; # (don't try to add again)
|
|
166
177
|
my $start;
|
|
167
178
|
unless ($pass) {
|
|
168
179
|
# write the EXIF and save the result for the next pass
|
|
@@ -170,8 +181,15 @@ sub WriteRIFF($$)
|
|
|
170
181
|
if ($tag eq 'EXIF') {
|
|
171
182
|
# (only need to set directory $start for EXIF)
|
|
172
183
|
if ($buff =~ /^Exif\0\0/) {
|
|
173
|
-
|
|
174
|
-
|
|
184
|
+
if ($$et{DEL_GROUP}{EXIF}) {
|
|
185
|
+
# remove incorrect header if rewriting anyway
|
|
186
|
+
$buff = substr($buff, 6);
|
|
187
|
+
$len -= 6;
|
|
188
|
+
$len2 -= 6;
|
|
189
|
+
} else {
|
|
190
|
+
$et->Warn('Improper EXIF header',1) unless $pass;
|
|
191
|
+
$start = 6;
|
|
192
|
+
}
|
|
175
193
|
} else {
|
|
176
194
|
$start = 0;
|
|
177
195
|
}
|
|
@@ -194,6 +212,7 @@ sub WriteRIFF($$)
|
|
|
194
212
|
my $writeProc = $dir eq 'EXIF' ? \&Image::ExifTool::WriteTIFF : undef;
|
|
195
213
|
$dirDat{$dir} = $et->WriteDirectory(\%dirInfo, $tagTablePtr, $writeProc);
|
|
196
214
|
}
|
|
215
|
+
delete $$addDirs{$dir}; # (don't try to add again)
|
|
197
216
|
if (defined $dirDat{$dir}) {
|
|
198
217
|
if ($dir eq $tag) {
|
|
199
218
|
$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} = [ '' ];
|
|
@@ -1320,6 +1319,7 @@ sub SetNewValuesFromFile($$;@)
|
|
|
1320
1319
|
Unknown => $$options{Unknown},
|
|
1321
1320
|
UserParam => $$options{UserParam},
|
|
1322
1321
|
Validate => $$options{Validate},
|
|
1322
|
+
WindowsWideFile => $$options{WindowsWideFile},
|
|
1323
1323
|
XAttrTags => $$options{XAttrTags},
|
|
1324
1324
|
XMPAutoConv => $$options{XMPAutoConv},
|
|
1325
1325
|
);
|
|
@@ -1371,8 +1371,8 @@ sub SetNewValuesFromFile($$;@)
|
|
|
1371
1371
|
#
|
|
1372
1372
|
unless (@setTags) {
|
|
1373
1373
|
# transfer maker note information to this object
|
|
1374
|
-
$$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
|
|
1375
1374
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
|
1375
|
+
my $tagExtra = $$srcExifTool{TAG_EXTRA};
|
|
1376
1376
|
foreach $tag (@tags) {
|
|
1377
1377
|
# don't try to set errors or warnings
|
|
1378
1378
|
next if $tag =~ /^(Error|Warning)\b/;
|
|
@@ -1380,10 +1380,13 @@ sub SetNewValuesFromFile($$;@)
|
|
|
1380
1380
|
if ($opts{SrcType} and $opts{SrcType} ne $srcType) {
|
|
1381
1381
|
$$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType});
|
|
1382
1382
|
}
|
|
1383
|
+
my $fixup = $$tagExtra{$tag}{Fixup};
|
|
1384
|
+
$opts{Fixup} = $fixup if $fixup;
|
|
1383
1385
|
# set value for this tag
|
|
1384
1386
|
my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts);
|
|
1385
1387
|
# delete this tag if we couldn't set it
|
|
1386
1388
|
$n or delete $$info{$tag};
|
|
1389
|
+
delete $opts{Fixup} if $fixup;
|
|
1387
1390
|
}
|
|
1388
1391
|
return $info;
|
|
1389
1392
|
}
|
|
@@ -1616,7 +1619,7 @@ SET: foreach $set (@setList) {
|
|
|
1616
1619
|
}
|
|
1617
1620
|
# transfer maker note information if setting this tag
|
|
1618
1621
|
if ($$srcExifTool{TAG_INFO}{$tag}{MakerNotes}) {
|
|
1619
|
-
$$
|
|
1622
|
+
$$opts{Fixup} = $$srcExifTool{TAG_EXTRA}{$tag}{Fixup};
|
|
1620
1623
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
|
1621
1624
|
}
|
|
1622
1625
|
if ($dstTag eq '*') {
|
|
@@ -1648,6 +1651,7 @@ SET: foreach $set (@setList) {
|
|
|
1648
1651
|
$rtnInfo{NextFreeTagKey(\%rtnInfo, 'Warning')} = $wrn;
|
|
1649
1652
|
$noWarn = 1;
|
|
1650
1653
|
}
|
|
1654
|
+
delete $$opts{Fixup};
|
|
1651
1655
|
$rtnInfo{$tag} = $val if $rtn; # tag was set successfully
|
|
1652
1656
|
}
|
|
1653
1657
|
}
|
|
@@ -4175,6 +4179,7 @@ sub WriteDirectory($$$;$)
|
|
|
4175
4179
|
$out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose};
|
|
4176
4180
|
# set directory name from default group0 name if not done already
|
|
4177
4181
|
my $dirName = $$dirInfo{DirName};
|
|
4182
|
+
my $parent = $$dirInfo{Parent} || '';
|
|
4178
4183
|
my $dataPt = $$dirInfo{DataPt};
|
|
4179
4184
|
my $grp0 = $$tagTablePtr{GROUPS}{0};
|
|
4180
4185
|
$dirName or $dirName = $$dirInfo{DirName} = $grp0;
|
|
@@ -4189,7 +4194,9 @@ sub WriteDirectory($$$;$)
|
|
|
4189
4194
|
$self->IsRawType() and
|
|
4190
4195
|
# allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
|
|
4191
4196
|
(not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
|
|
4192
|
-
$$dirInfo{TagInfo}{Permanent})
|
|
4197
|
+
$$dirInfo{TagInfo}{Permanent}) and
|
|
4198
|
+
# allow MakerNotes to be deleted from ExifIFD of CR3 file
|
|
4199
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
|
4193
4200
|
{
|
|
4194
4201
|
$self->WarnOnce("Can't delete $1 from $$self{FileType}",1);
|
|
4195
4202
|
undef $grp1;
|
|
@@ -4225,7 +4232,6 @@ sub WriteDirectory($$$;$)
|
|
|
4225
4232
|
if ($delFlag == 2 and $right) {
|
|
4226
4233
|
# also check grandparent because some routines create 2 levels in 1
|
|
4227
4234
|
my $right2 = $$self{ADD_DIRS}{$right} || '';
|
|
4228
|
-
my $parent = $$dirInfo{Parent};
|
|
4229
4235
|
if (not $parent or $parent eq $right or $parent eq $right2) {
|
|
4230
4236
|
# prevent duplicate directories from being recreated at the same path
|
|
4231
4237
|
my $path = join '-', @{$$self{PATH}}, $dirName;
|
|
@@ -4286,7 +4292,10 @@ sub WriteDirectory($$$;$)
|
|
|
4286
4292
|
unless (defined $newVal and length $newVal) {
|
|
4287
4293
|
return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed
|
|
4288
4294
|
# don't allow MakerNotes to be removed from RAW files
|
|
4289
|
-
if ($blockName eq 'MakerNotes' and $
|
|
4295
|
+
if ($blockName eq 'MakerNotes' and $self->IsRawType() and
|
|
4296
|
+
# but allow MakerNotes to be deleted from ExifIFD of CR3 image (shouldn't be there)
|
|
4297
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
|
4298
|
+
{
|
|
4290
4299
|
$self->Warn("Can't delete MakerNotes from $$self{FileType}",1);
|
|
4291
4300
|
return undef;
|
|
4292
4301
|
}
|
|
@@ -7185,6 +7194,39 @@ sub WriteTIFF($$$)
|
|
|
7185
7194
|
{
|
|
7186
7195
|
my ($self, $dirInfo, $tagTablePtr) = @_;
|
|
7187
7196
|
$self or return 1; # allow dummy access
|
|
7197
|
+
# hack to allow MakeNoteCanon to be written as a block in CMT3 chunk of CR3 image
|
|
7198
|
+
if ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'MakerNoteCanon') {
|
|
7199
|
+
require Image::ExifTool::Canon;
|
|
7200
|
+
my $tagInfo = $Image::ExifTool::Canon::uuid{CMT3};
|
|
7201
|
+
my $nvHash;
|
|
7202
|
+
if ($tagInfo and ($nvHash = $$self{NEW_VALUE}{$tagInfo}) and
|
|
7203
|
+
$self->IsOverwriting($nvHash) and not $$nvHash{CreateOnly})
|
|
7204
|
+
{
|
|
7205
|
+
my $newVal = $self->GetNewValue($nvHash);
|
|
7206
|
+
if (defined $newVal and length $newVal) {
|
|
7207
|
+
# fix up offsets
|
|
7208
|
+
if ($$nvHash{MAKER_NOTE_FIXUP}) {
|
|
7209
|
+
# must clone fixup because we will be shifting it
|
|
7210
|
+
my $makerFixup = $$nvHash{MAKER_NOTE_FIXUP}->Clone();
|
|
7211
|
+
$$makerFixup{Shift} += 8; # shift for TIFF header
|
|
7212
|
+
$makerFixup->ApplyFixup(\$newVal);
|
|
7213
|
+
}
|
|
7214
|
+
# add TIFF header
|
|
7215
|
+
my $hdr;
|
|
7216
|
+
if (substr($newVal, 0, 1) eq "\0") {
|
|
7217
|
+
$hdr = "MM\0\x2a" . pack('N', 8);
|
|
7218
|
+
} else {
|
|
7219
|
+
$hdr = "II\x2a\0" . pack('V', 8);
|
|
7220
|
+
}
|
|
7221
|
+
$self->VPrint(0, " Writing MakerNoteCanon as a block\n");
|
|
7222
|
+
++$$self{CHANGED};
|
|
7223
|
+
return $hdr . $newVal;
|
|
7224
|
+
} elsif ($$dirInfo{Parent} and $$dirInfo{Parent} eq 'UUID-Canon') {
|
|
7225
|
+
$self->Warn("Can't delete CanonMakerNotes from $$dirInfo{Parent}");
|
|
7226
|
+
return undef;
|
|
7227
|
+
}
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7188
7230
|
my $buff = '';
|
|
7189
7231
|
$$dirInfo{OutFile} = \$buff;
|
|
7190
7232
|
return $buff if $self->ProcessTIFF($dirInfo, $tagTablePtr) > 0;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#------------------------------------------------------------------------------
|
|
2
|
+
# File: XISF.pm
|
|
3
|
+
#
|
|
4
|
+
# Description: Read Extensible Image Serialization Format metadata
|
|
5
|
+
#
|
|
6
|
+
# Revisions: 2023-10-10 - P. Harvey Created
|
|
7
|
+
#
|
|
8
|
+
# References: 1) https://pixinsight.com/doc/docs/XISF-1.0-spec/XISF-1.0-spec.html
|
|
9
|
+
#------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
package Image::ExifTool::XISF;
|
|
12
|
+
|
|
13
|
+
use strict;
|
|
14
|
+
use vars qw($VERSION);
|
|
15
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
|
16
|
+
use Image::ExifTool::XMP;
|
|
17
|
+
|
|
18
|
+
$VERSION = '1.00';
|
|
19
|
+
|
|
20
|
+
# XISF tags (ref 1)
|
|
21
|
+
%Image::ExifTool::XISF::Main = (
|
|
22
|
+
GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
|
|
23
|
+
VARS => { LONG_TAGS => 1 },
|
|
24
|
+
NOTES => q{
|
|
25
|
+
This table lists some standard Extensible Image Serialization Format (XISF)
|
|
26
|
+
tags, but ExifTool will extract any other tags found. See
|
|
27
|
+
L<https://pixinsight.com/xisf/> for the specification.
|
|
28
|
+
},
|
|
29
|
+
ImageGeometry => { },
|
|
30
|
+
ImageSampleFormat => { },
|
|
31
|
+
ImageBounds => { },
|
|
32
|
+
ImageImageType => { Name => 'ImageType' },
|
|
33
|
+
ImageColorSpace => { Name => 'ColorSpace' },
|
|
34
|
+
ImageLocation => { },
|
|
35
|
+
ImageResolutionHorizontal => 'XResolution',
|
|
36
|
+
ImageResolutionVertical => 'YResolution',
|
|
37
|
+
ImageResolutionUnit => 'ResolutionUnit',
|
|
38
|
+
ImageICCProfile => {
|
|
39
|
+
Name => 'ICC_Profile',
|
|
40
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
|
41
|
+
Binary => 1,
|
|
42
|
+
},
|
|
43
|
+
ImageICCProfileLocation => { Name => 'ICCProfileLocation' },
|
|
44
|
+
ImagePixelStorage => { },
|
|
45
|
+
ImageOffset => { Name => 'ImagePixelOffset' },
|
|
46
|
+
ImageOrientation => { Name => 'Orientation' },
|
|
47
|
+
ImageId => { Name => 'ImageID' },
|
|
48
|
+
ImageUuid => { Name => 'UUID' },
|
|
49
|
+
ImageData => { Binary => 1 },
|
|
50
|
+
'CreationTime' => {
|
|
51
|
+
Name => 'CreateDate',
|
|
52
|
+
Shift => 'Time',
|
|
53
|
+
Groups => { 2 => 'Time' },
|
|
54
|
+
ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
|
|
55
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
|
56
|
+
},
|
|
57
|
+
CreatorApplication => { },
|
|
58
|
+
Abstract => { },
|
|
59
|
+
AccessRights => { },
|
|
60
|
+
Authors => { Groups => { 2 => 'Author' } },
|
|
61
|
+
BibliographicReferences => { },
|
|
62
|
+
BriefDescription => { },
|
|
63
|
+
CompressionLevel => { },
|
|
64
|
+
CompressionCodecs => { },
|
|
65
|
+
Contributors => { Groups => { 2 => 'Author' } },
|
|
66
|
+
Copyright => { Groups => { 2 => 'Author' } },
|
|
67
|
+
CreatorModule => { },
|
|
68
|
+
CreatorOS => { },
|
|
69
|
+
Description => { },
|
|
70
|
+
Keywords => { },
|
|
71
|
+
Languages => { },
|
|
72
|
+
License => { },
|
|
73
|
+
OriginalCreationTime => {
|
|
74
|
+
Name => 'DateTimeOriginal',
|
|
75
|
+
Description => 'Date/Time Original',
|
|
76
|
+
Shift => 'Time',
|
|
77
|
+
Groups => { 2 => 'Time' },
|
|
78
|
+
ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
|
|
79
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
|
80
|
+
},
|
|
81
|
+
RelatedResources => { },
|
|
82
|
+
Title => { },
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
#------------------------------------------------------------------------------
|
|
86
|
+
# Handle properties in XISF metadata structures
|
|
87
|
+
# Inputs: 0) attribute list ref, 1) attr hash ref,
|
|
88
|
+
# 2) property name ref, 3) property value ref
|
|
89
|
+
# Returns: true if value was changed
|
|
90
|
+
sub HandleXISFAttrs($$$$)
|
|
91
|
+
{
|
|
92
|
+
my ($attrList, $attrs, $prop, $valPt) = @_;
|
|
93
|
+
return 0 unless defined $$attrs{id};
|
|
94
|
+
my ($changed, $a);
|
|
95
|
+
# use "id" as the tag name, "value" as the value, and ignore "type"
|
|
96
|
+
$$prop = $$attrs{id};
|
|
97
|
+
$$prop =~ s/^XISF://; # remove XISF namespace
|
|
98
|
+
if (defined $$attrs{value}) {
|
|
99
|
+
$$valPt = $$attrs{value};
|
|
100
|
+
$changed = 1;
|
|
101
|
+
}
|
|
102
|
+
my @attrs = @$attrList;
|
|
103
|
+
@$attrList = ( );
|
|
104
|
+
foreach $a (@attrs) {
|
|
105
|
+
if ($a eq 'id' or $a eq 'value' or $a eq 'type') {
|
|
106
|
+
delete $$attrs{$a};
|
|
107
|
+
} else {
|
|
108
|
+
push @$attrList, $a;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return $changed;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
#------------------------------------------------------------------------------
|
|
115
|
+
# Read information in a XISF document
|
|
116
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref
|
|
117
|
+
# Returns: 1 on success, 0 if this wasn't a valid XISF file
|
|
118
|
+
sub ProcessXISF($$)
|
|
119
|
+
{
|
|
120
|
+
my ($et, $dirInfo) = @_;
|
|
121
|
+
my $raf = $$dirInfo{RAF};
|
|
122
|
+
my $buff;
|
|
123
|
+
|
|
124
|
+
return 0 unless $raf->Read($buff, 16) == 16 and $buff =~ /^XISF0100/;
|
|
125
|
+
$et->SetFileType();
|
|
126
|
+
SetByteOrder('II');
|
|
127
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::XISF::Main');
|
|
128
|
+
my $hdrLen = Get32u(\$buff, 8);
|
|
129
|
+
$raf->Read($buff, $hdrLen) == $hdrLen or $et->Warn('Error reading XISF header'), return 1;
|
|
130
|
+
$et->FoundTag(XML => $buff);
|
|
131
|
+
my %dirInfo = (
|
|
132
|
+
DataPt => \$buff,
|
|
133
|
+
IgnoreProp => { xisf => 1, Metadata => 1, Property => 1 },
|
|
134
|
+
XMPParseOpts => { AttrProc => \&HandleXISFAttrs },
|
|
135
|
+
);
|
|
136
|
+
Image::ExifTool::XMP::ProcessXMP($et, \%dirInfo, $tagTablePtr);
|
|
137
|
+
my $geo = $$et{VALUE}{ImageGeometry};
|
|
138
|
+
if ($geo) {
|
|
139
|
+
my ($w, $h, $n) = split /:/, $geo;
|
|
140
|
+
$et->FoundTag(ImageWidth => $w);
|
|
141
|
+
$et->FoundTag(ImageHeight => $h);
|
|
142
|
+
$et->FoundTag(NumPlanes => $n);
|
|
143
|
+
}
|
|
144
|
+
return 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
1; # end
|
|
148
|
+
|
|
149
|
+
__END__
|
|
150
|
+
|
|
151
|
+
=head1 NAME
|
|
152
|
+
|
|
153
|
+
Image::ExifTool::XISF - Read Extensible Image Serialization Format metadata
|
|
154
|
+
|
|
155
|
+
=head1 SYNOPSIS
|
|
156
|
+
|
|
157
|
+
This module is used by Image::ExifTool
|
|
158
|
+
|
|
159
|
+
=head1 DESCRIPTION
|
|
160
|
+
|
|
161
|
+
This module contains definitions required by Image::ExifTool to read meta
|
|
162
|
+
information from XISF (Extensible Image Serialization Format) images.
|
|
163
|
+
|
|
164
|
+
=head1 AUTHOR
|
|
165
|
+
|
|
166
|
+
Copyright 2003-2023, Phil Harvey (philharvey66 at gmail.com)
|
|
167
|
+
|
|
168
|
+
This library is free software; you can redistribute it and/or modify it
|
|
169
|
+
under the same terms as Perl itself.
|
|
170
|
+
|
|
171
|
+
=head1 REFERENCES
|
|
172
|
+
|
|
173
|
+
=over 4
|
|
174
|
+
|
|
175
|
+
=item L<https://pixinsight.com/doc/docs/XISF-1.0-spec/XISF-1.0-spec.html>
|
|
176
|
+
|
|
177
|
+
=back
|
|
178
|
+
|
|
179
|
+
=head1 SEE ALSO
|
|
180
|
+
|
|
181
|
+
L<Image::ExifTool::TagNames/XISF Tags>,
|
|
182
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
|
183
|
+
|
|
184
|
+
=cut
|
|
185
|
+
|
|
@@ -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)
|