summaryrefslogtreecommitdiff
path: root/lib/Image/ExifTool
diff options
context:
space:
mode:
authorexiftool <exiftool@users.sourceforge.net>2018-04-10 08:39:06 -0400
committerexiftool <exiftool@users.sourceforge.net>2018-04-10 08:39:06 -0400
commitd64051eb020080fd0d68357e58bb9e65debf1530 (patch)
tree56990b7bb446584009446c16096cb688b6552ec4 /lib/Image/ExifTool
parent3d58239904856656ea73b2d6b78e4fd47149fafe (diff)
Update to 10.92
Diffstat (limited to 'lib/Image/ExifTool')
-rw-r--r--lib/Image/ExifTool/PDF.pm15
-rw-r--r--lib/Image/ExifTool/QuickTime.pm12
-rw-r--r--lib/Image/ExifTool/QuickTimeStream.pl85
-rw-r--r--lib/Image/ExifTool/TagLookup.pm4
-rw-r--r--lib/Image/ExifTool/TagNames.pod18
-rw-r--r--lib/Image/ExifTool/WritePDF.pl19
6 files changed, 130 insertions, 23 deletions
diff --git a/lib/Image/ExifTool/PDF.pm b/lib/Image/ExifTool/PDF.pm
index 05f64fa9..8cf57a2d 100644
--- a/lib/Image/ExifTool/PDF.pm
+++ b/lib/Image/ExifTool/PDF.pm
@@ -21,7 +21,7 @@ use vars qw($VERSION $AUTOLOAD $lastFetched);
use Image::ExifTool qw(:DataAccess :Utils);
require Exporter;
-$VERSION = '1.44';
+$VERSION = '1.45';
sub FetchObject($$$$);
sub ExtractObject($$;$$);
@@ -747,7 +747,7 @@ sub FetchObject($$$$)
return ExtractObject($et, \$data);
}
my $raf = $$et{RAF};
- $raf->Seek($offset, 0) or $et->Warn("Bad $tag offset"), return undef;
+ $raf->Seek($offset+$$et{PDFBase}, 0) or $et->Warn("Bad $tag offset"), return undef;
# verify that we are reading the expected object
$raf->ReadLine($data) or $et->Warn("Error reading $tag data"), return undef;
($obj = $ref) =~ s/R/obj/;
@@ -949,7 +949,7 @@ sub ExtractObject($$;$$)
# (compressed objects are not allowed)
my $offset = LocateObject($xref, $length) or return $dict;
$offset or $et->Warn('Bad Length object'), return $dict;
- $raf->Seek($offset, 0) or $et->Warn('Bad Length offset'), return $dict;
+ $raf->Seek($offset+$$et{PDFBase}, 0) or $et->Warn('Bad Length offset'), return $dict;
# verify that we are reading the expected object
$raf->ReadLine($data) or $et->Warn('Error reading Length data'), return $dict;
$length =~ s/R/obj/;
@@ -2085,8 +2085,9 @@ sub ReadPDF($$)
#
# (linearization dictionary must be in the first 1024 bytes of the file)
$raf->Read($buff, 1024) >= 8 or return 0;
- $buff =~ /^%PDF-(\d+\.\d+)/ or return 0;
- $pdfVer = $1;
+ $buff =~ /^(\s*)%PDF-(\d+\.\d+)/ or return 0;
+ $$et{PDFBase} = length $1;
+ $pdfVer = $2;
$et->SetFileType(); # set the FileType tag
$et->Warn("May not be able to read a PDF version $pdfVer file") if $pdfVer >= 2.0;
# store PDFVersion tag
@@ -2105,7 +2106,7 @@ sub ReadPDF($$)
if (ref $dict eq 'HASH' and $$dict{Linearized} and $$dict{L}) {
if (not $$et{VALUE}{FileSize}) {
undef $lin; # can't determine if it is linearized
- } elsif ($$dict{L} == $$et{VALUE}{FileSize}) {
+ } elsif ($$dict{L} == $$et{VALUE}{FileSize} - $$et{PDFBase}) {
$lin = 'true';
}
}
@@ -2143,7 +2144,7 @@ XRef:
my $offset = shift @xrefOffsets;
my $type = shift @xrefOffsets;
next if $loaded{$offset}; # avoid infinite recursion
- unless ($raf->Seek($offset, 0)) {
+ unless ($raf->Seek($offset+$$et{PDFBase}, 0)) {
%loaded or return -5;
$et->Warn('Bad offset for secondary xref table');
next;
diff --git a/lib/Image/ExifTool/QuickTime.pm b/lib/Image/ExifTool/QuickTime.pm
index e8c9d646..cfc4c780 100644
--- a/lib/Image/ExifTool/QuickTime.pm
+++ b/lib/Image/ExifTool/QuickTime.pm
@@ -42,7 +42,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
use Image::ExifTool::Exif;
use Image::ExifTool::GPS;
-$VERSION = '2.15';
+$VERSION = '2.16';
sub ProcessMOV($$;$);
sub ProcessKeys($$$);
@@ -383,6 +383,7 @@ my %eeBox = (
vide => { %eeStd, JPEG => 1 }, # (add avcC to parse H264 stream)
text => { %eeStd },
meta => { %eeStd },
+ data => { %eeStd },
camm => { %eeStd }, # (Insta360)
'' => { 'gps ' => 1 }, # (no handler -- top level box)
);
@@ -6174,7 +6175,11 @@ my %eeBox = (
# MP4 generic sample description box
%Image::ExifTool::QuickTime::OtherSampleDesc = (
PROCESS_PROC => \&ProcessHybrid,
- 4 => { Name => 'OtherFormat', Format => 'undef[4]' },
+ 4 => {
+ Name => 'OtherFormat',
+ Format => 'undef[4]',
+ RawConv => '$$self{MetaFormat} = $val', # (yes, use MetaFormat for this too)
+ },
#
# Observed offsets for child atoms of various OtherFormat types:
#
@@ -6184,6 +6189,7 @@ my %eeBox = (
# mp4a 36 esds
# mp4s 16 esds
# tmcd 34 name
+# data - -
#
ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' },
);
@@ -7164,7 +7170,7 @@ sub ProcessSampleDesc($$$)
$pos += 8;
my $i;
for ($i=0; $i<$num; ++$i) { # loop through sample descriptions
- last if $pos + 16 > $dirLen;
+ last if $pos + 8 > $dirLen;
my $size = Get32u($dataPt, $pos);
last if $pos + $size > $dirLen;
$$dirInfo{DirStart} = $pos;
diff --git a/lib/Image/ExifTool/QuickTimeStream.pl b/lib/Image/ExifTool/QuickTimeStream.pl
index 1fd7cfac..c9b268bb 100644
--- a/lib/Image/ExifTool/QuickTimeStream.pl
+++ b/lib/Image/ExifTool/QuickTimeStream.pl
@@ -71,13 +71,17 @@ my $mpsToKph = 3.6; # m/s --> km/h
GPSTrackRef => { PrintConv => { M => 'Magnetic North', T => 'True North' } },
GPSDateTime => { PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } },
Accelerometer=> { Notes => 'right/up/backward acceleration in units of g' },
+ RawGSensor => {
+ # (same as GSensor, but offset by some unknown value)
+ ValueConv => 'my @a=split " ",$val; $_/=1000 foreach @a; "@a"',
+ },
Text => { Groups => { 2 => 'Other' } },
TimeCode => { Groups => { 2 => 'Video' } },
FrameNumber => { Groups => { 2 => 'Video' } },
SampleTime => { Groups => { 2 => 'Video' }, PrintConv => 'ConvertDuration($val)', Notes => 'sample decoding time' },
SampleDuration=>{ Groups => { 2 => 'Video' }, PrintConv => 'ConvertDuration($val)' },
#
-# timed metadata decoded based on MetaFormat (format of 'meta' sample description)
+# timed metadata decoded based on MetaFormat (format of 'meta' or 'data' sample description)
# [or HandlerType, or specific 'vide' type if specified]
#
mebx => {
@@ -105,6 +109,22 @@ my $mpsToKph = 3.6; # m/s --> km/h
Name => 'CTMD',
SubDirectory => { TagTable => 'Image::ExifTool::Canon::CTMD' },
},
+ RVMI => [{ # data "OtherFormat" written by E-PRANCE B47FS editing app
+ Name => 'RVMI_g',
+ Condition => '$$valPt =~ /^gReV/', # GPS data
+ SubDirectory => {
+ TagTable => 'Image::ExifTool::QuickTime::RVMI_g',
+ ByteOrder => 'Little-endian',
+ },
+ },{
+ Name => 'RVMI_s',
+ Condition => '$$valPt =~ /^sReV/', # sensor data?
+ SubDirectory => {
+ TagTable => 'Image::ExifTool::QuickTime::RVMI_s',
+ ByteOrder => 'Little-endian',
+ },
+ # (there is also "tReV" data that hasn't been decoded yet)
+ }],
camm => { # (written by Insta360) - [HandlerType, not MetaFormat]
Name => 'camm6',
Condition => '$$valPt =~ /^\0\0\x06\0/',
@@ -150,6 +170,48 @@ my $mpsToKph = 3.6; # m/s --> km/h
# 0x30 - float (GPSSpeed?)
);
+# tags found in 'RVMI' 'gReV' timed metadata (ref PH)
+%Image::ExifTool::QuickTime::RVMI_g = (
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
+ GROUPS => { 2 => 'Location' },
+ FIRST_ENTRY => 0,
+ 4 => {
+ Name => 'GPSLatitude',
+ Format => 'int32s',
+ ValueConv => 'Image::ExifTool::GPS::ToDegrees($val/1e6, 1)',
+ PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
+ },
+ 8 => {
+ Name => 'GPSLongitude',
+ Format => 'int32s',
+ ValueConv => 'Image::ExifTool::GPS::ToDegrees($val/1e6, 1)',
+ PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
+ },
+ # 12 - int32s: space for altitude? (always zero in my sample)
+ 16 => {
+ Name => 'GPSSpeed', # km/h
+ Format => 'int16s',
+ ValueConv => '$val / 10',
+ },
+ 18 => {
+ Name => 'GPSTrack',
+ Format => 'int16u',
+ ValueConv => '$val * 2',
+ },
+);
+
+# tags found in 'RVMI' 'sReV' timed metadata (ref PH)
+%Image::ExifTool::QuickTime::RVMI_s = (
+ PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
+ GROUPS => { 2 => 'Location' },
+ FIRST_ENTRY => 0,
+ 4 => {
+ Name => 'GSensor',
+ Format => 'int16s[3]', # X Y Z
+ ValueConv => 'my @a=split " ",$val; $_/=1000 foreach @a; "@a"',
+ },
+);
+
#------------------------------------------------------------------------------
# Save information from keys in OtherSampleDesc directory for processing timed metadata
# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
@@ -376,8 +438,23 @@ sub ProcessSamples($)
next if $size == 2;
$buff = substr($buff,2);
}
- $et->HandleTag($tagTbl, Text => $buff);
- next;
+ my $val;
+ # check for encrypted GPS text as written by E-PRANCE B47FS camera
+ if ($buff =~ /^\0/ and $buff =~ /\x0a$/ and length($buff) > 5) {
+ # decode simple ASCII difference cipher,
+ # based on known value of 4th-last char = '*'
+ my $dif = ord('*') - ord(substr($buff, -4, 1));
+ my $tmp = pack 'C*',map { $_=($_+$dif)&0xff } unpack 'C*',substr $buff,1,-1;
+ if ($tmp =~ /^(.*?)(\$GPRMC.*)/s) {
+ ($val, $buff) = ($1, $2);
+ $val =~ tr/\t/ /;
+ $et->HandleTag($tagTbl, RawGSensor => $val) if length $val;
+ }
+ }
+ unless (defined $val) {
+ $et->HandleTag($tagTbl, Text => $buff); # just store any other text
+ next;
+ }
}
while ($buff =~ /\$(\w+)([^\$]*)/g) {
my ($tag, $dat) = ($1, $2);
@@ -406,7 +483,7 @@ sub ProcessSamples($)
}
}
- } elsif ($type eq 'meta') {
+ } elsif ($type eq 'meta' or $type eq 'data') {
if ($$tagTbl{$metaFormat}) {
my $tagInfo = $et->GetTagInfo($tagTbl, $metaFormat, \$buff);
diff --git a/lib/Image/ExifTool/TagLookup.pm b/lib/Image/ExifTool/TagLookup.pm
index e89d25c3..ec98d56e 100644
--- a/lib/Image/ExifTool/TagLookup.pm
+++ b/lib/Image/ExifTool/TagLookup.pm
@@ -7078,6 +7078,7 @@ my %tagExists = (
'groupcaption' => 1,
'grouping' => 1,
'groupmutualexclusion' => 1,
+ 'gsensor' => 1,
'gspherical' => 1,
'gtcitation' => 1,
'gtmodeltype' => 1,
@@ -8476,6 +8477,7 @@ my %tagExists = (
'rawdevelopment' => 1,
'rawdevelopmentifd' => 1,
'rawexposurebias' => 1,
+ 'rawgsensor' => 1,
'rawimagefullheight' => 1,
'rawimagefullsize' => 1,
'rawimagefullwidth' => 1,
@@ -8644,6 +8646,8 @@ my %tagExists = (
'runtimesincepowerup' => 1,
'runtimevalue' => 1,
'runwindow' => 1,
+ 'rvmi_g' => 1,
+ 'rvmi_s' => 1,
's2n' => 1,
'sampledegradationpriority' => 1,
'sampleduration' => 1,
diff --git a/lib/Image/ExifTool/TagNames.pod b/lib/Image/ExifTool/TagNames.pod
index e9805ff0..ee0ed5dd 100644
--- a/lib/Image/ExifTool/TagNames.pod
+++ b/lib/Image/ExifTool/TagNames.pod
@@ -23737,6 +23737,9 @@ when the ExtractEmbedded option is used.
'GPSTrack' GPSTrack no
'GPSTrackRef' GPSTrackRef no
'JPEG' JpgFromRaw no
+ 'RVMI' RVMI_g QuickTime RVMI_g
+ RVMI_s QuickTime RVMI_s
+ 'RawGSensor' RawGSensor no
'SampleDuration' SampleDuration no
'SampleTime' SampleTime no
'Text' Text no
@@ -23747,6 +23750,21 @@ when the ExtractEmbedded option is used.
'mebx' mebx QuickTime Keys
'rtmd' rtmd Sony rtmd
+=head3 QuickTime RVMI_g Tags
+
+ Index1 Tag Name Writable
+ ------ -------- --------
+ 4 GPSLatitude no
+ 8 GPSLongitude no
+ 16 GPSSpeed no
+ 18 GPSTrack no
+
+=head3 QuickTime RVMI_s Tags
+
+ Index1 Tag Name Writable
+ ------ -------- --------
+ 4 GSensor no
+
=head3 QuickTime camm6 Tags
These tags are extracted from record type 6 of the 'camm' timed metadata of
diff --git a/lib/Image/ExifTool/WritePDF.pl b/lib/Image/ExifTool/WritePDF.pl
index 0716c12e..4d67d99f 100644
--- a/lib/Image/ExifTool/WritePDF.pl
+++ b/lib/Image/ExifTool/WritePDF.pl
@@ -284,8 +284,9 @@ sub WritePDF($$)
# make sure this is a PDF file
my $pos = $raf->Tell();
- $raf->Read($buff, 10) >= 8 or return 0;
- $buff =~ /^%PDF-(\d+\.\d+)/ or return 0;
+ $raf->Read($buff, 1024) >= 8 or return 0;
+ $buff =~ /^(\s*)%PDF-(\d+\.\d+)/ or return 0;
+ $$et{PDFBase} = length $1;
$raf->Seek($pos, 0);
# create a new ExifTool object and use it to read PDF and XMP information
@@ -331,13 +332,13 @@ sub WritePDF($$)
if ($buff =~ /$endComment(\d+)\s+(startxref\s+\d+\s+%%EOF\s+)?$/s) {
$prevUpdate = $1;
# rewrite the file up to the original EOF
- Image::ExifTool::CopyBlock($raf, $outfile, $prevUpdate) or $rtn = -1;
+ Image::ExifTool::CopyBlock($raf, $outfile, $prevUpdate + $$et{PDFBase}) or $rtn = -1;
# verify that we are now at the start of an ExifTool update
unless ($raf->Read($buff, length $beginComment) and $buff eq $beginComment) {
$et->Error('Previous ExifTool update is corrupted');
return $rtn;
}
- $raf->Seek($prevUpdate, 0) or $rtn = -1;
+ $raf->Seek($prevUpdate+$$et{PDFBase}, 0) or $rtn = -1;
if ($$et{DEL_GROUP}{'PDF-update'}) {
$et->VPrint(0, " Reverted previous ExifTool updates\n");
++$$et{CHANGED};
@@ -570,7 +571,7 @@ sub WritePDF($$)
#
if ($$et{CHANGED}) {
# remember position of original EOF
- my $oldEOF = Tell($outfile);
+ my $oldEOF = Tell($outfile) - $$et{PDFBase};
Write($outfile, $beginComment) or $rtn = -1;
# write new objects
@@ -584,7 +585,7 @@ sub WritePDF($$)
next;
}
# create new entry for xref table
- $newXRef{$id} = [ Tell($outfile) + length($/), $gen, 'n' ];
+ $newXRef{$id} = [ Tell($outfile) - $$et{PDFBase} + length($/), $gen, 'n' ];
$keyExt = "$id $gen obj"; # (must set for stream encryption)
Write($outfile, $/, $keyExt) or $rtn = -1;
WriteObject($outfile, $newObj{$objRef}) or $rtn = -1;
@@ -645,13 +646,13 @@ sub WritePDF($$)
}
# remember position of xref table in file (we will write this next)
- my $startxref = Tell($outfile) + length($/);
+ my $startxref = Tell($outfile) - $$et{PDFBase} + length($/);
# must write xref as a stream in xref-stream-only files
if ($$mainDict{Type} and $$mainDict{Type} eq '/XRef') {
# create entry for the xref stream object itself
- $newXRef{$nextObject++} = [ Tell($outfile) + length($/), 0, 'n' ];
+ $newXRef{$nextObject++} = [ Tell($outfile) - $$et{PDFBase} + length($/), 0, 'n' ];
$$mainDict{Size} = $nextObject;
# create xref stream and Index entry
$$mainDict{W} = [ 1, 4, 2 ]; # int8u, int32u, int16u ('CNn')
@@ -711,7 +712,7 @@ sub WritePDF($$)
} elsif ($prevUpdate) {
# nothing new changed, so copy over previous incremental update
- $raf->Seek($prevUpdate, 0) or $rtn = -1;
+ $raf->Seek($prevUpdate+$$et{PDFBase}, 0) or $rtn = -1;
while ($raf->Read($buff, 65536)) {
Write($outfile, $buff) or $rtn = -1;
}