exiftool_vendored 12.58.0 → 12.59.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 +25 -0
- data/bin/MANIFEST +3 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/config_files/example.config +1 -0
- data/bin/exiftool +53 -38
- data/bin/lib/Image/ExifTool/DJI.pm +2 -2
- data/bin/lib/Image/ExifTool/FlashPix.pm +27 -9
- data/bin/lib/Image/ExifTool/LIF.pm +10 -2
- data/bin/lib/Image/ExifTool/MinoltaRaw.pm +9 -1
- data/bin/lib/Image/ExifTool/Nikon.pm +6 -5
- data/bin/lib/Image/ExifTool/Olympus.pm +87 -7
- data/bin/lib/Image/ExifTool/PNG.pm +15 -2
- data/bin/lib/Image/ExifTool/PanasonicRaw.pm +27 -1
- data/bin/lib/Image/ExifTool/PhaseOne.pm +14 -1
- data/bin/lib/Image/ExifTool/QuickTime.pm +11 -6
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +37 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +39 -11
- data/bin/lib/Image/ExifTool/TagLookup.pm +2251 -2244
- data/bin/lib/Image/ExifTool/TagNames.pod +42 -25
- data/bin/lib/Image/ExifTool/WriteExif.pl +11 -4
- data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
- data/bin/lib/Image/ExifTool/Writer.pl +71 -13
- data/bin/lib/Image/ExifTool/XMP.pm +18 -3
- data/bin/lib/Image/ExifTool/XMP2.pl +2 -1
- data/bin/lib/Image/ExifTool.pm +82 -13
- data/bin/lib/Image/ExifTool.pod +40 -5
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
@@ -12,7 +12,7 @@ meta information extracted from or written to a file.
|
|
12
12
|
=head1 TAG TABLES
|
13
13
|
|
14
14
|
The tables listed below give the names of all tags recognized by ExifTool.
|
15
|
-
They contain a total of
|
15
|
+
They contain a total of 26390 tags, with 16859 unique tag names.
|
16
16
|
|
17
17
|
B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each
|
18
18
|
table. A B<Tag ID> is the computer-readable equivalent of a tag name, and
|
@@ -1287,6 +1287,7 @@ L<http://www.adobe.com/devnet/xmp/> for the official XMP specification.
|
|
1287
1287
|
digiKam XMP digiKam
|
1288
1288
|
drone-dji DJI XMP
|
1289
1289
|
dwc DarwinCore
|
1290
|
+
et XMP ExifTool
|
1290
1291
|
exif XMP exif
|
1291
1292
|
exifEX XMP exifEX
|
1292
1293
|
expressionmedia XMP ExpressionMedia
|
@@ -4034,6 +4035,14 @@ These tags belong to the ExifTool XMP-digiKam family 1 group.
|
|
4034
4035
|
PickLabel string
|
4035
4036
|
TagsList string+
|
4036
4037
|
|
4038
|
+
=head3 XMP ExifTool Tags
|
4039
|
+
|
4040
|
+
These tags belong to the ExifTool XMP-et family 1 group.
|
4041
|
+
|
4042
|
+
Tag Name Writable
|
4043
|
+
-------- --------
|
4044
|
+
OriginalImageMD5 string
|
4045
|
+
|
4037
4046
|
=head3 XMP exif Tags
|
4038
4047
|
|
4039
4048
|
EXIF namespace for EXIF tags. See
|
@@ -5307,7 +5316,8 @@ These tags belong to the ExifTool XMP-pmi family 1 group.
|
|
5307
5316
|
=head3 XMP prism Tags
|
5308
5317
|
|
5309
5318
|
Publishing Requirements for Industry Standard Metadata 3.0 namespace
|
5310
|
-
tags. (see
|
5319
|
+
tags. (see
|
5320
|
+
L<https://www.w3.org/Submission/2020/SUBM-prism-20200910/prism-basic.html/>)
|
5311
5321
|
|
5312
5322
|
These tags belong to the ExifTool XMP-prism family 1 group.
|
5313
5323
|
|
@@ -17329,6 +17339,8 @@ any information found here will be extracted, even if the tag is not listed.
|
|
17329
17339
|
0x0304 FocusStepNear int16u
|
17330
17340
|
0x0305 FocusDistance rational64u
|
17331
17341
|
0x0308 AFPoint int16u
|
17342
|
+
0x031b AFPointDetails no
|
17343
|
+
AFPointDetails int16u
|
17332
17344
|
0x0328 AFInfo Olympus AFInfo
|
17333
17345
|
0x1201 ExternalFlash int16u[2]
|
17334
17346
|
0x1203 ExternalFlashGuideNumber? rational64s
|
@@ -21862,7 +21874,10 @@ These tags are found in IFD0 of Panasonic/Leica RAW, RW2 and RWL images.
|
|
21862
21874
|
0x011c Gamma int16u
|
21863
21875
|
0x0120 CameraIFD PanasonicRaw CameraIFD
|
21864
21876
|
0x0121 Multishot int32u
|
21877
|
+
0x0127 JpgFromRaw2 no
|
21878
|
+
0x013b Artist string
|
21865
21879
|
0x02bc ApplicationNotes XMP
|
21880
|
+
0x8298 Copyright string
|
21866
21881
|
0x83bb IPTC-NAA IPTC
|
21867
21882
|
0x8769 ExifOffset EXIF
|
21868
21883
|
0x8825 GPSInfo GPS
|
@@ -22143,30 +22158,32 @@ Note that Microsoft is not consistent with the time zone used for some
|
|
22143
22158
|
date/time tags, and it may be either UTC or local time depending on the
|
22144
22159
|
software used to create the file.
|
22145
22160
|
|
22146
|
-
Tag ID
|
22147
|
-
------
|
22148
|
-
"\x01CompObj"
|
22149
|
-
"\x05Audio Info"
|
22150
|
-
"\x05Data Object"
|
22161
|
+
Tag ID Tag Name Writable
|
22162
|
+
------ -------- --------
|
22163
|
+
"\x01CompObj" CompObj FlashPix CompObj
|
22164
|
+
"\x05Audio Info" AudioInfo FlashPix AudioInfo
|
22165
|
+
"\x05Data Object" DataObject FlashPix DataObject
|
22151
22166
|
"\x05DocumentSummaryInformation" DocumentInfo FlashPix DocumentInfo
|
22152
|
-
"\x05Extension List"
|
22153
|
-
"\x05Global Info"
|
22154
|
-
"\x05Image Contents"
|
22155
|
-
"\x05Image Info"
|
22156
|
-
"\x05Operation"
|
22157
|
-
"\x05Screen Nail"
|
22158
|
-
"\x05SummaryInformation"
|
22159
|
-
"\x05Transform"
|
22160
|
-
'Audio Stream'
|
22161
|
-
'BasicFileInfo'
|
22162
|
-
'Contents'
|
22163
|
-
'Current User'
|
22164
|
-
'ICC Profile 0001'
|
22165
|
-
'IeImg'
|
22166
|
-
'
|
22167
|
-
'
|
22168
|
-
'
|
22169
|
-
'
|
22167
|
+
"\x05Extension List" Extensions FlashPix Extensions
|
22168
|
+
"\x05Global Info" GlobalInfo FlashPix GlobalInfo
|
22169
|
+
"\x05Image Contents" Image FlashPix Image
|
22170
|
+
"\x05Image Info" ImageInfo FlashPix ImageInfo
|
22171
|
+
"\x05Operation" Operation FlashPix Operation
|
22172
|
+
"\x05Screen Nail" ScreenNail no
|
22173
|
+
"\x05SummaryInformation" SummaryInfo FlashPix SummaryInfo
|
22174
|
+
"\x05Transform" Transform FlashPix Transform
|
22175
|
+
'Audio Stream' AudioStream no
|
22176
|
+
'BasicFileInfo' BasicFileInfo no
|
22177
|
+
'Contents' Contents XMP
|
22178
|
+
'Current User' CurrentUser no
|
22179
|
+
'ICC Profile 0001' ICC_Profile ICC_Profile
|
22180
|
+
'IeImg' EmbeddedImage no
|
22181
|
+
'IeImg_class' EmbeddedImageClass no
|
22182
|
+
'IeImg_rect' EmbeddedImageRectangle no
|
22183
|
+
'Preview' PreviewImage no
|
22184
|
+
'Property' PreviewInfo FlashPix PreviewInfo
|
22185
|
+
'Subimage 0000 Header' SubimageHdr FlashPix SubimageHdr
|
22186
|
+
'WordDocument' WordDocument FlashPix WordDocument
|
22170
22187
|
|
22171
22188
|
=head3 FlashPix CompObj Tags
|
22172
22189
|
|
@@ -435,11 +435,18 @@ sub AddImageDataMD5($$$)
|
|
435
435
|
foreach $tagID (sort keys %$offsetInfo) {
|
436
436
|
next unless ref $$offsetInfo{$tagID} eq 'ARRAY'; # ignore scalar tag values used for Validate
|
437
437
|
my $tagInfo = $$offsetInfo{$tagID}[0];
|
438
|
-
next unless $$tagInfo{IsImageData}
|
438
|
+
next unless $$tagInfo{IsImageData}; # only consider image data
|
439
439
|
my $sizeID = $$tagInfo{OffsetPair};
|
440
|
-
|
440
|
+
my @sizes;
|
441
|
+
if ($$tagInfo{NotRealPair}) {
|
442
|
+
@sizes = 999999999; # (Panasonic hack: raw data runs to end of file)
|
443
|
+
} elsif ($sizeID and $$offsetInfo{$sizeID}) {
|
444
|
+
@sizes = split ' ', $$offsetInfo{$sizeID}[1];
|
445
|
+
} else {
|
446
|
+
next;
|
447
|
+
}
|
441
448
|
my @offsets = split ' ', $$offsetInfo{$tagID}[1];
|
442
|
-
|
449
|
+
$sizes[0] = 999999999 if $$tagInfo{NotRealPair};
|
443
450
|
my $total = 0;
|
444
451
|
foreach $offset (@offsets) {
|
445
452
|
my $size = shift @sizes;
|
@@ -455,7 +462,7 @@ sub AddImageDataMD5($$$)
|
|
455
462
|
}
|
456
463
|
if ($verbose) {
|
457
464
|
my $name = "$$dirInfo{DirName}:$$tagInfo{Name}";
|
458
|
-
$name =~ s/Offsets
|
465
|
+
$name =~ s/Offsets?|Start$//;
|
459
466
|
$et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $total bytes of $name data)\n");
|
460
467
|
}
|
461
468
|
}
|
@@ -1490,7 +1490,7 @@ sub WriteXMP($$;$)
|
|
1490
1490
|
my @ns = sort keys %nsCur;
|
1491
1491
|
$long[-2] .= "$nl$sp<$prop rdf:about='${about}'";
|
1492
1492
|
# generate et:toolkit attribute if this is an exiftool RDF/XML output file
|
1493
|
-
if (@ns and $nsCur{$ns[0]} =~ m{^http://ns.exiftool.(?:ca|org)/}) {
|
1493
|
+
if ($$et{XMP_NO_XMPMETA} and @ns and $nsCur{$ns[0]} =~ m{^http://ns.exiftool.(?:ca|org)/}) {
|
1494
1494
|
$long[-2] .= "\n$sp${sp}xmlns:et='http://ns.exiftool.org/1.0/'" .
|
1495
1495
|
" et:toolkit='Image::ExifTool $Image::ExifTool::VERSION'";
|
1496
1496
|
}
|
@@ -1321,6 +1321,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1321
1321
|
XMPAutoConv => $$options{XMPAutoConv},
|
1322
1322
|
);
|
1323
1323
|
$$srcExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
1324
|
+
$$srcExifTool{ALT_EXIFTOOL} = $$self{ALT_EXIFTOOL};
|
1324
1325
|
foreach $tag (@setTags) {
|
1325
1326
|
next if ref $tag;
|
1326
1327
|
if ($tag =~ /^-(.*)/) {
|
@@ -1387,7 +1388,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1387
1388
|
# transfer specified tags in the proper order
|
1388
1389
|
#
|
1389
1390
|
# 1) loop through input list of tags to set, and build @setList
|
1390
|
-
my (@setList, $set, %setMatches, $t);
|
1391
|
+
my (@setList, $set, %setMatches, $t, %altFiles);
|
1391
1392
|
foreach $t (@setTags) {
|
1392
1393
|
if (ref $t eq 'HASH') {
|
1393
1394
|
# update current options
|
@@ -1424,6 +1425,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1424
1425
|
$opt = $1 if $tag =~ s/^([-+])\s*//;
|
1425
1426
|
}
|
1426
1427
|
}
|
1428
|
+
$$opts{Replace} = 0 if $dstTag =~ s/^\+//;
|
1427
1429
|
# validate tag name(s)
|
1428
1430
|
unless ($$opts{EXPR} or ValidTagName($tag)) {
|
1429
1431
|
$self->Warn("Invalid tag name '${tag}'. Use '=' not '<' to assign a tag value");
|
@@ -1440,6 +1442,8 @@ sub SetNewValuesFromFile($$;@)
|
|
1440
1442
|
$$opts{Type} = 'ValueConv' if $dstTag =~ s/#$//;
|
1441
1443
|
# replace tag name of 'all' with '*'
|
1442
1444
|
$dstTag = '*' if $dstTag eq 'all';
|
1445
|
+
} else {
|
1446
|
+
$$opts{Replace} = 0 if $tag =~ s/^\+//;
|
1443
1447
|
}
|
1444
1448
|
unless ($$opts{EXPR}) {
|
1445
1449
|
$isExclude = ($tag =~ s/^-//);
|
@@ -1449,7 +1453,17 @@ sub SetNewValuesFromFile($$;@)
|
|
1449
1453
|
# save family/groups in list (ignoring 'all' and '*')
|
1450
1454
|
next unless length($_) and /^(\d+)?(.*)/;
|
1451
1455
|
my ($f, $g) = ($1, $2);
|
1452
|
-
$f = 7 if $g =~ s/^ID-//i;
|
1456
|
+
$f = 7 if (not $f or $f eq '7') and $g =~ s/^ID-//i;
|
1457
|
+
if ($g =~ /^file\d+$/i and (not $f or $f eq '8')) {
|
1458
|
+
$f = 8;
|
1459
|
+
my $g8 = ucfirst $g;
|
1460
|
+
if ($$srcExifTool{ALT_EXIFTOOL}{$g8}) {
|
1461
|
+
$$opts{GROUP8} = $g8;
|
1462
|
+
$altFiles{$g8} or $altFiles{$g8} = [ ];
|
1463
|
+
# save list of requested tags for this alternate ExifTool object
|
1464
|
+
push @{$altFiles{$g8}}, "$grp:$tag";
|
1465
|
+
}
|
1466
|
+
}
|
1453
1467
|
push @fg, [ $f, $g ] unless $g eq '*' or $g eq 'all';
|
1454
1468
|
}
|
1455
1469
|
}
|
@@ -1486,26 +1500,44 @@ sub SetNewValuesFromFile($$;@)
|
|
1486
1500
|
# save in reverse order so we don't set tags before an exclude
|
1487
1501
|
unshift @setList, [ \@fg, $tag, $dst, $opts ];
|
1488
1502
|
}
|
1503
|
+
# 1b) copy requested tags for each alternate ExifTool object
|
1504
|
+
my $g8;
|
1505
|
+
foreach $g8 (sort keys %altFiles) {
|
1506
|
+
# request specific alternate tags to load them from the alternate ExifTool object
|
1507
|
+
my $altInfo = $srcExifTool->GetInfo($altFiles{$g8});
|
1508
|
+
# add to tags list after dummy entry to signify start of tags for this alt file
|
1509
|
+
if (%$altInfo) {
|
1510
|
+
push @tags, 'Warning DUMMY', reverse sort keys %$altInfo;
|
1511
|
+
$$info{$_} = $$altInfo{$_} foreach keys %$altInfo;
|
1512
|
+
}
|
1513
|
+
}
|
1489
1514
|
# 2) initialize lists of matching tags for each setTag
|
1490
1515
|
foreach $set (@setList) {
|
1491
1516
|
$$set[2] and $setMatches{$set} = [ ];
|
1492
1517
|
}
|
1493
1518
|
# 3) loop through all tags in source image and save tags matching each setTag
|
1494
|
-
my %rtnInfo;
|
1519
|
+
my (%rtnInfo, $isAlt);
|
1495
1520
|
foreach $tag (@tags) {
|
1496
1521
|
# don't try to set errors or warnings
|
1497
1522
|
if ($tag =~ /^(Error|Warning)( |$)/) {
|
1498
|
-
$
|
1523
|
+
if ($tag eq 'Warning DUMMY') {
|
1524
|
+
$isAlt = 1; # start of the alt tags
|
1525
|
+
} else {
|
1526
|
+
$rtnInfo{$tag} = $$info{$tag};
|
1527
|
+
}
|
1499
1528
|
next;
|
1500
1529
|
}
|
1501
1530
|
# only set specified tags
|
1502
1531
|
my $lcTag = lc(GetTagName($tag));
|
1503
1532
|
my (@grp, %grp);
|
1504
1533
|
SET: foreach $set (@setList) {
|
1534
|
+
my $opts = $$set[3];
|
1535
|
+
next if $$opts{EXPR}; # (expressions handled in step 4)
|
1536
|
+
next if $$opts{GROUP8} xor $isAlt;
|
1505
1537
|
# check first for matching tag
|
1506
1538
|
unless ($$set[1] eq $lcTag or $$set[1] eq '*') {
|
1507
1539
|
# handle wildcards
|
1508
|
-
next unless $$
|
1540
|
+
next unless $$opts{WILD} and $lcTag =~ /^$$set[1]$/;
|
1509
1541
|
}
|
1510
1542
|
# then check for matching group
|
1511
1543
|
if (@{$$set[0]}) {
|
@@ -1837,6 +1869,27 @@ sub RestoreNewValues($)
|
|
1837
1869
|
$$self{DEL_GROUP} = \%delGrp;
|
1838
1870
|
}
|
1839
1871
|
|
1872
|
+
#------------------------------------------------------------------------------
|
1873
|
+
# Set alternate file for extracting information
|
1874
|
+
# Inputs: 0) ExifTool ref, 1) family 8 group name (of the form "File#" where # is any number)
|
1875
|
+
# 2) alternate file name, or undef to reset
|
1876
|
+
# Returns: 1 on success, or 0 on invalid group name
|
1877
|
+
sub SetAlternateFile($$$)
|
1878
|
+
{
|
1879
|
+
my ($self, $g8, $file) = @_;
|
1880
|
+
$g8 = ucfirst lc $g8;
|
1881
|
+
return 0 unless $g8 =~ /^File\d+$/;
|
1882
|
+
# keep the same file if already initialized (possibly has metadata extracted)
|
1883
|
+
if (not defined $file) {
|
1884
|
+
delete $$self{ALT_EXIFTOOL}{$g8};
|
1885
|
+
} elsif (not ($$self{ALT_EXIFTOOL}{$g8} and $$self{ALT_EXIFTOOL}{$g8}{ALT_FILE} eq $file)) {
|
1886
|
+
my $altExifTool = Image::ExifTool->new;
|
1887
|
+
$$altExifTool{ALT_FILE} = $file;
|
1888
|
+
$$self{ALT_EXIFTOOL}{$g8} = $altExifTool;
|
1889
|
+
}
|
1890
|
+
return 1;
|
1891
|
+
}
|
1892
|
+
|
1840
1893
|
#------------------------------------------------------------------------------
|
1841
1894
|
# Set filesystem time from from FileModifyDate or FileCreateDate tag
|
1842
1895
|
# Inputs: 0) ExifTool object reference, 1) file name or file ref
|
@@ -2724,6 +2777,7 @@ sub GetAllGroups($;$)
|
|
2724
2777
|
$family == 4 and return('Copy#');
|
2725
2778
|
$family == 5 and return('[too many possibilities to list]');
|
2726
2779
|
$family == 6 and return(@Image::ExifTool::Exif::formatName[1..$#Image::ExifTool::Exif::formatName]);
|
2780
|
+
$family == 8 and return('File#');
|
2727
2781
|
|
2728
2782
|
LoadAllTables(); # first load all our tables
|
2729
2783
|
|
@@ -3163,42 +3217,46 @@ sub InsertTagValues($$$;$$$)
|
|
3163
3217
|
$tag = $docGrp . ':' . $tag;
|
3164
3218
|
$lcTag = lc $tag;
|
3165
3219
|
}
|
3220
|
+
my $et = $self;
|
3221
|
+
if ($tag =~ s/(\bfile\d+)://i) {
|
3222
|
+
$et = $$self{ALT_EXIFTOOL}{ucfirst lc $1} or $et=$self, $tag = 'no_alt_file';
|
3223
|
+
}
|
3166
3224
|
if ($lcTag eq 'all') {
|
3167
3225
|
$val = 1; # always some tag available
|
3168
|
-
} elsif (defined $$
|
3169
|
-
$val = $$
|
3226
|
+
} elsif (defined $$et{OPTIONS}{UserParam}{$lcTag}) {
|
3227
|
+
$val = $$et{OPTIONS}{UserParam}{$lcTag};
|
3170
3228
|
} elsif ($tag =~ /(.*):(.+)/) {
|
3171
3229
|
my $group;
|
3172
3230
|
($group, $tag) = ($1, $2);
|
3173
3231
|
if (lc $tag eq 'all') {
|
3174
3232
|
# see if any tag from the specified group exists
|
3175
|
-
my $match = $
|
3233
|
+
my $match = $et->GroupMatches($group, $foundTags);
|
3176
3234
|
$val = $match ? 1 : 0;
|
3177
3235
|
} else {
|
3178
3236
|
# find the specified tag
|
3179
3237
|
my @matches = grep /^$tag(\s|$)/i, @$foundTags;
|
3180
|
-
@matches = $
|
3238
|
+
@matches = $et->GroupMatches($group, \@matches);
|
3181
3239
|
foreach $tg (@matches) {
|
3182
3240
|
if (defined $val and $tg =~ / \((\d+)\)$/) {
|
3183
3241
|
# take the most recently extracted tag
|
3184
3242
|
my $tagNum = $1;
|
3185
3243
|
next if $tag !~ / \((\d+)\)$/ or $1 > $tagNum;
|
3186
3244
|
}
|
3187
|
-
$val = $
|
3245
|
+
$val = $et->GetValue($tg, $type);
|
3188
3246
|
$tag = $tg;
|
3189
3247
|
last unless $tag =~ / /; # all done if we got our best match
|
3190
3248
|
}
|
3191
3249
|
}
|
3192
3250
|
} elsif ($tag eq 'self') {
|
3193
|
-
$val = $
|
3251
|
+
$val = $et; # ("$self{var}" or "$file1:self{var}" in string)
|
3194
3252
|
} else {
|
3195
3253
|
# get the tag value
|
3196
|
-
$val = $
|
3254
|
+
$val = $et->GetValue($tag, $type);
|
3197
3255
|
unless (defined $val) {
|
3198
3256
|
# check for tag name with different case
|
3199
3257
|
($tg) = grep /^$tag$/i, @$foundTags;
|
3200
3258
|
if (defined $tg) {
|
3201
|
-
$val = $
|
3259
|
+
$val = $et->GetValue($tg, $type);
|
3202
3260
|
$tag = $tg;
|
3203
3261
|
}
|
3204
3262
|
}
|
@@ -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.58';
|
54
54
|
@ISA = qw(Exporter);
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
56
56
|
|
@@ -753,6 +753,10 @@ my %sRangeMask = (
|
|
753
753
|
Name => 'album',
|
754
754
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Album' },
|
755
755
|
},
|
756
|
+
et => {
|
757
|
+
Name => 'et',
|
758
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::ExifTool' },
|
759
|
+
},
|
756
760
|
prism => {
|
757
761
|
Name => 'prism',
|
758
762
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::prism' },
|
@@ -2550,6 +2554,14 @@ my %sPantryItem = (
|
|
2550
2554
|
Notes => { },
|
2551
2555
|
);
|
2552
2556
|
|
2557
|
+
# ExifTool namespace properties (et)
|
2558
|
+
%Image::ExifTool::XMP::ExifTool = (
|
2559
|
+
%xmpTableDefaults,
|
2560
|
+
GROUPS => { 1 => 'XMP-et', 2 => 'Image' },
|
2561
|
+
NAMESPACE => 'et',
|
2562
|
+
OriginalImageMD5 => { Notes => 'used to store ExifTool ImageDataMD5 digest' },
|
2563
|
+
);
|
2564
|
+
|
2553
2565
|
# table to add tags in other namespaces
|
2554
2566
|
%Image::ExifTool::XMP::other = (
|
2555
2567
|
GROUPS => { 2 => 'Unknown' },
|
@@ -3539,6 +3551,7 @@ NoLoop:
|
|
3539
3551
|
DirLen => length $$dataPt,
|
3540
3552
|
IgnoreProp => $$subdir{IgnoreProp}, # (allow XML to ignore specified properties)
|
3541
3553
|
IsExtended => 1, # (hack to avoid Duplicate warning for embedded XMP)
|
3554
|
+
NoStruct => 1, # (don't try to build structures since this isn't true XMP)
|
3542
3555
|
);
|
3543
3556
|
my $oldOrder = GetByteOrder();
|
3544
3557
|
SetByteOrder($$subdir{ByteOrder}) if $$subdir{ByteOrder};
|
@@ -4375,8 +4388,10 @@ sub ProcessXMP($$;$)
|
|
4375
4388
|
|
4376
4389
|
# restore structures if necessary
|
4377
4390
|
if ($$et{IsStruct}) {
|
4378
|
-
|
4379
|
-
|
4391
|
+
unless ($$dirInfo{NoStruct}) {
|
4392
|
+
require 'Image/ExifTool/XMPStruct.pl';
|
4393
|
+
RestoreStruct($et, $keepFlat);
|
4394
|
+
}
|
4380
4395
|
delete $$et{IsStruct};
|
4381
4396
|
}
|
4382
4397
|
# reset NO_LIST flag (must do this _after_ RestoreStruct() above)
|
@@ -843,7 +843,8 @@ my %prismPublicationDate = (
|
|
843
843
|
AVOID => 1,
|
844
844
|
NOTES => q{
|
845
845
|
Publishing Requirements for Industry Standard Metadata 3.0 namespace
|
846
|
-
tags. (see
|
846
|
+
tags. (see
|
847
|
+
L<https://www.w3.org/Submission/2020/SUBM-prism-20200910/prism-basic.html/>)
|
847
848
|
},
|
848
849
|
academicField => { }, # (3.0)
|
849
850
|
aggregateIssueNumber => { Writable => 'integer' }, # (3.0)
|
data/bin/lib/Image/ExifTool.pm
CHANGED
@@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
|
|
29
29
|
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
|
30
30
|
%static_vars);
|
31
31
|
|
32
|
-
$VERSION = '12.
|
32
|
+
$VERSION = '12.59';
|
33
33
|
$RELEASE = '';
|
34
34
|
@ISA = qw(Exporter);
|
35
35
|
%EXPORT_TAGS = (
|
@@ -75,6 +75,7 @@ sub GetAllGroups($;$);
|
|
75
75
|
sub GetNewGroups($);
|
76
76
|
sub GetDeleteGroups();
|
77
77
|
sub AddUserDefinedTags($%);
|
78
|
+
sub SetAlternateFile($$$);
|
78
79
|
# non-public routines below
|
79
80
|
sub InsertTagValues($$$;$$$);
|
80
81
|
sub IsWritable($);
|
@@ -1824,8 +1825,11 @@ my %systemTagsNotes = (
|
|
1824
1825
|
ImageDataMD5 => {
|
1825
1826
|
Notes => q{
|
1826
1827
|
MD5 of image data. Generated only if specifically requested for JPEG and
|
1827
|
-
TIFF-based images,
|
1828
|
-
|
1828
|
+
TIFF-based images, CR3, MRW and PNG images, MOV/MP4 videos, and RIFF-based
|
1829
|
+
files. The MD5 includes the main image data, plus JpgFromRaw/OtherImage for
|
1830
|
+
some formats, but does not include ThumbnailImage or PreviewImage. Includes
|
1831
|
+
video and audio data for MOV/MP4. The L<XMP-et:OriginalImageMD5
|
1832
|
+
tag|XMP.html#ExifTool> provides a place to store these values in the file.
|
1829
1833
|
},
|
1830
1834
|
},
|
1831
1835
|
);
|
@@ -2052,6 +2056,7 @@ sub new
|
|
2052
2056
|
$$self{FILE_SEQUENCE} = 0; # sequence number for files when reading
|
2053
2057
|
$$self{FILES_WRITTEN} = 0; # count of files successfully written
|
2054
2058
|
$$self{INDENT2} = ''; # indentation of verbose messages from SetNewValue
|
2059
|
+
$$self{ALT_EXIFTOOL} = { }; # alternate exiftool objects
|
2055
2060
|
|
2056
2061
|
# initialize our new groups for writing
|
2057
2062
|
$self->SetNewGroups(@defaultWriteGroups);
|
@@ -2496,6 +2501,23 @@ sub ExtractInfo($;@)
|
|
2496
2501
|
}
|
2497
2502
|
}
|
2498
2503
|
++$$self{FILE_SEQUENCE}; # count files read
|
2504
|
+
# extract information from alternate files if necessary
|
2505
|
+
my ($g8, $altExifTool);
|
2506
|
+
foreach $g8 (keys %{$$self{ALT_EXIFTOOL}}) {
|
2507
|
+
$altExifTool = $$self{ALT_EXIFTOOL}{$g8};
|
2508
|
+
next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
|
2509
|
+
$$altExifTool{OPTIONS} = $$self{OPTIONS};
|
2510
|
+
$$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
|
2511
|
+
$$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
|
2512
|
+
$altExifTool->ExtractInfo($$altExifTool{ALT_FILE});
|
2513
|
+
# set family 8 group name for all tags
|
2514
|
+
foreach (keys %{$$altExifTool{VALUE}}) {
|
2515
|
+
my $ex = $$altExifTool{TAG_EXTRA}{$_};
|
2516
|
+
$ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
|
2517
|
+
$$ex{G8} = $g8;
|
2518
|
+
}
|
2519
|
+
$$altExifTool{DID_EXTRACT} = 1;
|
2520
|
+
}
|
2499
2521
|
}
|
2500
2522
|
|
2501
2523
|
my $filename = $$self{FILENAME}; # image file name ('' if already open)
|
@@ -3520,6 +3542,10 @@ sub GetGroup($$;$)
|
|
3520
3542
|
$groups[6] = $$ex{G6};
|
3521
3543
|
}
|
3522
3544
|
}
|
3545
|
+
if ($$ex{G8}) {
|
3546
|
+
$groups[7] = '';
|
3547
|
+
$groups[8] = $$ex{G8};
|
3548
|
+
}
|
3523
3549
|
# generate tag ID group names unless obviously not needed
|
3524
3550
|
unless ($noID) {
|
3525
3551
|
my $id = $$tagInfo{KeysID} || $$tagInfo{TagID};
|
@@ -4153,7 +4179,11 @@ sub SplitFileName($)
|
|
4153
4179
|
} else {
|
4154
4180
|
($name = $file) =~ tr/\\/\//;
|
4155
4181
|
# remove path
|
4156
|
-
|
4182
|
+
if ($name =~ s/(.*)\///) {
|
4183
|
+
$dir = length($1) ? $1 : '/';
|
4184
|
+
} else {
|
4185
|
+
$dir = '.';
|
4186
|
+
}
|
4157
4187
|
}
|
4158
4188
|
return ($dir, $name);
|
4159
4189
|
}
|
@@ -4594,11 +4624,18 @@ sub SetFoundTags($)
|
|
4594
4624
|
my $tagHash = $$self{VALUE};
|
4595
4625
|
my $reqTag;
|
4596
4626
|
foreach $reqTag (@$reqTags) {
|
4597
|
-
my (@matches, $group, $allGrp, $allTag, $byValue);
|
4627
|
+
my (@matches, $group, $allGrp, $allTag, $byValue, $g8, $altOrder);
|
4628
|
+
my $et = $self;
|
4598
4629
|
if ($reqTag =~ /^(.*):(.+)/) {
|
4599
4630
|
($group, $tag) = ($1, $2);
|
4600
4631
|
if ($group =~ /^(\*|all)$/i) {
|
4601
4632
|
$allGrp = 1;
|
4633
|
+
} elsif ($reqTag =~ /\bfile(\d+):/i) {
|
4634
|
+
$g8 = "File$1";
|
4635
|
+
$altOrder = ($1 + 1) * 100000;
|
4636
|
+
$et = $$self{ALT_EXIFTOOL}{$g8} || $self;
|
4637
|
+
$fileOrder = $$et{FILE_ORDER};
|
4638
|
+
$tagHash = $$et{VALUE};
|
4602
4639
|
} elsif ($group !~ /^[-\w:]*$/) {
|
4603
4640
|
$self->Warn("Invalid group name '${group}'");
|
4604
4641
|
$group = 'invalid';
|
@@ -4640,7 +4677,7 @@ sub SetFoundTags($)
|
|
4640
4677
|
}
|
4641
4678
|
if (defined $group and not $allGrp) {
|
4642
4679
|
# keep only specified group
|
4643
|
-
@matches = $
|
4680
|
+
@matches = $et->GroupMatches($group, \@matches);
|
4644
4681
|
next unless @matches or not $allTag;
|
4645
4682
|
}
|
4646
4683
|
if (@matches > 1) {
|
@@ -4649,9 +4686,9 @@ sub SetFoundTags($)
|
|
4649
4686
|
# return only the highest priority tag unless duplicates wanted
|
4650
4687
|
unless ($doDups or $allTag or $allGrp) {
|
4651
4688
|
$tag = shift @matches;
|
4652
|
-
my $oldPriority = $$
|
4689
|
+
my $oldPriority = $$et{PRIORITY}{$tag} || 1;
|
4653
4690
|
foreach (@matches) {
|
4654
|
-
my $priority = $$
|
4691
|
+
my $priority = $$et{PRIORITY}{$_};
|
4655
4692
|
$priority = 1 unless defined $priority;
|
4656
4693
|
next unless $priority >= $oldPriority;
|
4657
4694
|
$tag = $_;
|
@@ -4665,6 +4702,22 @@ sub SetFoundTags($)
|
|
4665
4702
|
# bogus file order entry to avoid warning if sorting in file order
|
4666
4703
|
$$self{FILE_ORDER}{$matches[0]} = 9999;
|
4667
4704
|
}
|
4705
|
+
# copy over necessary information for tags from alternate files
|
4706
|
+
if ($g8) {
|
4707
|
+
my $tag;
|
4708
|
+
foreach $tag (@matches) {
|
4709
|
+
my $vtag = $tag;
|
4710
|
+
$vtag =~ s/( |$)/ #[$g8]/;
|
4711
|
+
$$self{VALUE}{$vtag} = $$et{VALUE}{$tag};
|
4712
|
+
$$self{TAG_INFO}{$vtag} = $$et{TAG_INFO}{$tag};
|
4713
|
+
$$self{TAG_EXTRA}{$vtag} = $$et{TAG_EXTRA}{$tag} || { };
|
4714
|
+
$$self{FILE_ORDER}{$vtag} = ($$et{FILE_ORDER}{$tag} || 0) + $altOrder;
|
4715
|
+
$tag = $vtag;
|
4716
|
+
}
|
4717
|
+
# restore variables to original values for main file
|
4718
|
+
$fileOrder = $$self{FILE_ORDER};
|
4719
|
+
$tagHash = $$self{VALUE};
|
4720
|
+
}
|
4668
4721
|
# save indices of tags extracted by value
|
4669
4722
|
push @byValue, scalar(@$rtnTags) .. (scalar(@$rtnTags)+scalar(@matches)-1) if $byValue;
|
4670
4723
|
# save indices of wildcard tags
|
@@ -6347,7 +6400,6 @@ sub ProcessJPEG($$)
|
|
6347
6400
|
{
|
6348
6401
|
local $_;
|
6349
6402
|
my ($self, $dirInfo) = @_;
|
6350
|
-
my ($ch, $s, $length);
|
6351
6403
|
my $options = $$self{OPTIONS};
|
6352
6404
|
my $verbose = $$options{Verbose};
|
6353
6405
|
my $out = $$options{TextOut};
|
@@ -6356,12 +6408,16 @@ sub ProcessJPEG($$)
|
|
6356
6408
|
my $req = $$self{REQ_TAG_LOOKUP};
|
6357
6409
|
my $htmlDump = $$self{HTML_DUMP};
|
6358
6410
|
my %dumpParms = ( Out => $out );
|
6411
|
+
my ($ch, $s, $length, $md5, $md5size);
|
6359
6412
|
my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk);
|
6360
6413
|
my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
|
6361
|
-
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP
|
6414
|
+
my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
|
6362
6415
|
|
6363
6416
|
# get pointer to MD5 object if it exists and we are the top-level JPEG
|
6364
|
-
|
6417
|
+
if ($$self{FILE_TYPE} eq 'JPEG' and not $$self{DOC_NUM}) {
|
6418
|
+
$md5 = $$self{ImageDataMD5};
|
6419
|
+
$md5size = 0;
|
6420
|
+
}
|
6365
6421
|
|
6366
6422
|
# check to be sure this is a valid JPG (or J2C, or EXV) file
|
6367
6423
|
return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/;
|
@@ -6441,8 +6497,19 @@ sub ProcessJPEG($$)
|
|
6441
6497
|
$nextSegPos = $raf->Tell();
|
6442
6498
|
$len -= 4; # subtract size of length word
|
6443
6499
|
last unless $raf->Seek($len, 1);
|
6444
|
-
} elsif ($md5 and defined $marker and ($marker == 0x00 or $marker == 0xda
|
6445
|
-
|
6500
|
+
} elsif ($md5 and defined $marker and ($marker == 0x00 or $marker == 0xda or
|
6501
|
+
($marker >= 0xd0 and $marker <= 0xd7)))
|
6502
|
+
{
|
6503
|
+
# calculate MD5 for image data (includes leading ff d9 but not trailing ff da)
|
6504
|
+
$md5->add("\xff" . chr($marker));
|
6505
|
+
my $n = $skipped - (length($buff) - 1); # number of extra 0xff's
|
6506
|
+
if (not $n) {
|
6507
|
+
$buff = substr($buff, 0, -1); # remove trailing 0xff
|
6508
|
+
} elsif ($n > 1) {
|
6509
|
+
$buff .= "\xff" x ($n - 1); # add back extra 0xff's
|
6510
|
+
}
|
6511
|
+
$md5->add($buff);
|
6512
|
+
$md5size += $skipped + 2;
|
6446
6513
|
}
|
6447
6514
|
# read second segment too if this was the first
|
6448
6515
|
next unless defined $marker;
|
@@ -7457,6 +7524,8 @@ sub ProcessJPEG($$)
|
|
7457
7524
|
delete $extendedXMP{$guid};
|
7458
7525
|
}
|
7459
7526
|
}
|
7527
|
+
# print verbose MD5 message if necessary
|
7528
|
+
print $out "$$self{INDENT}(ImageDataMD5: $md5size bytes of JPEG image data)\n" if $md5size and $verbose;
|
7460
7529
|
# calculate JPEGDigest if requested
|
7461
7530
|
if (@dqt) {
|
7462
7531
|
require Image::ExifTool::JPEGDigest;
|