Skip to content

Commit

Permalink
Upgrading to exiftool v13.17
Browse files Browse the repository at this point in the history
  • Loading branch information
morozgrafix committed Jan 29, 2025
1 parent 4323405 commit f8a00f0
Show file tree
Hide file tree
Showing 24 changed files with 8,314 additions and 8,079 deletions.
15 changes: 15 additions & 0 deletions bin/Changes
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@ RSS feed: https://exiftool.org/rss.xml
Note: The most recent production release is Version 13.10. (Other versions are
considered development releases, and are not uploaded to MetaCPAN.)

Jan. 29, 2025 - Version 13.17

- Added support for reading more embedded images and videos written in the
JPEG trailer by some phones
- Added support for reading JPEG trailer written by some OnePlus phones
- Added a -validate warning for QuickTime 'wide' atoms with an invalid size
- Added a new CanonLensType
- Extract more embedded videos and depth/gain maps from JPEG images written
- Avoid decoding Sony 0x9050 data for the ILCE-1M2 because the encoding has
changed since the ILCE-1 and the new encoding is not yet known
- Fixed issue that could cause runtime error when using -j with -b
- Fixed some issues decoding AFPointsUsed for some newer Nikon models
- Fixed problem corrupting QuickTime-format videos when writing if they
contain a 'wide' atom with an invalid size

Jan. 25, 2025 - Version 13.16

- Added a couple of new Nikon Z lenses (thanks Warren Hatch)
Expand Down
4 changes: 2 additions & 2 deletions bin/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,9 @@ html/TagNames/Stim.html
html/TagNames/Text.html
html/TagNames/Theora.html
html/TagNames/Torrent.html
html/TagNames/Trailer.html
html/TagNames/Unknown.html
html/TagNames/VCard.html
html/TagNames/Vivo.html
html/TagNames/Vorbis.html
html/TagNames/WPG.html
html/TagNames/WTV.html
Expand Down Expand Up @@ -429,10 +429,10 @@ lib/Image/ExifTool/TagNames.pod
lib/Image/ExifTool/Text.pm
lib/Image/ExifTool/Theora.pm
lib/Image/ExifTool/Torrent.pm
lib/Image/ExifTool/Trailer.pm
lib/Image/ExifTool/Unknown.pm
lib/Image/ExifTool/VCard.pm
lib/Image/ExifTool/Validate.pm
lib/Image/ExifTool/Vivo.pm
lib/Image/ExifTool/Vorbis.pm
lib/Image/ExifTool/WPG.pm
lib/Image/ExifTool/WTV.pm
Expand Down
2 changes: 1 addition & 1 deletion bin/META.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@
}
},
"release_status" : "stable",
"version" : "13.16"
"version" : "13.17"
}
2 changes: 1 addition & 1 deletion bin/META.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ recommends:
Time::HiRes: '0'
requires:
perl: '5.004'
version: '13.16'
version: '13.17'
4 changes: 2 additions & 2 deletions bin/README
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ your home directory, then you would type the following commands in a
terminal window to extract and run ExifTool:

cd ~/Desktop
gzip -dc Image-ExifTool-13.16.tar.gz | tar -xf -
cd Image-ExifTool-13.16
gzip -dc Image-ExifTool-13.17.tar.gz | tar -xf -
cd Image-ExifTool-13.17
./exiftool t/images/ExifTool.jpg

Note: These commands extract meta information from one of the test images.
Expand Down
6 changes: 3 additions & 3 deletions bin/exiftool
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use strict;
use warnings;
require 5.004;

my $version = '13.16';
my $version = '13.17';

# add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
my $exePath;
Expand Down Expand Up @@ -1525,7 +1525,7 @@ if (($tagOut or defined $diff) and ($csv or $json or %printFmt or $tabFormat or
}

if ($csv and $csv eq 'CSV' and not $isWriting) {
undef $json; # (not compatible)
$json = 0; # (not compatible)
if ($textOut) {
Warn "Sorry, -w may not be combined with -csv\n";
$rtnVal = 1;
Expand Down Expand Up @@ -5984,7 +5984,7 @@ with this command:
produces output like this:
-- Generated by ExifTool 13.16 --
-- Generated by ExifTool 13.17 --
File: a.jpg - 2003:10:31 15:44:19
(f/5.6, 1/60s, ISO 100)
File: b.jpg - 2006:05:23 11:57:38
Expand Down
205 changes: 136 additions & 69 deletions bin/lib/Image/ExifTool.pm
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
%static_vars $advFmtSelf);

$VERSION = '13.16';
$VERSION = '13.17';
$RELEASE = '';
@ISA = qw(Exporter);
%EXPORT_TAGS = (
Expand Down Expand Up @@ -6898,6 +6898,8 @@ sub IdentifyTrailer($;$)
$type = 'NikonApp';
} elsif ($buff =~ /\xff{4}\x1b\*9HWfu\x84\x93\xa2\xb1$/) {
$type = 'Vivo';
} elsif ($buff =~ /jxrs...\0$/s) {
$type = 'OnePlus';
}
last;
}
Expand Down Expand Up @@ -6929,18 +6931,24 @@ sub ProcessTrailers($$)
my $success = 1;
my $path = $$self{PATH};

# get position of end of file
$raf->Seek(0,2);
$$self{FileEnd} = $raf->Tell();

for (;;) { # loop through all trailers
$raf->Seek($pos);
my ($proc, $outBuff);
if ($dirName eq 'Insta360') {
require 'Image/ExifTool/QuickTimeStream.pl';
$proc = 'Image::ExifTool::QuickTime::ProcessInsta360';
} elsif ($dirName eq 'NikonApp') {
require Image::ExifTool::Nikon;
$proc = 'Image::ExifTool::Nikon::ProcessNikonApp';
} else {
require "Image/ExifTool/$dirName.pm";
$proc = "Image::ExifTool::${dirName}::Process$dirName";
}
# trailer-processing procs residing in modules of a different name
my $module = {
Insta360 => 'QuickTimeStream.pl',
NikonApp => 'Nikon.pm',
Vivo => 'Trailer.pm',
OnePlus => 'Trailer.pm',
Google => 'Trailer.pm',
}->{$dirName} || "$dirName.pm";
require "Image/ExifTool/$module";
$module =~ s/(Stream)?\..*//; # remove extension and change QuickTimeStream to QuickTime
$proc = "Image::ExifTool::${module}::Process$dirName";
if ($outfile) {
# write to local buffer so we can add trailer in proper order later
$$outfile and $$dirInfo{OutFile} = \$outBuff, $outBuff = '';
Expand All @@ -6953,20 +6961,66 @@ sub ProcessTrailers($$)
$$dirInfo{Trailer} = 1; # set Trailer flag in case proc cares
# add trailer and DirName to SubDirectory PATH
push @$path, 'Trailer', $dirName;

# read or write this trailer
# (proc takes Offset as positive offset from end of trailer to end of file,
# and returns DataPos and DirLen, and Fixup if applicable, and updates
# OutFile when writing. Returns < 0 if we must scan for this trailer)
#
# Call proc to read or write this trailer
#
# Proc inputs:
# 0) ExifTool ref, with FileEnd set, and TrailerStart possibly set (start of all trailers)
# 1) DirInfo with the following elements:
# DirName - name of this trailer
# RAF - RAF reference
# Offset - positive offset from end of this trailer to the end of file
# OutFile - (write mode) scalar reference for output buffer consisting of an empty string
# Trailer - flag set so proc knows we are processing a trailer (if it cares)
# Fixup - optional fixup for pointers in trailer
# ScanForTrailer - set if we should now scan for the trailer start. For JPEG
# images the ExifTool TrailerStart member will also be set, but for TIFF
# images TrailerStart will only be set when writing, so the proc should
# scan from the current file position when reading in a TIFF image.
# Proc returns in read mode (OutFile not set):
# 1 = success
# 0 = error processing trailer (no warning will be issued and remaining trailers will be ignored)
# -1 = must scan from TrailerStart since length can not be determined
# (in which case this routine will be called again later when TrailerStart is known)
# Proc returns in write mode:
# 1 = success (and proc updates OutFile with the trailer to write, or empty string to delete)
# 0 = error processing trailer (will issue minor error)
# -1 = caller to copy or delete the trailer as-is (from TrailerStart if DataPos isn't set)
# - TrailerStart will always be set in write mode
# - the write routine will not be called if all trailers are being deleted
# Proc sets the following elements of $dirInfo in both read and write mode:
# DataPos - file position for start of this trailer
# DirLen - length of this trailer (subsequent trailers are not processed if this is not set)
# Fixup - for any pointers in the trailer that need adjusting
#
no strict 'refs';
my $result = &$proc($self, $dirInfo);
use strict 'refs';

# restore PATH (pop last 2 items)
splice @$path, -2;

# check result
my ($dataPos, $dirLen) = @$dirInfo{'DataPos','DirLen'};
if ($outfile) {
if ($result < 0) {
# copy or delete the trailer ourself
$result = 1;
if ($$self{TrailerStart}) {
$dataPos or $dataPos = $$self{TrailerStart};
$dirLen or $dirLen = $$self{FileEnd} - $offset - $dataPos;
}
if ($$self{DEL_GROUP}{Trailer} or $$self{DEL_GROUP}{$dirName}) {
my $bytes = $dirLen ? " ($dirLen bytes)" : '';
$self->VPrint(0, "Deleting $dirName trailer$bytes\n");
++$$self{CHANGED};
} elsif ($dataPos and $dirLen) {
$self->VPrint(0, "Copying $dirName trailer ($dirLen bytes)\n");
$result = 0 unless $raf->Seek($dataPos) and
$raf->Read(${$$dirInfo{OutFile}}, $dirLen) == $dirLen;
} else {
$result = 0;
}
}
if ($result > 0) {
if ($outBuff) {
# write trailers to OutFile in original order
Expand Down Expand Up @@ -6994,15 +7048,20 @@ sub ProcessTrailers($$)
$success = 0;
last;
}
last unless $result > 0 and $$dirInfo{DirLen};
last unless $result > 0 and $dirLen;
$offset += $dirLen;
last if $dataPos and $$self{TrailerStart} and $dataPos <= $$self{TrailerStart};
# look for next trailer
$offset += $$dirInfo{DirLen};
my $nextTrail = IdentifyTrailer($raf, $offset) or last;
my $nextTrail = IdentifyTrailer($raf, $offset);
# process Google trailer after all others if necessary and not done already
unless ($nextTrail) {
last unless $$self{ProcessGoogleTrailer};
$nextTrail = { DirName => 'Google', RAF => $raf };
}
$dirName = $$dirInfo{DirName} = $$nextTrail{DirName};
$raf->Seek($pos, 0);
}
SetByteOrder($byteOrder); # restore original byte order
$raf->Seek($pos, 0); # restore original file position
$raf->Seek($pos); # restore original file position
$$dirInfo{OutFile} = $outfile; # restore original outfile
$$dirInfo{Offset} = $offset; # return offset from EOF to start of first trailer
$$dirInfo{Fixup} = $fixup; # return fixup information
Expand Down Expand Up @@ -7399,12 +7458,61 @@ sub ProcessJPEG($$;$)
$foundSOS = 1;
# all done with meta information unless we have a trailer
$verbose and print $out "${indent}JPEG SOS\n";
# process extended XMP now if it existed
# (must do this before trailers because XMP is required to process Google trailer)
if (%extendedXMP) {
my $guid;
# GUID indicated by the last main XMP segment
my $goodGuid = $$self{VALUE}{HasExtendedXMP} || '';
# GUID of the extended XMP that we will process ('2' for all)
my $readGuid = $$options{ExtendedXMP} || 0;
$readGuid = $goodGuid if $readGuid eq '1';
foreach $guid (sort keys %extendedXMP) {
next unless length $guid == 32; # ignore other (internal) keys
my $extXMP = $extendedXMP{$guid};
my ($off, @offsets, $warn);
# make sure we have all chunks, and create a list of sorted offsets
for ($off=0; $off<$$extXMP{Size}; ) {
last unless defined $$extXMP{$off};
push @offsets, $off;
$off += length $$extXMP{$off};
}
unless ($off == $$extXMP{Size}) {
$self->Warn("Incomplete extended XMP (GUID $guid)");
next;
}
if ($guid eq $readGuid or $readGuid eq '2') {
$warn = 'Reading non-' if $guid ne $goodGuid;
my $buff = '';
# assemble XMP all together
$buff .= $$extXMP{$_} foreach @offsets;
my $tagTablePtr = GetTagTable('Image::ExifTool::XMP::Main');
my %dirInfo = (
DataPt => \$buff,
Parent => 'APP1',
IsExtended => 1,
);
$$path[$pn] = 'APP1';
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
pop @$path;
} else {
$warn = 'Ignored ';
$warn .= 'non-' if $guid ne $goodGuid;
}
$self->Warn("${warn}standard extended XMP (GUID $guid)") if $warn;
delete $extendedXMP{$guid};
}
}
unless ($fast) {
$trailInfo = IdentifyTrailer($raf);
# check for Google trailer information if specific XMP tags exist
if (not $trailInfo and $$self{ProcessGoogleTrailer}) {
$trailInfo = { DirName => 'Google', RAF => $raf };
}
# process trailer now unless we are doing verbose dump
if ($trailInfo and $verbose < 3 and not $htmlDump) {
# process trailers (keep trailInfo to finish processing later
# only if we can't finish without scanning from end of file)
# only if we can't finish without scanning from JPEG EOF)
$self->ProcessTrailers($trailInfo) and undef $trailInfo;
}
if ($wantTrailer and $$self{PreviewImageStart}) {
Expand Down Expand Up @@ -7577,7 +7685,7 @@ sub ProcessJPEG($$;$)
my $n = length($1) + 1;
$self->HDump($segPos+pos($$dataPt)-$n, $n, '[Vivo HiddenData]', undef, 0x08);
}
my $tbl = GetTagTable('Image::ExifTool::Vivo::Main');
my $tbl = GetTagTable('Image::ExifTool::Trailer::Vivo');
$self->HandleTag($tbl, HiddenData => $1);
}
# avoid looking for preview unless necessary because it really slows
Expand Down Expand Up @@ -8237,50 +8345,6 @@ sub ProcessJPEG($$;$)
}
undef $$segDataPt;
}
# process extended XMP now if it existed
if (%extendedXMP) {
my $guid;
# GUID indicated by the last main XMP segment
my $goodGuid = $$self{VALUE}{HasExtendedXMP} || '';
# GUID of the extended XMP that we will process ('2' for all)
my $readGuid = $$options{ExtendedXMP} || 0;
$readGuid = $goodGuid if $readGuid eq '1';
foreach $guid (sort keys %extendedXMP) {
next unless length $guid == 32; # ignore other (internal) keys
my $extXMP = $extendedXMP{$guid};
my ($off, @offsets, $warn);
# make sure we have all chunks, and create a list of sorted offsets
for ($off=0; $off<$$extXMP{Size}; ) {
last unless defined $$extXMP{$off};
push @offsets, $off;
$off += length $$extXMP{$off};
}
unless ($off == $$extXMP{Size}) {
$self->Warn("Incomplete extended XMP (GUID $guid)");
next;
}
if ($guid eq $readGuid or $readGuid eq '2') {
$warn = 'Reading non-' if $guid ne $goodGuid;
my $buff = '';
# assemble XMP all together
$buff .= $$extXMP{$_} foreach @offsets;
my $tagTablePtr = GetTagTable('Image::ExifTool::XMP::Main');
my %dirInfo = (
DataPt => \$buff,
Parent => 'APP1',
IsExtended => 1,
);
$$path[$pn] = 'APP1';
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
pop @$path;
} else {
$warn = 'Ignored ';
$warn .= 'non-' if $guid ne $goodGuid;
}
$self->Warn("${warn}standard extended XMP (GUID $guid)") if $warn;
delete $extendedXMP{$guid};
}
}
# print verbose hash message if necessary
print $out "${indent}(ImageDataHash: $hashsize bytes of JPEG image data)\n" if $hashsize and $verbose;
# calculate JPEGDigest if requested
Expand Down Expand Up @@ -8557,7 +8621,9 @@ sub DoProcessTIFF($$;$)
if ($raf) {
my $trailInfo = IdentifyTrailer($raf);
if ($trailInfo) {
$$trailInfo{ScanForTrailer} = 1; # scan to find AFCP if necessary
# scan to find AFCP if necessary (Note: we are scanning
# from a random file position in the TIFF)
$$trailInfo{ScanForTrailer} = 1;
$self->ProcessTrailers($trailInfo);
}
# dump any other known trailer (eg. A100 RAW Data)
Expand Down Expand Up @@ -8663,6 +8729,7 @@ sub DoProcessTIFF($$;$)
my $tbuf = '';
$$trailInfo{OutFile} = \$tbuf; # rewrite trailer(s)
$$trailInfo{ScanForTrailer} = 1; # scan for AFCP if necessary
$$self{TrailerStart} = $tiffEnd;
# rewrite all trailers to buffer
unless ($self->ProcessTrailers($trailInfo)) {
undef $trailInfo;
Expand Down
Loading

0 comments on commit f8a00f0

Please sign in to comment.