exiftool_vendored 13.12.0 → 13.16.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.
- checksums.yaml +4 -4
- data/bin/Changes +79 -22
- data/bin/MANIFEST +7 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/arg_files/exif2xmp.args +4 -0
- data/bin/arg_files/xmp2exif.args +2 -1
- data/bin/build_geolocation +1 -1
- data/bin/exiftool +6 -5
- data/bin/lib/Image/ExifTool/AFCP.pm +5 -5
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +20 -15
- data/bin/lib/Image/ExifTool/Canon.pm +5 -3
- data/bin/lib/Image/ExifTool/DJI.pm +64 -11
- data/bin/lib/Image/ExifTool/EXE.pm +17 -3
- data/bin/lib/Image/ExifTool/Geolocation.pm +16 -7
- data/bin/lib/Image/ExifTool/ID3.pm +4 -4
- data/bin/lib/Image/ExifTool/JPEG.pm +5 -1
- data/bin/lib/Image/ExifTool/LigoGPS.pm +1 -0
- data/bin/lib/Image/ExifTool/MIE.pm +6 -3
- data/bin/lib/Image/ExifTool/Nikon.pm +328 -4
- data/bin/lib/Image/ExifTool/NikonCustom.pm +1 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +7 -1
- data/bin/lib/Image/ExifTool/Protobuf.pm +25 -7
- data/bin/lib/Image/ExifTool/QuickTime.pm +215 -59
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +12 -12
- data/bin/lib/Image/ExifTool/README +4 -1
- data/bin/lib/Image/ExifTool/RIFF.pm +11 -1
- data/bin/lib/Image/ExifTool/Samsung.pm +1 -1
- data/bin/lib/Image/ExifTool/TagLookup.pm +4821 -4811
- data/bin/lib/Image/ExifTool/TagNames.pod +231 -25
- data/bin/lib/Image/ExifTool/Torrent.pm +2 -2
- data/bin/lib/Image/ExifTool/Vivo.pm +124 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +114 -63
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +3 -1
- data/bin/lib/Image/ExifTool/Writer.pl +16 -11
- data/bin/lib/Image/ExifTool.pm +24 -8
- data/bin/lib/Image/ExifTool.pod +52 -49
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -15,6 +15,8 @@ my %movMap = (
|
|
15
15
|
QuickTime => 'ItemList', # (default location for QuickTime tags)
|
16
16
|
ItemList => 'Meta', # MOV-Movie-UserData-Meta-ItemList
|
17
17
|
Keys => 'Movie', # MOV-Movie-Meta-Keys !! (hack due to different Meta location)
|
18
|
+
AudioKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
19
|
+
VideoKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
18
20
|
Meta => 'UserData',
|
19
21
|
XMP => 'UserData', # MOV-Movie-UserData-XMP
|
20
22
|
Microsoft => 'UserData', # MOV-Movie-UserData-Microsoft
|
@@ -29,6 +31,8 @@ my %mp4Map = (
|
|
29
31
|
QuickTime => 'ItemList', # (default location for QuickTime tags)
|
30
32
|
ItemList => 'Meta', # MOV-Movie-UserData-Meta-ItemList
|
31
33
|
Keys => 'Movie', # MOV-Movie-Meta-Keys !! (hack due to different Meta location)
|
34
|
+
AudioKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
35
|
+
VideoKeys => 'Track', # MOV-Movie-Track-Meta-Keys !!
|
32
36
|
Meta => 'UserData',
|
33
37
|
UserData => 'Movie', # MOV-Movie-UserData
|
34
38
|
Microsoft => 'UserData', # MOV-Movie-UserData-Microsoft
|
@@ -374,6 +378,9 @@ sub WriteNextbase($$$)
|
|
374
378
|
# Write Meta Keys to add/delete entries as necessary ('mdta' handler) (ref PH)
|
375
379
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
376
380
|
# Returns: updated keys box data
|
381
|
+
# Note: Residual entries may be left in the 'keys' directory when deleting tags
|
382
|
+
# with language codes because the language code(s) are not known until the
|
383
|
+
# corresponding ItemList entry(s) are processed
|
377
384
|
sub WriteKeys($$$)
|
378
385
|
{
|
379
386
|
my ($et, $dirInfo, $tagTablePtr) = @_;
|
@@ -383,13 +390,14 @@ sub WriteKeys($$$)
|
|
383
390
|
my $outfile = $$dirInfo{OutFile};
|
384
391
|
my ($tag, %done, %remap, %info, %add, $i);
|
385
392
|
|
393
|
+
my $keysGrp = $avType{$$et{MediaType}} ? "$avType{$$et{MediaType}}Keys" : 'Keys';
|
386
394
|
$dirLen < 8 and $et->Warn('Short Keys box'), $dirLen = 8, $$dataPt = "\0" x 8;
|
387
|
-
if ($$et{DEL_GROUP}{
|
395
|
+
if ($$et{DEL_GROUP}{$keysGrp}) {
|
388
396
|
$dirLen = 8; # delete all existing keys
|
389
397
|
# deleted keys are identified by a zero entry in the Remap lookup
|
390
398
|
my $n = Get32u($dataPt, 4);
|
391
399
|
for ($i=1; $i<=$n; ++$i) { $remap{$i} = 0; }
|
392
|
-
$et->VPrint(0, " [deleting $n
|
400
|
+
$et->VPrint(0, " [deleting $n $keysGrp entr".($n==1 ? 'y' : 'ies')."]\n");
|
393
401
|
++$$et{CHANGED};
|
394
402
|
}
|
395
403
|
my $pos = 8;
|
@@ -425,7 +433,7 @@ sub WriteKeys($$$)
|
|
425
433
|
}
|
426
434
|
unless ($dontDelete) {
|
427
435
|
# delete this key
|
428
|
-
$et->VPrint(1, "$$et{INDENT}\[deleting
|
436
|
+
$et->VPrint(1, "$$et{INDENT}\[deleting $keysGrp entry $index '${tag}']\n");
|
429
437
|
$pos += $len;
|
430
438
|
$remap{$index++} = 0;
|
431
439
|
++$$et{CHANGED};
|
@@ -455,7 +463,7 @@ sub WriteKeys($$$)
|
|
455
463
|
# add new entry to 'keys' data
|
456
464
|
my $val = $id =~ /^com\./ ? $id : "com.apple.quicktime.$id";
|
457
465
|
$newData .= Set32u(8 + length($val)) . 'mdta' . $val;
|
458
|
-
$et->VPrint(1, "$$et{INDENT}\[adding
|
466
|
+
$et->VPrint(1, "$$et{INDENT}\[adding $keysGrp entry $newIndex '${id}']\n");
|
459
467
|
$add{$newIndex++} = $tagInfo;
|
460
468
|
++$$et{CHANGED};
|
461
469
|
}
|
@@ -470,7 +478,7 @@ sub WriteKeys($$$)
|
|
470
478
|
# Info - Keys tag information, based on old index value
|
471
479
|
# Add - Keys items deleted, based on old index value
|
472
480
|
# Num - Number of items in edited Keys box
|
473
|
-
$$et{
|
481
|
+
$$et{$keysGrp} = { Remap => \%remap, Info => \%info, Add => \%add, Num => $num };
|
474
482
|
|
475
483
|
return $newData; # return updated Keys box
|
476
484
|
}
|
@@ -883,7 +891,7 @@ sub WriteQuickTime($$$)
|
|
883
891
|
$et or return 1; # allow dummy access to autoload this package
|
884
892
|
my ($mdat, @mdat, @mdatEdit, $edit, $track, $outBuff, $co, $term, $delCount);
|
885
893
|
my (%langTags, $canCreate, $delGrp, %boxPos, %didDir, $writeLast, $err, $atomCount);
|
886
|
-
my ($tag, $lastTag, $lastPos, $errStr, $trailer, $buf2);
|
894
|
+
my ($tag, $lastTag, $lastPos, $errStr, $trailer, $buf2, $keysGrp, $keysPath);
|
887
895
|
my $outfile = $$dirInfo{OutFile} || return 0;
|
888
896
|
my $raf = $$dirInfo{RAF}; # (will be null for lower-level atoms)
|
889
897
|
my $dataPt = $$dirInfo{DataPt}; # (will be null for top-level atoms)
|
@@ -896,15 +904,10 @@ sub WriteQuickTime($$$)
|
|
896
904
|
my $createKeys = 0;
|
897
905
|
my ($rtnVal, $rtnErr) = $dataPt ? (undef, undef) : (1, 0);
|
898
906
|
|
899
|
-
# check for
|
907
|
+
# check for trailer at end of file
|
900
908
|
if ($raf) {
|
901
|
-
|
902
|
-
|
903
|
-
substr($buf2, 8) eq '8db42d694ccc418790edff439fe026bf')
|
904
|
-
{
|
905
|
-
$trailer = [ 'Insta360', $raf->Tell() - unpack('V',$buf2) ];
|
906
|
-
}
|
907
|
-
$raf->Seek($pos, 0) or return 0;
|
909
|
+
$trailer = IdentifyTrailers($raf);
|
910
|
+
$trailer and not ref $trailer and $et->Error($trailer), return 1;
|
908
911
|
}
|
909
912
|
if ($dataPt) {
|
910
913
|
$raf = File::RandomAccess->new($dataPt);
|
@@ -917,15 +920,26 @@ sub WriteQuickTime($$$)
|
|
917
920
|
|
918
921
|
$raf->Seek($dirStart, 1) if $dirStart; # skip header if it exists
|
919
922
|
|
923
|
+
if ($avType{$$et{MediaType}}) {
|
924
|
+
# (note: these won't be correct now if we haven't yet processed the Media box,
|
925
|
+
# but in this case they won't be needed until after we set them properly below)
|
926
|
+
($keysGrp, $keysPath) = ("$avType{$$et{MediaType}}Keys", 'MOV-Movie-Track');
|
927
|
+
} else {
|
928
|
+
($keysGrp, $keysPath) = ('Keys', 'MOV-Movie');
|
929
|
+
}
|
920
930
|
my $curPath = join '-', @{$$et{PATH}};
|
921
931
|
my ($dir, $writePath) = ($dirName, $dirName);
|
922
932
|
$writePath = "$dir-$writePath" while defined($dir = $$et{DirMap}{$dir});
|
923
933
|
# hack to create Keys directories if necessary (its containing Meta is in a different location)
|
924
|
-
if ($$addDirs{Keys} and $curPath =~ /^MOV-Movie(-Meta)?$/) {
|
934
|
+
if (($$addDirs{Keys} and $curPath =~ /^MOV-Movie(-Meta)?$/)) {
|
925
935
|
$createKeys = 1; # create new Keys directories
|
926
|
-
} elsif ($curPath
|
936
|
+
} elsif (($$addDirs{AudioKeys} or $$addDirs{VideoKeys}) and $curPath =~ /^MOV-Movie-Track(-Meta)?$/) {
|
937
|
+
$createKeys = -1; # (must wait until MediaType is known)
|
938
|
+
} elsif (($curPath eq 'MOV-Movie-Meta-ItemList') or
|
939
|
+
($curPath eq 'MOV-Movie-Track-Meta-ItemList' and $avType{$$et{MediaType}}))
|
940
|
+
{
|
927
941
|
$createKeys = 2; # create new Keys tags
|
928
|
-
my $keys = $$et{
|
942
|
+
my $keys = $$et{$keysGrp};
|
929
943
|
if ($keys) {
|
930
944
|
# add new tag entries for existing Keys tags, now that we know their ID's
|
931
945
|
# - first make lookup to convert Keys tagInfo ref to index number
|
@@ -933,7 +947,7 @@ sub WriteQuickTime($$$)
|
|
933
947
|
foreach $index (keys %{$$keys{Info}}) {
|
934
948
|
$keysInfo{$$keys{Info}{$index}} = $index if $$keys{Remap}{$index};
|
935
949
|
}
|
936
|
-
my $keysTable = GetTagTable(
|
950
|
+
my $keysTable = GetTagTable("Image::ExifTool::QuickTime::$keysGrp");
|
937
951
|
my $newKeysTags = $et->GetNewTagInfoHash($keysTable);
|
938
952
|
foreach (keys %$newKeysTags) {
|
939
953
|
my $tagInfo = $$newKeysTags{$_};
|
@@ -962,7 +976,8 @@ sub WriteQuickTime($$$)
|
|
962
976
|
}
|
963
977
|
if ($curPath eq $writePath or $createKeys) {
|
964
978
|
$canCreate = 1;
|
965
|
-
|
979
|
+
# (must check the appropriate Keys delete flag if this is a Keys ItemList)
|
980
|
+
$delGrp = $$et{DEL_GROUP}{$createKeys ? $keysGrp : $dirName};
|
966
981
|
}
|
967
982
|
$atomCount = $$tagTablePtr{VARS}{ATOM_COUNT} if $$tagTablePtr{VARS};
|
968
983
|
|
@@ -1080,12 +1095,12 @@ sub WriteQuickTime($$$)
|
|
1080
1095
|
last;
|
1081
1096
|
}
|
1082
1097
|
}
|
1083
|
-
# save the handler type
|
1084
|
-
if ($tag eq 'hdlr' and length $buff >= 12
|
1085
|
-
|
1086
|
-
|
1098
|
+
# save the handler type of the track media
|
1099
|
+
if ($tag eq 'hdlr' and length $buff >= 12 and
|
1100
|
+
@{$$et{PATH}} and $$et{PATH}[-1] eq 'Media')
|
1101
|
+
{
|
1102
|
+
$$et{MediaType} = substr($buff,8,4);
|
1087
1103
|
}
|
1088
|
-
|
1089
1104
|
# if this atom stores offsets, save its location so we can fix up offsets later
|
1090
1105
|
# (are there any other atoms that may store absolute file offsets?)
|
1091
1106
|
if ($tag =~ /^(stco|co64|iloc|mfra|moof|sidx|saio|gps |CTBO|uuid)$/) {
|
@@ -1130,11 +1145,11 @@ sub WriteQuickTime($$$)
|
|
1130
1145
|
&{$$tagInfo{WriteHook}}($buff,$et) if $tagInfo and $$tagInfo{WriteHook};
|
1131
1146
|
|
1132
1147
|
# allow numerical tag ID's (ItemList entries defined by Keys)
|
1133
|
-
if (not $tagInfo and $dirName eq 'ItemList' and $$et{
|
1148
|
+
if (not $tagInfo and $dirName eq 'ItemList' and $$et{$keysGrp}) {
|
1134
1149
|
$keysIndex = unpack('N', $tag);
|
1135
|
-
my $newIndex = $$et{
|
1150
|
+
my $newIndex = $$et{$keysGrp}{Remap}{$keysIndex};
|
1136
1151
|
if (defined $newIndex) {
|
1137
|
-
$tagInfo = $$et{
|
1152
|
+
$tagInfo = $$et{$keysGrp}{Info}{$keysIndex};
|
1138
1153
|
unless ($newIndex) {
|
1139
1154
|
if ($tagInfo) {
|
1140
1155
|
$et->VPrint(1," - Keys:$$tagInfo{Name}");
|
@@ -1174,7 +1189,7 @@ sub WriteQuickTime($$$)
|
|
1174
1189
|
if ($subdir) { # process atoms in this container from a buffer in memory
|
1175
1190
|
|
1176
1191
|
if ($tag eq 'trak') {
|
1177
|
-
|
1192
|
+
$$et{MediaType} = ''; # init media type for this track
|
1178
1193
|
delete $$et{AssumedDataRef};
|
1179
1194
|
}
|
1180
1195
|
my $subName = $$subdir{DirName} || $$tagInfo{Name};
|
@@ -1243,10 +1258,13 @@ sub WriteQuickTime($$$)
|
|
1243
1258
|
$$et{CHANGED} = $oldChanged;
|
1244
1259
|
undef $newData;
|
1245
1260
|
}
|
1246
|
-
if ($tag eq 'trak'
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1261
|
+
if ($tag eq 'trak') {
|
1262
|
+
$$et{MediaType} = ''; # reset media type at end of track
|
1263
|
+
if ($$et{AssumedDataRef}) {
|
1264
|
+
my $grp = $$et{CUR_WRITE_GROUP} || $dirName;
|
1265
|
+
$et->Error("Can't locate data reference to update offsets for $grp");
|
1266
|
+
delete $$et{AssumedDataRef};
|
1267
|
+
}
|
1250
1268
|
}
|
1251
1269
|
$$et{CUR_WRITE_GROUP} = $oldWriteGroup;
|
1252
1270
|
SetByteOrder('MM');
|
@@ -1542,7 +1560,7 @@ sub WriteQuickTime($$$)
|
|
1542
1560
|
}
|
1543
1561
|
if ($msg) {
|
1544
1562
|
# (allow empty sample description for non-audio/video handler types, eg. 'url ', 'meta')
|
1545
|
-
if ($$et{
|
1563
|
+
if ($$et{MediaType}) {
|
1546
1564
|
my $grp = $$et{CUR_WRITE_GROUP} || $parent;
|
1547
1565
|
$et->Error("$msg for $grp");
|
1548
1566
|
return $rtnErr;
|
@@ -1578,16 +1596,26 @@ sub WriteQuickTime($$$)
|
|
1578
1596
|
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and not $dataPt and (not $$tagTablePtr{$tag} or
|
1579
1597
|
ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
1580
1598
|
{
|
1581
|
-
# identify other known trailers
|
1599
|
+
# identify other known trailers from their first bytes
|
1582
1600
|
$buf2 = '';
|
1583
1601
|
$raf->Seek($lastPos,0) and $raf->Read($buf2,8);
|
1602
|
+
my ($type, $len);
|
1584
1603
|
if ($buf2 eq 'CCCCCCCC') {
|
1585
|
-
$
|
1604
|
+
$type = 'Kenwood';
|
1586
1605
|
} elsif ($buf2 =~ /^(gpsa|gps0|gsen|gsea)...\0/s) {
|
1587
|
-
$
|
1606
|
+
$type = 'RIFF';
|
1588
1607
|
} else {
|
1589
|
-
$
|
1608
|
+
$type = 'Unknown';
|
1590
1609
|
}
|
1610
|
+
# determine length of this trailer
|
1611
|
+
if ($trailer) {
|
1612
|
+
$len = $$trailer[1] - $lastPos; # runs to start of next trailer
|
1613
|
+
} else {
|
1614
|
+
$raf->Seek(0, 2) or $et->Error('Seek error'), return $dataPt ? undef : 1;
|
1615
|
+
$len = $raf->Tell() - $lastPos; # runs to end of file
|
1616
|
+
}
|
1617
|
+
# add to start of linked list of trailers
|
1618
|
+
$trailer = [ $type, $lastPos, $len, $trailer ];
|
1591
1619
|
} else {
|
1592
1620
|
$et->Error($errStr);
|
1593
1621
|
return $dataPt ? undef : 1;
|
@@ -1595,7 +1623,16 @@ sub WriteQuickTime($$$)
|
|
1595
1623
|
}
|
1596
1624
|
$et->VPrint(0, " [deleting $delCount $dirName tag".($delCount==1 ? '' : 's')."]\n") if $delCount;
|
1597
1625
|
|
1598
|
-
|
1626
|
+
# can finally set necessary variables for creating Video/AudioKeys tags
|
1627
|
+
if ($createKeys < 0) {
|
1628
|
+
if ($avType{$$et{MediaType}}) {
|
1629
|
+
$createKeys = 1;
|
1630
|
+
($keysGrp, $keysPath) = ("$avType{$$et{MediaType}}Keys", 'MOV-Movie-Track');
|
1631
|
+
} else {
|
1632
|
+
$canCreate = 0;
|
1633
|
+
}
|
1634
|
+
}
|
1635
|
+
$createKeys &= ~0x01 unless $$addDirs{$keysGrp}; # (Keys may have been written)
|
1599
1636
|
|
1600
1637
|
# add new directories/tags at this level if necessary
|
1601
1638
|
if ($canCreate and (exists $$et{EDIT_DIRS}{$dirName} or $createKeys)) {
|
@@ -1606,13 +1643,13 @@ sub WriteQuickTime($$$)
|
|
1606
1643
|
my ($tag, $index);
|
1607
1644
|
# add Keys tags if necessary
|
1608
1645
|
if ($createKeys) {
|
1609
|
-
if ($curPath eq
|
1646
|
+
if ($curPath eq $keysPath) {
|
1610
1647
|
# add Meta for Keys if necessary
|
1611
1648
|
unless ($didDir{meta}) {
|
1612
1649
|
$$dirs{meta} = $Image::ExifTool::QuickTime::Movie{meta};
|
1613
1650
|
push @addTags, 'meta';
|
1614
1651
|
}
|
1615
|
-
} elsif ($curPath eq
|
1652
|
+
} elsif ($curPath eq "$keysPath-Meta") {
|
1616
1653
|
# special case for Keys Meta -- reset directories and start again
|
1617
1654
|
undef @addTags;
|
1618
1655
|
$dirs = { };
|
@@ -1621,10 +1658,10 @@ sub WriteQuickTime($$$)
|
|
1621
1658
|
$$dirs{$_} = $Image::ExifTool::QuickTime::Meta{$_};
|
1622
1659
|
push @addTags, $_;
|
1623
1660
|
}
|
1624
|
-
} elsif ($curPath eq
|
1625
|
-
foreach $index (sort { $a <=> $b } keys %{$$et{
|
1661
|
+
} elsif ($curPath eq "$keysPath-Meta-ItemList" and $$et{$keysGrp}) {
|
1662
|
+
foreach $index (sort { $a <=> $b } keys %{$$et{$keysGrp}{Add}}) {
|
1626
1663
|
my $id = Set32u($index);
|
1627
|
-
$$newTags{$id} = $$et{
|
1664
|
+
$$newTags{$id} = $$et{$keysGrp}{Add}{$index};
|
1628
1665
|
push @addTags, $id;
|
1629
1666
|
}
|
1630
1667
|
} else {
|
@@ -1636,8 +1673,7 @@ sub WriteQuickTime($$$)
|
|
1636
1673
|
foreach $tag (@addTags) {
|
1637
1674
|
my $tagInfo = $$dirs{$tag} || $$newTags{$tag};
|
1638
1675
|
next if defined $$tagInfo{CanCreate} and not $$tagInfo{CanCreate};
|
1639
|
-
next if defined $$tagInfo{
|
1640
|
-
(not $$et{HandlerType} or $$et{HandlerType} ne $$tagInfo{HandlerType});
|
1676
|
+
next if defined $$tagInfo{MediaType} and $$et{MediaType} ne $$tagInfo{MediaType};
|
1641
1677
|
my $subdir = $$tagInfo{SubDirectory};
|
1642
1678
|
unless ($subdir) {
|
1643
1679
|
my $nvHash = $et->GetNewValueHash($tagInfo);
|
@@ -1699,13 +1735,13 @@ sub WriteQuickTime($$$)
|
|
1699
1735
|
}
|
1700
1736
|
my $subName = $$subdir{DirName} || $$tagInfo{Name};
|
1701
1737
|
# QuickTime hierarchy is complex, so check full directory path before adding
|
1702
|
-
if ($createKeys and $curPath eq
|
1738
|
+
if ($createKeys and $curPath eq $keysPath and $subName eq 'Meta') {
|
1703
1739
|
$et->VPrint(0, " Creating Meta with mdta Handler and Keys\n");
|
1704
1740
|
# init Meta box for Keys tags with mdta Handler and empty Keys+ItemList
|
1705
1741
|
$buf2 = "\0\0\0\x20hdlr\0\0\0\0\0\0\0\0mdta\0\0\0\0\0\0\0\0\0\0\0\0" .
|
1706
1742
|
"\0\0\0\x10keys\0\0\0\0\0\0\0\0" .
|
1707
1743
|
"\0\0\0\x08ilst";
|
1708
|
-
} elsif ($createKeys and $curPath eq
|
1744
|
+
} elsif ($createKeys and $curPath eq "$keysPath-Meta") {
|
1709
1745
|
$buf2 = ($subName eq 'Keys' ? "\0\0\0\0\0\0\0\0" : '');
|
1710
1746
|
} elsif ($subName eq 'Meta' and $$et{OPTIONS}{QuickTimeHandler}) {
|
1711
1747
|
$et->VPrint(0, " Creating Meta with mdir Handler\n");
|
@@ -1754,8 +1790,8 @@ sub WriteQuickTime($$$)
|
|
1754
1790
|
}
|
1755
1791
|
}
|
1756
1792
|
# add only once (must delete _after_ call to WriteDirectory())
|
1757
|
-
# (Keys
|
1758
|
-
delete $$addDirs{$subName} unless $
|
1793
|
+
# (Keys tags are a special case, and are handled separately)
|
1794
|
+
delete $$addDirs{$subName} unless $createKeys;
|
1759
1795
|
}
|
1760
1796
|
}
|
1761
1797
|
# write HEIC metadata after top-level 'meta' box has been processed if editing this information
|
@@ -1781,9 +1817,9 @@ sub WriteQuickTime($$$)
|
|
1781
1817
|
# (could report a file if editing nothing when it contained an empty Meta atom)
|
1782
1818
|
# ++$$et{CHANGED};
|
1783
1819
|
}
|
1784
|
-
if ($curPath eq
|
1785
|
-
delete $$addDirs{
|
1786
|
-
delete $$et{
|
1820
|
+
if ($curPath eq "$keysPath-Meta") {
|
1821
|
+
delete $$addDirs{$keysGrp}; # prevent creation of another Meta for Keys tags
|
1822
|
+
delete $$et{$keysGrp};
|
1787
1823
|
}
|
1788
1824
|
}
|
1789
1825
|
|
@@ -2041,21 +2077,35 @@ sub WriteQuickTime($$$)
|
|
2041
2077
|
# write the stuff that must come last
|
2042
2078
|
Write($outfile, $writeLast) or $rtnVal = 0 if $writeLast;
|
2043
2079
|
|
2044
|
-
# copy
|
2045
|
-
|
2046
|
-
# are we deleting the
|
2080
|
+
# copy trailers if necessary
|
2081
|
+
while ($rtnVal and $trailer) {
|
2082
|
+
# are we deleting the trailers?
|
2047
2083
|
my $nvTrail = $et->GetNewValueHash($Image::ExifTool::Extra{Trailer});
|
2048
|
-
if ($$et{DEL_GROUP}{Trailer} or
|
2084
|
+
if ($$et{DEL_GROUP}{Trailer} or $$et{DEL_GROUP}{$$trailer[0]} or
|
2085
|
+
($nvTrail and not ($$nvTrail{Value} and $$nvTrail{Value}[0])))
|
2086
|
+
{
|
2049
2087
|
$et->Warn("Deleted $$trailer[0] trailer", 1);
|
2050
|
-
|
2051
|
-
$
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2088
|
+
++$$et{CHANGED};
|
2089
|
+
$trailer = $$trailer[3];
|
2090
|
+
next;
|
2091
|
+
}
|
2092
|
+
$raf->Seek($$trailer[1], 0) or $rtnVal = 0, last;
|
2093
|
+
if ($$trailer[0] eq 'MIE') {
|
2094
|
+
require Image::ExifTool::MIE;
|
2095
|
+
my %dirInfo = ( RAF => $raf, OutFile => $outfile );
|
2096
|
+
my $result = Image::ExifTool::MIE::ProcessMIE($et, \%dirInfo);
|
2097
|
+
$result > 0 or $et->Error('Error writing MIE trailer'), $rtnVal = 0, last;
|
2055
2098
|
} else {
|
2056
|
-
$
|
2099
|
+
$et->Warn(sprintf('Copying %s trailer from offset 0x%x (%d bytes)', @$trailer[0..2]), 1);
|
2100
|
+
my $len = $$trailer[2];
|
2101
|
+
while ($len) {
|
2102
|
+
my $n = $len > 65536 ? 65536 : $len;
|
2103
|
+
$raf->Read($buf2, $n) == $n and Write($outfile, $buf2) or $rtnVal = 0, last;
|
2104
|
+
$len -= $n;
|
2105
|
+
}
|
2106
|
+
$rtnVal or $et->Error("Error copying $$trailer[0] trailer"), last;
|
2057
2107
|
}
|
2058
|
-
$
|
2108
|
+
$trailer = $$trailer[3]; # step to next trailer in linked list
|
2059
2109
|
}
|
2060
2110
|
return $rtnVal;
|
2061
2111
|
}
|
@@ -2111,6 +2161,7 @@ sub WriteMOV($$)
|
|
2111
2161
|
$raf->Seek(0,0);
|
2112
2162
|
|
2113
2163
|
# write the file
|
2164
|
+
$$et{MediaType} = '';
|
2114
2165
|
$$dirInfo{Parent} = '';
|
2115
2166
|
$$dirInfo{DirName} = 'MOV';
|
2116
2167
|
$$dirInfo{ChunkOffset} = [ ]; # (just to be safe)
|
@@ -324,8 +324,10 @@ sub WriteRIFF($$)
|
|
324
324
|
$raf->Read($buff, 6) == 6 or $et->Error('Truncated VP8L chunk'), return 1;
|
325
325
|
$outsize += 6;
|
326
326
|
if ($buff =~ /^\x2f/s) {
|
327
|
+
my $word = Get32u(\$buff, 2);
|
327
328
|
$imageWidth = (Get16u(\$buff, 1) & 0x3fff) + 1;
|
328
|
-
$imageHeight = ((
|
329
|
+
$imageHeight = (($word >> 6) & 0x3fff) + 1;
|
330
|
+
$has{ALPH} = 1 if $word & 0x100000; # set alpha flag if necessary
|
329
331
|
}
|
330
332
|
$len2 -= 6;
|
331
333
|
}
|
@@ -138,11 +138,12 @@ my %rawType = (
|
|
138
138
|
# 2) any dependencies must be added to %excludeGroups
|
139
139
|
my @delGroups = qw(
|
140
140
|
Adobe AFCP APP0 APP1 APP2 APP3 APP4 APP5 APP6 APP7 APP8 APP9 APP10 APP11 APP12
|
141
|
-
APP13 APP14 APP15 CanonVRD CIFF Ducky EXIF ExifIFD File FlashPix
|
142
|
-
GlobParamIFD GPS ICC_Profile IFD0 IFD1 Insta360 InteropIFD IPTC
|
143
|
-
Jpeg2000 JUMBF Keys MakerNotes Meta MetaIFD Microsoft
|
144
|
-
NikonCapture PDF PDF-update PhotoMechanic
|
145
|
-
QuickTime RMETA RSRC SEAL SubIFD Trailer
|
141
|
+
APP13 APP14 APP15 AudioKeys CanonVRD CIFF Ducky EXIF ExifIFD File FlashPix
|
142
|
+
FotoStation GlobParamIFD GPS ICC_Profile IFD0 IFD1 Insta360 InteropIFD IPTC
|
143
|
+
ItemList iTunes JFIF Jpeg2000 JUMBF Keys MakerNotes Meta MetaIFD Microsoft
|
144
|
+
MIE MPF Nextbase NikonApp NikonCapture PDF PDF-update PhotoMechanic
|
145
|
+
Photoshop PNG PNG-pHYs PrintIM QuickTime RMETA RSRC SEAL SubIFD Trailer
|
146
|
+
UserData VideoKeys Vivo XML XML-* XMP XMP-*
|
146
147
|
);
|
147
148
|
# family 2 group names that we can delete
|
148
149
|
my @delGroup2 = qw(
|
@@ -2823,7 +2824,10 @@ sub GetAllGroups($;$)
|
|
2823
2824
|
|
2824
2825
|
my %allGroups;
|
2825
2826
|
# add family 1 groups not in tables
|
2826
|
-
|
2827
|
+
no warnings; # (avoid "possible attempt to put comments in qw()")
|
2828
|
+
$family == 1 and map { $allGroups{$_} = 1 } qw(Garmin AudioItemList AudioUserData
|
2829
|
+
VideoItemList VideoUserData Track#Keys Track#ItemList Track#UserData);
|
2830
|
+
use warnings;
|
2827
2831
|
# loop through all tag tables and get all group names
|
2828
2832
|
while (@tableNames) {
|
2829
2833
|
my $table = GetTagTable(pop @tableNames);
|
@@ -2852,7 +2856,7 @@ sub GetAllGroups($;$)
|
|
2852
2856
|
}
|
2853
2857
|
}
|
2854
2858
|
delete $allGroups{'*'}; # (not a real group)
|
2855
|
-
return sort keys %allGroups;
|
2859
|
+
return sort { lc $a cmp lc $b } keys %allGroups;
|
2856
2860
|
}
|
2857
2861
|
|
2858
2862
|
#------------------------------------------------------------------------------
|
@@ -2870,7 +2874,7 @@ sub GetNewGroups($)
|
|
2870
2874
|
# Returns: List of group names (sorted alphabetically)
|
2871
2875
|
sub GetDeleteGroups()
|
2872
2876
|
{
|
2873
|
-
return sort @delGroups, @delGroup2;
|
2877
|
+
return sort { lc $a cmp lc $b } @delGroups, @delGroup2;
|
2874
2878
|
}
|
2875
2879
|
|
2876
2880
|
#------------------------------------------------------------------------------
|
@@ -3336,7 +3340,8 @@ sub InsertTagValues($$;$$$$)
|
|
3336
3340
|
} elsif ($tag eq 'self') {
|
3337
3341
|
$val = $et; # ("$self{var}" or "$file1:self{var}" in string)
|
3338
3342
|
} else {
|
3339
|
-
# get the tag value
|
3343
|
+
# get the tag value (note: this direct access allows excluded tags
|
3344
|
+
# to be accessed if the case is correct and a group name is not used)
|
3340
3345
|
$val = $et->GetValue($tag, $type);
|
3341
3346
|
unless (defined $val) {
|
3342
3347
|
# check for tag name with different case
|
@@ -5229,7 +5234,7 @@ sub Set64u(@)
|
|
5229
5234
|
{
|
5230
5235
|
my $val = $_[0];
|
5231
5236
|
my $hi = int($val / 4294967296);
|
5232
|
-
my $lo = Set32u($val - $hi * 4294967296);
|
5237
|
+
my $lo = Set32u($val - $hi * 4294967296); # NOTE: subject to round-off errors!
|
5233
5238
|
$hi = Set32u($hi);
|
5234
5239
|
$val = GetByteOrder() eq 'MM' ? $hi . $lo : $lo . $hi;
|
5235
5240
|
$_[1] and substr(${$_[1]}, $_[2], length($val)) = $val;
|
@@ -6103,7 +6108,7 @@ sub WriteJPEG($$)
|
|
6103
6108
|
my $tbuf = '';
|
6104
6109
|
$raf->Seek(-length($buff), 1); # seek back to just after EOI
|
6105
6110
|
$$trailInfo{OutFile} = \$tbuf; # rewrite the trailer
|
6106
|
-
$$trailInfo{
|
6111
|
+
$$trailInfo{ScanForTrailer} = 1;# scan if necessary
|
6107
6112
|
$self->ProcessTrailers($trailInfo) or undef $trailInfo;
|
6108
6113
|
}
|
6109
6114
|
if (not $oldOutfile) {
|
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 $advFmtSelf);
|
31
31
|
|
32
|
-
$VERSION = '13.
|
32
|
+
$VERSION = '13.16';
|
33
33
|
$RELEASE = '';
|
34
34
|
@ISA = qw(Exporter);
|
35
35
|
%EXPORT_TAGS = (
|
@@ -4166,7 +4166,7 @@ sub GetFileType(;$$)
|
|
4166
4166
|
$desc = $$fileType[1];
|
4167
4167
|
}
|
4168
4168
|
} else {
|
4169
|
-
$desc = $fileDescription{$file};
|
4169
|
+
$desc = $fileDescription{$file} || $file;
|
4170
4170
|
}
|
4171
4171
|
$desc .= ", $subType" if $subType;
|
4172
4172
|
return $desc;
|
@@ -4494,7 +4494,7 @@ sub DoneExtract($)
|
|
4494
4494
|
# set family 8 group name for all tags
|
4495
4495
|
$$altExifTool{TAG_EXTRA}{$_}{G8} = $g8 foreach keys %{$$altExifTool{VALUE}};
|
4496
4496
|
# prepare our sorted list of found tags
|
4497
|
-
$$altExifTool{FoundTags} =
|
4497
|
+
$$altExifTool{FoundTags} = $altExifTool->SetFoundTags();
|
4498
4498
|
$$altExifTool{DID_EXTRACT} = 1;
|
4499
4499
|
}
|
4500
4500
|
# if necessary, build composite tags that rely on tags from alternate files
|
@@ -6896,6 +6896,8 @@ sub IdentifyTrailer($;$)
|
|
6896
6896
|
$type = 'Insta360';
|
6897
6897
|
} elsif ($buff =~ m(\0{6}/NIKON APP$)) {
|
6898
6898
|
$type = 'NikonApp';
|
6899
|
+
} elsif ($buff =~ /\xff{4}\x1b\*9HWfu\x84\x93\xa2\xb1$/) {
|
6900
|
+
$type = 'Vivo';
|
6899
6901
|
}
|
6900
6902
|
last;
|
6901
6903
|
}
|
@@ -6908,7 +6910,8 @@ sub IdentifyTrailer($;$)
|
|
6908
6910
|
# Inputs: 0) ExifTool object ref, 1) DirInfo ref:
|
6909
6911
|
# - requires RAF and DirName
|
6910
6912
|
# - OutFile is a scalar reference for writing
|
6911
|
-
# - scans from current file position if
|
6913
|
+
# - scans from current file position for each trailer if ScanForTrailer is set
|
6914
|
+
# (current file position is just after JPEG EOF for a JPEG image)
|
6912
6915
|
# Returns: 1 if trailer was processed or couldn't be processed (or written OK)
|
6913
6916
|
# 0 if trailer was recognized but offsets need fixing (or write error)
|
6914
6917
|
# - DirName, DirLen, DataPos, Offset, Fixup and OutFile are updated
|
@@ -6954,7 +6957,7 @@ sub ProcessTrailers($$)
|
|
6954
6957
|
# read or write this trailer
|
6955
6958
|
# (proc takes Offset as positive offset from end of trailer to end of file,
|
6956
6959
|
# and returns DataPos and DirLen, and Fixup if applicable, and updates
|
6957
|
-
# OutFile when writing)
|
6960
|
+
# OutFile when writing. Returns < 0 if we must scan for this trailer)
|
6958
6961
|
no strict 'refs';
|
6959
6962
|
my $result = &$proc($self, $dirInfo);
|
6960
6963
|
use strict 'refs';
|
@@ -7364,7 +7367,7 @@ sub ProcessJPEG($$;$)
|
|
7364
7367
|
# and scan for AFCP if necessary
|
7365
7368
|
my $fromEnd = 0;
|
7366
7369
|
if ($trailInfo) {
|
7367
|
-
$$trailInfo{
|
7370
|
+
$$trailInfo{ScanForTrailer} = 1; # scan now if necessary
|
7368
7371
|
$self->ProcessTrailers($trailInfo);
|
7369
7372
|
# save offset from end of file to start of first trailer
|
7370
7373
|
$fromEnd = $$trailInfo{Offset};
|
@@ -7564,6 +7567,19 @@ sub ProcessJPEG($$;$)
|
|
7564
7567
|
$$self{SkipData} = \@skipData if @skipData;
|
7565
7568
|
# extract the EXIF information (it is in standard TIFF format)
|
7566
7569
|
$self->ProcessTIFF(\%dirInfo) or $self->Warn('Malformed APP1 EXIF segment');
|
7570
|
+
# scan for Vivo HiddenData if necessary
|
7571
|
+
if ($$self{Make} eq 'vivo' and
|
7572
|
+
# (stored as UserComment by some models)
|
7573
|
+
not ($$self{VALUE}{UserComment} and $$self{VALUE}{UserComment} =~ /^filter:/) and
|
7574
|
+
$$dataPt =~ /(filter: .*?; \n)\0/sg)
|
7575
|
+
{
|
7576
|
+
if ($htmlDump) {
|
7577
|
+
my $n = length($1) + 1;
|
7578
|
+
$self->HDump($segPos+pos($$dataPt)-$n, $n, '[Vivo HiddenData]', undef, 0x08);
|
7579
|
+
}
|
7580
|
+
my $tbl = GetTagTable('Image::ExifTool::Vivo::Main');
|
7581
|
+
$self->HandleTag($tbl, HiddenData => $1);
|
7582
|
+
}
|
7567
7583
|
# avoid looking for preview unless necessary because it really slows
|
7568
7584
|
# us down -- only look for it if we found pointer, and preview is
|
7569
7585
|
# outside EXIF, and PreviewImage is specifically requested
|
@@ -8541,7 +8557,7 @@ sub DoProcessTIFF($$;$)
|
|
8541
8557
|
if ($raf) {
|
8542
8558
|
my $trailInfo = IdentifyTrailer($raf);
|
8543
8559
|
if ($trailInfo) {
|
8544
|
-
$$trailInfo{
|
8560
|
+
$$trailInfo{ScanForTrailer} = 1; # scan to find AFCP if necessary
|
8545
8561
|
$self->ProcessTrailers($trailInfo);
|
8546
8562
|
}
|
8547
8563
|
# dump any other known trailer (eg. A100 RAW Data)
|
@@ -8646,7 +8662,7 @@ sub DoProcessTIFF($$;$)
|
|
8646
8662
|
last unless $trailInfo;
|
8647
8663
|
my $tbuf = '';
|
8648
8664
|
$$trailInfo{OutFile} = \$tbuf; # rewrite trailer(s)
|
8649
|
-
$$trailInfo{
|
8665
|
+
$$trailInfo{ScanForTrailer} = 1; # scan for AFCP if necessary
|
8650
8666
|
# rewrite all trailers to buffer
|
8651
8667
|
unless ($self->ProcessTrailers($trailInfo)) {
|
8652
8668
|
undef $trailInfo;
|