exiftool_vendored 13.37.0 → 13.40.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +41 -3
  3. data/bin/MANIFEST +7 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +49 -47
  7. data/bin/config_files/local_time.config +55 -0
  8. data/bin/exiftool +83 -70
  9. data/bin/lib/Image/ExifTool/BMP.pm +1 -1
  10. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -2
  11. data/bin/lib/Image/ExifTool/DJI.pm +256 -20
  12. data/bin/lib/Image/ExifTool/DSF.pm +138 -0
  13. data/bin/lib/Image/ExifTool/EXE.pm +3 -1
  14. data/bin/lib/Image/ExifTool/Font.pm +386 -118
  15. data/bin/lib/Image/ExifTool/Geolocation.pm +10 -7
  16. data/bin/lib/Image/ExifTool/Geotag.pm +21 -2
  17. data/bin/lib/Image/ExifTool/GoPro.pm +6 -3
  18. data/bin/lib/Image/ExifTool/Google.pm +16 -6
  19. data/bin/lib/Image/ExifTool/ID3.pm +11 -10
  20. data/bin/lib/Image/ExifTool/LNK.pm +63 -2
  21. data/bin/lib/Image/ExifTool/M2TS.pm +32 -23
  22. data/bin/lib/Image/ExifTool/MIEUnits.pod +1 -1
  23. data/bin/lib/Image/ExifTool/OOXML.pm +3 -2
  24. data/bin/lib/Image/ExifTool/Olympus.pm +3 -1
  25. data/bin/lib/Image/ExifTool/Pentax.pm +7 -2
  26. data/bin/lib/Image/ExifTool/QuickTime.pm +3 -3
  27. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +44 -35
  28. data/bin/lib/Image/ExifTool/Sony.pm +19 -14
  29. data/bin/lib/Image/ExifTool/TagLookup.pm +35 -1
  30. data/bin/lib/Image/ExifTool/TagNames.pod +1383 -1217
  31. data/bin/lib/Image/ExifTool/WavPack.pm +144 -0
  32. data/bin/lib/Image/ExifTool/XMP.pm +12 -7
  33. data/bin/lib/Image/ExifTool/XMP2.pl +11 -5
  34. data/bin/lib/Image/ExifTool.pm +46 -26
  35. data/bin/lib/Image/ExifTool.pod +64 -56
  36. data/bin/perl-Image-ExifTool.spec +47 -46
  37. data/lib/exiftool_vendored/version.rb +1 -1
  38. metadata +4 -1
@@ -20,6 +20,7 @@
20
20
  # 2024/11/26 - PH Also write GPSMeasureMode and GPSDOP
21
21
  # 2024/11/05 - PH Added support for Google Maps "Export timeline data"
22
22
  # JSON format
23
+ # 2025/09/22 - PH Added ability to read Columbus CSV log files
23
24
  #
24
25
  # References: 1) http://www.topografix.com/GPX/1/1/
25
26
  # 2) http://www.gpsinformation.org/dale/nmea.htm#GSA
@@ -34,7 +35,7 @@ use vars qw($VERSION);
34
35
  use Image::ExifTool qw(:Public);
35
36
  use Image::ExifTool::GPS;
36
37
 
37
- $VERSION = '1.82';
38
+ $VERSION = '1.83';
38
39
 
39
40
  sub JITTER() { return 2 } # maximum time jitter
40
41
 
@@ -1344,6 +1345,23 @@ Category: foreach $category (qw{pos track alt orient atemp err dop}) {
1344
1345
  if (defined $dop) {
1345
1346
  $et->SetNewValue(GPSMeasureMode => $mm, %opts);
1346
1347
  $et->SetNewValue(GPSDOP => $dop, %opts);
1348
+ # also set GPSHPositioningError if specified
1349
+ my $hposErr = $$et{OPTIONS}{GeoHPosErr};
1350
+ if ($hposErr) {
1351
+ $hposErr =~ s/gpsdop/GPSDOP/i;
1352
+ my $GPSDOP = $dop;
1353
+ local $SIG{'__WARN__'} = \&Image::ExifTool::SetWarning;
1354
+ undef $Image::ExifTool::evalWarning;
1355
+ #### eval GeoHPosErr ($GPSDOP)
1356
+ $hposErr = eval $hposErr;
1357
+ my $err = Image::ExifTool::GetWarning() || $@;
1358
+ if ($err) {
1359
+ $err = Image::ExifTool::CleanWarning($err);
1360
+ $et->Warn("Error calculating GPSHPositioningError: $err", 1);
1361
+ } else {
1362
+ $et->SetNewValue(GPSHPositioningError => $hposErr, %opts);
1363
+ }
1364
+ }
1347
1365
  }
1348
1366
  }
1349
1367
  unless ($xmp) {
@@ -1557,7 +1575,8 @@ This module loads GPS track logs, interpolates to determine position based
1557
1575
  on time, and sets new GPS values for geotagging images. Currently supported
1558
1576
  formats are GPX, NMEA RMC/GGA/GLL/GSA/ZDA, KML, IGC, Garmin XML and TCX,
1559
1577
  Magellan PMGNTRK, Honeywell PTNTHPR, Bramor gEO, Winplus Beacon text,
1560
- GPS/IMU CSV, DJI CSV, ExifTool CSV and 3 different Google JSON formats.
1578
+ GPS/IMU CSV, DJI/Columbus/ExifTool CSV format and 3 different Google JSON
1579
+ formats.
1561
1580
 
1562
1581
  Methods in this module should not be called directly. Instead, the Geotag
1563
1582
  feature is accessed by writing the values of the ExifTool Geotag, Geosync
@@ -17,7 +17,7 @@ use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
  use Image::ExifTool::QuickTime;
19
19
 
20
- $VERSION = '1.14';
20
+ $VERSION = '1.15';
21
21
 
22
22
  sub ProcessGoPro($$$);
23
23
  sub ProcessString($$$);
@@ -251,7 +251,8 @@ my %noYes = ( N => 'No', Y => 'Yes' );
251
251
  Notes => 'gyroscope readings in rad/s',
252
252
  Binary => 1,
253
253
  },
254
- HCLT => 'HorizonControl', #3
254
+ LOGS => 'HealthLogs',
255
+ HCTL => 'HorizonControl', #3
255
256
  HDRV => { Name => 'HDRVideo', PrintConv => \%noYes }, #3/PH (NC)
256
257
  # HFLG (APP6) - seen: 0
257
258
  HSGT => 'HindsightSettings', #3
@@ -409,6 +410,7 @@ my %noYes = ( N => 'No', Y => 'Yes' );
409
410
  },
410
411
  # TOCK => { Name => 'OutTime', Unknown => 1, ValueConv => '$val/1000' }, #1 (gpmd)
411
412
  TSMP => { Name => 'TotalSamples', Unknown => 1 }, #2 (gpmd)
413
+ TIMO => 'TimeOffset',
412
414
  TYPE => { Name => 'StructureType', Unknown => 1 }, #2 (gpmd,GPMF - eg 'LLLllfFff', fmt c)
413
415
  TZON => { # (GPMF) - seen: 60 (fmt s)
414
416
  Name => 'TimeZone',
@@ -469,7 +471,8 @@ my %noYes = ( N => 'No', Y => 'Yes' );
469
471
  AALP => { Name => 'AudioLevel', Notes => 'dBFS' },
470
472
  GPSA => 'GPSAltitudeSystem', # (eg. 'MSLV')
471
473
  GRAV => { Name => 'GravityVector', Binary => 1 },
472
- HUES => 'PrediminantHue',
474
+ # DISP - Disparity track
475
+ HUES => 'PredominantHue',
473
476
  IORI => { Name => 'ImageOrientation', Binary => 1, Notes => 'quaternions 0-1' },
474
477
  # LRVO - ? Part of LRV Frame Skip
475
478
  # LRVS - ? Part of LRV Frame Skip
@@ -512,11 +512,20 @@ my %sAppInfo = (
512
512
  GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
513
513
  TAG_PREFIX => 'HDRPlusMakerNote',
514
514
  PROCESS_PROC => \&ProcessHDRP,
515
- VARS => { ID_FMT => 'str' },
515
+ VARS => {
516
+ ID_FMT => 'str',
517
+ SORT_PROC => sub {
518
+ my ($a,$b) = @_;
519
+ $a =~ s/(\d+)/sprintf("%.3d",$1)/eg;
520
+ $b =~ s/(\d+)/sprintf("%.3d",$1)/eg;
521
+ return $a cmp $b;
522
+ },
523
+ },
516
524
  NOTES => q{
517
525
  Google protobuf-format HDR-Plus maker notes. Tag ID's are hierarchical
518
526
  protobuf field numbers. Stored as base64-encoded, encrypted and gzipped
519
- Protobuf data.
527
+ Protobuf data. Much of this metadata is still unknown, but is extracted
528
+ using the Unknown option.
520
529
  },
521
530
  '1-1' => 'ImageName',
522
531
  '1-2' => { Name => 'ImageData', Format => 'undef', Binary => 1 },
@@ -693,8 +702,8 @@ sub ProcessHDRP($$$)
693
702
  my $i = 0;
694
703
  while ($i < @words) {
695
704
  # (messy, but handle all 64-bit arithmetic with 32-bit backward
696
- # compatibility -- no bit operations on any number > 0xffffffff)
697
- # rotate the key
705
+ # compatibility, so no bit operations on any number > 0xffffffff)
706
+ # rotate the key for each new 64-bit word
698
707
  # $key ^= $key >> 12;
699
708
  $lo ^= $lo >> 12 | ($hi & 0xfff) << 20;
700
709
  $hi ^= $hi >> 12;
@@ -715,7 +724,8 @@ sub ProcessHDRP($$$)
715
724
  $c[$j+$k] += $a[$j] * $b[$k];
716
725
  }
717
726
  }
718
- # (we only care about the low 32-bits, so don't bother with the upper 32)
727
+ # (we will only retain the low 64-bits of the key, so
728
+ # don't bother finishing the calculation of the upper bits)
719
729
  for ($j=6; $j>=3; --$j) {
720
730
  while ($c[$j] > 0xffffffff) {
721
731
  ++$c[$j-2];
@@ -726,7 +736,7 @@ sub ProcessHDRP($$$)
726
736
  }
727
737
  $hi = ($c[3] << 16) + $c[4];
728
738
  $lo = ($c[5] << 16) + $c[6];
729
- # apply the xor
739
+ # apply the key to this 64-bit word
730
740
  $words[$i++] ^= $lo;
731
741
  $words[$i++] ^= $hi;
732
742
  }
@@ -18,7 +18,7 @@ use strict;
18
18
  use vars qw($VERSION);
19
19
  use Image::ExifTool qw(:DataAccess :Utils);
20
20
 
21
- $VERSION = '1.63';
21
+ $VERSION = '1.64';
22
22
 
23
23
  sub ProcessID3v2($$$);
24
24
  sub ProcessPrivate($$$);
@@ -79,13 +79,13 @@ my %userTagName = (
79
79
  VARS => { ID_FMT => 'none' },
80
80
  PROCESS_PROC => \&ProcessID3Dir, # (used to process 'id3 ' chunk in WAV files)
81
81
  NOTES => q{
82
- ExifTool extracts ID3 and Lyrics3 information from MP3, MPEG, WAV, AIFF,
83
- OGG, FLAC, APE, MPC and RealAudio files. ID3v2 tags which support multiple
84
- languages (eg. Comment and Lyrics) are extracted by specifying the tag name,
85
- followed by a dash ('-'), then a 3-character ISO 639-2 language code (eg.
86
- "Comment-spa"). See L<https://id3.org/> for the official ID3 specification
87
- and L<http://www.loc.gov/standards/iso639-2/php/code_list.php> for a list of
88
- ISO 639-2 language codes.
82
+ ExifTool extracts ID3 and Lyrics3 information from MP3, MPEG, WAV, WV, AIFF,
83
+ OGG, FLAC, APE, DSF, MPC and RealAudio files. ID3v2 tags which support
84
+ multiple languages (eg. Comment and Lyrics) are extracted by specifying the
85
+ tag name, followed by a dash ('-'), then a 3-character ISO 639-2 language
86
+ code (eg. "Comment-spa"). See L<https://id3.org/> for the official ID3
87
+ specification and L<http://www.loc.gov/standards/iso639-2/php/code_list.php>
88
+ for a list of ISO 639-2 language codes.
89
89
  },
90
90
  ID3v1 => {
91
91
  Name => 'ID3v1',
@@ -1437,6 +1437,7 @@ sub ProcessID3($$)
1437
1437
 
1438
1438
  # allow this to be called with either RAF or DataPt
1439
1439
  my $raf = $$dirInfo{RAF} || File::RandomAccess->new($$dirInfo{DataPt});
1440
+ my $dataPos = $$dirInfo{DataPos} || 0;
1440
1441
  my ($buff, %id3Header, %id3Trailer, $hBuff, $tBuff, $eBuff, $tagTablePtr);
1441
1442
  my $rtnVal = 0;
1442
1443
  my $hdrEnd = 0;
@@ -1486,7 +1487,7 @@ sub ProcessID3($$)
1486
1487
  }
1487
1488
  %id3Header = (
1488
1489
  DataPt => \$hBuff,
1489
- DataPos => $pos,
1490
+ DataPos => $dataPos + $pos,
1490
1491
  DirStart => 0,
1491
1492
  DirLen => length($hBuff),
1492
1493
  Version => $vers,
@@ -1511,7 +1512,7 @@ sub ProcessID3($$)
1511
1512
  $trailSize = 128;
1512
1513
  %id3Trailer = (
1513
1514
  DataPt => \$tBuff,
1514
- DataPos => $raf->Tell() - 128,
1515
+ DataPos => $dataPos + $raf->Tell() - 128,
1515
1516
  DirStart => 0,
1516
1517
  DirLen => length($tBuff),
1517
1518
  );
@@ -4,6 +4,7 @@
4
4
  # Description: Read meta information from MS Shell Link files
5
5
  #
6
6
  # Revisions: 2009/09/19 - P. Harvey Created
7
+ # 2025/10/20 - PH Added .URL file support
7
8
  #
8
9
  # References: 1) http://msdn.microsoft.com/en-us/library/dd871305(PROT.10).aspx
9
10
  # 2) http://www.i2s-lab.com/Papers/The_Windows_Shortcut_File_Format.pdf
@@ -17,7 +18,7 @@ use vars qw($VERSION);
17
18
  use Image::ExifTool qw(:DataAccess :Utils);
18
19
  use Image::ExifTool::Microsoft;
19
20
 
20
- $VERSION = '1.11';
21
+ $VERSION = '1.12';
21
22
 
22
23
  sub ProcessItemID($$$);
23
24
  sub ProcessLinkInfo($$$);
@@ -447,6 +448,39 @@ sub ProcessLinkInfo($$$);
447
448
  },
448
449
  );
449
450
 
451
+ %Image::ExifTool::LNK::INI = (
452
+ GROUPS => { 2 => 'Document' },
453
+ VARS => { ID_FMT => 'none' },
454
+ NOTES => 'Tags found in INI-format Windows .URL files.',
455
+ URL => { },
456
+ IconFile => { },
457
+ IconIndex => { },
458
+ WorkingDirectory => { },
459
+ HotKey => { },
460
+ ShowCommand => { PrintConv => { 1 => 'Normal', 2 => 'Minimized', 3 => 'Maximized' } },
461
+ Modified => {
462
+ Groups => { 2 => 'Time' },
463
+ Format => 'int64u',
464
+ Groups => { 2 => 'Time' },
465
+ # convert time from 100-ns intervals since Jan 1, 1601 (NC)
466
+ RawConv => q{
467
+ my $dat = pack('H*', $val);
468
+ return undef if length $dat < 8;
469
+ my ($lo, $hi) = unpack('V2', $dat);
470
+ return undef unless $lo or $hi;
471
+ return $hi * 4294967296 + $lo;
472
+ },
473
+ ValueConv => '$val=$val/1e7-11644473600; ConvertUnixTime($val,1)',
474
+ PrintConv => '$self->ConvertDateTime($val)',
475
+ },
476
+ Author => { Groups => { 2 => 'Author' } },
477
+ WhatsNew => { },
478
+ Comment => { },
479
+ Desc => { },
480
+ Roamed => { Notes => '1 if synced across multiple devices' },
481
+ IDList => { },
482
+ );
483
+
450
484
  #------------------------------------------------------------------------------
451
485
  # Extract null-terminated ASCII or Unicode string from buffer
452
486
  # Inputs: 0) buffer ref, 1) start position, 2) flag for unicode string
@@ -588,6 +622,27 @@ sub ProcessLinkInfo($$$)
588
622
  return 1;
589
623
  }
590
624
 
625
+ #------------------------------------------------------------------------------
626
+ # Extract information from a INI-format file
627
+ # Inputs: 0) ExifTool object reference, 1) dirInfo reference
628
+ # Returns: 1 on success, 0 if this wasn't a valid INI file
629
+ sub ProcessINI($$)
630
+ {
631
+ my ($et, $dirInfo) = @_;
632
+ my $raf = $$dirInfo{RAF};
633
+ my $buff;
634
+ local $/ = "\x0d\x0a";
635
+ my $tagTablePtr = GetTagTable('Image::ExifTool::LNK::INI');
636
+ while ($raf->ReadLine($buff)) {
637
+ if ($buff =~ /^\[(.*?)\]/) {
638
+ $et->VPrint(0, "$1 section:\n");
639
+ } elsif ($buff =~ /^\s*(\w+)=(.*)\x0d\x0a$/) {
640
+ $et->HandleTag($tagTablePtr, $1, $2, MakeTagInfo => 1);
641
+ }
642
+ }
643
+ return 1;
644
+ }
645
+
591
646
  #------------------------------------------------------------------------------
592
647
  # Extract information from a MS Shell Link (Windows shortcut) file
593
648
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
@@ -600,7 +655,13 @@ sub ProcessLNK($$)
600
655
 
601
656
  # read LNK file header
602
657
  $raf->Read($buff, 0x4c) == 0x4c or return 0;
603
- $buff =~ /^.{4}\x01\x14\x02\0{5}\xc0\0{6}\x46/s or return 0;
658
+ unless ($buff =~ /^.{4}\x01\x14\x02\0{5}\xc0\0{6}\x46/s) {
659
+ # check for INI-format LNK file (eg. .URL file)
660
+ return undef unless $buff =~ /^\[[InternetShortcut\][\x0d\x0a]/;
661
+ $raf->Seek(0,0) or return 0;
662
+ $et->SetFileType('URL', 'application/x-mswinurl');
663
+ return ProcessINI($et, $dirInfo);
664
+ };
604
665
  $len = unpack('V', $buff);
605
666
  $len >= 0x4c or return 0;
606
667
  if ($len > 0x4c) {
@@ -32,7 +32,7 @@ use strict;
32
32
  use vars qw($VERSION);
33
33
  use Image::ExifTool qw(:DataAccess :Utils);
34
34
 
35
- $VERSION = '1.30';
35
+ $VERSION = '1.31';
36
36
 
37
37
  # program map table "stream_type" lookup (ref 6/1/9)
38
38
  my %streamType = (
@@ -322,7 +322,7 @@ sub ParsePID($$$$$)
322
322
  if ($$et{OPTIONS}{ExtractEmbedded}) {
323
323
  $more = 1;
324
324
  } elsif (not $$et{OPTIONS}{Validate}) {
325
- $et->Warn('The ExtractEmbedded option may find more tags in the video data',3);
325
+ $et->Warn('The ExtractEmbedded option may find more tags in the video data',7);
326
326
  }
327
327
  } elsif ($type == 0x81 or $type == 0x87 or $type == 0x91) {
328
328
  # AC-3 audio
@@ -557,31 +557,40 @@ sub ProcessM2TS($$)
557
557
  {
558
558
  my ($et, $dirInfo) = @_;
559
559
  my $raf = $$dirInfo{RAF};
560
- my ($buff, $pLen, $j, $fileType, $eof);
560
+ my ($buff, $j, $eof, $pLen, $readSize);
561
561
  my (%pmt, %pidType, %data, %sectLen, %packLen, %fromStart);
562
562
  my ($startTime, $endTime, $fwdTime, $backScan, $maxBack);
563
563
  my $verbose = $et->Options('Verbose');
564
564
  my $out = $et->Options('TextOut');
565
565
 
566
- # read first packet
567
- return 0 unless $raf->Read($buff, 8) == 8;
566
+ # read enough to guarantee 2 sync bytes
567
+ return 0 unless $raf->Read($buff, 383) == 383;
568
568
  # test for magic number (sync byte is the only thing we can safely check)
569
- return 0 unless $buff =~ /^(....)?\x47/s;
570
- unless ($1) {
571
- $pLen = 188; # no timecode
572
- $fileType = 'M2T'; # (just as a way to tell there is no timecode)
573
- } else {
574
- $pLen = 192; # 188-byte transport packet + leading 4-byte timecode (ref 4)
575
- }
576
- my $prePos = $pLen - 188; # byte position of packet prefix
577
- my $readSize = 64 * $pLen; # size of our read buffer
578
- $raf->Seek(0,0); # rewind to start
579
- $raf->Read($buff, $readSize) >= $pLen * 4 or return 0; # require at least 4 packets
580
- # validate the sync byte in the next 3 packets
581
- for ($j=1; $j<4; ++$j) {
582
- return 0 unless substr($buff, $prePos + $pLen * $j, 1) eq 'G'; # (0x47)
569
+ return 0 unless $buff =~ /^(.{0,190}?)\x47(.{187}|.{191})\x47/s;
570
+ my $tcLen = length($2) - 187; # (length of timecode = 0 or 4 bytes)
571
+ my $start = length($1) - $tcLen;
572
+ # we may need to try the validation twice to handle the edge case
573
+ # where the first byte of a timecode is 0x47 and we were fooled
574
+ # into thinking there was no timecode
575
+ Try: for (;;) {
576
+ $start += 192 if $start < 0; # (if all or part of first timecode was missing)
577
+ $pLen = 188 + $tcLen;
578
+ $readSize = 64 * $pLen; # size of our read buffer
579
+ $raf->Seek($start, 0); # rewind to start
580
+ $raf->Read($buff, $readSize) >= $pLen * 4 or return 0; # require at least 4 packets
581
+ # validate the sync byte in the next 3 packets
582
+ for ($j=1; $j<4; ++$j) {
583
+ next if substr($buff, $tcLen + $pLen * $j, 1) eq 'G'; # (0x47)
584
+ return 0 if $tcLen;
585
+ $tcLen = 4;
586
+ $start -= 4;
587
+ next Try;
588
+ }
589
+ last; # success!
583
590
  }
584
- $et->SetFileType($fileType);
591
+ # (use M2T instead of M2TS just as an indicator that there is no timecode)
592
+ $et->SetFileType($tcLen ? 'M2TS' : 'M2T');
593
+ $et->Warn("File doesn't begin with the start of a packet") if $start;
585
594
  SetByteOrder('MM');
586
595
  my $tagTablePtr = GetTagTable('Image::ExifTool::M2TS::Main');
587
596
 
@@ -667,7 +676,7 @@ sub ProcessM2TS($$)
667
676
  }
668
677
  $pEnd += $pLen;
669
678
  # decode the packet prefix
670
- $pos += $prePos;
679
+ $pos += $tcLen;
671
680
  my $prefix = unpack("x${pos}N", $buff); # (use unpack instead of Get32u for speed)
672
681
  # validate sync byte
673
682
  unless (($prefix & 0xff000000) == 0x47000000) {
@@ -685,9 +694,9 @@ sub ProcessM2TS($$)
685
694
  if ($verbose > 1) {
686
695
  my $i = ($raf->Tell() - length($buff) + $pEnd) / $pLen - 1;
687
696
  print $out "Transport packet $i:\n";
688
- $et->VerboseDump(\$buff, Len => $pLen, Addr => $i * $pLen, Start => $pos - $prePos);
697
+ $et->VerboseDump(\$buff, Len => $pLen, Addr => $i * $pLen, Start => $pos - $tcLen);
689
698
  my $str = $pidName{$pid} ? " ($pidName{$pid})" : ' <not in Program Map Table!>';
690
- printf $out " Timecode: 0x%.4x\n", Get32u(\$buff, $pos - $prePos) if $pLen == 192;
699
+ printf $out " Timecode: 0x%.4x\n", Get32u(\$buff, $pos - $tcLen) if $pLen == 192;
691
700
  printf $out " Packet ID: 0x%.4x$str\n", $pid;
692
701
  printf $out " Start Flag: %s\n", $payload_unit_start_indicator ? 'Yes' : 'No';
693
702
  }
@@ -172,7 +172,7 @@ strings.
172
172
  hp_C homeopathic potency of centesimal series (homeopathic potency)
173
173
  hp_X homeopathic potency of decimal series (homeopathic potency)
174
174
  HPF high power field (view area in microscope)
175
- Hz Herz (frequency)
175
+ Hz Hertz (frequency)
176
176
  in inch, international (length)
177
177
  in_br inch, British (length)
178
178
  in_us inch, U.S. (length)
@@ -14,7 +14,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
14
14
  use Image::ExifTool::XMP;
15
15
  use Image::ExifTool::ZIP;
16
16
 
17
- $VERSION = '1.09';
17
+ $VERSION = '1.10';
18
18
 
19
19
  # test for recognized OOXML document extensions
20
20
  my %isOOXML = (
@@ -27,6 +27,7 @@ my %isOOXML = (
27
27
  XLAM => 1,
28
28
  XLSX => 1, XLSM => 1, XLSB => 1,
29
29
  XLTX => 1, XLTM => 1,
30
+ VSDX => 1,
30
31
  );
31
32
 
32
33
  # generate reverse lookup for file type based on MIME
@@ -57,7 +58,7 @@ my @vectorVals;
57
58
  VARS => { ID_FMT => 'none' },
58
59
  NOTES => q{
59
60
  The Office Open XML (OOXML) format was introduced with Microsoft Office 2007
60
- and is used by file types such as DOCX, PPTX and XLSX. These are
61
+ and is used by file types such as DOCX, PPTX, XLSX and VSDX. These are
61
62
  essentially ZIP archives containing XML files. The table below lists some
62
63
  tags which have been observed in OOXML documents, but ExifTool will extract
63
64
  any tags found from XML files of the OOXML document properties ("docProps")
@@ -31,6 +31,7 @@
31
31
  # 25) Karsten Gieselmann private communication (OM series)
32
32
  # IB) Iliah Borg private communication (LibRaw)
33
33
  # NJ) Niels Kristian Bech Jensen private communication
34
+ # KG) Karsten Gieselmann private communication
34
35
  #------------------------------------------------------------------------------
35
36
 
36
37
  package Image::ExifTool::Olympus;
@@ -41,7 +42,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
41
42
  use Image::ExifTool::Exif;
42
43
  use Image::ExifTool::APP12;
43
44
 
44
- $VERSION = '2.91';
45
+ $VERSION = '2.92';
45
46
 
46
47
  sub PrintLensInfo($$$);
47
48
 
@@ -201,6 +202,7 @@ my %olympusLensTypes = (
201
202
  # Other makes
202
203
  '24 01 10' => 'Venus Optics Laowa 50mm F2.8 2x Macro', #DonKomarechka
203
204
  'f7 03 10' => 'LAOWA C&D-Dreamer MFT 7.5mm F2.0', #forum3833
205
+ 'f7 10 10' => 'LAOWA C&D-Dreamer MFT 6.0mm F2.0', #KG
204
206
  );
205
207
 
206
208
  # lookup for Olympus camera types (ref PH)
@@ -59,7 +59,7 @@ use Image::ExifTool::Exif;
59
59
  use Image::ExifTool::GPS;
60
60
  use Image::ExifTool::HP;
61
61
 
62
- $VERSION = '3.58';
62
+ $VERSION = '3.59';
63
63
 
64
64
  sub CryptShutterCount($$);
65
65
  sub PrintFilter($$$);
@@ -1947,7 +1947,8 @@ my %binaryDataAttrs = (
1947
1947
  '0 28' => 'Quick Macro', # (Q)
1948
1948
  '0 29' => 'Forest', # (Q)
1949
1949
  '0 30' => 'Backlight Silhouette', # (Q)
1950
- '0 32' => 'DOF', #PH (GR III)
1950
+ '0 31' => 'Max. Aperture Priority', #KG (Ricoh GR III)
1951
+ '0 32' => 'DOF', #PH (GR III) #KG ???? GR III 'DOF Priority (Deep)' is mapped to '0 2' ???
1951
1952
  # AUTO PICT modes (auto-selected)
1952
1953
  '1 4' => 'Auto PICT (Standard)', #13
1953
1954
  '1 5' => 'Auto PICT (Portrait)', #7 (K100D)
@@ -1962,7 +1963,11 @@ my %binaryDataAttrs = (
1962
1963
  '2 22' => 'Shallow DOF (HyP)', #PH (K-5)
1963
1964
  '3 0' => 'Green Mode', #16
1964
1965
  '4 0' => 'Shutter Speed Priority',
1966
+ '4 2' => 'Shutter Speed Priority 2', #KG Coding error? 'DOF Priority' in Tv makes no sense
1967
+ '4 31' => 'Shutter Speed Priority 31',#KG Coding error? 'Max Aperture' in Tv makes no sense
1965
1968
  '5 0' => 'Aperture Priority',
1969
+ '5 2' => 'Aperture Priority 2', #KG Coding error? 'DOF Priority' in Av makes no sense
1970
+ '5 31' => 'Aperture Priority 31', #KG Coding error? 'DOF Priority' in Av makes no sense
1966
1971
  '6 0' => 'Program Tv Shift',
1967
1972
  '7 0' => 'Program Av Shift', #19
1968
1973
  '8 0' => 'Manual',
@@ -49,7 +49,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
49
49
  use Image::ExifTool::Exif;
50
50
  use Image::ExifTool::GPS;
51
51
 
52
- $VERSION = '3.21';
52
+ $VERSION = '3.22';
53
53
 
54
54
  sub ProcessMOV($$;$);
55
55
  sub ProcessKeys($$$);
@@ -10515,9 +10515,9 @@ ItemID: foreach $id (reverse sort { $a <=> $b } keys %$items) {
10515
10515
  $et->Warn($warnStr);
10516
10516
  }
10517
10517
  }
10518
- # tweak file type based on track content ("iso*" and "dash" ftyp only)
10518
+ # tweak file type based on track content ("iso*" and "dash" ftyp only ["mp42" added in 13.39])
10519
10519
  if ($topLevel and $$et{FileType} and $$et{FileType} eq 'MP4' and
10520
- $$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and
10520
+ $$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash|mp42)/ and
10521
10521
  $$et{HasHandler}{soun} and not $$et{HasHandler}{vide})
10522
10522
  {
10523
10523
  $et->OverrideFileType('M4A', 'audio/mp4');
@@ -111,7 +111,7 @@ my %insvLimit = (
111
111
  The tags below are extracted from timed metadata in QuickTime and other
112
112
  formats of video files when the ExtractEmbedded option is used. Although
113
113
  most of these tags are combined into the single table below, ExifTool
114
- currently reads 111 different types of timed GPS metadata from video files.
114
+ currently reads 116 different types of timed GPS metadata from video files.
115
115
  },
116
116
  GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' },
117
117
  GPSLongitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")' },
@@ -984,7 +984,9 @@ sub SetGPSDateTime($$$;$)
984
984
  }
985
985
  $sampleTime -= $tzOff; # shift from local time to UTC
986
986
  }
987
+ $$et{SET_GROUP0} = 'Composite';
987
988
  $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($sampleTime,0,3) . 'Z');
989
+ delete $$et{SET_GROUP0};
988
990
  }
989
991
  }
990
992
 
@@ -1004,6 +1006,28 @@ sub HandleTextTags($$$)
1004
1006
  undef %$tags; # clear the hash
1005
1007
  }
1006
1008
 
1009
+ #------------------------------------------------------------------------------
1010
+ # Handle new time in NMEA stream and store queued tags if necessary
1011
+ # Inputs: 0) ExifTool ref, 1) time string, 2) tag table ref, 3) tags hash
1012
+ sub HandleNewTime($$$$)
1013
+ {
1014
+ my ($et, $time, $tagTbl, $tags) = @_;
1015
+ if ($$et{LastTime}) {
1016
+ if ($$et{LastTime} eq $time) {
1017
+ # combine with the previous NMEA sentence
1018
+ $$et{DOC_NUM} = $$et{LastDoc};
1019
+ } elsif (%$tags) {
1020
+ # handle existing tags and start a new document
1021
+ # (see https://exiftool.org/forum/index.php?msg=75422)
1022
+ HandleTextTags($et, $tagTbl, $tags);
1023
+ # increment document number and update document count if necessary
1024
+ $$et{DOC_COUNT} < ++$$et{DOC_NUM} and $$et{DOC_COUNT} = $$et{DOC_NUM};
1025
+ }
1026
+ }
1027
+ $$et{LastTime} = $time;
1028
+ $$et{LastDoc} = $$et{DOC_NUM};
1029
+ }
1030
+
1007
1031
  #------------------------------------------------------------------------------
1008
1032
  # Process subtitle 'text'
1009
1033
  # Inputs: 0) ExifTool ref, 1) data ref or dirInfo ref, 2) tag table ref
@@ -1030,41 +1054,18 @@ sub Process_text($$$;$)
1030
1054
  next;
1031
1055
  }
1032
1056
  my $time = "$1:$2:$3";
1033
- if ($$et{LastTime}) {
1034
- if ($$et{LastTime} eq $time) {
1035
- # combine with the previous NMEA sentence
1036
- $$et{DOC_NUM} = $$et{LastDoc};
1037
- } elsif (%tags) {
1038
- # handle existing tags and start a new document
1039
- # (see https://exiftool.org/forum/index.php?msg=75422)
1040
- HandleTextTags($et, $tagTbl, \%tags);
1041
- undef %tags;
1042
- # increment document number and update document count if necessary
1043
- $$et{DOC_COUNT} < ++$$et{DOC_NUM} and $$et{DOC_COUNT} = $$et{DOC_NUM};
1044
- }
1045
- }
1046
- $$et{LastTime} = $time;
1047
- $$et{LastDoc} = $$et{DOC_NUM};
1057
+ HandleNewTime($et, $time, $tagTbl, \%tags);
1048
1058
  my $year = $14 + ($14 >= 70 ? 1900 : 2000);
1049
- my $dateTime = sprintf('%.4d:%.2d:%.2d %sZ', $year, $13, $12, $time);
1050
- $tags{GPSDateTime} = $dateTime;
1059
+ my $date = sprintf('%.4d:%.2d:%.2d', $year, $13, $12);
1060
+ $$et{LastDate} = $date;
1061
+ $tags{GPSDateTime} = "$date ${time}Z";
1051
1062
  $tags{GPSLatitude} = (($4 || 0) + $5/60) * ($6 eq 'N' ? 1 : -1);
1052
1063
  $tags{GPSLongitude} = (($7 || 0) + $8/60) * ($9 eq 'E' ? 1 : -1);
1053
1064
  $tags{GPSSpeed} = $10 * $knotsToKph if length $10;
1054
1065
  $tags{GPSTrack} = $11 if length $11;
1055
1066
  } elsif ($tag =~ /^[A-Z]{2}GGA$/ and $dat =~ /^,(\d{2})(\d{2})(\d+(?:\.\d*)?),(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),[1-6]?,(\d+)?,(\.\d+|\d+\.?\d*)?,(-?\d+\.?\d*)?,M?/s) {
1056
1067
  my $time = "$1:$2:$3";
1057
- if ($$et{LastTime}) {
1058
- if ($$et{LastTime} eq $time) {
1059
- $$et{DOC_NUM} = $$et{LastDoc};
1060
- } elsif (%tags) {
1061
- HandleTextTags($et, $tagTbl, \%tags);
1062
- undef %tags;
1063
- $$et{DOC_COUNT} < ++$$et{DOC_NUM} and $$et{DOC_COUNT} = $$et{DOC_NUM};
1064
- }
1065
- }
1066
- $$et{LastTime} = $time;
1067
- $$et{LastDoc} = $$et{DOC_NUM};
1068
+ HandleNewTime($et, $time, $tagTbl, \%tags);
1068
1069
  $tags{GPSTimeStamp} = $time;
1069
1070
  $tags{GPSLatitude} = (($4 || 0) + $5/60) * ($6 eq 'N' ? 1 : -1);
1070
1071
  $tags{GPSLongitude} = (($7 || 0) + $8/60) * ($9 eq 'E' ? 1 : -1);
@@ -1112,6 +1113,11 @@ sub Process_text($$$;$)
1112
1113
  }
1113
1114
  }
1114
1115
  }
1116
+ if ($tags{GPSTimeStamp} and not $tags{GPSDateTime} and $$et{LastDate}) {
1117
+ # hack to fill in missing date for NextBase 662GW
1118
+ # (note: this doesn't necessarily handle day rollover properly)
1119
+ $tags{GPSDateTime} = "$$et{LastDate} $tags{GPSTimeStamp}Z";
1120
+ }
1115
1121
  HandleTextTags($et, $tagTbl, \%tags);
1116
1122
  return;
1117
1123
  }
@@ -3488,14 +3494,17 @@ sub ProcessGarminGPS($$$)
3488
3494
  while ($pos + 20 <= $dataLen) {
3489
3495
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
3490
3496
  my $time = Image::ExifTool::ConvertUnixTime(Get32u($dataPt, $pos) - $epoch) . 'Z';
3491
- my $lat = Get32s($dataPt, $pos + 12) * $scl;
3492
- my $lon = Get32s($dataPt, $pos + 16) * $scl;
3497
+ my $lat = Get32s($dataPt, $pos + 12);
3498
+ my $lon = Get32s($dataPt, $pos + 16);
3493
3499
  my $spd = Get16u($dataPt, $pos + 4); # (in mph)
3494
3500
  $et->HandleTag($tagTbl, 'GPSDateTime', $time);
3495
- $et->HandleTag($tagTbl, 'GPSLatitude', $lat);
3496
- $et->HandleTag($tagTbl, 'GPSLongitude', $lon);
3497
- $et->HandleTag($tagTbl, 'GPSSpeed', $spd);
3498
- $et->HandleTag($tagTbl, 'GPSSpeedRef', 'M');
3501
+ # skip bad GPS fixes
3502
+ if ($lat != -2147483648 or $lon != -2147483648) {
3503
+ $et->HandleTag($tagTbl, 'GPSLatitude', $lat * $scl);
3504
+ $et->HandleTag($tagTbl, 'GPSLongitude', $lon * $scl);
3505
+ $et->HandleTag($tagTbl, 'GPSSpeed', $spd);
3506
+ $et->HandleTag($tagTbl, 'GPSSpeedRef', 'M');
3507
+ }
3499
3508
  $pos += 20;
3500
3509
  }
3501
3510
  delete $$et{DOC_NUM};