exiftool-vendored.pl 12.91.0 → 12.97.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 +58 -3
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +2 -2
- package/bin/exiftool +41 -57
- package/bin/lib/Image/ExifTool/Canon.pm +136 -3
- package/bin/lib/Image/ExifTool/Font.pm +15 -4
- package/bin/lib/Image/ExifTool/FujiFilm.pm +23 -1
- package/bin/lib/Image/ExifTool/Geotag.pm +19 -5
- package/bin/lib/Image/ExifTool/InDesign.pm +17 -3
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +3 -3
- package/bin/lib/Image/ExifTool/Nikon.pm +356 -62
- package/bin/lib/Image/ExifTool/NikonCustom.pm +421 -11
- package/bin/lib/Image/ExifTool/NikonSettings.pm +56 -1
- package/bin/lib/Image/ExifTool/OpenEXR.pm +3 -1
- package/bin/lib/Image/ExifTool/PostScript.pm +3 -12
- package/bin/lib/Image/ExifTool/QuickTime.pm +34 -14
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +118 -37
- package/bin/lib/Image/ExifTool/Samsung.pm +5 -3
- package/bin/lib/Image/ExifTool/TagLookup.pm +6935 -6904
- package/bin/lib/Image/ExifTool/TagNames.pod +293 -7
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +48 -16
- package/bin/lib/Image/ExifTool/Writer.pl +8 -54
- package/bin/lib/Image/ExifTool/XMP2.pl +1 -1
- package/bin/lib/Image/ExifTool.pm +66 -4
- package/bin/perl-Image-ExifTool.spec +1 -1
- package/bin/windows_exiftool.txt +2836 -0
- package/package.json +3 -3
|
@@ -48,7 +48,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
|
|
|
48
48
|
use Image::ExifTool::Exif;
|
|
49
49
|
use Image::ExifTool::GPS;
|
|
50
50
|
|
|
51
|
-
$VERSION = '
|
|
51
|
+
$VERSION = '3.02';
|
|
52
52
|
|
|
53
53
|
sub ProcessMOV($$;$);
|
|
54
54
|
sub ProcessKeys($$$);
|
|
@@ -6552,7 +6552,7 @@ my %userDefined = (
|
|
|
6552
6552
|
PROCESS_PROC => \&ProcessKeys,
|
|
6553
6553
|
WRITE_PROC => \&WriteKeys,
|
|
6554
6554
|
CHECK_PROC => \&CheckQTValue,
|
|
6555
|
-
VARS => { LONG_TAGS =>
|
|
6555
|
+
VARS => { LONG_TAGS => 8 },
|
|
6556
6556
|
WRITABLE => 1,
|
|
6557
6557
|
# (not PREFERRED when writing)
|
|
6558
6558
|
GROUPS => { 1 => 'Keys' },
|
|
@@ -6606,6 +6606,8 @@ my %userDefined = (
|
|
|
6606
6606
|
PrintConv => '$val * 1e6 . " microseconds"',
|
|
6607
6607
|
PrintConvInv => '$val =~ s/ .*//; $val * 1e-6',
|
|
6608
6608
|
},
|
|
6609
|
+
# 'camera.focal_length.35mm_equivalent' - not top level (written to Keys in video track)
|
|
6610
|
+
# 'camera.lens_model' - not top level (written to Keys in video track)
|
|
6609
6611
|
'location.ISO6709' => {
|
|
6610
6612
|
Name => 'GPSCoordinates',
|
|
6611
6613
|
Groups => { 2 => 'Location' },
|
|
@@ -6668,7 +6670,12 @@ my %userDefined = (
|
|
|
6668
6670
|
#
|
|
6669
6671
|
'com.apple.photos.captureMode' => 'CaptureMode',
|
|
6670
6672
|
'com.android.version' => 'AndroidVersion',
|
|
6671
|
-
'com.android.capture.fps' => 'AndroidCaptureFPS',
|
|
6673
|
+
'com.android.capture.fps' => { Name => 'AndroidCaptureFPS', Writable => 'float' },
|
|
6674
|
+
'com.android.manufacturer' => 'AndroidMake',
|
|
6675
|
+
'com.android.model' => 'AndroidModel',
|
|
6676
|
+
'com.xiaomi.preview_video_cover' => { Name => 'XiaomiPreviewVideoCover', Writable => 'int32s' },
|
|
6677
|
+
'xiaomi.exifInfo.videoinfo' => 'XiaomiExifInfo',
|
|
6678
|
+
'com.xiaomi.hdr10' => { Name => 'XiaomiHDR10', Writable => 'int32s' },
|
|
6672
6679
|
#
|
|
6673
6680
|
# also seen
|
|
6674
6681
|
#
|
|
@@ -9484,7 +9491,7 @@ sub ProcessKeys($$$)
|
|
|
9484
9491
|
$$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name
|
|
9485
9492
|
AddTagToTable($itemList, $id, $newInfo);
|
|
9486
9493
|
$msg or $msg = '';
|
|
9487
|
-
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $
|
|
9494
|
+
$out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $full$msg\n";
|
|
9488
9495
|
}
|
|
9489
9496
|
$pos += $len;
|
|
9490
9497
|
++$index;
|
|
@@ -9521,7 +9528,7 @@ sub ProcessMOV($$;$)
|
|
|
9521
9528
|
my $dirID = $$dirInfo{DirID} || '';
|
|
9522
9529
|
my $charsetQuickTime = $et->Options('CharsetQuickTime');
|
|
9523
9530
|
my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index);
|
|
9524
|
-
my ($dirEnd, $unkOpt, %saveOptions, $atomCount, $warnStr);
|
|
9531
|
+
my ($dirEnd, $unkOpt, %saveOptions, $atomCount, $warnStr, $trailer);
|
|
9525
9532
|
|
|
9526
9533
|
my $topLevel = not $$et{InQuickTime};
|
|
9527
9534
|
$$et{InQuickTime} = 1;
|
|
@@ -9550,6 +9557,17 @@ sub ProcessMOV($$;$)
|
|
|
9550
9557
|
$tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main');
|
|
9551
9558
|
}
|
|
9552
9559
|
($size, $tag) = unpack('Na4', $buff);
|
|
9560
|
+
my $fast = $$et{OPTIONS}{FastScan} || 0;
|
|
9561
|
+
# check for Insta360 trailer
|
|
9562
|
+
if ($topLevel and not $fast) {
|
|
9563
|
+
my $pos = $raf->Tell();
|
|
9564
|
+
if ($raf->Seek(-40, 2) and $raf->Read($buff, 40) == 40 and
|
|
9565
|
+
substr($buff, 8) eq '8db42d694ccc418790edff439fe026bf')
|
|
9566
|
+
{
|
|
9567
|
+
$trailer = [ 'Insta360', $raf->Tell() - unpack('V',$buff) ];
|
|
9568
|
+
}
|
|
9569
|
+
$raf->Seek($pos,0) or return 0;
|
|
9570
|
+
}
|
|
9553
9571
|
if ($dataPt) {
|
|
9554
9572
|
$verbose and $et->VerboseDir($$dirInfo{DirName});
|
|
9555
9573
|
} else {
|
|
@@ -9588,7 +9606,6 @@ sub ProcessMOV($$;$)
|
|
|
9588
9606
|
# have XMP take priority except for HEIC
|
|
9589
9607
|
$$et{PRIORITY_DIR} = 'XMP' unless $fileType and $fileType eq 'HEIC';
|
|
9590
9608
|
}
|
|
9591
|
-
my $fast = $$et{OPTIONS}{FastScan} || 0;
|
|
9592
9609
|
$$raf{NoBuffer} = 1 if $fast; # disable buffering in FastScan mode
|
|
9593
9610
|
|
|
9594
9611
|
my $ee = $$et{OPTIONS}{ExtractEmbedded};
|
|
@@ -10129,6 +10146,10 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
|
10129
10146
|
$dataPos += $size + 8; # point to start of next atom data
|
|
10130
10147
|
last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes)
|
|
10131
10148
|
$lastPos = $raf->Tell() + $dirBase;
|
|
10149
|
+
if ($trailer and $lastPos >= $$trailer[1]) {
|
|
10150
|
+
$et->Warn(sprintf('%s trailer at offset 0x%x', @$trailer), 1);
|
|
10151
|
+
last;
|
|
10152
|
+
}
|
|
10132
10153
|
$raf->Read($buff, 8) == 8 or last;
|
|
10133
10154
|
$lastTag = $tag if $$tagTablePtr{$tag} and $tag ne 'free'; # (Insta360 sometimes puts free block before trailer)
|
|
10134
10155
|
($size, $tag) = unpack('Na4', $buff);
|
|
@@ -10137,14 +10158,10 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
|
|
|
10137
10158
|
if ($warnStr) {
|
|
10138
10159
|
# assume this is an unknown trailer if it comes immediately after
|
|
10139
10160
|
# mdat or moov and has a tag name we don't recognize
|
|
10140
|
-
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and
|
|
10141
|
-
ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
|
10161
|
+
if (($lastTag eq 'mdat' or $lastTag eq 'moov') and
|
|
10162
|
+
(not $$tagTablePtr{$tag} or ref $$tagTablePtr{$tag} eq 'HASH' and $$tagTablePtr{$tag}{Unknown}))
|
|
10142
10163
|
{
|
|
10143
|
-
|
|
10144
|
-
$et->Warn(sprintf('Insta360 trailer at offset 0x%x', $lastPos), 1);
|
|
10145
|
-
} else {
|
|
10146
|
-
$et->Warn('Unknown trailer with '.lcfirst($warnStr));
|
|
10147
|
-
}
|
|
10164
|
+
$et->Warn('Unknown trailer with '.lcfirst($warnStr));
|
|
10148
10165
|
} else {
|
|
10149
10166
|
$et->Warn($warnStr);
|
|
10150
10167
|
}
|
|
@@ -10171,7 +10188,10 @@ QTLang: foreach $tag (@{$$et{QTLang}}) {
|
|
|
10171
10188
|
for ($i=0, $key=$name; $$infoHash{$key}; ++$i, $key="$name ($i)") {
|
|
10172
10189
|
next QTLang if $et->GetGroup($key, 0) eq 'QuickTime';
|
|
10173
10190
|
}
|
|
10174
|
-
$et->FoundTag($tagInfo, $$et{VALUE}{$tag});
|
|
10191
|
+
$key = $et->FoundTag($tagInfo, $$et{VALUE}{$tag});
|
|
10192
|
+
# copy extra tag information (groups, etc) to the synthetic tag
|
|
10193
|
+
$$et{TAG_EXTRA}{$key} = $$et{TAG_EXTRA}{$tag};
|
|
10194
|
+
$et->VPrint(0, "(synthesized default-language tag for QuickTime:$$tagInfo{Name})");
|
|
10175
10195
|
}
|
|
10176
10196
|
delete $$et{QTLang};
|
|
10177
10197
|
}
|
|
@@ -109,7 +109,7 @@ my %insvLimit = (
|
|
|
109
109
|
The tags below are extracted from timed metadata in QuickTime and other
|
|
110
110
|
formats of video files when the ExtractEmbedded option is used. Although
|
|
111
111
|
most of these tags are combined into the single table below, ExifTool
|
|
112
|
-
currently reads
|
|
112
|
+
currently reads 77 different formats of timed GPS metadata from video files.
|
|
113
113
|
},
|
|
114
114
|
VARS => { NO_ID => 1 },
|
|
115
115
|
GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
|
|
@@ -341,6 +341,7 @@ my %insvLimit = (
|
|
|
341
341
|
},
|
|
342
342
|
# djmd - DJI AC003 Osmo Action 4 cam
|
|
343
343
|
#TODO djmd => { SubDirectory => { TagTable => 'Image::ExifTool::DJI::djmd', ByteOrder => 'Little-Endian' } },
|
|
344
|
+
# (also DJI_20240615181302_0006_D.LRF)
|
|
344
345
|
# dbgi - DJI AC003 Osmo Action 4 cam -- lots more unknown stuff
|
|
345
346
|
Unknown00 => { Unknown => 1 },
|
|
346
347
|
Unknown01 => { Unknown => 1 },
|
|
@@ -757,6 +758,15 @@ my %insvLimit = (
|
|
|
757
758
|
10 => { Name => 'FusionYPR', Format => 'float[3]' },
|
|
758
759
|
);
|
|
759
760
|
|
|
761
|
+
#------------------------------------------------------------------------------
|
|
762
|
+
# Convert unsigned 32-bit integer to signed
|
|
763
|
+
# Inputs: <none> (uses value in $_)
|
|
764
|
+
# Returns: signed integer
|
|
765
|
+
sub SignedInt32()
|
|
766
|
+
{
|
|
767
|
+
return $_ < 0x80000000 ? $_ : $_ - 4294967296;
|
|
768
|
+
}
|
|
769
|
+
|
|
760
770
|
#------------------------------------------------------------------------------
|
|
761
771
|
# Save information from keys in OtherSampleDesc directory for processing timed metadata
|
|
762
772
|
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
|
|
@@ -1474,6 +1484,31 @@ sub ConvertLatLon($$)
|
|
|
1474
1484
|
$_[1] = $deg + ($_[1] - $deg * 100) / 60;
|
|
1475
1485
|
}
|
|
1476
1486
|
|
|
1487
|
+
#------------------------------------------------------------------------------
|
|
1488
|
+
# Decrypt Lucky data
|
|
1489
|
+
# Inputs: 0) string to decrypt, 1) encryption key
|
|
1490
|
+
# Returns: decrypted string
|
|
1491
|
+
my @luckyKeys = ('luckychip gps', 'customer ## gps');
|
|
1492
|
+
sub DecryptLucky($$) {
|
|
1493
|
+
my ($str, $key) = @_;
|
|
1494
|
+
my @str = unpack('C*', $str);
|
|
1495
|
+
my @key = unpack('C*', $key);
|
|
1496
|
+
my @enc = (0..255);
|
|
1497
|
+
my ($i, $j, $k) = (0, 0, 0);
|
|
1498
|
+
do {
|
|
1499
|
+
$j = ($j + $enc[$i] + $key[$i % length($key)]) & 0xff;
|
|
1500
|
+
@enc[$i,$j] = @enc[$j,$i];
|
|
1501
|
+
} while (++$i < 256);
|
|
1502
|
+
($i, $j, $k) = (0, 0, 0);
|
|
1503
|
+
do {
|
|
1504
|
+
$j = ($j + 1) & 0xff;
|
|
1505
|
+
$k = ($k + $enc[$j]) & 0xff;
|
|
1506
|
+
@enc[$j,$k] = @enc[$k,$j];
|
|
1507
|
+
$str[$i] ^= $enc[($enc[$j] + $enc[$k]) & 0xff];
|
|
1508
|
+
} while (++$i < @str);
|
|
1509
|
+
return pack('C*', @str);
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1477
1512
|
#------------------------------------------------------------------------------
|
|
1478
1513
|
# Process "freeGPS " data blocks
|
|
1479
1514
|
# Inputs: 0) ExifTool ref, 1) dirInfo ref {DataPt,SampleTime,SampleDuration}, 2) tagTable ref
|
|
@@ -1589,40 +1624,87 @@ sub ProcessFreeGPS($$$)
|
|
|
1589
1624
|
}
|
|
1590
1625
|
if (defined $lat) {
|
|
1591
1626
|
# extract accelerometer readings if GPS was valid
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc;
|
|
1627
|
+
# and change to signed integer and divide by 256
|
|
1628
|
+
@acc = map { SignedInt32 / 256 } unpack('x68V3', $$dataPt);
|
|
1595
1629
|
}
|
|
1596
1630
|
|
|
1597
|
-
} elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])/s) {
|
|
1631
|
+
} elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])\0/s) {
|
|
1598
1632
|
|
|
1599
|
-
$debug and $et->FoundTag(GPSType => 3);
|
|
1600
|
-
# decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
|
|
1601
|
-
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
|
1602
|
-
# 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........]
|
|
1603
|
-
# 0020: 09 00 00 00 1b 00 00 00 41 4e 57 00 25 d1 99 45 [........ANW.%..E]
|
|
1604
|
-
# 0030: f1 47 40 46 66 66 d2 41 85 eb 83 41 00 00 00 00 [.G@Fff.A...A....]
|
|
1605
1633
|
($latRef, $lonRef) = ($1, $2);
|
|
1606
1634
|
($hr,$min,$sec,$yr,$mon,$day) = unpack('x16V6', $$dataPt);
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
$
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
}
|
|
1617
|
-
$
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1635
|
+
# test for base64-encoded and encrypted lucky gps strings
|
|
1636
|
+
my ($notEnc, $notStr, $lt, $ln);
|
|
1637
|
+
if (length($$dataPt) < 0x78) {
|
|
1638
|
+
$notEnc = $notStr = 1;
|
|
1639
|
+
} else {
|
|
1640
|
+
$lt = substr($$dataPt, 0x2c, 20), # latitude
|
|
1641
|
+
$ln = substr($$dataPt, 0x40, 20), # longitude
|
|
1642
|
+
/^[A-Za-z0-9+\/]{8,20}={0,2}\0*$/ or $notEnc = 1, last foreach ($lt, $ln);
|
|
1643
|
+
/^\d{1,5}\.\d+\0*$/ or $notStr = 1, last foreach ($lt, $ln);
|
|
1644
|
+
}
|
|
1645
|
+
if ($notEnc and $notStr) {
|
|
1646
|
+
|
|
1647
|
+
$debug and $et->FoundTag(GPSType => '3a');
|
|
1648
|
+
# decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format)
|
|
1649
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
|
1650
|
+
# 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........]
|
|
1651
|
+
# 0020: 09 00 00 00 1b 00 00 00 41 4e 57 00 25 d1 99 45 [........ANW.%..E]
|
|
1652
|
+
# 0030: f1 47 40 46 66 66 d2 41 85 eb 83 41 00 00 00 00 [.G@Fff.A...A....]
|
|
1653
|
+
if ($yr >= 2000) {
|
|
1654
|
+
# Kenwood dashcam sometimes stores absolute year and local time
|
|
1655
|
+
# (but sometimes year since 2000 and UTC time in same video!)
|
|
1656
|
+
require Time::Local;
|
|
1657
|
+
my $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$yr);
|
|
1658
|
+
($sec,$min,$hr,$day,$mon,$yr) = gmtime($time);
|
|
1659
|
+
$yr += 1900;
|
|
1660
|
+
++$mon;
|
|
1661
|
+
$et->WarnOnce('Converting GPSDateTime to UTC based on local time zone',1);
|
|
1662
|
+
}
|
|
1663
|
+
$lat = GetFloat($dataPt, 0x2c);
|
|
1664
|
+
$lon = GetFloat($dataPt, 0x30);
|
|
1665
|
+
$spd = GetFloat($dataPt, 0x34) * $knotsToKph;
|
|
1666
|
+
$trk = GetFloat($dataPt, 0x38);
|
|
1667
|
+
# (may be all zeros or int16u counting from 1 to 6 if not valid)
|
|
1668
|
+
my $tmp = substr($$dataPt, 60, 12);
|
|
1669
|
+
if ($tmp ne "\0\0\0\0\0\0\0\0\0\0\0\0" and $tmp ne "\x01\0\x02\0\x03\0\x04\0\x05\0\x06\0") {
|
|
1670
|
+
@acc = map { SignedInt32 / 256 } unpack('V3', $tmp);
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
} else {
|
|
1674
|
+
|
|
1675
|
+
$debug and $et->FoundTag(GPSType => '3b');
|
|
1676
|
+
# decode freeGPS from E-ACE B44 dashcam
|
|
1677
|
+
# 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....]
|
|
1678
|
+
# 0010: 08 00 00 00 22 00 00 00 01 00 00 00 18 00 00 00 [...."...........]
|
|
1679
|
+
# 0020: 08 00 00 00 10 00 00 00 41 4e 45 00 67 4e 69 69 [........ANE.gNii]
|
|
1680
|
+
# 0030: 5a 38 4a 54 74 48 63 61 36 74 77 3d 00 00 00 00 [Z8JTtHca6tw=....]
|
|
1681
|
+
# 0040: 68 74 75 69 5a 4d 4a 53 73 58 55 58 37 4e 6f 3d [htuiZMJSsXUX7No=]
|
|
1682
|
+
# 0050: 00 00 00 00 64 3b ac 41 e1 3a 1d 43 2b 01 00 00 [....d;.A.:.C+...]
|
|
1683
|
+
# 0060: fd ff ff ff 43 00 00 00 32 4a 37 31 50 70 55 48 [....C...2J71PpUH]
|
|
1684
|
+
# 0070: 37 69 68 66 00 00 00 00 00 00 00 00 00 00 00 00 [7ihf............]
|
|
1685
|
+
# (16-byte string at 0x68 is base64 encoded and encrypted 'luckychip' string)
|
|
1686
|
+
$spd = GetFloat($dataPt, 0x54) * $knotsToKph;
|
|
1687
|
+
$trk = GetFloat($dataPt, 0x58);
|
|
1688
|
+
@acc = map SignedInt32, unpack('x92V3', $$dataPt);
|
|
1689
|
+
# (accelerometer scaling is roughly 1G=250-300, but it varies depending on the axis,
|
|
1690
|
+
# so leave the values as raw. The axes are positive acceleration up,left,forward)
|
|
1691
|
+
if ($notEnc) { # (not encrypted)
|
|
1692
|
+
($lat = $lt) =~ s/\0+$//;
|
|
1693
|
+
($lon = $ln) =~ s/\0+$//;
|
|
1694
|
+
} else {
|
|
1695
|
+
# decode base64 strings
|
|
1696
|
+
require Image::ExifTool::XMP;
|
|
1697
|
+
$_ = ${Image::ExifTool::XMP::DecodeBase64($_)} foreach ($lt, $ln);
|
|
1698
|
+
# try various keys to decrypt lat/lon
|
|
1699
|
+
my ($i, $ch, $key) = (0, 'a', $luckyKeys[0]);
|
|
1700
|
+
for (; $i<20; ++$i) {
|
|
1701
|
+
$i and ($key = $luckyKeys[1]) =~ s/#/$ch/g, ++$ch;
|
|
1702
|
+
($lat = DecryptLucky($lt, $key)) =~ /^\d{1,4}\.\d+$/ or undef($lat), next;
|
|
1703
|
+
($lon = DecryptLucky($ln, $key)) =~ /^\d{1,5}\.\d+$/ or undef($lon), next;
|
|
1704
|
+
last;
|
|
1705
|
+
}
|
|
1706
|
+
$lon or $et->WarnOnce('Unknown encryption for latitude/longitude');
|
|
1707
|
+
}
|
|
1626
1708
|
}
|
|
1627
1709
|
|
|
1628
1710
|
} elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) {
|
|
@@ -1683,7 +1765,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1683
1765
|
$trk -= 360 if $trk >= 360;
|
|
1684
1766
|
undef @acc;
|
|
1685
1767
|
} else {
|
|
1686
|
-
|
|
1768
|
+
@acc = map { SignedInt32 / 1000 } @acc; # (NC)
|
|
1687
1769
|
}
|
|
1688
1770
|
|
|
1689
1771
|
} elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) {
|
|
@@ -1787,7 +1869,7 @@ sub ProcessFreeGPS($$$)
|
|
|
1787
1869
|
return 0;
|
|
1788
1870
|
}
|
|
1789
1871
|
# (not sure about acc scaling)
|
|
1790
|
-
|
|
1872
|
+
@acc = map { SignedInt32 / 1000 } @acc;
|
|
1791
1873
|
$lon = GetFloat($dataPt, 0x5c);
|
|
1792
1874
|
$lat = GetFloat($dataPt, 0x60);
|
|
1793
1875
|
$spd = GetFloat($dataPt, 0x64) * $knotsToKph;
|
|
@@ -1932,7 +2014,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1932
2014
|
# 0x7c - int32s[3] accelerometer * 1000
|
|
1933
2015
|
($latRef, $lonRef) = ($1, $2);
|
|
1934
2016
|
($hr,$min,$sec,$yr,$mon,$day,@acc) = unpack('x48V3x52V6', $$dataPt);
|
|
1935
|
-
|
|
2017
|
+
@acc = map { SignedInt32 / 1000 } @acc;
|
|
1936
2018
|
$lat = GetDouble($dataPt, 0x40);
|
|
1937
2019
|
$lon = GetDouble($dataPt, 0x50);
|
|
1938
2020
|
$spd = GetDouble($dataPt, 0x60) * $knotsToKph;
|
|
@@ -1948,8 +2030,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1948
2030
|
$lon = abs(GetFloat(\$dat, 8)); # (abs just to be safe)
|
|
1949
2031
|
$spd = GetFloat(\$dat, 12) * $knotsToKph;
|
|
1950
2032
|
$trk = GetFloat(\$dat, 16);
|
|
1951
|
-
@acc = unpack('x20V3', $dat);
|
|
1952
|
-
map { $_ = $_ - 4294967296 if $_ >= 0x80000000 } @acc;
|
|
2033
|
+
@acc = map SignedInt32, unpack('x20V3', $dat);
|
|
1953
2034
|
ConvertLatLon($lat, $lon);
|
|
1954
2035
|
$$et{DOC_NUM} = ++$$et{DOC_COUNT};
|
|
1955
2036
|
$et->HandleTag($tagTbl, GPSLatitude => $lat * (substr($dat,1,1) eq 'S' ? -1 : 1));
|
|
@@ -1983,7 +2064,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
1983
2064
|
$lon = abs(GetDouble($dataPt, 48)); # (abs just to be safe)
|
|
1984
2065
|
$spd = GetDouble($dataPt, 64) * $knotsToKph;
|
|
1985
2066
|
$trk = GetDouble($dataPt, 72);
|
|
1986
|
-
|
|
2067
|
+
@acc = map { SignedInt32 / 1000 } @acc; # (NC)
|
|
1987
2068
|
# (not necessary to read RMC sentence because we already have it all)
|
|
1988
2069
|
|
|
1989
2070
|
} elsif ($$dataPt =~ /^.{72}A[NS][EW]\0/s) {
|
|
@@ -2117,7 +2198,7 @@ ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) {
|
|
|
2117
2198
|
$day < 1 or $day > 31 or
|
|
2118
2199
|
$hr > 59 or $min > 59 or $sec > 600;
|
|
2119
2200
|
# change lat/lon to signed integer and divide by 1e7
|
|
2120
|
-
|
|
2201
|
+
($lat, $lon) = map { SignedInt32 / 1e7 } $lat, $lon;
|
|
2121
2202
|
$trk -= 0x10000 if $trk >= 0x8000; # make it signed
|
|
2122
2203
|
$trk /= 100;
|
|
2123
2204
|
$trk += 360 if $trk < 0;
|
|
@@ -22,7 +22,7 @@ use vars qw($VERSION %samsungLensTypes);
|
|
|
22
22
|
use Image::ExifTool qw(:DataAccess :Utils);
|
|
23
23
|
use Image::ExifTool::Exif;
|
|
24
24
|
|
|
25
|
-
$VERSION = '1.
|
|
25
|
+
$VERSION = '1.58';
|
|
26
26
|
|
|
27
27
|
sub WriteSTMN($$$);
|
|
28
28
|
sub ProcessINFO($$$);
|
|
@@ -957,7 +957,7 @@ my %formatMinMax = (
|
|
|
957
957
|
Samsung models such as the Galaxy S4 and Tab S, and from the 'sefd' atom in
|
|
958
958
|
HEIC images from models such as the S10+.
|
|
959
959
|
},
|
|
960
|
-
'0x0001-name' => 'EmbeddedImageName', # ("DualShot_1","DualShot_2")
|
|
960
|
+
'0x0001-name' => 'EmbeddedImageName', # ("DualShot_1","DualShot_2","SingleShot")
|
|
961
961
|
'0x0001' => [
|
|
962
962
|
{
|
|
963
963
|
Name => 'EmbeddedImage',
|
|
@@ -970,6 +970,7 @@ my %formatMinMax = (
|
|
|
970
970
|
Groups => { 2 => 'Preview' },
|
|
971
971
|
Binary => 1,
|
|
972
972
|
},
|
|
973
|
+
# (have also seen the string "BOKEH" here (SM-A226B)
|
|
973
974
|
],
|
|
974
975
|
'0x0100-name' => 'EmbeddedAudioFileName', # ("SoundShot_000")
|
|
975
976
|
'0x0100' => { Name => 'EmbeddedAudioFile', Groups => { 2 => 'Audio' }, Binary => 1 },
|
|
@@ -1265,6 +1266,7 @@ my %formatMinMax = (
|
|
|
1265
1266
|
'0x0b40' => { # (SM-N975X front camera)
|
|
1266
1267
|
Name => 'SingleShotMeta',
|
|
1267
1268
|
SubDirectory => { TagTable => 'Image::ExifTool::Samsung::SingleShotMeta' },
|
|
1269
|
+
# (have also see the string "BOKEH_INFO" here (SM-A226B)
|
|
1268
1270
|
},
|
|
1269
1271
|
# 0x0b41-name - seen 'SingeShot_DepthMap_1' (Yes, "Singe") (SM-N975X front camera)
|
|
1270
1272
|
'0x0b41' => { Name => 'SingleShotDepthMap', Binary => 1 },
|
|
@@ -1493,7 +1495,7 @@ sub ProcessSamsungMeta($$$)
|
|
|
1493
1495
|
my $pos = $$dirInfo{DirStart};
|
|
1494
1496
|
my $end = $$dirInfo{DirLen} + $pos;
|
|
1495
1497
|
unless ($pos + 8 <= $end and substr($$dataPt, $pos, 4) eq 'DOFS') {
|
|
1496
|
-
$et->Warn("Unrecognized $dirName data");
|
|
1498
|
+
$et->Warn("Unrecognized $dirName data", 1);
|
|
1497
1499
|
return 0;
|
|
1498
1500
|
}
|
|
1499
1501
|
my $ver = Get32u($dataPt, $pos + 4);
|