exiftool-vendored.pl 12.56.0 → 12.60.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 (59) hide show
  1. package/bin/Changes +80 -5
  2. package/bin/MANIFEST +4 -0
  3. package/bin/META.json +1 -1
  4. package/bin/META.yml +1 -1
  5. package/bin/README +2 -2
  6. package/bin/config_files/example.config +1 -0
  7. package/bin/config_files/rotate_regions.config +1 -1
  8. package/bin/exiftool +174 -99
  9. package/bin/lib/Image/ExifTool/AIFF.pm +2 -2
  10. package/bin/lib/Image/ExifTool/APE.pm +2 -2
  11. package/bin/lib/Image/ExifTool/BuildTagLookup.pm +19 -15
  12. package/bin/lib/Image/ExifTool/Canon.pm +26 -6
  13. package/bin/lib/Image/ExifTool/CanonRaw.pm +5 -1
  14. package/bin/lib/Image/ExifTool/DJI.pm +28 -2
  15. package/bin/lib/Image/ExifTool/Exif.pm +77 -19
  16. package/bin/lib/Image/ExifTool/FlashPix.pm +32 -10
  17. package/bin/lib/Image/ExifTool/FujiFilm.pm +7 -3
  18. package/bin/lib/Image/ExifTool/GPS.pm +7 -2
  19. package/bin/lib/Image/ExifTool/Geotag.pm +30 -7
  20. package/bin/lib/Image/ExifTool/JPEG.pm +14 -2
  21. package/bin/lib/Image/ExifTool/Jpeg2000.pm +5 -5
  22. package/bin/lib/Image/ExifTool/LIF.pm +10 -2
  23. package/bin/lib/Image/ExifTool/LNK.pm +5 -4
  24. package/bin/lib/Image/ExifTool/MIE.pm +3 -3
  25. package/bin/lib/Image/ExifTool/MPEG.pm +2 -2
  26. package/bin/lib/Image/ExifTool/MakerNotes.pm +3 -2
  27. package/bin/lib/Image/ExifTool/Minolta.pm +6 -7
  28. package/bin/lib/Image/ExifTool/MinoltaRaw.pm +2 -1
  29. package/bin/lib/Image/ExifTool/Nikon.pm +1003 -907
  30. package/bin/lib/Image/ExifTool/NikonCustom.pm +2 -2
  31. package/bin/lib/Image/ExifTool/NikonSettings.pm +1 -1
  32. package/bin/lib/Image/ExifTool/Olympus.pm +88 -6
  33. package/bin/lib/Image/ExifTool/PNG.pm +10 -2
  34. package/bin/lib/Image/ExifTool/PanasonicRaw.pm +27 -1
  35. package/bin/lib/Image/ExifTool/Pentax.pm +8 -5
  36. package/bin/lib/Image/ExifTool/PhaseOne.pm +14 -1
  37. package/bin/lib/Image/ExifTool/Photoshop.pm +38 -7
  38. package/bin/lib/Image/ExifTool/QuickTime.pm +44 -13
  39. package/bin/lib/Image/ExifTool/QuickTimeStream.pl +40 -6
  40. package/bin/lib/Image/ExifTool/README +19 -2
  41. package/bin/lib/Image/ExifTool/RIFF.pm +34 -13
  42. package/bin/lib/Image/ExifTool/Rawzor.pm +2 -2
  43. package/bin/lib/Image/ExifTool/Ricoh.pm +2 -1
  44. package/bin/lib/Image/ExifTool/Sigma.pm +5 -4
  45. package/bin/lib/Image/ExifTool/SigmaRaw.pm +9 -3
  46. package/bin/lib/Image/ExifTool/Sony.pm +24 -1
  47. package/bin/lib/Image/ExifTool/TagLookup.pm +4678 -4628
  48. package/bin/lib/Image/ExifTool/TagNames.pod +305 -113
  49. package/bin/lib/Image/ExifTool/Validate.pm +5 -5
  50. package/bin/lib/Image/ExifTool/WriteExif.pl +42 -0
  51. package/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
  52. package/bin/lib/Image/ExifTool/Writer.pl +150 -36
  53. package/bin/lib/Image/ExifTool/XMP.pm +19 -4
  54. package/bin/lib/Image/ExifTool/XMP2.pl +2 -1
  55. package/bin/lib/Image/ExifTool.pm +195 -42
  56. package/bin/lib/Image/ExifTool.pod +44 -9
  57. package/bin/perl-Image-ExifTool.spec +1 -1
  58. package/bin/pp_build_exe.args +4 -4
  59. package/package.json +3 -3
@@ -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.56';
32
+ $VERSION = '12.60';
33
33
  $RELEASE = '';
34
34
  @ISA = qw(Exporter);
35
35
  %EXPORT_TAGS = (
@@ -75,6 +75,7 @@ sub GetAllGroups($;$);
75
75
  sub GetNewGroups($);
76
76
  sub GetDeleteGroups();
77
77
  sub AddUserDefinedTags($%);
78
+ sub SetAlternateFile($$$);
78
79
  # non-public routines below
79
80
  sub InsertTagValues($$$;$$$);
80
81
  sub IsWritable($);
@@ -113,6 +114,7 @@ sub WriteTIFF($$$);
113
114
  sub PackUTF8(@);
114
115
  sub UnpackUTF8($);
115
116
  sub SetPreferredByteOrder($;$);
117
+ sub ImageDataMD5($$$;$$);
116
118
  sub CopyBlock($$$);
117
119
  sub CopyFileAttrs($$$);
118
120
  sub TimeNow(;$$);
@@ -1821,6 +1823,17 @@ my %systemTagsNotes = (
1821
1823
  if specifically requested
1822
1824
  },
1823
1825
  },
1826
+ ImageDataMD5 => {
1827
+ Notes => q{
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.
1833
+ The L<XMP-et:OriginalImageMD5 tag|XMP.html#ExifTool> provides a place to
1834
+ store these values in the file.
1835
+ },
1836
+ },
1824
1837
  );
1825
1838
 
1826
1839
  # tags defined by UserParam option (added at runtime)
@@ -2043,7 +2056,9 @@ sub new
2043
2056
  $$self{DEL_GROUP} = { }; # lookup for groups to delete when writing
2044
2057
  $$self{SAVE_COUNT} = 0; # count calls to SaveNewValues()
2045
2058
  $$self{FILE_SEQUENCE} = 0; # sequence number for files when reading
2059
+ $$self{FILES_WRITTEN} = 0; # count of files successfully written
2046
2060
  $$self{INDENT2} = ''; # indentation of verbose messages from SetNewValue
2061
+ $$self{ALT_EXIFTOOL} = { }; # alternate exiftool objects
2047
2062
 
2048
2063
  # initialize our new groups for writing
2049
2064
  $self->SetNewGroups(@defaultWriteGroups);
@@ -2478,8 +2493,33 @@ sub ExtractInfo($;@)
2478
2493
  $self->WarnOnce('Install Time::HiRes to generate ProcessingTime');
2479
2494
  }
2480
2495
  }
2481
-
2496
+
2497
+ # create MD5 object if ImageDataMD5 is requested
2498
+ if ($$req{imagedatamd5} and not $$self{ImageDataMD5}) {
2499
+ if (require Digest::MD5) {
2500
+ $$self{ImageDataMD5} = Digest::MD5->new;
2501
+ } else {
2502
+ $self->WarnOnce('Install Digest::MD5 to calculate image data MD5');
2503
+ }
2504
+ }
2482
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
+ }
2483
2523
  }
2484
2524
 
2485
2525
  my $filename = $$self{FILENAME}; # image file name ('' if already open)
@@ -2869,6 +2909,10 @@ sub ExtractInfo($;@)
2869
2909
  # restore necessary members when exiting re-entrant code
2870
2910
  $$self{$_} = $$reEntry{$_} foreach keys %$reEntry;
2871
2911
  SetByteOrder($saveOrder);
2912
+ } elsif ($$self{ImageDataMD5}) {
2913
+ my $digest = $$self{ImageDataMD5}->hexdigest;
2914
+ # (don't store empty digest)
2915
+ $self->FoundTag(ImageDataMD5 => $digest) unless $digest eq 'd41d8cd98f00b204e9800998ecf8427e';
2872
2916
  }
2873
2917
 
2874
2918
  # ($type may be undef without an Error when processing sub-documents)
@@ -3500,6 +3544,10 @@ sub GetGroup($$;$)
3500
3544
  $groups[6] = $$ex{G6};
3501
3545
  }
3502
3546
  }
3547
+ if ($$ex{G8}) {
3548
+ $groups[7] = '';
3549
+ $groups[8] = $$ex{G8};
3550
+ }
3503
3551
  # generate tag ID group names unless obviously not needed
3504
3552
  unless ($noID) {
3505
3553
  my $id = $$tagInfo{KeysID} || $$tagInfo{TagID};
@@ -3685,13 +3733,21 @@ COMPOSITE_TAG:
3685
3733
  next COMPOSITE_TAG;
3686
3734
  }
3687
3735
  }
3736
+ my ($i, $key, @keys, $altFile);
3737
+ my $et = $self;
3738
+ # get tags from alternate file if a family 8 group was specified
3739
+ if ($reqTag =~ /\b(File\d+):/i and $$self{ALT_EXIFTOOL}{$1}) {
3740
+ $et = $$self{ALT_EXIFTOOL}{$1};
3741
+ $altFile = $1;
3742
+ }
3688
3743
  # (CAREFUL! keys may not be sequential if one was deleted)
3689
- my ($i, $key, @keys);
3690
- for ($key=$name, $i=$$self{DUPL_TAG}{$name} || 0; ; --$i) {
3691
- push @keys, $key if defined $$rawValue{$key};
3744
+ for ($key=$name, $i=$$et{DUPL_TAG}{$name} || 0; ; --$i) {
3745
+ push @keys, $key if defined $$et{VALUE}{$key};
3692
3746
  last if $i <= 0;
3693
3747
  $key = "$name ($i)";
3694
3748
  }
3749
+ # make sure the necessary information is available from the alternate file
3750
+ $self->CopyAltInfo($altFile, \@keys) if $altFile;
3695
3751
  # find first matching tag
3696
3752
  $key = $self->GroupMatches($reqGroup, \@keys);
3697
3753
  $reqTag = $key || "$name (0)";
@@ -4133,7 +4189,11 @@ sub SplitFileName($)
4133
4189
  } else {
4134
4190
  ($name = $file) =~ tr/\\/\//;
4135
4191
  # remove path
4136
- $dir = length($1) ? $1 : '/' if $name =~ s/(.*)\///;
4192
+ if ($name =~ s/(.*)\///) {
4193
+ $dir = length($1) ? $1 : '/';
4194
+ } else {
4195
+ $dir = '.';
4196
+ }
4137
4197
  }
4138
4198
  return ($dir, $name);
4139
4199
  }
@@ -4296,9 +4356,9 @@ sub GetFileTime($$)
4296
4356
  # on Windows, try to work around incorrect file times when daylight saving time is in effect
4297
4357
  if ($^O eq 'MSWin32') {
4298
4358
  if (not eval { require Win32::API }) {
4299
- $self->WarnOnce('Install Win32::API for proper handling of Windows file times');
4359
+ $self->WarnOnce('Install Win32::API for proper handling of Windows file times', 1);
4300
4360
  } elsif (not eval { require Win32API::File }) {
4301
- $self->WarnOnce('Install Win32API::File for proper handling of Windows file times');
4361
+ $self->WarnOnce('Install Win32API::File for proper handling of Windows file times', 1);
4302
4362
  } else {
4303
4363
  # get Win32 handle, needed for GetFileTime
4304
4364
  my $win32Handle = eval { Win32API::File::GetOsFHandle($file) };
@@ -4548,6 +4608,29 @@ sub RemoveTagsFromList($$$$;$)
4548
4608
  $_[0] = \@filteredTags; # update tag list
4549
4609
  }
4550
4610
 
4611
+ #------------------------------------------------------------------------------
4612
+ # Copy tags from alternate input file
4613
+ # Inputs: 0) ExifTool ref, 1) family 8 group, 2) list ref for tag keys to copy
4614
+ # - updates tag key list to match keys newly added to $self
4615
+ sub CopyAltInfo($$$)
4616
+ {
4617
+ my ($self, $g8, $tags) = @_;
4618
+ my ($tag, $vtag);
4619
+ return unless $g8 =~ /(\d+)/;
4620
+ my $et = $$self{ALT_EXIFTOOL}{$g8} or return;
4621
+ my $altOrder = ($1 + 1) * 100000; # increment file order
4622
+ foreach $tag (@$tags) {
4623
+ ($vtag = $tag) =~ s/( |$)/ #[$g8]/;
4624
+ unless (defined $$self{VALUE}{$vtag}) {
4625
+ $$self{VALUE}{$vtag} = $$et{VALUE}{$tag};
4626
+ $$self{TAG_INFO}{$vtag} = $$et{TAG_INFO}{$tag};
4627
+ $$self{TAG_EXTRA}{$vtag} = $$et{TAG_EXTRA}{$tag} || { };
4628
+ $$self{FILE_ORDER}{$vtag} = ($$et{FILE_ORDER}{$tag} || 0) + $altOrder;
4629
+ }
4630
+ $tag = $vtag;
4631
+ }
4632
+ }
4633
+
4551
4634
  #------------------------------------------------------------------------------
4552
4635
  # Set list of found tags from previously requested tags
4553
4636
  # Inputs: 0) ExifTool object reference
@@ -4574,11 +4657,17 @@ sub SetFoundTags($)
4574
4657
  my $tagHash = $$self{VALUE};
4575
4658
  my $reqTag;
4576
4659
  foreach $reqTag (@$reqTags) {
4577
- my (@matches, $group, $allGrp, $allTag, $byValue);
4660
+ my (@matches, $group, $allGrp, $allTag, $byValue, $g8);
4661
+ my $et = $self;
4578
4662
  if ($reqTag =~ /^(.*):(.+)/) {
4579
4663
  ($group, $tag) = ($1, $2);
4580
4664
  if ($group =~ /^(\*|all)$/i) {
4581
4665
  $allGrp = 1;
4666
+ } elsif ($reqTag =~ /\bfile(\d+):/i) {
4667
+ $g8 = "File$1";
4668
+ $et = $$self{ALT_EXIFTOOL}{$g8} || $self;
4669
+ $fileOrder = $$et{FILE_ORDER};
4670
+ $tagHash = $$et{VALUE};
4582
4671
  } elsif ($group !~ /^[-\w:]*$/) {
4583
4672
  $self->Warn("Invalid group name '${group}'");
4584
4673
  $group = 'invalid';
@@ -4620,7 +4709,7 @@ sub SetFoundTags($)
4620
4709
  }
4621
4710
  if (defined $group and not $allGrp) {
4622
4711
  # keep only specified group
4623
- @matches = $self->GroupMatches($group, \@matches);
4712
+ @matches = $et->GroupMatches($group, \@matches);
4624
4713
  next unless @matches or not $allTag;
4625
4714
  }
4626
4715
  if (@matches > 1) {
@@ -4629,9 +4718,9 @@ sub SetFoundTags($)
4629
4718
  # return only the highest priority tag unless duplicates wanted
4630
4719
  unless ($doDups or $allTag or $allGrp) {
4631
4720
  $tag = shift @matches;
4632
- my $oldPriority = $$self{PRIORITY}{$tag} || 1;
4721
+ my $oldPriority = $$et{PRIORITY}{$tag} || 1;
4633
4722
  foreach (@matches) {
4634
- my $priority = $$self{PRIORITY}{$_};
4723
+ my $priority = $$et{PRIORITY}{$_};
4635
4724
  $priority = 1 unless defined $priority;
4636
4725
  next unless $priority >= $oldPriority;
4637
4726
  $tag = $_;
@@ -4645,6 +4734,13 @@ sub SetFoundTags($)
4645
4734
  # bogus file order entry to avoid warning if sorting in file order
4646
4735
  $$self{FILE_ORDER}{$matches[0]} = 9999;
4647
4736
  }
4737
+ # copy over necessary information for tags from alternate files
4738
+ if ($g8) {
4739
+ $self->CopyAltInfo($g8, \@matches);
4740
+ # restore variables to original values for main file
4741
+ $fileOrder = $$self{FILE_ORDER};
4742
+ $tagHash = $$self{VALUE};
4743
+ }
4648
4744
  # save indices of tags extracted by value
4649
4745
  push @byValue, scalar(@$rtnTags) .. (scalar(@$rtnTags)+scalar(@matches)-1) if $byValue;
4650
4746
  # save indices of wildcard tags
@@ -5867,7 +5963,8 @@ sub ConvertTimeSpan($;$)
5867
5963
  #------------------------------------------------------------------------------
5868
5964
  # Patched timelocal() that fixes ActivePerl timezone bug
5869
5965
  # Inputs/Returns: same as timelocal()
5870
- # Notes: must 'require Time::Local' before calling this routine
5966
+ # Notes: must 'require Time::Local' before calling this routine.
5967
+ # Also note that year should be full year, and not relative to 1900 as with localtime
5871
5968
  sub TimeLocal(@)
5872
5969
  {
5873
5970
  my $tm = Time::Local::timelocal(@_);
@@ -6326,7 +6423,6 @@ sub ProcessJPEG($$)
6326
6423
  {
6327
6424
  local $_;
6328
6425
  my ($self, $dirInfo) = @_;
6329
- my ($ch, $s, $length);
6330
6426
  my $options = $$self{OPTIONS};
6331
6427
  my $verbose = $$options{Verbose};
6332
6428
  my $out = $$options{TextOut};
@@ -6335,10 +6431,17 @@ sub ProcessJPEG($$)
6335
6431
  my $req = $$self{REQ_TAG_LOOKUP};
6336
6432
  my $htmlDump = $$self{HTML_DUMP};
6337
6433
  my %dumpParms = ( Out => $out );
6434
+ my ($ch, $s, $length, $md5, $md5size);
6338
6435
  my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk);
6339
6436
  my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal);
6340
6437
  my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP);
6341
6438
 
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}) {
6441
+ $md5 = $$self{ImageDataMD5};
6442
+ $md5size = 0;
6443
+ }
6444
+
6342
6445
  # check to be sure this is a valid JPG (or J2C, or EXV) file
6343
6446
  return 0 unless $raf->Read($s, 2) == 2 and $s =~ /^\xff[\xd8\x4f\x01]/;
6344
6447
  if ($s eq "\xff\x01") {
@@ -6385,7 +6488,9 @@ sub ProcessJPEG($$)
6385
6488
  #
6386
6489
  # read ahead to the next segment unless we have reached EOI, SOS or SOD
6387
6490
  #
6388
- unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer) or $marker==0x93)) {
6491
+ unless ($marker and ($marker==0xd9 or ($marker==0xda and not $wantTrailer and not $md5) or
6492
+ $marker==0x93))
6493
+ {
6389
6494
  # read up to next marker (JPEG markers begin with 0xff)
6390
6495
  my $buff;
6391
6496
  $raf->ReadLine($buff) or last;
@@ -6415,6 +6520,19 @@ sub ProcessJPEG($$)
6415
6520
  $nextSegPos = $raf->Tell();
6416
6521
  $len -= 4; # subtract size of length word
6417
6522
  last unless $raf->Seek($len, 1);
6523
+ } elsif ($md5 and defined $marker and ($marker == 0x00 or $marker == 0xda or
6524
+ ($marker >= 0xd0 and $marker <= 0xd7)))
6525
+ {
6526
+ # calculate MD5 for image data (includes leading ff d9 but not trailing ff da)
6527
+ $md5->add("\xff" . chr($marker));
6528
+ my $n = $skipped - (length($buff) - 1); # number of extra 0xff's
6529
+ if (not $n) {
6530
+ $buff = substr($buff, 0, -1); # remove trailing 0xff
6531
+ } elsif ($n > 1) {
6532
+ $buff .= "\xff" x ($n - 1); # add back extra 0xff's
6533
+ }
6534
+ $md5->add($buff);
6535
+ $md5size += $skipped + 2;
6418
6536
  }
6419
6537
  # read second segment too if this was the first
6420
6538
  next unless defined $marker;
@@ -6625,7 +6743,7 @@ sub ProcessJPEG($$)
6625
6743
  next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump;
6626
6744
  }
6627
6745
  # must scan to EOI if Validate or JpegCompressionFactor used
6628
- next if $$options{Validate} or $calcImageLen or $$req{trailer};
6746
+ next if $$options{Validate} or $calcImageLen or $$req{trailer} or $md5;
6629
6747
  # nothing interesting to parse after start of scan (SOS)
6630
6748
  $success = 1;
6631
6749
  last; # all done parsing file
@@ -6707,7 +6825,7 @@ sub ProcessJPEG($$)
6707
6825
  } elsif ($marker == 0xe1) { # APP1 (EXIF, XMP, QVCI, PARROT)
6708
6826
  # (some Kodak cameras don't put a second "\0", and I have seen an
6709
6827
  # example where there was a second 4-byte APP1 segment header)
6710
- if ($$segDataPt =~ /^(.{0,4})Exif\0/is) {
6828
+ if ($$segDataPt =~ /^(.{0,4})Exif\0./is) {
6711
6829
  undef $dumpType; # (will be dumped here)
6712
6830
  # this is EXIF data --
6713
6831
  # get the data block (into a common variable)
@@ -7008,7 +7126,7 @@ sub ProcessJPEG($$)
7008
7126
  $self->FoundTag('PreviewImage', $preview);
7009
7127
  undef $preview;
7010
7128
  }
7011
- } elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, PreviewImage)
7129
+ } elsif ($marker == 0xe4) { # APP4 (InfiRay, "SCALADO", FPXR, DJI, PreviewImage)
7012
7130
  if ($$segDataPt =~ /^SCALADO\0/ and $length >= 16) {
7013
7131
  $dumpType = 'SCALADO';
7014
7132
  my ($num, $idx, $len) = unpack('x8n2N', $$segDataPt);
@@ -7039,6 +7157,16 @@ sub ProcessJPEG($$)
7039
7157
  DirStart(\%dirInfo, 0, 0);
7040
7158
  my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams');
7041
7159
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7160
+ } elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^(.{32})?.{32}\x2c\x01\x20\0/s) {
7161
+ $dumpType = 'DJI ThermalParams2';
7162
+ DirStart(\%dirInfo, $1 ? 32 : 0, 0);
7163
+ my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams2');
7164
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7165
+ } elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^.{32}\xaa\x55\x38\0/s) {
7166
+ $dumpType = 'DJI ThermalParams3';
7167
+ DirStart(\%dirInfo, 32, 0);
7168
+ my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams3');
7169
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7042
7170
  } elsif ($$self{HasIJPEG} and $length >= 120) {
7043
7171
  $dumpType = 'InfiRay Factory';
7044
7172
  SetByteOrder('II');
@@ -7152,6 +7280,13 @@ sub ProcessJPEG($$)
7152
7280
  $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7153
7281
  delete $$self{SET_GROUP0};
7154
7282
  delete $$self{SET_GROUP1};
7283
+ } elsif ($$segDataPt =~ /^DJI-DBG\0/) {
7284
+ $dumpType = 'DJI Info';
7285
+ my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::Info');
7286
+ DirStart(\%dirInfo, 8, 0);
7287
+ $$self{SET_GROUP0} = 'APP7';
7288
+ $self->ProcessDirectory(\%dirInfo, $tagTablePtr);
7289
+ delete $$self{SET_GROUP0};
7155
7290
  } elsif ($$segDataPt =~ /^\x1aQualcomm Camera Attributes/) {
7156
7291
  # found in HP iPAQ_VoiceMessenger
7157
7292
  $dumpType = 'Qualcomm';
@@ -7412,6 +7547,8 @@ sub ProcessJPEG($$)
7412
7547
  delete $extendedXMP{$guid};
7413
7548
  }
7414
7549
  }
7550
+ # print verbose MD5 message if necessary
7551
+ print $out "$$self{INDENT}(ImageDataMD5: $md5size bytes of JPEG image data)\n" if $md5size and $verbose;
7415
7552
  # calculate JPEGDigest if requested
7416
7553
  if (@dqt) {
7417
7554
  require Image::ExifTool::JPEGDigest;
@@ -7680,7 +7817,7 @@ sub DoProcessTIFF($$;$)
7680
7817
  }
7681
7818
  }
7682
7819
  # update FileType if necessary now that we know more about the file
7683
- if ($$self{DNGVersion} and $$self{VALUE}{FileType} !~ /^(DNG|GPR)$/) {
7820
+ if ($$self{DNGVersion} and $$self{FileType} !~ /^(DNG|GPR)$/) {
7684
7821
  # override whatever FileType we set since we now know it is DNG
7685
7822
  $self->OverrideFileType($$self{TIFF_TYPE} = 'DNG');
7686
7823
  }
@@ -7988,7 +8125,7 @@ sub ProcessDirectory($$$;$)
7988
8125
  # patch for bug in Windows phone 7.5 O/S that writes incorrect InteropIFD pointer
7989
8126
  return 0 unless $dirName eq 'GPS' and $$self{PROCESSED}{$addr} eq 'InteropIFD';
7990
8127
  }
7991
- $$self{PROCESSED}{$addr} = $dirName;
8128
+ $$self{PROCESSED}{$addr} = $dirName unless $$tagTablePtr{VARS} and $$tagTablePtr{VARS}{ALLOW_REPROCESS};
7992
8129
  }
7993
8130
  my $oldOrder = GetByteOrder();
7994
8131
  my @save = @$self{'INDENT','DIR_NAME','Compression','SubfileType'};
@@ -8566,7 +8703,7 @@ sub DoEscape($$)
8566
8703
  sub SetFileType($;$$$)
8567
8704
  {
8568
8705
  my ($self, $fileType, $mimeType, $normExt) = @_;
8569
- unless ($$self{VALUE}{FileType} and not $$self{DOC_NUM}) {
8706
+ unless ($$self{FileType} and not $$self{DOC_NUM}) {
8570
8707
  my $baseType = $$self{FILE_TYPE};
8571
8708
  my $ext = $$self{FILE_EXT};
8572
8709
  $fileType or $fileType = $baseType;
@@ -8585,7 +8722,8 @@ sub SetFileType($;$$$)
8585
8722
  $normExt = $fileTypeExt{$fileType};
8586
8723
  $normExt = $fileType unless defined $normExt;
8587
8724
  }
8588
- $$self{FileType} = $fileType;
8725
+ # ($$self{FileType} is the file type of the main document)
8726
+ $$self{FileType} = $fileType unless $$self{DOC_NUM};
8589
8727
  $self->FoundTag('FileType', $fileType);
8590
8728
  $self->FoundTag('FileTypeExtension', uc $normExt);
8591
8729
  $self->FoundTag('MIMEType', $mimeType || 'application/unknown');
@@ -8749,13 +8887,16 @@ sub ProcessBinaryData($$$)
8749
8887
  {
8750
8888
  my ($self, $dirInfo, $tagTablePtr) = @_;
8751
8889
  my $dataPt = $$dirInfo{DataPt};
8752
- my $offset = $$dirInfo{DirStart} || 0;
8753
- my $size = $$dirInfo{DirLen} || (length($$dataPt) - $offset);
8890
+ my $dataLen = length $$dataPt;
8891
+ my $dirStart = $$dirInfo{DirStart} || 0;
8892
+ my $maxLen = $dataLen - $dirStart;
8893
+ my $size = $$dirInfo{DirLen};
8754
8894
  my $base = $$dirInfo{Base} || 0;
8755
8895
  my $verbose = $$self{OPTIONS}{Verbose};
8756
8896
  my $unknown = $$self{OPTIONS}{Unknown};
8757
8897
  my $dataPos = $$dirInfo{DataPos} || 0;
8758
8898
 
8899
+ $size = $maxLen if not defined $size or $size > $maxLen;
8759
8900
  # get default format ('int8u' unless specified)
8760
8901
  my $defaultFormat = $$tagTablePtr{FORMAT} || 'int8u';
8761
8902
  my $increment = $formatSize{$defaultFormat};
@@ -8797,6 +8938,7 @@ sub ProcessBinaryData($$$)
8797
8938
  $tagInfo = $self->GetTagInfo($tagTablePtr, $index);
8798
8939
  unless ($tagInfo) {
8799
8940
  next unless defined $tagInfo;
8941
+ # $entry = offset of value relative to directory start (or end if negative)
8800
8942
  my $entry = int($index) * $increment + $varSize;
8801
8943
  if ($entry < 0) {
8802
8944
  $entry += $size;
@@ -8805,7 +8947,7 @@ sub ProcessBinaryData($$$)
8805
8947
  next if $entry >= $size;
8806
8948
  my $more = $size - $entry;
8807
8949
  $more = 128 if $more > 128;
8808
- my $v = substr($$dataPt, $entry+$offset, $more);
8950
+ my $v = substr($$dataPt, $entry+$dirStart, $more);
8809
8951
  $tagInfo = $self->GetTagInfo($tagTablePtr, $index, \$v);
8810
8952
  next unless $tagInfo;
8811
8953
  }
@@ -8838,7 +8980,7 @@ sub ProcessBinaryData($$$)
8838
8980
  $count = $more;
8839
8981
  } elsif ($format eq 'pstring') {
8840
8982
  $format = 'string';
8841
- $count = Get8u($dataPt, ($entry++)+$offset);
8983
+ $count = Get8u($dataPt, ($entry++)+$dirStart);
8842
8984
  --$more;
8843
8985
  } elsif (not $formatSize{$format}) {
8844
8986
  if ($format =~ /(.*)\[(.*)\]/) {
@@ -8867,17 +9009,17 @@ sub ProcessBinaryData($$$)
8867
9009
  } elsif ($format =~ /^var_/) {
8868
9010
  # handle variable-length string formats
8869
9011
  $format = substr($format, 4);
8870
- pos($$dataPt) = $entry + $offset;
9012
+ pos($$dataPt) = $entry + $dirStart;
8871
9013
  undef $count;
8872
9014
  if ($format eq 'ustring') {
8873
- $count = pos($$dataPt) - ($entry+$offset) if $$dataPt =~ /\G(..)*?\0\0/sg;
9015
+ $count = pos($$dataPt) - ($entry+$dirStart) if $$dataPt =~ /\G(..)*?\0\0/sg;
8874
9016
  $varSize -= 2; # ($count includes base size of 2 bytes)
8875
9017
  } elsif ($format eq 'pstring') {
8876
- $count = Get8u($dataPt, ($entry++)+$offset);
9018
+ $count = Get8u($dataPt, ($entry++)+$dirStart);
8877
9019
  --$more;
8878
9020
  } elsif ($format eq 'pstr32' or $format eq 'ustr32') {
8879
9021
  last if $more < 4;
8880
- $count = Get32u($dataPt, $entry + $offset);
9022
+ $count = Get32u($dataPt, $entry + $dirStart);
8881
9023
  $count *= 2 if $format eq 'ustr32';
8882
9024
  $entry += 4;
8883
9025
  $more -= 4;
@@ -8885,22 +9027,22 @@ sub ProcessBinaryData($$$)
8885
9027
  } elsif ($format eq 'int16u') {
8886
9028
  # int16u size of binary data to follow
8887
9029
  last if $more < 2;
8888
- $count = Get16u($dataPt, $entry + $offset) + 2;
9030
+ $count = Get16u($dataPt, $entry + $dirStart) + 2;
8889
9031
  $varSize -= 2; # ($count includes size word)
8890
9032
  $format = 'undef';
8891
9033
  } elsif ($format eq 'ue7') {
8892
9034
  require Image::ExifTool::BPG;
8893
- ($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $offset);
9035
+ ($val, $count) = Image::ExifTool::BPG::Get_ue7($dataPt, $entry + $dirStart);
8894
9036
  last unless defined $val;
8895
9037
  --$varSize; # ($count includes base size of 1 byte)
8896
9038
  } elsif ($$dataPt =~ /\0/g) {
8897
- $count = pos($$dataPt) - ($entry+$offset);
9039
+ $count = pos($$dataPt) - ($entry+$dirStart);
8898
9040
  --$varSize; # ($count includes base size of 1 byte)
8899
9041
  }
8900
9042
  $count = $more if not defined $count or $count > $more;
8901
9043
  $varSize += $count; # shift subsequent indices
8902
9044
  unless (defined $val) {
8903
- $val = substr($$dataPt, $entry+$offset, $count);
9045
+ $val = substr($$dataPt, $entry+$dirStart, $count);
8904
9046
  $val = $self->Decode($val, 'UCS2') if $format eq 'ustring' or $format eq 'ustr32';
8905
9047
  $val =~ s/\0.*//s unless $format eq 'undef'; # truncate at null
8906
9048
  }
@@ -8914,7 +9056,7 @@ sub ProcessBinaryData($$$)
8914
9056
  # hook to allow format, etc to be set dynamically
8915
9057
  if (defined $$tagInfo{Hook}) {
8916
9058
  my $oldVarSize = $varSize;
8917
- my $pos = $entry + $offset;
9059
+ my $pos = $entry + $dirStart;
8918
9060
  #### eval Hook ($format, $varSize, $size, $dataPt, $pos)
8919
9061
  eval $$tagInfo{Hook};
8920
9062
  # save variable size data if required for writing (in case changed by Hook)
@@ -8939,7 +9081,7 @@ sub ProcessBinaryData($$$)
8939
9081
  next if $$tagInfo{LargeTag} and $$self{EXCL_TAG_LOOKUP}{lc $$tagInfo{Name}};
8940
9082
  # read value now if necessary
8941
9083
  unless (defined $val and not $$tagInfo{SubDirectory}) {
8942
- $val = ReadValue($dataPt, $entry+$offset, $format, $count, $more, \$rational);
9084
+ $val = ReadValue($dataPt, $entry+$dirStart, $format, $count, $more, \$rational);
8943
9085
  next unless defined $val;
8944
9086
  $mask = $$tagInfo{Mask};
8945
9087
  $val = ($val & $mask) >> $$tagInfo{BitShift} if $mask;
@@ -8956,8 +9098,8 @@ sub ProcessBinaryData($$$)
8956
9098
  Value => $val,
8957
9099
  DataPt => $dataPt,
8958
9100
  Size => $len,
8959
- Start => $entry+$offset,
8960
- Addr => $entry+$offset+$base+$dataPos,
9101
+ Start => $entry+$dirStart,
9102
+ Addr => $entry+$dirStart+$base+$dataPos,
8961
9103
  Format => $format,
8962
9104
  Count => $count,
8963
9105
  Extra => $mask ? sprintf(', mask 0x%.2x',$mask) : undef,
@@ -8983,16 +9125,27 @@ sub ProcessBinaryData($$$)
8983
9125
  my $subdirBase = $base;
8984
9126
  if (defined $$subdir{Base}) {
8985
9127
  #### eval Base ($start,$base)
8986
- my $start = $entry + $offset + $dataPos;
9128
+ my $start = $entry + $dirStart + $dataPos;
8987
9129
  $subdirBase = eval($$subdir{Base}) + $base;
8988
9130
  }
8989
9131
  my $start = $$subdir{Start} || 0;
9132
+ if ($start =~ /\$/) {
9133
+ # ignore directories with a zero offset (ie. missing Nikon ShotInfo entries)
9134
+ next unless $val;
9135
+ #### eval Start ($val, $dirStart)
9136
+ $start = eval($start);
9137
+ next if $start < $dirStart or $start > $dataLen;
9138
+ $len = $$subdir{DirLen};
9139
+ $len = $dataLen - $start unless $len and $len <= $dataLen - $start;
9140
+ } else {
9141
+ $start += $dirStart + $entry;
9142
+ }
8990
9143
  my %subdirInfo = (
8991
9144
  DataPt => $dataPt,
8992
9145
  DataPos => $dataPos,
8993
- DataLen => length $$dataPt,
8994
- DirStart => $entry + $offset + $start,
8995
- DirLen => $len - $start,
9146
+ DataLen => $dataLen,
9147
+ DirStart => $start,
9148
+ DirLen => $len,
8996
9149
  Base => $subdirBase,
8997
9150
  );
8998
9151
  delete $$self{NO_UNKNOWN};
@@ -1727,10 +1727,11 @@ sensitive, and may be prefixed by one or more family 0, 1, 2 or 7 group
1727
1727
  names with optional leading family numbers, separated by colons (eg.
1728
1728
  'exif:iso'). A leading '-' indicates tags to be excluded (eg. '-comment'),
1729
1729
  or a trailing '#' causes the ValueConv value to be copied (same as setting
1730
- the Type option to 'ValueConv' for this tag only). Wildcards ('*' and '?')
1731
- may be used in the tag name. A tag name of '*' is commonly used when a
1732
- group is specified to copy all tags in the group (eg. 'XMP:*'). A special
1733
- feature allows tag names of the form 'DSTTAGE<lt>SRCTAG' (or
1730
+ the Type option to 'ValueConv' for this tag only). A leading '+' sets the
1731
+ Replace option to 0 on a per-tag basis (see Options below). Wildcards ('*'
1732
+ and '?') may be used in the tag name. A tag name of '*' is commonly used
1733
+ when a group is specified to copy all tags in the group (eg. 'XMP:*'). A
1734
+ special feature allows tag names of the form 'DSTTAGE<lt>SRCTAG' (or
1734
1735
  'SRCTAGE<gt>DSTTAG') to be specified to copy information to a tag with a
1735
1736
  different name or a specified group. Both 'SRCTAG' and 'DSTTAG' may contain
1736
1737
  wildcards and/or be prefixed by a group name (eg.
@@ -1769,7 +1770,9 @@ copies all information while preserving the original family 1 groups, while
1769
1770
  The options are the same was for L</SetNewValue>, and are passed directly
1770
1771
  to L</SetNewValue> internally, with a few exceptions:
1771
1772
 
1772
- - The Replace option defaults to 1 instead of 0 as with L</SetNewValue>.
1773
+ - The Replace option defaults to 1 instead of 0 as with L</SetNewValue>,
1774
+ however the tag name argument may be prefixed with '+' to set the Replace
1775
+ option to 0 for this argument only.
1773
1776
 
1774
1777
  - The AddValue or DelValue option is set for individual tags if '+>' or '->'
1775
1778
  (or '+E<lt>' or '-E<lt>') are used.
@@ -1870,6 +1873,31 @@ None.
1870
1873
 
1871
1874
  =back
1872
1875
 
1876
+ =head2 SetAlternateFile
1877
+
1878
+ Specify alternate file from which to read metadata. Tags from the alternate
1879
+ file are available after L</ExtractInfo> is called or during a call to
1880
+ L</SetNewValuesFromFile> by using a family 8 group name (eg. 'File1' in the
1881
+ example below).
1882
+
1883
+ $exifTool->SetAlternateFile(File1 => 'images/test1.jpg');
1884
+
1885
+ =over 4
1886
+
1887
+ =item Inputs:
1888
+
1889
+ 0) ExifTool object reference
1890
+
1891
+ 1) Family 8 group name, case insensitive (eg. 'File1', 'File2'...)
1892
+
1893
+ 2) Name of alternate input file, or undef to reset
1894
+
1895
+ =item Return Values:
1896
+
1897
+ 1 on success, or 0 if the group name is invalid.
1898
+
1899
+ =back
1900
+
1873
1901
  =head2 SetFileModifyDate
1874
1902
 
1875
1903
  Write the filesystem modification or creation time from the new value of the
@@ -2088,6 +2116,7 @@ The group family numbers are currently available:
2088
2116
  5) Metadata Path (eg. JPEG-APP1-IFD0-ExifIFD)
2089
2117
  6) EXIF/TIFF Format (eg. int8u, int32u, undef, string)
2090
2118
  7) Tag ID (eg. ID-271, ID-rights, ID-a9aut)
2119
+ 8) Alternate File Number (eg. File1, File2, File3...)
2091
2120
 
2092
2121
  Families 0 and 1 are based on the file structure, and are similar except
2093
2122
  that family 1 is more specific and sub-divides some groups to give more
@@ -2140,6 +2169,8 @@ non-numerical ID's may or may not have characters other than [-_A-Za-z0-9]
2140
2169
  converted to hex. Note that unlike other group names, the tag ID's of
2141
2170
  family 7 group names are case sensitive (but the leading "ID-" is not).
2142
2171
 
2172
+ Family 8 specifies the alternate file set from a call to L</SetAlternateFile>.
2173
+
2143
2174
  See L</GetAllGroups [static]> for complete lists of group names.
2144
2175
 
2145
2176
  =back
@@ -2327,9 +2358,9 @@ CBOR, CIFF, CameraIFD, Canon, CanonCustom, CanonDR4, CanonRaw, CanonVRD,
2327
2358
  Casio, Chapter#, Composite, DICOM, DJI, DNG, DV, DjVu, DjVu-Meta, Ducky,
2328
2359
  EPPIM, EXE, EXIF, ExifIFD, ExifTool, FITS, FLAC, FLIR, File, Flash,
2329
2360
  FlashPix, Font, FotoStation, FujiFilm, FujiIFD, GE, GIF, GIMP, GPS,
2330
- GSpherical, GeoTiff, GlobParamIFD, GoPro, GraphConv, H264, HP, HTC, HTML,
2331
- HTML-dc, HTML-ncc, HTML-office, HTML-prod, HTML-vw96, HTTP-equiv, ICC-chrm,
2332
- ICC-clrt, ICC-header, ICC-meas, ICC-meta, ICC-view, ICC_Profile,
2361
+ GSpherical, Garmin, GeoTiff, GlobParamIFD, GoPro, GraphConv, H264, HP, HTC,
2362
+ HTML, HTML-dc, HTML-ncc, HTML-office, HTML-prod, HTML-vw96, HTTP-equiv,
2363
+ ICC-chrm, ICC-clrt, ICC-header, ICC-meas, ICC-meta, ICC-view, ICC_Profile,
2333
2364
  ICC_Profile#, ID3, ID3v1, ID3v1_Enh, ID3v2_2, ID3v2_3, ID3v2_4, IFD0, IFD1,
2334
2365
  IPTC, IPTC#, ISO, ITC, InfiRay, Insta360, InteropIFD, ItemList, JFIF, JFXX,
2335
2366
  JPEG, JPEG-HDR, JPS, JSON, JUMBF, JVC, Jpeg2000, KDC_IFD, Keys, Kodak,
@@ -2349,7 +2380,7 @@ RMETA, RSRC, RTF, Radiance, Rawzor, Real, Real-CONT, Real-MDPR, Real-PROP,
2349
2380
  Real-RA3, Real-RA4, Real-RA5, Real-RJMD, Reconyx, Red, Ricoh, SPIFF, SR2,
2350
2381
  SR2DataIFD, SR2SubIFD, SRF#, SVG, Samsung, Sanyo, Scalado, Sigma, SigmaRaw,
2351
2382
  Sony, SonyIDC, Stim, SubIFD, System, Theora, Torrent, Track#, UserData,
2352
- VCalendar, VCard, Version0, VNote, Vorbis, WTV, XML, XMP, XMP-DICOM,
2383
+ VCalendar, VCard, VNote, Version0, Vorbis, WTV, XML, XMP, XMP-DICOM,
2353
2384
  XMP-Device, XMP-GAudio, XMP-GCamera, XMP-GCreations, XMP-GDepth, XMP-GFocus,
2354
2385
  XMP-GImage, XMP-GPano, XMP-GSpherical, XMP-LImage, XMP-MP, XMP-MP1,
2355
2386
  XMP-PixelLive, XMP-aas, XMP-acdsee, XMP-album, XMP-apple-fi, XMP-ast,
@@ -2392,6 +2423,10 @@ leading "0x" if the HexTagIDs option is set, or decimal otherwise.
2392
2423
  Characters in non-numerical ID's which are not valid in a group name are
2393
2424
  returned as 2 hex digits.)
2394
2425
 
2426
+ =item Family 8 (Alternate File):
2427
+
2428
+ File#
2429
+
2395
2430
  =back
2396
2431
 
2397
2432
  Note: This function may also be called as an ExifTool member function to
@@ -1,6 +1,6 @@
1
1
  Summary: perl module for image data extraction
2
2
  Name: perl-Image-ExifTool
3
- Version: 12.56
3
+ Version: 12.60
4
4
  Release: 1
5
5
  License: Artistic/GPL
6
6
  Group: Development/Libraries/Perl