exiftool_vendored 12.60.0 → 12.61.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 348c2538720f815bacaf609de1dbb52e18f720663ea9e2194c92941b5f80d5ec
4
- data.tar.gz: 124c2564aba8f2fa4af8b2bf16c654b46624031b38bb64e6ed4ed3d6cc2fb596
3
+ metadata.gz: e42c8004f68374320f592b26a0d8ceaa0d44e09331c9be1f66986d2fe94ad7d0
4
+ data.tar.gz: eab311e1d2c27c522ed174ae054adc3d44e31c91992fdacbb6c6fb02e965da20
5
5
  SHA512:
6
- metadata.gz: b32a41d3586f914940ddfc5f3f947c323006f627ce6c3a050f34111817776e26a4a5e535f56194998ec38aa5ea7f27e350388fbbd517dd366d826324c9dcd9e4
7
- data.tar.gz: 9b3d5cb69b62ca6bc41293ec56110e0c28e7510561303bc8c3f3eb0ee01500f5c92dd8ff60ace8f53c54c64a28c92cfa84b0fbebe7238cb190872433c62f4103
6
+ metadata.gz: 27e28a24360bd3651900c9db4b30ddff5517d777a8d6fa9723b80e758b71947697ca80e2149107be7ed6aac3c8b9ae37364d16126ddb2ee1a6c8aeaf8034e11a
7
+ data.tar.gz: 4845253fe922519e454c45d5e35e89b75a242ddf21183de8a6f5a32417d5cf814280161e46d2c722934175b4293f83ee1b0a2878bc6ea1c6fbd139cd105a6b25
data/bin/Changes CHANGED
@@ -7,6 +7,29 @@ RSS feed: https://exiftool.org/rss.xml
7
7
  Note: The most recent production release is Version 12.60. (Other versions are
8
8
  considered development releases, and are not uploaded to MetaCPAN.)
9
9
 
10
+ Apr. 24, 2023 - Version 12.61
11
+
12
+ - Added ImageDataMD5 support for J2C and JXL images
13
+ - Added support for PDF 2.0 (specification is finally freely available)
14
+ - Added ability to extract timed Accelerometer data from Azdome GS63H MP4
15
+ videos which don't contain GPS
16
+ - Added some new Sony lenses (thanks Jos Roost)
17
+ - Decode some new tags for the Sony ZV-E1 (thanks Jos Roost)
18
+ - Decode more tags for the Nikon Z30 (thanks Xavier)
19
+ - Enhanced -fileNUM option to allow tags from the main file to be used in the
20
+ file name string
21
+ - Validate sample offset and size when calculating ImageDataMD5 for MP4 videos
22
+ (note: may change ImageDataMD5 value for videos where audio data runs past
23
+ end of media data)
24
+ - Return error when attempting to write a fragmented JXL file
25
+ - Improved robustness for determining image size for corrupted JPEG
26
+ - Patched to allow Insta360 GPS records of unexpected length and tweaked
27
+ verification algorithm to determine validity of these records
28
+ - Fixed bug introduced in 12.57 where -progress:%f gave runtime warnings
29
+ - Fixed "--" option to ignore subsequent -common_args option
30
+ - Fixed incorrect ImageDataMD5 for Sony A100 ARW images
31
+ - Fixed problem reading new XMP-et:OriginalImageMD5 tag
32
+
10
33
  Apr. 5, 2023 - Version 12.60 (production release)
11
34
 
12
35
  - Added a new Sony FileFormat value
data/bin/META.json CHANGED
@@ -47,5 +47,5 @@
47
47
  }
48
48
  },
49
49
  "release_status" : "stable",
50
- "version" : "12.60"
50
+ "version" : "12.61"
51
51
  }
data/bin/META.yml CHANGED
@@ -28,4 +28,4 @@ recommends:
28
28
  Time::HiRes: 0
29
29
  requires:
30
30
  perl: 5.004
31
- version: 12.60
31
+ version: 12.61
data/bin/README CHANGED
@@ -107,8 +107,8 @@ your home directory, then you would type the following commands in a
107
107
  terminal window to extract and run ExifTool:
108
108
 
109
109
  cd ~/Desktop
110
- gzip -dc Image-ExifTool-12.60.tar.gz | tar -xf -
111
- cd Image-ExifTool-12.60
110
+ gzip -dc Image-ExifTool-12.61.tar.gz | tar -xf -
111
+ cd Image-ExifTool-12.61
112
112
  ./exiftool t/images/ExifTool.jpg
113
113
 
114
114
  Note: These commands extract meta information from one of the test images.
data/bin/exiftool CHANGED
@@ -11,7 +11,7 @@ use strict;
11
11
  use warnings;
12
12
  require 5.004;
13
13
 
14
- my $version = '12.60';
14
+ my $version = '12.61';
15
15
 
16
16
  # add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
17
17
  BEGIN {
@@ -365,13 +365,14 @@ sub Cleanup() {
365
365
 
366
366
  # isolate arguments common to all commands
367
367
  if (grep /^-common_args$/i, @ARGV) {
368
- my (@newArgs, $common);
368
+ my (@newArgs, $common, $end);
369
369
  foreach (@ARGV) {
370
- if (/^-common_args$/i) {
370
+ if (/^-common_args$/i and not $end) {
371
371
  $common = 1;
372
372
  } elsif ($common) {
373
373
  push @commonArgs, $_;
374
374
  } else {
375
+ $end = 1 if $_ eq '--';
375
376
  push @newArgs, $_;
376
377
  }
377
378
  }
@@ -1951,23 +1952,31 @@ sub GetImageInfo($$)
1951
1952
  my (@foundTags, $info, $file, $ind, $g8);
1952
1953
 
1953
1954
  # set window title for this file if necessary
1954
- if (defined $windowTitle and $progressCount >= $progressNext) {
1955
- my $prog = $progressMax ? "$progressCount/$progressMax" : '0/0';
1956
- my $title = $windowTitle;
1957
- my ($num, $denom) = split '/', $prog;
1958
- my $frac = $num / ($denom || 1);
1959
- my $n = $title =~ s/%(\d+)b/%b/ ? $1 : 20; # length of bar
1960
- my $bar = int($frac * $n + 0.5);
1961
- my %lkup = (
1962
- b => ('I' x $bar) . ('.' x ($n - $bar)), # (undocumented)
1963
- f => $orig,
1964
- p => int(100 * $frac + 0.5),
1965
- r => $prog,
1966
- '%'=> '%',
1967
- );
1968
- $title =~ s/%([%bfpr])/$lkup{$1}/eg;
1969
- SetWindowTitle($title);
1970
- undef $progressNext;
1955
+ if (defined $windowTitle) {
1956
+ if ($progressCount >= $progressNext) {
1957
+ my $prog = $progressMax ? "$progressCount/$progressMax" : '0/0';
1958
+ my $title = $windowTitle;
1959
+ my ($num, $denom) = split '/', $prog;
1960
+ my $frac = $num / ($denom || 1);
1961
+ my $n = $title =~ s/%(\d+)b/%b/ ? $1 : 20; # length of bar
1962
+ my $bar = int($frac * $n + 0.5);
1963
+ my %lkup = (
1964
+ b => ('I' x $bar) . ('.' x ($n - $bar)),
1965
+ f => $orig,
1966
+ p => int(100 * $frac + 0.5),
1967
+ r => $prog,
1968
+ '%'=> '%',
1969
+ );
1970
+ $title =~ s/%([%bfpr])/$lkup{$1}/eg;
1971
+ SetWindowTitle($title);
1972
+ if (defined $progressMax) {
1973
+ undef $progressNext;
1974
+ } else {
1975
+ $progressNext += $progressIncr;
1976
+ }
1977
+ }
1978
+ # ($progressMax is not defined for "-progress:%f")
1979
+ ++$progressCount unless defined $progressMax;
1971
1980
  }
1972
1981
  unless (length $orig or $outOpt) {
1973
1982
  Warn qq(Error: Zero-length file name - ""\n);
@@ -1993,7 +2002,11 @@ sub GetImageInfo($$)
1993
2002
  }
1994
2003
  # set alternate file names
1995
2004
  foreach $g8 (sort keys %altFile) {
1996
- my $altName = FilenameSPrintf($altFile{$g8}, $orig);
2005
+ my $altName = $orig;
2006
+ # must double any '$' symbols in the original file name because
2007
+ # they are used for tag names in a -fileNUM argument
2008
+ $altName =~ s/\$/\$\$/g;
2009
+ $altName = FilenameSPrintf($altFile{$g8}, $altName);
1997
2010
  $et->SetAlternateFile($g8, $altName);
1998
2011
  }
1999
2012
 
@@ -2536,6 +2549,7 @@ TAG: foreach $tag (@foundTags) {
2536
2549
  $xtra .= " et:table='${table}'";
2537
2550
  $xtra .= " et:index='${index}'" if defined $index;
2538
2551
  }
2552
+ # Note: New $xtra attributes must be added to %ignoreEtProp in XMP.pm!
2539
2553
  my $lastVal = $val;
2540
2554
  for ($valNum=0; $valNum<2; ++$valNum) {
2541
2555
  $val = FormatXML($val, $ind, $group);
@@ -3700,7 +3714,7 @@ sub ProcessFiles($;$)
3700
3714
  if (defined $progressMax) {
3701
3715
  unless (defined $progressNext) {
3702
3716
  $progressNext = $progressCount + $progressIncr;
3703
- $progressNext -= $progressNext % $progressIncr;
3717
+ $progressNext -= $progressNext % $progressIncr; # (show even multiples)
3704
3718
  $progressNext = $progressMax if $progressNext > $progressMax;
3705
3719
  }
3706
3720
  ++$progressCount;
@@ -4479,7 +4493,7 @@ sub Progress($$)
4479
4493
  my ($file, $msg) = @_;
4480
4494
  if (defined $progStr) {
4481
4495
  print $file $msg, $progStr, "\n";
4482
- undef $progressNext;
4496
+ undef $progressNext if defined $progressMax;
4483
4497
  }
4484
4498
  }
4485
4499
 
@@ -4669,7 +4683,7 @@ L<Tag operations|/Tag operations>
4669
4683
  -TAG or --TAG Extract or exclude specified tag
4670
4684
  -TAG[+-^]=[VALUE] Write new value for tag
4671
4685
  -TAG[+-]<=DATFILE Write tag value from contents of file
4672
- -TAG[+-]<SRCTAG Copy tag value (see -tagsFromFile)
4686
+ -[+]TAG[+-]<SRCTAG Copy tag value (see -tagsFromFile)
4673
4687
 
4674
4688
  -tagsFromFile SRCFILE Copy tag values from file
4675
4689
  -x TAG (-exclude) Exclude specified tag
@@ -5541,7 +5555,7 @@ with this command:
5541
5555
 
5542
5556
  produces output like this:
5543
5557
 
5544
- -- Generated by ExifTool 12.60 --
5558
+ -- Generated by ExifTool 12.61 --
5545
5559
  File: a.jpg - 2003:10:31 15:44:19
5546
5560
  (f/5.6, 1/60s, ISO 100)
5547
5561
  File: b.jpg - 2006:05:23 11:57:38
@@ -6544,11 +6558,22 @@ option no longer suppresses the output "{readyNUM}" message.
6544
6558
 
6545
6559
  =item B<-file>I<NUM> I<ALTFILE>
6546
6560
 
6547
- Read tags from an alternate source file. These tags are accessed via the
6561
+ Read tags from an alternate source file. Among other things, this allows
6562
+ tags from different files to be compared and combined using the B<-if> and
6563
+ B<-p> options. Tags from alternate files are accessed via the corresponding
6548
6564
  family 8 group name (eg. C<File1:TAG> for the B<-file1> option, C<File2:TAG>
6549
- for B<-file2>, etc). I<ALTFILE> may contain filename formatting codes %d,
6550
- %f and %e. Among other things, this allows tags from different files to be
6551
- compared and combined using the B<-if> and B<-p> options.
6565
+ for B<-file2>, etc). I<ALTFILE> may contain filename formatting codes like
6566
+ the B<-w> option (%d, %f, etc) , and/or tag names with a leading C<$> symbol
6567
+ in the same way as the B<-p> option (so any other dollar symbol in the file
6568
+ name must be doubled, eg. C<money$$.jpg>). For example, assuming that the
6569
+ OriginalFileName tag has been set in the edited file, a command to copy
6570
+ Rights from the original file could look like this:
6571
+
6572
+ exiftool -file1 '$originalfilename' '-rights<file1:rights' edited.jpg
6573
+
6574
+ Tag names in a B<-fileNUM> argument may access any tag from the original
6575
+ file except for Composite tags, and any tag from earlier (alphabetically
6576
+ sorted) B<-fileNUM> options (including Composite tags).
6552
6577
 
6553
6578
  =item B<-list_dir>
6554
6579
 
@@ -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.33';
19
+ $VERSION = '1.34';
20
20
 
21
21
  sub ProcessJpeg2000Box($$$);
22
22
  sub ProcessJUMD($$$);
@@ -34,6 +34,9 @@ my %resolutionUnit = (
34
34
  6 => 'um',
35
35
  );
36
36
 
37
+ # top-level boxes containing image data
38
+ my %isImageData = ( jp2c=>1, jbrd=>1, jxlp=>1, jxlc=>1 );
39
+
37
40
  # map of where information is written in JPEG2000 image
38
41
  my %jp2Map = (
39
42
  IPTC => 'UUID-IPTC',
@@ -428,6 +431,7 @@ my %j2cMarker = (
428
431
  # stuff seen in JPEG XL images:
429
432
  #
430
433
  # jbrd - JPEG Bitstream Reconstruction Data (allows lossless conversion back to original JPG)
434
+ # jxlp - partial JXL codestream
431
435
  jxlc => {
432
436
  Name => 'JXLCodestream',
433
437
  Format => 'undef',
@@ -930,7 +934,7 @@ sub ProcessJpeg2000Box($$$)
930
934
  my $raf = $$dirInfo{RAF};
931
935
  my $outfile = $$dirInfo{OutFile};
932
936
  my $dirEnd = $dirStart + $dirLen;
933
- my ($err, $outBuff, $verbose, $doColour);
937
+ my ($err, $outBuff, $verbose, $doColour, $md5);
934
938
 
935
939
  if ($outfile) {
936
940
  unless ($raf) {
@@ -948,6 +952,8 @@ sub ProcessJpeg2000Box($$$)
948
952
  # (must not set verbose flag when writing!)
949
953
  $verbose = $$et{OPTIONS}{Verbose};
950
954
  $et->VerboseDir($$dirInfo{DirName}) if $verbose;
955
+ # do MD5 if requested, but only for top-level image data
956
+ $md5 = $$et{ImageDataMD5} if $raf;
951
957
  }
952
958
  # loop through all contained boxes
953
959
  my ($pos, $boxLen, $lastBox);
@@ -971,6 +977,11 @@ sub ProcessJpeg2000Box($$$)
971
977
  }
972
978
  $boxLen = unpack("x$pos N",$$dataPt); # (length includes header and data)
973
979
  $boxID = substr($$dataPt, $pos+4, 4);
980
+ # (ftbl box contains flst boxes with absolute file offsets, not currently handled)
981
+ if ($outfile and $boxID eq 'ftbl') {
982
+ $et->Error("Can't yet handle fragmented JPX files");
983
+ return -1;
984
+ }
974
985
  # remove old colr boxes if necessary
975
986
  if ($doColour and $boxID eq 'colr') {
976
987
  if ($doColour == 1) { # did we successfully write the new colr box?
@@ -1007,9 +1018,14 @@ sub ProcessJpeg2000Box($$$)
1007
1018
  while ($raf->Read($buff, 65536)) {
1008
1019
  Write($outfile, $buff) or $err = 1;
1009
1020
  }
1010
- } elsif ($verbose) {
1011
- my $msg = sprintf("offset 0x%.4x to end of file", $dataPos + $base + $pos);
1012
- $et->VPrint(0, "$$et{INDENT}- Tag '${boxID}' ($msg)\n");
1021
+ } else {
1022
+ if ($verbose) {
1023
+ my $msg = sprintf("offset 0x%.4x to end of file", $dataPos + $base + $pos);
1024
+ $et->VPrint(0, "$$et{INDENT}- Tag '${boxID}' ($msg)\n");
1025
+ }
1026
+ if ($md5 and $isImageData{$boxID}) {
1027
+ $et->ImageDataMD5($raf, undef, $boxID);
1028
+ }
1013
1029
  }
1014
1030
  last; # (ignore the rest of the file when reading)
1015
1031
  }
@@ -1026,6 +1042,8 @@ sub ProcessJpeg2000Box($$$)
1026
1042
  Write($outfile, $$dataPt) or $err = 1;
1027
1043
  $raf->Read($buff,$boxLen) == $boxLen or $err = '', last;
1028
1044
  Write($outfile, $buff) or $err = 1;
1045
+ } elsif ($md5 and $isImageData{$boxID}) {
1046
+ $et->ImageDataMD5($raf, $boxLen, $boxID);
1029
1047
  } else {
1030
1048
  $raf->Seek($boxLen, 1) or $err = 'Seek error', last;
1031
1049
  }
@@ -1038,6 +1056,10 @@ sub ProcessJpeg2000Box($$$)
1038
1056
  # read the box data
1039
1057
  $dataPos = $raf->Tell() - $base;
1040
1058
  $raf->Read($buff,$boxLen) == $boxLen or $err = '', last;
1059
+ if ($md5 and $isImageData{$boxID}) {
1060
+ $md5->add($buff);
1061
+ $et->VPrint(0, "$$et{INDENT}(ImageDataMD5: $boxLen bytes of $boxID data)\n");
1062
+ }
1041
1063
  $valuePtr = 0;
1042
1064
  $dataLen = $boxLen;
1043
1065
  } elsif ($pos + $boxLen > $dirEnd) {
@@ -1311,7 +1333,7 @@ sub ProcessJP2($$)
1311
1333
  }
1312
1334
 
1313
1335
  #------------------------------------------------------------------------------
1314
- # Read meta information from a JPEG XL image
1336
+ # Read/write meta information in a JPEG XL image
1315
1337
  # Inputs: 0) ExifTool object reference, 1) dirInfo reference
1316
1338
  # Returns: 1 on success, 0 if this wasn't a valid JPEG XL file, -1 on write error
1317
1339
  sub ProcessJXL($$)
@@ -1340,6 +1362,9 @@ sub ProcessJXL($$)
1340
1362
  $$dirInfo{RAF} = new File::RandomAccess(\$buff);
1341
1363
  } else {
1342
1364
  $et->SetFileType('JXL Codestream','image/jxl', 'jxl');
1365
+ if ($$et{ImageDataMD5} and $raf->Seek(0,0)) {
1366
+ $et->ImageDataMD5($raf, undef, 'JXL');
1367
+ }
1343
1368
  return ProcessJXLCodestream($et, \$hdr);
1344
1369
  }
1345
1370
  } else {
@@ -17,7 +17,7 @@ use vars qw($VERSION);
17
17
  use Image::ExifTool qw(:DataAccess :Utils);
18
18
  use Image::ExifTool::Minolta;
19
19
 
20
- $VERSION = '1.17';
20
+ $VERSION = '1.18';
21
21
 
22
22
  sub ProcessMRW($$;$);
23
23
  sub WriteMRW($$;$);
@@ -489,7 +489,7 @@ sub ProcessMRW($$;$)
489
489
  $err and $et->Error("MRW format error", $$et{TIFF_TYPE} eq 'ARW');
490
490
  } else {
491
491
  $err and $et->Warn("MRW format error");
492
- $et->ImageDataMD5($raf, undef, 'raw');
492
+ $et->ImageDataMD5($raf, undef, 'raw') unless $$et{A100DataOffset};
493
493
  }
494
494
  return $rtnVal;
495
495
  }
@@ -64,7 +64,7 @@ use Image::ExifTool::Exif;
64
64
  use Image::ExifTool::GPS;
65
65
  use Image::ExifTool::XMP;
66
66
 
67
- $VERSION = '4.21';
67
+ $VERSION = '4.22';
68
68
 
69
69
  sub LensIDConv($$$);
70
70
  sub ProcessNikonAVI($$$);
@@ -2300,8 +2300,8 @@ my %base64coord = (
2300
2300
  },
2301
2301
  },
2302
2302
  { # (Z6_2 firmware version 1.00 and Z7II firmware versions 1.00 & 1.01, ref 28)
2303
- # 0800=Z6/Z7 0801=Z50 0802=Z5 0803=Z6II/Z7II 0804=Zfc
2304
- Condition => '$$valPt =~ /^080[01234]/',
2303
+ # 0800=Z6/Z7 0801=Z50 0802=Z5 0803=Z6II/Z7II 0804=Zfc 0807=Z30
2304
+ Condition => '$$valPt =~ /^080[012347]/',
2305
2305
  Name => 'ShotInfoZ7II',
2306
2306
  SubDirectory => {
2307
2307
  TagTable => 'Image::ExifTool::Nikon::ShotInfoZ7II',
@@ -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.55';
24
+ $VERSION = '1.56';
25
25
 
26
26
  sub FetchObject($$$$);
27
27
  sub ExtractObject($$;$$);
@@ -41,7 +41,7 @@ my $cryptStream; # flag that streams are encrypted
41
41
  my $lastOffset; # last fetched object offset
42
42
  my %streamObjs; # hash of stream objects
43
43
  my %fetched; # dicts fetched in verbose mode (to avoid cyclical recursion)
44
- my $pdfVer; # version of PDF file being processed
44
+ my $pdfVer; # version of PDF file being processed (from header)
45
45
 
46
46
  # filters supported in DecodeStream()
47
47
  my %supportedFilter = (
@@ -115,6 +115,7 @@ my %supportedFilter = (
115
115
  CreationDate => {
116
116
  Name => 'CreateDate',
117
117
  Writable => 'date',
118
+ PDF2 => 1, # not deprecated in PDF 2.0
118
119
  Groups => { 2 => 'Time' },
119
120
  Shift => 'Time',
120
121
  PrintConv => '$self->ConvertDateTime($val)',
@@ -123,6 +124,7 @@ my %supportedFilter = (
123
124
  ModDate => {
124
125
  Name => 'ModifyDate',
125
126
  Writable => 'date',
127
+ PDF2 => 1, # not deprecated in PDF 2.0
126
128
  Groups => { 2 => 'Time' },
127
129
  Shift => 'Time',
128
130
  PrintConv => '$self->ConvertDateTime($val)',
@@ -168,7 +170,10 @@ my %supportedFilter = (
168
170
  Lang => 'Language',
169
171
  PageLayout => { },
170
172
  PageMode => { },
171
- Version => 'PDFVersion',
173
+ Version => {
174
+ Name => 'PDFVersion',
175
+ RawConv => '$$self{PDFVersion} = $val if $$self{PDFVersion} < $val; $val',
176
+ },
172
177
  );
173
178
 
174
179
  # tags extracted from the PDF Encrypt dictionary
@@ -1754,7 +1759,7 @@ sub ProcessDict($$$$;$$)
1754
1759
  my $unknown = $$tagTablePtr{EXTRACT_UNKNOWN};
1755
1760
  my $embedded = (defined $unknown and not $unknown and $et->Options('ExtractEmbedded'));
1756
1761
  my @tags = @{$$dict{_tags}};
1757
- my ($next, %join);
1762
+ my ($next, %join, $validInfo);
1758
1763
  my $index = 0;
1759
1764
 
1760
1765
  $nesting = ($nesting || 0) + 1;
@@ -1775,6 +1780,7 @@ sub ProcessDict($$$$;$$)
1775
1780
  last;
1776
1781
  }
1777
1782
  }
1783
+ $validInfo = ($et->Options('Validate') and $tagTablePtr eq \%Image::ExifTool::PDF::Info);
1778
1784
  #
1779
1785
  # extract information from all tags in the dictionary
1780
1786
  #
@@ -1810,6 +1816,10 @@ sub ProcessDict($$$$;$$)
1810
1816
  $isSubDoc = 1; # treat as a sub-document
1811
1817
  }
1812
1818
  }
1819
+ if ($validInfo and $$et{PDFVersion} >= 2.0 and (not $tagInfo or not $$tagInfo{PDF2})) {
1820
+ my $name = $tagInfo ? ":$$tagInfo{Name}" : " Info tag '${tag}'";
1821
+ $et->Warn("PDF$name is deprecated in PDF 2.0");
1822
+ }
1813
1823
  if ($verbose) {
1814
1824
  my ($val2, $extra);
1815
1825
  if (ref $val eq 'SCALAR') {
@@ -2118,9 +2128,8 @@ sub ReadPDF($$)
2118
2128
  $raf->Read($buff, 1024) >= 8 or return 0;
2119
2129
  $buff =~ /^(\s*)%PDF-(\d+\.\d+)/ or return 0;
2120
2130
  $$et{PDFBase} = length $1 and $et->Warn('PDF header is not at start of file',1);
2121
- $pdfVer = $2;
2131
+ $pdfVer = $$et{PDFVersion} = $2;
2122
2132
  $et->SetFileType(); # set the FileType tag
2123
- $et->Warn("The PDF $pdfVer specification is held hostage by the ISO") if $pdfVer >= 2.0;
2124
2133
  # store PDFVersion tag
2125
2134
  my $tagTablePtr = GetTagTable('Image::ExifTool::PDF::Root');
2126
2135
  $et->HandleTag($tagTablePtr, 'Version', $pdfVer);
@@ -28,7 +28,7 @@ sub Process360Fly($$$);
28
28
  sub ProcessFMAS($$$);
29
29
  sub ProcessCAMM($$$);
30
30
 
31
- my $debug; # set to 1 for extra debugging messages
31
+ my $debug; # set to 'tEST' (all caps) for extra debugging messages
32
32
 
33
33
  # QuickTime data types that have ExifTool equivalents
34
34
  # (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35)
@@ -89,6 +89,7 @@ my %insvDataLen = (
89
89
  0x600 => 8, # timestamps (ref 6)
90
90
  0x700 => 53, # GPS
91
91
  # 0x900 => 48, # ? (Insta360 X3)
92
+ # 0xa00 => 5?, # ? (Insta360 ONE RS)
92
93
  # 0xb00 => 10, # ? (Insta360 X3)
93
94
  );
94
95
 
@@ -1134,6 +1135,7 @@ sub ProcessSamples($)
1134
1135
  my $et = shift;
1135
1136
  my ($raf, $ee) = @$et{qw(RAF ee)};
1136
1137
  my ($i, $buff, $pos, $hdrLen, $hdrFmt, @time, @dur, $oldIndent, $md5);
1138
+ my ($mdatOffset, $mdatSize); # (for range-checking samples when MD5 is done)
1137
1139
 
1138
1140
  return unless $ee;
1139
1141
  delete $$et{ee}; # use only once
@@ -1230,6 +1232,10 @@ Sample: for ($i=0; ; ) {
1230
1232
  $oldIndent = $$et{INDENT};
1231
1233
  $$et{INDENT} = '';
1232
1234
  }
1235
+ if ($md5) {
1236
+ $mdatSize = $$et{MediaDataSize};
1237
+ $mdatOffset = $$et{MediaDataOffset} if defined $mdatSize;
1238
+ }
1233
1239
  # get required information from avcC box if parsing video data
1234
1240
  if ($type eq 'avcC') {
1235
1241
  $hdrLen = (Get8u(\$$ee{avcC}, 4) & 0x03) + 1;
@@ -1243,10 +1249,25 @@ Sample: for ($i=0; ; ) {
1243
1249
  delete $$et{FoundGPSLatitude};
1244
1250
  delete $$et{FoundGPSDateTime};
1245
1251
 
1246
- # read the sample data
1252
+ # range check the sample data for MD5 if necessary
1247
1253
  my $size = $$size[$i];
1248
- next unless $raf->Seek($$start[$i], 0) and $raf->Read($buff, $size) == $size;
1249
-
1254
+ if (defined $mdatOffset) {
1255
+ if ($$start[$i] < $mdatOffset) {
1256
+ $et->Warn("Sample $i for '${type}' data is before start of mdat");
1257
+ } elsif ($$start[$i] + $size > $mdatOffset + $mdatSize) {
1258
+ $et->Warn("Sample $i for '${type}' data runs off end of mdat");
1259
+ $size = $mdatOffset + $mdatSize - $$start[$i];
1260
+ $size = 0 if $size < 0;
1261
+ }
1262
+ }
1263
+ # read the sample data
1264
+ $raf->Seek($$start[$i], 0) or $et->WarnOnce("Seek error in $type data"), next;
1265
+ my $n = $raf->Read($buff, $size);
1266
+ unless ($n == $size) {
1267
+ $et->WarnOnce("Error reading $type data");
1268
+ next unless $n;
1269
+ $size = $n;
1270
+ }
1250
1271
  if ($md5) {
1251
1272
  $md5->add($buff);
1252
1273
  $md5size += length $buff;
@@ -1455,16 +1476,15 @@ sub ProcessFreeGPS($$$)
1455
1476
  $et->VerboseDump(\$buf2);
1456
1477
  }
1457
1478
  # (extract longitude as 9 digits, not 8, ref PH)
1458
- return 0 unless $buf2 =~ /^.{8}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).(.{15})([NS])(\d{8})([EW])(\d{9})(\d{8})?/s;
1459
- ($yr,$mon,$day,$hr,$min,$sec,$lbl,$latRef,$lat,$lonRef,$lon,$spd) = ($1,$2,$3,$4,$5,$6,$7,$8,$9/1e4,$10,$11/1e4,$12);
1460
- if (defined $spd) { # (Azdome)
1461
- $spd += 0; # remove leading 0's
1462
- } elsif ($buf2 =~ /^.{57}([-+]\d{4})(\d{3})/s) { # (EEEkit)
1463
- # $alt = $1 + 0; (doesn't look right for my sample, but the Ambarella A12 text has this)
1464
- $spd = $2 + 0;
1465
- }
1466
- $lbl =~ s/\0.*//s; $lbl =~ s/\s+$//; # truncate at null and remove trailing spaces
1467
- push @xtra, UserLabel => $lbl if length $lbl;
1479
+ if ($buf2 =~ /^.{8}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).(.{15})([NS])(\d{8})([EW])(\d{9})(\d{8})?/s) {
1480
+ ($yr,$mon,$day,$hr,$min,$sec,$lbl,$latRef,$lat,$lonRef,$lon,$spd) = ($1,$2,$3,$4,$5,$6,$7,$8,$9/1e4,$10,$11/1e4,$12);
1481
+ if (defined $spd) { # (Azdome)
1482
+ $spd += 0; # remove leading 0's
1483
+ } elsif ($buf2 =~ /^.{57}([-+]\d{4})(\d{3})/s) { # (EEEkit)
1484
+ # $alt = $1 + 0; (doesn't look right for my sample, but the Ambarella A12 text has this)
1485
+ $spd = $2 + 0;
1486
+ }
1487
+ }
1468
1488
  # extract accelerometer data (ref PH)
1469
1489
  if ($buf2 =~ /^.{65}(([-+]\d{3})([-+]\d{3})([-+]\d{3})([-+]\d{3})*)/s) {
1470
1490
  $_ = $1;
@@ -1472,7 +1492,15 @@ sub ProcessFreeGPS($$$)
1472
1492
  s/([-+])/ $1/g; s/^ //;
1473
1493
  push @xtra, AccelerometerData => $_;
1474
1494
  } elsif ($buf2 =~ /^.{173}([-+]\d{3})([-+]\d{3})([-+]\d{3})/s) { # (Azdome)
1495
+ # (Adzome may contain acc and date/time/label even if GPS doesn't exist)
1475
1496
  @acc = ($1/100, $2/100, $3/100);
1497
+ if (not defined $yr and $buf2 =~ /^.{8}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).(.{15})/s) {
1498
+ ($yr,$mon,$day,$hr,$min,$sec,$lbl) = ($1,$2,$3,$4,$5,$6,$7);
1499
+ }
1500
+ }
1501
+ if (defined $lbl) {
1502
+ $lbl =~ s/\0.*//s; $lbl =~ s/\s+$//; # truncate at null and remove trailing spaces
1503
+ push @xtra, UserLabel => $lbl if length $lbl;
1476
1504
  }
1477
1505
 
1478
1506
  } elsif ($$dataPt =~ /^.{52}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/s) {
@@ -1741,8 +1769,6 @@ sub ProcessFreeGPS($$$)
1741
1769
  # save tag values extracted by above code
1742
1770
  #
1743
1771
  FoundSomething($et, $tagTbl, $$dirInfo{SampleTime}, $$dirInfo{SampleDuration});
1744
- # lat/long are in DDDMM.MMMM format
1745
- ConvertLatLon($lat, $lon) unless $ddd;
1746
1772
  $sec = '0' . $sec unless $sec =~ /^\d{2}/; # pad integer part of seconds to 2 digits
1747
1773
  if (defined $yr) {
1748
1774
  my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%sZ',$yr,$mon,$day,$hr,$min,$sec);
@@ -1751,8 +1777,12 @@ sub ProcessFreeGPS($$$)
1751
1777
  my $time = sprintf('%.2d:%.2d:%sZ',$hr,$min,$sec);
1752
1778
  $et->HandleTag($tagTbl, GPSTimeStamp => $time);
1753
1779
  }
1754
- $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
1755
- $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
1780
+ if (defined $lat) {
1781
+ # lat/long are in DDDMM.MMMM format unless $ddd is set
1782
+ ConvertLatLon($lat, $lon) unless $ddd;
1783
+ $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1));
1784
+ $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1));
1785
+ }
1756
1786
  $et->HandleTag($tagTbl, GPSAltitude => $alt) if defined $alt;
1757
1787
  $et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd;
1758
1788
  $et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk;
@@ -2835,7 +2865,7 @@ sub ProcessInsta360($;$)
2835
2865
  $raf->Read($buff, $len) == $len or last;
2836
2866
  $et->VerboseDump(\$buff) if $verbose > 2;
2837
2867
  if ($dlen) {
2838
- if ($len % $dlen) {
2868
+ if ($len % $dlen and $id != 0x700) { # (have seen one 0x700 record which was expected format but not multiple of 53 bytes)
2839
2869
  $et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id));
2840
2870
  } elsif ($id == 0x200) {
2841
2871
  $et->FoundTag(PreviewImage => $buff);
@@ -2865,10 +2895,9 @@ sub ProcessInsta360($;$)
2865
2895
  $et->HandleTag($tagTbl, VideoTimeStamp => sprintf('%.3f', Get64u(\$buff, $p) / 1000));
2866
2896
  }
2867
2897
  } elsif ($id == 0x700) {
2868
- for ($p=0; $p<$len; $p+=$dlen) {
2898
+ for ($p=0; $p+$dlen<=$len; $p+=$dlen) {
2869
2899
  my $tmp = substr($buff, $p, $dlen);
2870
2900
  my @a = unpack('VVvaa8aa8aa8a8a8', $tmp);
2871
- next unless $a[3] eq 'A'; # (ignore void fixes)
2872
2901
  unless (($a[5] eq 'N' or $a[5] eq 'S') and # (quick validation)
2873
2902
  ($a[7] eq 'E' or $a[7] eq 'W' or
2874
2903
  # (odd, but I've seen "O" instead of "W". Perhaps
@@ -2878,6 +2907,7 @@ sub ProcessInsta360($;$)
2878
2907
  $et->Warn('Unrecognized INSV GPS format');
2879
2908
  last;
2880
2909
  }
2910
+ next unless $a[3] eq 'A'; # (ignore void fixes)
2881
2911
  $$et{DOC_NUM} = ++$$et{DOC_COUNT};
2882
2912
  $a[$_] = GetDouble(\$a[$_], 0) foreach 4,6,8,9,10;
2883
2913
  $a[4] = -abs($a[4]) if $a[5] eq 'S'; # (abs just in case it was already signed)
@@ -34,7 +34,7 @@ use Image::ExifTool qw(:DataAccess :Utils);
34
34
  use Image::ExifTool::Exif;
35
35
  use Image::ExifTool::Minolta;
36
36
 
37
- $VERSION = '3.59';
37
+ $VERSION = '3.60';
38
38
 
39
39
  sub ProcessSRF($$$);
40
40
  sub ProcessSR2($$$);
@@ -161,6 +161,7 @@ sub PrintInvLensSpec($;$$);
161
161
  32876 => 'Sony E 11mm F1.8', #JR
162
162
  32877 => 'Sony E 15mm F1.4 G', #JR
163
163
  32878 => 'Sony FE 20-70mm F4 G', #JR
164
+ 32879 => 'Sony FE 50mm F1.4 GM', #JR
164
165
 
165
166
  # (comment this out so LensID will report the LensModel, which is more useful)
166
167
  # 32952 => 'Metabones Canon EF Speed Booster Ultra', #JR (corresponds to 184, but 'Advanced' mode, LensMount reported as E-mount)
@@ -259,7 +260,10 @@ sub PrintInvLensSpec($;$$);
259
260
  50534 => 'Sigma 20mm F1.4 DG DN | A', #JR (022)
260
261
  50535 => 'Sigma 24mm F1.4 DG DN | A', #JR (022)
261
262
  50536 => 'Sigma 60-600mm F4.5-6.3 DG DN OS | S', #JR (023)
263
+ 50537 => 'Sigma 50mm F2 DG DN | C', #JR (023)
264
+ 50538 => 'Sigma 17mm F4 DG DN | C', #JR (023)
262
265
  50539 => 'Sigma 50mm F1.4 DG DN | A', #JR (023)
266
+ 50544 => 'Sigma 23mm F1.4 DC DN | C', #JR (023)
263
267
 
264
268
  50992 => 'Voigtlander SUPER WIDE-HELIAR 15mm F4.5 III', #JR
265
269
  50993 => 'Voigtlander HELIAR-HYPER WIDE 10mm F5.6', #IB
@@ -1165,7 +1169,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1165
1169
  },
1166
1170
  },{
1167
1171
  Name => 'AFAreaModeSetting',
1168
- Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2))/',
1172
+ Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|ZV-E|DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2))/',
1169
1173
  Notes => 'NEX, ILCE and some DSC models',
1170
1174
  RawConv => '$$self{AFAreaILCE} = $val',
1171
1175
  DataMember => 'AFAreaILCE',
@@ -1201,7 +1205,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1201
1205
  # observed values in range (0 0) to (640 480), with center (320 240) often seen
1202
1206
  # for NEX-5R/6, positions appear to be in an 11x9 grid
1203
1207
  Name => 'FlexibleSpotPosition',
1204
- Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2))/',
1208
+ Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|ZV-E|DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2))/',
1205
1209
  Writable => 'int16u',
1206
1210
  Count => 2,
1207
1211
  Notes => q{
@@ -1669,6 +1673,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1669
1673
  # 0x28 (e) for ILCE-7RM4/9M2, DSC-RX100M7, ZV-1/E10
1670
1674
  # 0x31 (e) for ILCE-1/7M4/7SM3, ILME-FX3
1671
1675
  # 0x32 (e) for ILCE-7RM5, ILME-FX30
1676
+ # 0x33 (e) for ZV-E1
1672
1677
  # first byte decoded: 40, 204, 202, 27, 58, 62, 48, 215, 28, 106, 89 respectively
1673
1678
  {
1674
1679
  Name => 'Tag9400a',
@@ -1683,7 +1688,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1683
1688
  SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9400b' },
1684
1689
  },{
1685
1690
  Name => 'Tag9400c',
1686
- Condition => '$$valPt =~ /^[\x23\x24\x26\x28\x31\x32]/',
1691
+ Condition => '$$valPt =~ /^[\x23\x24\x26\x28\x31\x32\x33]/',
1687
1692
  SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9400c' },
1688
1693
  },{
1689
1694
  Name => 'Sony_0x9400',
@@ -1896,7 +1901,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
1896
1901
  },
1897
1902
  0x940c => [{
1898
1903
  Name => 'Tag940c',
1899
- Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|Lunar|ZV-E10)\b/',
1904
+ Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|Lunar|ZV-E10|ZV-E1)\b/',
1900
1905
  SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag940c' },
1901
1906
  },{
1902
1907
  Name => 'Sony_0x940c',
@@ -2064,6 +2069,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 );
2064
2069
  389 => 'ZV-1F', #IB
2065
2070
  390 => 'ILCE-7RM5', #IB
2066
2071
  391 => 'ILME-FX30', #JR
2072
+ 393 => 'ZV-E1', #JR
2067
2073
  },
2068
2074
  },
2069
2075
  0xb020 => { #2
@@ -8238,7 +8244,7 @@ my %isoSetting2010 = (
8238
8244
  },
8239
8245
  0x002a => [{
8240
8246
  Name => 'Quality2',
8241
- Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-FX3)\b/',
8247
+ Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-(FX3|FX30)|ZV-E1)\b/',
8242
8248
  PrintConv => {
8243
8249
  0 => 'JPEG',
8244
8250
  1 => 'RAW',
@@ -8247,7 +8253,6 @@ my %isoSetting2010 = (
8247
8253
  },
8248
8254
  },{
8249
8255
  Name => 'Quality2',
8250
- Condition => '$$self{Model} =~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-FX3)\b/',
8251
8256
  PrintConv => {
8252
8257
  1 => 'JPEG',
8253
8258
  2 => 'RAW',
@@ -8258,13 +8263,13 @@ my %isoSetting2010 = (
8258
8263
  }],
8259
8264
  0x0047 => {
8260
8265
  Name => 'SonyImageHeight',
8261
- Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-FX3)\b/',
8266
+ Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-(FX3|FX30)|ZV-E1)\b/',
8262
8267
  Format => 'int16u',
8263
8268
  PrintConv => '$val > 0 ? 8*$val : "n.a."',
8264
8269
  },
8265
8270
  0x0053 => {
8266
8271
  Name => 'ModelReleaseYear',
8267
- Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-FX3)\b/',
8272
+ Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7RM5|7SM3)|ILME-(FX3|FX30)|ZV-E1)\b/',
8268
8273
  Format => 'int8u',
8269
8274
  PrintConv => 'sprintf("20%.2d", $val)',
8270
8275
  },
@@ -8279,9 +8284,10 @@ my %isoSetting2010 = (
8279
8284
  FIRST_ENTRY => 0,
8280
8285
  GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
8281
8286
  DATAMEMBER => [ 0 ],
8282
- IS_SUBDIR => [ 0x044e, 0x0498, 0x049d, 0x04a1, 0x04a2, 0x059d, 0x0634, 0x0636, 0x064c, 0x0653, 0x0678, 0x06b8, 0x06de, 0x06e7 ],
8287
+ IS_SUBDIR => [ 0x03e2, 0x044e, 0x0498, 0x049d, 0x04a1, 0x04a2, 0x059d, 0x0634, 0x0636, 0x064c, 0x0653, 0x0678, 0x06b8, 0x06de, 0x06e7 ],
8283
8288
  0x0000 => { Name => 'Ver9401', Hidden => 1, RawConv => '$$self{Ver9401} = $val; $$self{OPTIONS}{Unknown}<2 ? undef : $val' },
8284
8289
 
8290
+ 0x03e2 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 181', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } },
8285
8291
  0x044e => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 178', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } },
8286
8292
  0x0498 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 148', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } },
8287
8293
  0x049d => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 167', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } },
@@ -20827,6 +20827,7 @@ WX350/WX500, ILCE-1/7/7C/7R/7S/7M2/7M3/7RM2/7RM3/7RM4/7SM2/7SM3/9/9M2/5000/
20827
20827
 
20828
20828
  Index1 Tag Name Writable
20829
20829
  ------ -------- --------
20830
+ 994 ISOInfo Sony ISOInfo
20830
20831
  1102 ISOInfo Sony ISOInfo
20831
20832
  1176 ISOInfo Sony ISOInfo
20832
20833
  1181 ISOInfo Sony ISOInfo
@@ -23,7 +23,7 @@ my $beginComment = '%BeginExifToolUpdate';
23
23
  my $endComment = '%EndExifToolUpdate ';
24
24
 
25
25
  my $keyExt; # crypt key extension
26
- my $pdfVer; # version of PDF file we are currently writing
26
+ my $pdfVer; # version of PDF file we are writing (highest Version in Root dictionaries)
27
27
 
28
28
  # internal tags used in dictionary objects
29
29
  my %myDictTags = (
@@ -297,15 +297,11 @@ sub WritePDF($$)
297
297
  $$newTool{PDF_CAPTURE} = \%capture;
298
298
  my $info = $newTool->ImageInfo($raf, 'XMP', 'PDF:*', 'Error', 'Warning');
299
299
  # not a valid PDF file unless we got a version number
300
- # (note: can't just check $$info{PDFVersion} due to possibility of XMP-pdf:PDFVersion)
301
- my $vers = $newTool->GetInfo('PDF:PDFVersion');
302
- # take highest version number if multiple versions in an incremental save
303
- ($pdfVer) = sort { $b <=> $a } values %$vers;
300
+ $pdfVer = $$newTool{PDFVersion};
304
301
  $pdfVer or $et->Error('Missing PDF:PDFVersion'), return 0;
305
302
  # check version number
306
- if ($pdfVer > 1.7) {
307
- $et->Warn("The PDF $pdfVer specification is not freely available", 1);
308
- # (so writing by ExifTool is based on trial and error)
303
+ if ($pdfVer > 2.0) {
304
+ $et->Error("Writing PDF $pdfVer is untested", 1) and return 0;
309
305
  }
310
306
  # fail if we had any serious errors while extracting information
311
307
  if ($capture{Error} or $$info{Error}) {
@@ -412,6 +408,9 @@ sub WritePDF($$)
412
408
  my $tagID;
413
409
  foreach $tagID (sort keys %$newTags) {
414
410
  my $tagInfo = $$newTags{$tagID};
411
+ if ($pdfVer >= 2.0 and not $$tagInfo{PDF2}) {
412
+ next if $et->Warn("Writing PDF:$$tagInfo{Name} is deprecated for PDF 2.0 documents",2);
413
+ }
415
414
  my $nvHash = $et->GetNewValueHash($tagInfo);
416
415
  my (@vals, $deleted);
417
416
  my $tag = $$tagInfo{Name};
@@ -248,7 +248,11 @@ my %boolConv = (
248
248
 
249
249
  # XMP namespaces which we don't want to contribute to generated EXIF tag names
250
250
  # (Note: namespaces with non-standard prefixes aren't currently ignored)
251
- my %ignoreNamespace = ( 'x'=>1, rdf=>1, xmlns=>1, xml=>1, svg=>1, et=>1, office=>1 );
251
+ my %ignoreNamespace = ( 'x'=>1, rdf=>1, xmlns=>1, xml=>1, svg=>1, office=>1 );
252
+
253
+ # ExifTool properties that don't generate tag names (et:tagid is historic)
254
+ my %ignoreEtProp = ( 'et:desc'=>1, 'et:prt'=>1, 'et:val'=>1 , 'et:id'=>1, 'et:tagid'=>1,
255
+ 'et:toolkit'=>1, 'et:table'=>1, 'et:index'=>1 );
252
256
 
253
257
  # XMP properties to ignore (set dynamically via dirInfo IgnoreProp)
254
258
  my %ignoreProp;
@@ -2850,7 +2854,7 @@ sub GetXMPTagID($;$$)
2850
2854
  # split name into namespace and property name
2851
2855
  # (Note: namespace can be '' for property qualifiers)
2852
2856
  my ($ns, $nm) = ($prop =~ /(.*?):(.*)/) ? ($1, $2) : ('', $prop);
2853
- if ($ignoreNamespace{$ns} or $ignoreProp{$prop}) {
2857
+ if ($ignoreNamespace{$ns} or $ignoreProp{$prop} or $ignoreEtProp{$prop}) {
2854
2858
  # special case: don't ignore rdf numbered items
2855
2859
  # (not technically allowed in XMP, but used in RDF/XML)
2856
2860
  unless ($prop =~ /^rdf:(_\d+)$/) {
@@ -3420,7 +3424,10 @@ NoLoop:
3420
3424
  my %grps = ( 0 => $1, 1 => $2 );
3421
3425
  # apply a little magic to recover original group names
3422
3426
  # from this exiftool-written RDF/XML file
3423
- if ($grps{1} =~ /^\d/) {
3427
+ if ($grps{1} eq 'System') {
3428
+ $grps{1} = 'XML-System';
3429
+ $grps{0} = 'XML';
3430
+ } elsif ($grps{1} =~ /^\d/) {
3424
3431
  # URI's with only family 0 are internal tags from the source file,
3425
3432
  # so change the group name to avoid confusion with tags from this file
3426
3433
  $grps{1} = "XML-$grps{0}";
@@ -3888,7 +3895,9 @@ sub ParseXMPElement($$$;$$$$)
3888
3895
  }
3889
3896
  }
3890
3897
  my $shortVal = $attrs{$shortName};
3891
- if ($ignoreNamespace{$ns} or $ignoreProp{$prop}) {
3898
+ # Note: $prop is the containing property in this loop (not the shorthand property)
3899
+ # so $ignoreProp ignores all attributes of the ignored property
3900
+ if ($ignoreNamespace{$ns} or $ignoreProp{$prop} or $ignoreEtProp{$propName}) {
3892
3901
  $ignored = $propName;
3893
3902
  # handle special attributes (extract as tags only once if not empty)
3894
3903
  if (ref $recognizedAttrs{$propName} and $shortVal) {
@@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
29
29
  %jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
30
30
  %static_vars);
31
31
 
32
- $VERSION = '12.60';
32
+ $VERSION = '12.61';
33
33
  $RELEASE = '';
34
34
  @ISA = qw(Exporter);
35
35
  %EXPORT_TAGS = (
@@ -1826,10 +1826,10 @@ my %systemTagsNotes = (
1826
1826
  ImageDataMD5 => {
1827
1827
  Notes => q{
1828
1828
  MD5 of image data. Generated only if specifically requested for JPEG and
1829
- TIFF-based images, PNG, CRW, CR3, MRW, RAF, X3F and AVIF images, MOV/MP4
1830
- videos, and some RIFF-based files. The MD5 includes the main image data,
1831
- plus JpgFromRaw/OtherImage for some formats, but does not include
1832
- ThumbnailImage or PreviewImage. Includes video and audio data for MOV/MP4.
1829
+ TIFF-based images, PNG, CRW, CR3, MRW, RAF, X3F, JP2, JXL and AVIF images,
1830
+ MOV/MP4 videos, and some RIFF-based files. The MD5 includes the main image
1831
+ data, plus JpgFromRaw/OtherImage for some formats, but does not include
1832
+ ThumbnailImage or PreviewImage. Includes video and audio data for MOV/MP4.
1833
1833
  The L<XMP-et:OriginalImageMD5 tag|XMP.html#ExifTool> provides a place to
1834
1834
  store these values in the file.
1835
1835
  },
@@ -2503,23 +2503,6 @@ sub ExtractInfo($;@)
2503
2503
  }
2504
2504
  }
2505
2505
  ++$$self{FILE_SEQUENCE}; # count files read
2506
- # extract information from alternate files if necessary
2507
- my ($g8, $altExifTool);
2508
- foreach $g8 (keys %{$$self{ALT_EXIFTOOL}}) {
2509
- $altExifTool = $$self{ALT_EXIFTOOL}{$g8};
2510
- next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
2511
- $$altExifTool{OPTIONS} = $$self{OPTIONS};
2512
- $$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
2513
- $$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
2514
- $altExifTool->ExtractInfo($$altExifTool{ALT_FILE});
2515
- # set family 8 group name for all tags
2516
- foreach (keys %{$$altExifTool{VALUE}}) {
2517
- my $ex = $$altExifTool{TAG_EXTRA}{$_};
2518
- $ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
2519
- $$ex{G8} = $g8;
2520
- }
2521
- $$altExifTool{DID_EXTRACT} = 1;
2522
- }
2523
2506
  }
2524
2507
 
2525
2508
  my $filename = $$self{FILENAME}; # image file name ('' if already open)
@@ -2661,6 +2644,7 @@ sub ExtractInfo($;@)
2661
2644
  if ($isDir or (defined $stat[2] and ($stat[2] & 0170000) == 0040000)) {
2662
2645
  $self->FoundTag('FileType', 'DIR');
2663
2646
  $self->FoundTag('FileTypeExtension', '');
2647
+ $self->ExtractAltInfo();
2664
2648
  $self->BuildCompositeTags() if $$options{Composite};
2665
2649
  $raf->Close() if $raf;
2666
2650
  return 1;
@@ -2679,6 +2663,7 @@ sub ExtractInfo($;@)
2679
2663
  } else {
2680
2664
  $self->Error('Unknown file type');
2681
2665
  }
2666
+ $self->ExtractAltInfo();
2682
2667
  $self->BuildCompositeTags() if $fast == 4 and $$options{Composite};
2683
2668
  last; # don't read the file
2684
2669
  }
@@ -2845,6 +2830,7 @@ sub ExtractInfo($;@)
2845
2830
  }
2846
2831
  unless ($reEntry) {
2847
2832
  $$self{PATH} = [ ]; # reset PATH
2833
+ $self->ExtractAltInfo();
2848
2834
  # calculate Composite tags
2849
2835
  $self->BuildCompositeTags() if $$options{Composite};
2850
2836
  # do our HTML dump if requested
@@ -4067,6 +4053,42 @@ sub CombineInfo($;@)
4067
4053
  return \%combinedInfo;
4068
4054
  }
4069
4055
 
4056
+ #------------------------------------------------------------------------------
4057
+ # Read metadata from alternate files
4058
+ # Inputs: 0) ExifTool ref
4059
+ # Notes: This is called after reading the main file so the tags are available
4060
+ # for being used in the file name, but before building Composite tags
4061
+ # so tags from the alternate files may be used in the Composite tags
4062
+ sub ExtractAltInfo($)
4063
+ {
4064
+ my $self = shift;
4065
+ # extract information from alternate files if necessary
4066
+ my ($g8, $altExifTool);
4067
+ foreach $g8 (sort keys %{$$self{ALT_EXIFTOOL}}) {
4068
+ $altExifTool = $$self{ALT_EXIFTOOL}{$g8};
4069
+ next if $$altExifTool{DID_EXTRACT}; # avoid extracting twice
4070
+ $$altExifTool{OPTIONS} = $$self{OPTIONS};
4071
+ $$altExifTool{GLOBAL_TIME_OFFSET} = $$self{GLOBAL_TIME_OFFSET};
4072
+ $$altExifTool{REQ_TAG_LOOKUP} = $$self{REQ_TAG_LOOKUP};
4073
+ my $fileName = $$altExifTool{ALT_FILE};
4074
+ # allow tags from the main file to be used in the alternate file names
4075
+ # (eg. -file1 '$originalfilename')
4076
+ if ($fileName =~ /\$/) {
4077
+ my @tags = reverse sort keys %{$$self{VALUE}};
4078
+ $fileName = $self->InsertTagValues(\@tags, $fileName, 'Warn');
4079
+ next unless defined $fileName;
4080
+ }
4081
+ $altExifTool->ExtractInfo($fileName);
4082
+ # set family 8 group name for all tags
4083
+ foreach (keys %{$$altExifTool{VALUE}}) {
4084
+ my $ex = $$altExifTool{TAG_EXTRA}{$_};
4085
+ $ex or $ex = $$altExifTool{TAG_EXTRA}{$_} = { };
4086
+ $$ex{G8} = $g8;
4087
+ }
4088
+ $$altExifTool{DID_EXTRACT} = 1;
4089
+ }
4090
+ }
4091
+
4070
4092
  #------------------------------------------------------------------------------
4071
4093
  # Get tag table name
4072
4094
  # Inputs: 0) ExifTool object reference, 1) tag key
@@ -6432,12 +6454,12 @@ sub ProcessJPEG($$)
6432
6454
  my $htmlDump = $$self{HTML_DUMP};
6433
6455
  my %dumpParms = ( Out => $out );
6434
6456
  my ($ch, $s, $length, $md5, $md5size);
6435
- my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk);
6457
+ my ($success, $wantTrailer, $trailInfo, $foundSOS, $gotSize, %jumbfChunk);
6436
6458
  my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
6437
6459
  my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
6438
6460
 
6439
- # get pointer to MD5 object if it exists and we are the top-level JPEG
6440
- if ($$self{FILE_TYPE} eq 'JPEG' and not $$self{DOC_NUM}) {
6461
+ # get pointer to MD5 object if it exists and we are the top-level JPEG or JP2
6462
+ if ($$self{FILE_TYPE} =~ /^(JPEG|JP2)$/ and not $$self{DOC_NUM}) {
6441
6463
  $md5 = $$self{ImageDataMD5};
6442
6464
  $md5size = 0;
6443
6465
  }
@@ -6561,7 +6583,8 @@ sub ProcessJPEG($$)
6561
6583
  $self->HDump($segPos-4, $length+4, "[JPEG $markerName]", undef, 0x08);
6562
6584
  $dumpEnd = $segPos + $length;
6563
6585
  }
6564
- next unless $length >= 6;
6586
+ next if $length < 6 or $gotSize;
6587
+ $gotSize = 1; # (ignore subsequent SOF segments in probably corrupted JPEG)
6565
6588
  # extract some useful information
6566
6589
  my ($p, $h, $w, $n) = unpack('Cn2C', $$segDataPt);
6567
6590
  my $sof = GetTagTable('Image::ExifTool::JPEG::SOF');
@@ -6751,6 +6774,11 @@ sub ProcessJPEG($$)
6751
6774
  pop @$path;
6752
6775
  $verbose and print $out "JPEG SOD\n";
6753
6776
  $success = 1;
6777
+ if ($md5 and $$self{FILE_TYPE} eq 'JP2') {
6778
+ my $pos = $raf->Tell();
6779
+ $self->ImageDataMD5($raf, undef, 'SOD');
6780
+ $raf->Seek($pos, 0);
6781
+ }
6754
6782
  next if $verbose > 2 or $htmlDump;
6755
6783
  last; # all done parsing file
6756
6784
  } elsif (defined $markerLenBytes{$marker}) {
@@ -7483,8 +7511,11 @@ sub ProcessJPEG($$)
7483
7511
  }
7484
7512
  } elsif ($marker == 0x51) { # SIZ (J2C)
7485
7513
  my ($w, $h) = unpack('x2N2', $$segDataPt);
7486
- $self->FoundTag('ImageWidth', $w);
7487
- $self->FoundTag('ImageHeight', $h);
7514
+ unless ($gotSize) {
7515
+ $gotSize = 1;
7516
+ $self->FoundTag('ImageWidth', $w);
7517
+ $self->FoundTag('ImageHeight', $h);
7518
+ }
7488
7519
  } elsif (($marker & 0xf0) != 0xe0) {
7489
7520
  $dumpType = "$markerName segment";
7490
7521
  $desc = "[JPEG $markerName]"; # (other known JPEG segments)
@@ -7824,6 +7855,9 @@ sub DoProcessTIFF($$;$)
7824
7855
  if ($$self{TIFF_TYPE} eq 'TIFF') {
7825
7856
  $self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage};
7826
7857
  }
7858
+ if ($$self{ImageDataMD5} and $$self{A100DataOffset} and $raf->Seek($$self{A100DataOffset},0)) {
7859
+ $self->ImageDataMD5($raf, undef, 'A100');
7860
+ }
7827
7861
  return 1;
7828
7862
  }
7829
7863
  #
@@ -1,6 +1,6 @@
1
1
  Summary: perl module for image data extraction
2
2
  Name: perl-Image-ExifTool
3
- Version: 12.60
3
+ Version: 12.61
4
4
  Release: 1
5
5
  License: Artistic/GPL
6
6
  Group: Development/Libraries/Perl
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExiftoolVendored
4
- VERSION = Gem::Version.new('12.60.0')
4
+ VERSION = Gem::Version.new('12.61.0')
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: exiftool_vendored
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.60.0
4
+ version: 12.61.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew McEachen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-04-07 00:00:00.000000000 Z
12
+ date: 2023-05-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: exiftool