exiftool_vendored 12.99.0 → 13.03.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +76 -3
  3. data/bin/META.json +1 -1
  4. data/bin/META.yml +1 -1
  5. data/bin/README +2 -2
  6. data/bin/arg_files/exif2xmp.args +4 -0
  7. data/bin/arg_files/xmp2exif.args +4 -0
  8. data/bin/exiftool +121 -50
  9. data/bin/lib/Image/ExifTool/Apple.pm +2 -2
  10. data/bin/lib/Image/ExifTool/CBOR.pm +4 -1
  11. data/bin/lib/Image/ExifTool/Canon.pm +35 -26
  12. data/bin/lib/Image/ExifTool/Exif.pm +15 -9
  13. data/bin/lib/Image/ExifTool/FlashPix.pm +5 -9
  14. data/bin/lib/Image/ExifTool/GIF.pm +143 -92
  15. data/bin/lib/Image/ExifTool/Geolocation.dat +0 -0
  16. data/bin/lib/Image/ExifTool/Geotag.pm +6 -5
  17. data/bin/lib/Image/ExifTool/GoPro.pm +2 -2
  18. data/bin/lib/Image/ExifTool/JPEG.pm +9 -1
  19. data/bin/lib/Image/ExifTool/Jpeg2000.pm +2 -2
  20. data/bin/lib/Image/ExifTool/LNK.pm +1 -1
  21. data/bin/lib/Image/ExifTool/M2TS.pm +2 -2
  22. data/bin/lib/Image/ExifTool/MIE.pm +9 -3
  23. data/bin/lib/Image/ExifTool/MacOS.pm +2 -1
  24. data/bin/lib/Image/ExifTool/Matroska.pm +10 -2
  25. data/bin/lib/Image/ExifTool/Nikon.pm +5 -2
  26. data/bin/lib/Image/ExifTool/PDF.pm +35 -4
  27. data/bin/lib/Image/ExifTool/PNG.pm +14 -3
  28. data/bin/lib/Image/ExifTool/PPM.pm +11 -2
  29. data/bin/lib/Image/ExifTool/PhaseOne.pm +2 -1
  30. data/bin/lib/Image/ExifTool/QuickTime.pm +6 -1
  31. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +69 -7
  32. data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
  33. data/bin/lib/Image/ExifTool/TagLookup.pm +5596 -5582
  34. data/bin/lib/Image/ExifTool/TagNames.pod +75 -21
  35. data/bin/lib/Image/ExifTool/Text.pm +3 -2
  36. data/bin/lib/Image/ExifTool/Validate.pm +2 -2
  37. data/bin/lib/Image/ExifTool/WriteRIFF.pl +13 -4
  38. data/bin/lib/Image/ExifTool/Writer.pl +42 -66
  39. data/bin/lib/Image/ExifTool/XMP.pm +19 -4
  40. data/bin/lib/Image/ExifTool/XMP2.pl +60 -0
  41. data/bin/lib/Image/ExifTool/XMPStruct.pl +1 -2
  42. data/bin/lib/Image/ExifTool.pm +204 -86
  43. data/bin/lib/Image/ExifTool.pod +58 -31
  44. data/bin/perl-Image-ExifTool.spec +1 -1
  45. data/lib/exiftool_vendored/version.rb +1 -1
  46. metadata +2 -2
@@ -11,7 +11,7 @@ use strict;
11
11
  use vars qw($VERSION);
12
12
  use Image::ExifTool qw(:DataAccess :Utils);
13
13
 
14
- $VERSION = '1.36';
14
+ $VERSION = '1.37';
15
15
 
16
16
  sub ProcessOcad($$$);
17
17
  sub ProcessJPEG_HDR($$$);
@@ -228,6 +228,10 @@ sub ProcessJPEG_HDR($$$);
228
228
  Name => 'InfiRayIsothermal',
229
229
  Condition => '$$self{HasIJPEG}',
230
230
  SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Isothermal' },
231
+ }, {
232
+ Name => 'SEAL',
233
+ Condition => '$$valPt =~ /^SEAL\0/',
234
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
231
235
  }],
232
236
  APP9 => [{
233
237
  Name => 'MediaJukebox',
@@ -237,6 +241,10 @@ sub ProcessJPEG_HDR($$$);
237
241
  Name => 'InfiRaySensor',
238
242
  Condition => '$$self{HasIJPEG}',
239
243
  SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Sensor' },
244
+ }, {
245
+ Name => 'SEAL',
246
+ Condition => '$$valPt =~ /^SEAL\0/',
247
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
240
248
  }],
241
249
  APP10 => {
242
250
  Name => 'Comment',
@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.41';
19
+ $VERSION = '1.42';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -1338,7 +1338,7 @@ sub ProcessJpeg2000Box($$$)
1338
1338
  if (defined $val) {
1339
1339
  my $key = $et->FoundTag($tagInfo, $val);
1340
1340
  # save Rational value
1341
- $$et{RATIONAL}{$key} = $rational if defined $rational and defined $key;
1341
+ $$et{TAG_EXTRA}{$key}{Rational} = $rational if defined $rational and defined $key;
1342
1342
  }
1343
1343
  } elsif ($outfile) {
1344
1344
  my $boxhdr = pack('N', $boxLen + 8) . $boxID;
@@ -650,7 +650,7 @@ sub ProcessLNK($$)
650
650
  my $mask = 0x04 << $i;
651
651
  next unless $flags & $mask;
652
652
  $raf->Read($buff, 2) or return 1;
653
- $len = unpack('v', $buff);
653
+ $len = unpack('v', $buff) or next;
654
654
  $len *= 2 if $flags & 0x80; # characters are 2 bytes if Unicode flag is set
655
655
  $raf->Read($buff, $len) or return 1;
656
656
  my $val;
@@ -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.25';
35
+ $VERSION = '1.26';
36
36
 
37
37
  # program map table "stream_type" lookup (ref 6/1/9)
38
38
  my %streamType = (
@@ -82,7 +82,7 @@ my %streamType = (
82
82
  0x86 => 'DTS-HD Audio',
83
83
  0x87 => 'E-AC-3 Audio',
84
84
  0x8a => 'DTS Audio',
85
- 0x90 => 'PGS Audio', #https://www.avsforum.com/threads/bass-eq-for-filtered-movies.2995212/page-399
85
+ 0x90 => 'Presentation Graphic Stream (subtitle)', #https://en.wikipedia.org/wiki/Program-specific_information
86
86
  0x91 => 'A52b/AC-3 Audio',
87
87
  0x92 => 'DVD_SPU vls Subtitle',
88
88
  0x94 => 'SDDS Audio',
@@ -14,7 +14,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
14
14
  use Image::ExifTool::Exif;
15
15
  use Image::ExifTool::GPS;
16
16
 
17
- $VERSION = '1.54';
17
+ $VERSION = '1.55';
18
18
 
19
19
  sub ProcessMIE($$);
20
20
  sub ProcessMIEGroup($$$);
@@ -1596,9 +1596,10 @@ sub ProcessMIEGroup($$$)
1596
1596
  } else {
1597
1597
  # process MIE data format types
1598
1598
  if ($tagInfo) {
1599
- my $rational;
1599
+ my ($rational, $binVal);
1600
1600
  # extract tag value
1601
1601
  my $val = ReadMIEValue(\$value, 0, $formatStr, undef, $valLen, \$rational);
1602
+ $binVal = substr($value, 0, $valLen) if $$et{OPTIONS}{SaveBin};
1602
1603
  unless (defined $val) {
1603
1604
  $et->Warn("Error reading $tag value");
1604
1605
  $val = '<err>';
@@ -1661,7 +1662,12 @@ sub ProcessMIEGroup($$$)
1661
1662
  $val .= "($units)" if defined $units;
1662
1663
  }
1663
1664
  my $key = $et->FoundTag($tagInfo, $val);
1664
- $$et{RATIONAL}{$key} = $rational if defined $rational and defined $key;
1665
+ if (defined $key) {
1666
+ my $ex = $$et{TAG_EXTRA}{$key};
1667
+ $$ex{Rational} = $rational if defined $rational;
1668
+ $$ex{BinVal} = $binVal if defined $binVal;
1669
+ $$ex{G6} = $formatStr if $$et{OPTIONS}{SaveFormat};
1670
+ }
1665
1671
  }
1666
1672
  } else {
1667
1673
  # skip over unknown information or free bytes
@@ -12,7 +12,7 @@ use strict;
12
12
  use vars qw($VERSION);
13
13
  use Image::ExifTool qw(:DataAccess :Utils);
14
14
 
15
- $VERSION = '1.13';
15
+ $VERSION = '1.14';
16
16
 
17
17
  sub MDItemLocalTime($);
18
18
  sub ProcessATTR($$$);
@@ -394,6 +394,7 @@ sub SetMacOSTags($$$)
394
394
  if ($val =~ /[-+Z]/) {
395
395
  my $time = Image::ExifTool::GetUnixTime($val, 1);
396
396
  $val = Image::ExifTool::ConvertUnixTime($time, 1) if $time;
397
+ $val =~ s/[-+].*//; # remove time zone
397
398
  }
398
399
  $val =~ s{(\d{4}):(\d{2}):(\d{2})}{$2/$3/$1}; # reformat for setfile
399
400
  $cmd = "/usr/bin/setfile -d '${val}' '${f}'";
@@ -15,7 +15,7 @@ use strict;
15
15
  use vars qw($VERSION);
16
16
  use Image::ExifTool qw(:DataAccess :Utils);
17
17
 
18
- $VERSION = '1.16';
18
+ $VERSION = '1.17';
19
19
 
20
20
  sub HandleStruct($$;$$$$);
21
21
 
@@ -685,6 +685,14 @@ my %uidInfo = (
685
685
  Name => 'Projection',
686
686
  SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Projection' },
687
687
  },
688
+ #
689
+ # other
690
+ #
691
+ 0x5345414c => { # ('SEAL' in hex)
692
+ Name => 'SEAL',
693
+ NotEBML => 1, # don't process SubDirectory as EBML elements
694
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
695
+ },
688
696
  );
689
697
 
690
698
  # Spherical video v2 projection tags (ref https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md)
@@ -1047,7 +1055,7 @@ sub ProcessMKV($$)
1047
1055
  $seekInfoOnly = 1;
1048
1056
  }
1049
1057
  if ($tagInfo) {
1050
- if ($$tagInfo{SubDirectory}) {
1058
+ if ($$tagInfo{SubDirectory} and not $$tagInfo{NotEBML}) {
1051
1059
  # stop processing at first cluster unless we are using -v -U or -ee
1052
1060
  # or there are Tags after this
1053
1061
  if ($$tagInfo{Name} eq 'Cluster' and $processAll < 2) {
@@ -65,7 +65,7 @@ use Image::ExifTool::Exif;
65
65
  use Image::ExifTool::GPS;
66
66
  use Image::ExifTool::XMP;
67
67
 
68
- $VERSION = '4.38';
68
+ $VERSION = '4.39';
69
69
 
70
70
  sub LensIDConv($$$);
71
71
  sub ProcessNikonAVI($$$);
@@ -13609,7 +13609,10 @@ sub ProcessNikonMOV($$$)
13609
13609
  Size => $size,
13610
13610
  Base => $$dirInfo{Base},
13611
13611
  );
13612
- $$et{RATIONAL}{$key} = $rational if $rational and $key;
13612
+ if ($key) {
13613
+ $$et{TAG_EXTRA}{$key}{Rational} = $rational if $rational;
13614
+ $$et{TAG_EXTRA}{$key}{BinVal} = substr($$dataPt, $pos, $size) if $$et{OPTIONS}{SaveBin};
13615
+ }
13613
13616
  } elsif (exists $needTags{$tag}) {
13614
13617
  $needTags{$tag} = ReadValue($dataPt, $pos, $fmtStr, $count, $size);
13615
13618
  $$et{NikonSerialKey} = SerialKey($et, $needTags{0x110a431});
@@ -21,7 +21,7 @@ use vars qw($VERSION $AUTOLOAD $lastFetched);
21
21
  use Image::ExifTool qw(:DataAccess :Utils);
22
22
  require Exporter;
23
23
 
24
- $VERSION = '1.58';
24
+ $VERSION = '1.60';
25
25
 
26
26
  sub FetchObject($$$$);
27
27
  sub ExtractObject($$;$$);
@@ -349,6 +349,7 @@ my %supportedFilter = (
349
349
  # tags in PDF ICCBased, Cs1 and CS0 dictionaries
350
350
  %Image::ExifTool::PDF::ICCBased = (
351
351
  _stream => {
352
+ Name => 'ICC_Profile',
352
353
  SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
353
354
  },
354
355
  );
@@ -470,6 +471,7 @@ my %supportedFilter = (
470
471
  # tags in PDF AIMetaData dictionary
471
472
  %Image::ExifTool::PDF::AIMetaData = (
472
473
  _stream => {
474
+ Name => 'AIStream',
473
475
  SubDirectory => { TagTable => 'Image::ExifTool::PostScript::Main' },
474
476
  },
475
477
  );
@@ -477,6 +479,7 @@ my %supportedFilter = (
477
479
  # tags in PDF ImageResources dictionary
478
480
  %Image::ExifTool::PDF::ImageResources = (
479
481
  _stream => {
482
+ Name => 'PhotoshopStream',
480
483
  SubDirectory => { TagTable => 'Image::ExifTool::Photoshop::Main' },
481
484
  },
482
485
  );
@@ -1595,9 +1598,13 @@ sub DecryptInit($$$)
1595
1598
  $password = $et->Options('Password');
1596
1599
  return 'Document is password protected (use Password option)' unless defined $password;
1597
1600
  # make sure there is no UTF-8 flag on the password
1598
- if ($] >= 5.006 and (eval { require Encode; Encode::is_utf8($password) } or $@)) {
1601
+ if ($] >= 5.006 and ($$et{OPTIONS}{EncodeHangs} or
1602
+ eval { require Encode; Encode::is_utf8($password) } or $@))
1603
+ {
1604
+ local $SIG{'__WARN__'} = sub { };
1599
1605
  # repack by hand if Encode isn't available
1600
- $password = $@ ? pack('C*',unpack($] < 5.010000 ? 'U0C*' : 'C0C*',$password)) : Encode::encode('utf8',$password);
1606
+ $password = ($$et{OPTIONS}{EncodeHangs} or $@) ? pack('C*', unpack($] < 5.010000 ?
1607
+ 'U0C*' : 'C0C*', $password)) : Encode::encode('utf8', $password);
1601
1608
  }
1602
1609
  } else {
1603
1610
  return 'Incorrect password';
@@ -2157,6 +2164,20 @@ sub ProcessDict($$$$;$$)
2157
2164
  last;
2158
2165
  }
2159
2166
  # decode stream if necessary
2167
+ if ($cryptInfo and ($$cryptInfo{_aesv2} or $$cryptInfo{_aesv3} and
2168
+ $$dict{Length} and $$dict{Length} > 10000) and not $$dict{_decrypted} and
2169
+ not $$et{PDF_CAPTURE}) # (capturing PDF for writing?)
2170
+ {
2171
+ my $type = $$dict{Type} || '';
2172
+ if ($type ne '/Metadata' or $$dict{Length} > 100000) {
2173
+ if ($$et{OPTIONS}{IgnoreMinorErrors}) {
2174
+ $et->WarnOnce("Decrypting large $$tagInfo{Name} (will be slow)");
2175
+ } else {
2176
+ $et->WarnOnce("Skipping large AES-encrypted $$tagInfo{Name}", 2);
2177
+ last;
2178
+ }
2179
+ }
2180
+ }
2160
2181
  DecodeStream($et, $dict) or last;
2161
2182
  if ($verbose > 2) {
2162
2183
  $et->VPrint(2,"$$et{INDENT}$$et{DIR_NAME} stream data\n");
@@ -2233,7 +2254,17 @@ sub ReadPDF($$)
2233
2254
  $raf->Read($buff, $len) == $len or return -3;
2234
2255
  # find the LAST xref table in the file (may be multiple %%EOF marks,
2235
2256
  # and comments between "startxref" and "%%EOF")
2236
- $buff =~ /^.*startxref(\s+)(\d+)(\s+)(%[^\x0d\x0a]*\s+)*%%EOF/s or return -4;
2257
+ $buff =~ /^.*startxref(\s+)(\d+)(\s+)((%[^\x0d\x0a]*\s+)*)%%EOF/s or return -4;
2258
+ # parse comments to read SEAL information
2259
+ if ($4) {
2260
+ my @com = split /[\x0d\x0d]+/, $4;
2261
+ foreach (@com) {
2262
+ /^(%+\s*)<seal seal=/ or next;
2263
+ my $dat = substr $_, length($1);
2264
+ my $tbl = GetTagTable('Image::ExifTool::XMP::SEAL');
2265
+ $et->ProcessDirectory({ DataPt => \$dat }, $tbl);
2266
+ }
2267
+ }
2237
2268
  my $ws = $1 . $3;
2238
2269
  my $xr = $2;
2239
2270
  push @xrefOffsets, $xr, 'Main';
@@ -36,7 +36,7 @@ use strict;
36
36
  use vars qw($VERSION $AUTOLOAD %stdCase);
37
37
  use Image::ExifTool qw(:DataAccess :Utils);
38
38
 
39
- $VERSION = '1.68';
39
+ $VERSION = '1.69';
40
40
 
41
41
  sub ProcessPNG_tEXt($$$);
42
42
  sub ProcessPNG_iTXt($$$);
@@ -371,6 +371,10 @@ my %noLeapFrog = ( SAVE => 1, SEEK => 1, IHDR => 1, JHDR => 1, IEND => 1, MEND =
371
371
  IgnoreProp => { meta => 1 }, # ignore 'meta' container
372
372
  },
373
373
  },
374
+ seAl => {
375
+ Name => 'SEAL',
376
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
377
+ },
374
378
  # mkBF,mkTS,mkBS,mkBT ? - written by Adobe FireWorks
375
379
  );
376
380
 
@@ -980,8 +984,15 @@ sub FoundPNG($$$$;$$$$)
980
984
  my $processProc = $$subdir{ProcessProc};
981
985
  # nothing more to do if writing and subdirectory is not writable
982
986
  my $subTable = GetTagTable($$subdir{TagTable});
983
- return 1 if $outBuff and not $$subTable{WRITE_PROC};
984
- my $dirName = $$subdir{DirName} || $tagName;
987
+ if ($outBuff and not $$subTable{WRITE_PROC}) {
988
+ if ($$et{DEL_GROUP}{$dirName}) {
989
+ # non-writable directories may be deleted as a group (eg. SEAL)
990
+ $et->VPrint(0, " Deleting $dirName\n");
991
+ $$outBuff = '';
992
+ ++$$et{CHANGED};
993
+ }
994
+ return 1;
995
+ }
985
996
  my %subdirInfo = (
986
997
  DataPt => \$val,
987
998
  DirStart => 0,
@@ -16,7 +16,7 @@ use strict;
16
16
  use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
 
19
- $VERSION = '1.10';
19
+ $VERSION = '1.11';
20
20
 
21
21
  #------------------------------------------------------------------------------
22
22
  # Read or write information in a PPM/PGM/PBM image
@@ -29,7 +29,7 @@ sub ProcessPPM($$)
29
29
  my $outfile = $$dirInfo{OutFile};
30
30
  my $verbose = $et->Options('Verbose');
31
31
  my $out = $et->Options('TextOut');
32
- my ($buff, $num, $type, %info);
32
+ my ($buff, $num, $type, %info, $seal);
33
33
  #
34
34
  # read as much of the image as necessary to extract the header and comments
35
35
  #
@@ -77,6 +77,7 @@ sub ProcessPPM($$)
77
77
  if (defined $info{Comment}) {
78
78
  $info{Comment} =~ s/^# ?//mg; # remove "# " at the start of each line
79
79
  $info{Comment} =~ s/[\n\r]+$//; # remove trailing newline
80
+ $seal = 1 if $info{Comment} =~ /^<seal seal=/;
80
81
  }
81
82
  $et->SetFileType($type);
82
83
  my $len = pos($buff);
@@ -91,6 +92,10 @@ sub ProcessPPM($$)
91
92
  ++$$et{CHANGED};
92
93
  $et->VerboseValue('- Comment', $oldComment) if defined $oldComment;
93
94
  $et->VerboseValue('+ Comment', $newComment) if defined $newComment;
95
+ } elsif ($seal and $$et{DEL_GROUP}{SEAL}) {
96
+ # delete SEAL comment
97
+ $et->VerboseValue('- Comment', $oldComment);
98
+ ++$$et{CHANGED};
94
99
  } else {
95
100
  $newComment = $oldComment; # use existing comment
96
101
  }
@@ -116,6 +121,10 @@ sub ProcessPPM($$)
116
121
  print $out "$type header ($len bytes):\n";
117
122
  $et->VerboseDump(\$buff, Len => $len);
118
123
  }
124
+ if ($seal) {
125
+ $et->ProcessDirectory({ DataPt => \$info{Comment} }, GetTagTable('Image::ExifTool::XMP::SEAL'));
126
+ delete $info{Comment};
127
+ }
119
128
  my $tag;
120
129
  foreach $tag (qw{Comment ImageWidth ImageHeight MaxVal}) {
121
130
  $et->FoundTag($tag, $info{$tag}) if defined $info{$tag};
@@ -15,7 +15,7 @@ use vars qw($VERSION);
15
15
  use Image::ExifTool qw(:DataAccess :Utils);
16
16
  use Image::ExifTool::Exif;
17
17
 
18
- $VERSION = '1.10';
18
+ $VERSION = '1.11';
19
19
 
20
20
  sub WritePhaseOne($$$);
21
21
  sub ProcessPhaseOne($$$);
@@ -71,6 +71,7 @@ my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' );
71
71
  # >2 = compressed
72
72
  # 5 = non-linear
73
73
  PrintConv => { #PH
74
+ 0 => 'Uncompressed', #https://github.com/darktable-org/darktable/issues/7308
74
75
  1 => 'RAW 1', #? (encrypted)
75
76
  2 => 'RAW 2', #? (encrypted)
76
77
  3 => 'IIQ L', # (now "L14", ref IB)
@@ -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 = '3.04';
51
+ $VERSION = '3.05';
52
52
 
53
53
  sub ProcessMOV($$;$);
54
54
  sub ProcessKeys($$$);
@@ -902,6 +902,10 @@ my %userDefined = (
902
902
  },
903
903
  # '35AX'? - seen "AT" (Yada RoadCam Pro 4K dashcam)
904
904
  cust => 'CustomInfo', # 70mai A810
905
+ SEAL => {
906
+ Name => 'SEAL',
907
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
908
+ },
905
909
  );
906
910
 
907
911
  # stuff seen in 'skip' atom (70mai Pro Plus+ MP4 videos)
@@ -3097,6 +3101,7 @@ my %userDefined = (
3097
3101
  10 => {
3098
3102
  Name => 'VideoFullRangeFlag',
3099
3103
  Mask => 0x80,
3104
+ PrintConv => { 0 => 'Limited', 1 => 'Full' },
3100
3105
  },
3101
3106
  );
3102
3107
 
@@ -591,8 +591,8 @@ my %insvLimit = (
591
591
  GROUPS => { 2 => 'Location' },
592
592
  FIRST_ENTRY => 0,
593
593
  NOTES => q{
594
- Tags extracted from the tx3g sbtl timed metadata of Yuneec drones, and
595
- subtitle text in some other videos.
594
+ Tags extracted from the tx3g sbtl timed metadata of Yuneec and Autel drones,
595
+ and subtitle text in some other videos.
596
596
  },
597
597
  Lat => {
598
598
  Name => 'GPSLatitude',
@@ -619,6 +619,32 @@ my %insvLimit = (
619
619
  PrintConv => '$self->ConvertDateTime($val)',
620
620
  },
621
621
  Text => { Groups => { 2 => 'Other' } },
622
+ # the following tags are extracted from Autel Evo II drone videos
623
+ GPSDateTime => {
624
+ Groups => { 2 => 'Time' },
625
+ Description => 'GPS Date/Time',
626
+ PrintConv => '$self->ConvertDateTime($val)',
627
+ },
628
+ HomeLat => {
629
+ Name => 'GPSHomeLatitude',
630
+ RawConv => '$$self{FoundGPSLatitude} = 1; $val',
631
+ PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
632
+ },
633
+ HomeLon => {
634
+ Name => 'GPSHomeLongitude',
635
+ PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
636
+ },
637
+ ISO => { },
638
+ SHUTTER => {
639
+ Name => 'ExposureTime',
640
+ ValueConv => '1 / $val',
641
+ PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
642
+ },
643
+ 'F-NUM' => {
644
+ Name => 'FNumber',
645
+ PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)',
646
+ },
647
+ EV => 'ExposureCompensation',
622
648
  );
623
649
 
624
650
  %Image::ExifTool::QuickTime::INSV_MakerNotes = (
@@ -2361,7 +2387,7 @@ sub ParseTag($$$)
2361
2387
  }
2362
2388
 
2363
2389
  #------------------------------------------------------------------------------
2364
- # Process Yuneec 'tx3g' sbtl metadata (ref PH)
2390
+ # Process Yuneec 'tx3g' and Autel sbtl metadata (ref PH)
2365
2391
  # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
2366
2392
  # Returns: 1 on success
2367
2393
  sub Process_tx3g($$$)
@@ -2369,13 +2395,49 @@ sub Process_tx3g($$$)
2369
2395
  my ($et, $dirInfo, $tagTablePtr) = @_;
2370
2396
  my $dataPt = $$dirInfo{DataPt};
2371
2397
  return 0 if length $$dataPt < 2;
2372
- pos($$dataPt) = 2; # skip 2-byte length word
2373
2398
  $et->VerboseDir('tx3g', undef, length($$dataPt)-2);
2374
- $et->HandleTag($tagTablePtr, 'Text', substr($$dataPt, 2));
2375
- if ($$dataPt =~ /^..\w{3} (\d{4})-(\d{2})-(\d{2}) (\d{2}:\d{2}:\d{2}) ?([-+])(\d{2}):?(\d{2})$/s) {
2399
+ my $text = substr($$dataPt, 2); # remove 2-byte length word
2400
+ $et->HandleTag($tagTablePtr, 'Text', $text);
2401
+ if ($text =~ /^HOME\(/) {
2402
+ # --- sample text from Autel Evo II drone ---
2403
+ # HOME(W: 109.318642, N: 40.769371) 2023-09-12 10:28:07
2404
+ # GPS(W: 109.339287, N: 40.768574, 2371.76m)
2405
+ # HDR ISO:100 SHUTTER:1000 EV:-0.7 F-NUM:1.8
2406
+ # F.PRY (1.0\xc2\xb0, -3.7\xc2\xb0, -59.0\xc2\xb0), G.PRY (-51.1\xc2\xb0, 0.0\xc2\xb0, -58.9\xc2\xb0)
2407
+ my $line;
2408
+ foreach $line (split /\x0a/, $text) {
2409
+ if ($line =~ /^HOME\(([EW]):\s*(\d+\.\d+),\s*([NS]):\s*(\d+\.\d+)\)\s*(.*)/) {
2410
+ my ($lon, $lat, $time) = ($2, $4, $5);
2411
+ $lon = -$lon if $1 eq 'W';
2412
+ $lat = -$lat if $3 eq 'S';
2413
+ $time =~ tr/-/:/; # (likely local time zone, but not confirmed)
2414
+ $et->HandleTag($tagTablePtr, GPSDateTime => $time);
2415
+ $et->HandleTag($tagTablePtr, HomeLat => $lat);
2416
+ $et->HandleTag($tagTablePtr, HomeLon => $lon);
2417
+ } elsif ($line =~ /^GPS\(([EW]):\s*(\d+\.\d+),\s*([NS]):\s*(\d+\.\d+),\s*(.*)m/) {
2418
+ my ($lon, $lat, $alt) = ($2, $4, $5);
2419
+ $lon = -$lon if $1 eq 'W';
2420
+ $lat = -$lat if $3 eq 'S';
2421
+ $et->HandleTag($tagTablePtr, Lat => $lat);
2422
+ $et->HandleTag($tagTablePtr, Lon => $lon);
2423
+ $et->HandleTag($tagTablePtr, Alt => $alt);
2424
+ } elsif ($line =~ /^F\.PRY\s*\((-?[\d.]+)\xc2\xb0,\s*(-?[\d.]+)\xc2\xb0,\s*(-?[\d.]+)\xc2\xb0/) {
2425
+ $et->HandleTag($tagTablePtr, Yaw => $1);
2426
+ $et->HandleTag($tagTablePtr, Pitch => $2);
2427
+ $et->HandleTag($tagTablePtr, Roll => $3);
2428
+ if ($line =~ /G\.PRY\s*\((-?[\d.]+)\xc2\xb0,\s*(-?[\d.]+)\xc2\xb0,\s*(-?[\d.]+)\xc2\xb0/) {
2429
+ $et->HandleTag($tagTablePtr, GimYaw => $1);
2430
+ $et->HandleTag($tagTablePtr, GimPitch => $2);
2431
+ $et->HandleTag($tagTablePtr, GimRoll => $3);
2432
+ }
2433
+ } else {
2434
+ $et->HandleTag($tagTablePtr, $1, $2) while $line =~ /([-\w]+):([^:]*[^:\s])(\s|$)/sg;
2435
+ }
2436
+ }
2437
+ } elsif ($text =~ /^\w{3} (\d{4})-(\d{2})-(\d{2}) (\d{2}:\d{2}:\d{2}) ?([-+])(\d{2}):?(\d{2})$/s) {
2376
2438
  $et->HandleTag($tagTablePtr, 'DateTime', "$1:$2:$3 $4$5$6:$7");
2377
2439
  } else {
2378
- $et->HandleTag($tagTablePtr, $1, $2) while $$dataPt =~ /(\w+):([^:]*[^:\s])(\s|$)/sg;
2440
+ $et->HandleTag($tagTablePtr, $1, $2) while $text =~ /(\w+):([^:]*[^:\s])(\s|$)/sg;
2379
2441
  }
2380
2442
  return 1;
2381
2443
  }
@@ -30,7 +30,7 @@ use strict;
30
30
  use vars qw($VERSION $AUTOLOAD);
31
31
  use Image::ExifTool qw(:DataAccess :Utils);
32
32
 
33
- $VERSION = '1.68';
33
+ $VERSION = '1.69';
34
34
 
35
35
  sub ConvertTimecode($);
36
36
  sub ProcessSGLT($$$);
@@ -664,6 +664,10 @@ my %code2charset = (
664
664
  SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Acidizer' },
665
665
  },
666
666
  guan => 'Guano', #forum14831
667
+ SEAL => {
668
+ Name => 'SEAL',
669
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
670
+ },
667
671
  );
668
672
 
669
673
  # the maker notes used by some digital cameras
@@ -2120,7 +2124,8 @@ sub ProcessRIFF($$)
2120
2124
  my $tagInfo = $$tagTbl{$tag};
2121
2125
  # (in LIST_movi chunk: ##db = uncompressed DIB, ##dc = compressed DIB, ##wb = audio data)
2122
2126
  if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) {
2123
- $raf->Read($buff, $len2) == $len2 or $err=1, next;
2127
+ $raf->Read($buff, $len2) >= $len or $err=1, next;
2128
+ length($buff) == $len2 or $et->Warn("No padding on odd-sized $tag chunk");
2124
2129
  if ($hash and $isImageData{$tag}) {
2125
2130
  $hash->add($buff);
2126
2131
  $et->VPrint(0, "$$et{INDENT}(ImageDataHash: '${tag}' chunk, $len2 bytes)\n");