diff options
author | exiftool <exiftool@users.sourceforge.net> | 2018-04-10 08:39:06 -0400 |
---|---|---|
committer | exiftool <exiftool@users.sourceforge.net> | 2018-04-10 08:39:06 -0400 |
commit | d64051eb020080fd0d68357e58bb9e65debf1530 (patch) | |
tree | 56990b7bb446584009446c16096cb688b6552ec4 /lib/Image/ExifTool | |
parent | 3d58239904856656ea73b2d6b78e4fd47149fafe (diff) |
Update to 10.92
Diffstat (limited to 'lib/Image/ExifTool')
-rw-r--r-- | lib/Image/ExifTool/PDF.pm | 15 | ||||
-rw-r--r-- | lib/Image/ExifTool/QuickTime.pm | 12 | ||||
-rw-r--r-- | lib/Image/ExifTool/QuickTimeStream.pl | 85 | ||||
-rw-r--r-- | lib/Image/ExifTool/TagLookup.pm | 4 | ||||
-rw-r--r-- | lib/Image/ExifTool/TagNames.pod | 18 | ||||
-rw-r--r-- | lib/Image/ExifTool/WritePDF.pl | 19 |
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; } |