exiftool_vendored 13.02.0 → 13.04.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/Changes +40 -3
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +76 -43
- data/bin/lib/Image/ExifTool/Apple.pm +2 -2
- data/bin/lib/Image/ExifTool/Canon.pm +7 -1
- data/bin/lib/Image/ExifTool/Exif.pm +15 -4
- data/bin/lib/Image/ExifTool/GIF.pm +143 -92
- data/bin/lib/Image/ExifTool/GPS.pm +33 -29
- data/bin/lib/Image/ExifTool/Geotag.pm +43 -9
- data/bin/lib/Image/ExifTool/GoPro.pm +118 -6
- data/bin/lib/Image/ExifTool/JPEG.pm +9 -1
- data/bin/lib/Image/ExifTool/Matroska.pm +10 -2
- data/bin/lib/Image/ExifTool/OOXML.pm +7 -7
- data/bin/lib/Image/ExifTool/PDF.pm +29 -2
- data/bin/lib/Image/ExifTool/PNG.pm +14 -3
- data/bin/lib/Image/ExifTool/PPM.pm +11 -2
- data/bin/lib/Image/ExifTool/Photoshop.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +6 -1
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +1 -1
- data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
- data/bin/lib/Image/ExifTool/TagLookup.pm +5598 -5583
- data/bin/lib/Image/ExifTool/TagNames.pod +64 -6
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +13 -4
- data/bin/lib/Image/ExifTool/Writer.pl +16 -11
- data/bin/lib/Image/ExifTool/XMP.pm +7 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +64 -0
- data/bin/lib/Image/ExifTool.pm +101 -72
- data/bin/lib/Image/ExifTool.pod +16 -3
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +2 -2
data/bin/lib/Image/ExifTool.pm
CHANGED
@@ -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 $advFmtSelf);
|
31
31
|
|
32
|
-
$VERSION = '13.
|
32
|
+
$VERSION = '13.04';
|
33
33
|
$RELEASE = '';
|
34
34
|
@ISA = qw(Exporter);
|
35
35
|
%EXPORT_TAGS = (
|
@@ -2583,7 +2583,7 @@ sub Options($$;@)
|
|
2583
2583
|
warn("Can't set $param to undef\n");
|
2584
2584
|
}
|
2585
2585
|
} elsif (lc $param eq 'geodir') {
|
2586
|
-
$Image::ExifTool::Geolocation::geoDir = $newVal;
|
2586
|
+
$Image::ExifTool::Geolocation::geoDir = $newVal;
|
2587
2587
|
} else {
|
2588
2588
|
if ($param eq 'Escape') {
|
2589
2589
|
# set ESCAPE_PROC
|
@@ -4404,6 +4404,7 @@ sub DoneExtract($)
|
|
4404
4404
|
local $SIG{'__WARN__'} = \&SetWarning;
|
4405
4405
|
undef $evalWarning;
|
4406
4406
|
$$opts{GeolocMulti} = $$opts{Duplicates};
|
4407
|
+
$self->VPrint(0, "Geolocation arguments: '${arg}'\n");
|
4407
4408
|
my ($cities, $dist) = Image::ExifTool::Geolocation::Geolocate($arg, $opts);
|
4408
4409
|
delete $$opts{GeolocMulti};
|
4409
4410
|
if ($cities and (@$cities < 2 or $dist or not $self->Warn('Multiple Geolocation cities are possible',2))) {
|
@@ -4660,74 +4661,56 @@ sub EncodeFileName($$;$)
|
|
4660
4661
|
# References:
|
4661
4662
|
# - https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
|
4662
4663
|
# - https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
|
4664
|
+
# GetFullPathName supported by Windows XP and later. It handles:
|
4665
|
+
# full path names EG: c:\foto\sub\abc.jpg
|
4666
|
+
# relative EG: .\abc.jpg, ..\abc.jpg
|
4667
|
+
# full UNC paths EG: \\server\share\abc.jpg
|
4668
|
+
# relative UNC paths EG: .\abc.jpg, ..\abc.jpg
|
4669
|
+
# Dos device paths EG: \\.\c:\fotoabc.jpg
|
4670
|
+
# relative path on other drives EG: z:abc.jpg (working dir on z: z:\foto called from c:\foto)
|
4671
|
+
# Wide chars EG: Chars that need UTF8.
|
4672
|
+
my $k32GetFullPathName;
|
4663
4673
|
sub WindowsLongPath($$)
|
4664
4674
|
{
|
4665
4675
|
my ($self, $path) = @_;
|
4666
4676
|
my $debug = $$self{OPTIONS}{Debug};
|
4667
4677
|
my $out = $$self{OPTIONS}{TextOut};
|
4668
|
-
my @fullParts;
|
4669
|
-
my $prefixLen = 0;
|
4670
4678
|
|
4671
4679
|
$debug and print $out "WindowsLongPath input : $path\n";
|
4672
|
-
$path =~ tr(/)(\\); # convert slashes to backslashes
|
4673
|
-
my @pathParts = split /\\/, $path;
|
4674
4680
|
|
4675
|
-
|
4676
|
-
$path =~
|
4677
|
-
|
4678
|
-
|
4679
|
-
$
|
4680
|
-
|
4681
|
-
|
4682
|
-
|
4683
|
-
|
4684
|
-
|
4685
|
-
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4689
|
-
|
4690
|
-
|
4691
|
-
my $drive;
|
4692
|
-
$drive = $1 if $pathParts[0] =~ s/^([a-z]:)//;
|
4693
|
-
my $cwd = Cwd::getdcwd($drive); # ($drive is undef for current working drive)
|
4694
|
-
$debug and print $out "WindowsLongPath getcwd: $cwd\n";
|
4695
|
-
@fullParts = split /[\\\/]/, $cwd;
|
4696
|
-
# UNC path starts with "\\", so first 2 elements are empty
|
4697
|
-
# --> shift and put UNC in first element.
|
4698
|
-
if (@fullParts > 1 and $fullParts[0] eq '' and $fullParts[1] eq '') {
|
4699
|
-
shift @fullParts;
|
4700
|
-
$fullParts[0] = 'UNC';
|
4701
|
-
unshift @fullParts, '', '', '?';
|
4702
|
-
$prefixLen = (@fullParts > 6 ? 6 : @fullParts);
|
4703
|
-
} else {
|
4704
|
-
$prefixLen = 1; # drive designator only
|
4681
|
+
for (;;) { # (cheap goto)
|
4682
|
+
$path =~ tr(/)(\\); # convert slashes to backslashes
|
4683
|
+
last if $path =~ /^\\\\\?\\/; # already a device path in the format we want
|
4684
|
+
|
4685
|
+
unless ($k32GetFullPathName) { # need to import (once) GetFullPathNameW
|
4686
|
+
last if defined $k32GetFullPathName;
|
4687
|
+
unless (eval { require Win32::API }) {
|
4688
|
+
$self->WarnOnce('Install Win32::API to use WindowsLongPath option');
|
4689
|
+
last;
|
4690
|
+
}
|
4691
|
+
$k32GetFullPathName = Win32::API->new('KERNEL32', 'GetFullPathNameW', 'PNPP', 'I');
|
4692
|
+
unless ($k32GetFullPathName) {
|
4693
|
+
$k32GetFullPathName = 0;
|
4694
|
+
$self->Warn('Error loading Win32::API GetFullPathNameW');
|
4695
|
+
last;
|
4696
|
+
}
|
4705
4697
|
}
|
4706
|
-
|
4707
|
-
|
4708
|
-
|
4709
|
-
|
4710
|
-
$
|
4711
|
-
|
4712
|
-
|
4713
|
-
|
4714
|
-
|
4715
|
-
if ($
|
4716
|
-
|
4717
|
-
} elsif ($part eq '') {
|
4718
|
-
# only allow double slashes at start of path name (max 2)
|
4719
|
-
push @fullParts, $part if not @fullParts or (@fullParts == 1 and $fullParts[0] eq '');
|
4720
|
-
} elsif ($part eq '..') {
|
4721
|
-
# step up one directory, but not into the prefix
|
4722
|
-
pop @fullParts if @fullParts > $prefixLen;
|
4698
|
+
my $enc = $$self{OPTIONS}{CharsetFileName};
|
4699
|
+
my $encPath = $self->Encode($path, 'UTF16', 'II', $enc); # need to encode to UTF16
|
4700
|
+
my $lenReq = $k32GetFullPathName->Call($encPath,0,0,0) + 1; # first pass gets length required, +1 for safety (null?)
|
4701
|
+
my $fullPath = "\0" x $lenReq x 2; # create buffer to hold full path
|
4702
|
+
$k32GetFullPathName->Call($encPath, $lenReq, $fullPath, 0); # fullPath is UTF16 now
|
4703
|
+
$path = $self->Decode($fullPath, 'UTF16', 'II', $enc);
|
4704
|
+
|
4705
|
+
last if length($path) <= 247;
|
4706
|
+
|
4707
|
+
if ($path =~ /^\\\\/) {
|
4708
|
+
$path = '\\\\?\\UNC' . substr($path, 1);
|
4723
4709
|
} else {
|
4724
|
-
|
4710
|
+
$path = '\\\\?\\' . $path;
|
4725
4711
|
}
|
4712
|
+
last;
|
4726
4713
|
}
|
4727
|
-
$path = join '\\', @fullParts;
|
4728
|
-
# add device path prefix ("\\?\") if path length near the limit (the most
|
4729
|
-
# conservative limit I can find is 247, which is the limit on the directory name)
|
4730
|
-
$path = '\\\\?\\' . $path unless $prefixLen > 1 or length($path) <= 247;
|
4731
4714
|
$debug and print $out "WindowsLongPath return: $path\n";
|
4732
4715
|
return $path;
|
4733
4716
|
}
|
@@ -4861,16 +4844,16 @@ sub CreateDirectory($$)
|
|
4861
4844
|
my $d2 = $dir; # (must make a copy in case EncodeFileName recodes it)
|
4862
4845
|
if ($self->EncodeFileName($d2)) {
|
4863
4846
|
# handle Windows Unicode directory names
|
4864
|
-
unless (eval { require Win32::API }) {
|
4865
|
-
$err = 'Install Win32::API to create directories with Unicode names';
|
4866
|
-
last;
|
4867
|
-
}
|
4868
4847
|
unless (defined $k32CreateDir) {
|
4848
|
+
unless (eval { require Win32::API }) {
|
4849
|
+
$err = 'Install Win32::API to create directories with Unicode names';
|
4850
|
+
last;
|
4851
|
+
}
|
4869
4852
|
$k32CreateDir = Win32::API->new('KERNEL32', 'CreateDirectoryW', 'PP', 'I');
|
4870
4853
|
unless ($k32CreateDir) {
|
4871
4854
|
$k32CreateDir = 0;
|
4872
4855
|
# give this error once, then just "Error creating" for subsequent attempts
|
4873
|
-
return 'Error
|
4856
|
+
return 'Error loading Win32::API CreateDirectoryW';
|
4874
4857
|
}
|
4875
4858
|
}
|
4876
4859
|
$success = $k32CreateDir->Call($d2, 0) if $k32CreateDir;
|
@@ -4928,13 +4911,13 @@ sub GetFileTime($$)
|
|
4928
4911
|
return () if defined $k32GetFileTime;
|
4929
4912
|
$k32GetFileTime = Win32::API->new('KERNEL32', 'GetFileTime', 'NPPP', 'I');
|
4930
4913
|
unless ($k32GetFileTime) {
|
4931
|
-
$self->Warn('Error
|
4914
|
+
$self->Warn('Error loading Win32::API GetFileTime');
|
4932
4915
|
$k32GetFileTime = 0;
|
4933
4916
|
return ();
|
4934
4917
|
}
|
4935
4918
|
}
|
4936
4919
|
unless ($k32GetFileTime->Call($win32Handle, $ctime, $atime, $mtime)) {
|
4937
|
-
$self->Warn("Win32::API
|
4920
|
+
$self->Warn("Win32::API GetFileTime returned " . Win32::GetLastError());
|
4938
4921
|
return ();
|
4939
4922
|
}
|
4940
4923
|
# convert FILETIME structs to Unix seconds
|
@@ -5085,7 +5068,7 @@ sub IsSameID($$)
|
|
5085
5068
|
|
5086
5069
|
#------------------------------------------------------------------------------
|
5087
5070
|
# Get list of tags in specified group
|
5088
|
-
# Inputs: 0) ExifTool ref, 1) group spec, 2) tag key or reference to list of tag keys
|
5071
|
+
# Inputs: 0) ExifTool ref, 1) group spec (case insensitive), 2) tag key or reference to list of tag keys
|
5089
5072
|
# Returns: list of matching tags in list context, or first match in scalar context
|
5090
5073
|
# Notes: Group spec may contain multiple groups separated by colons, each
|
5091
5074
|
# possibly with a leading family number
|
@@ -6450,9 +6433,45 @@ sub ConvertDateTime($$)
|
|
6450
6433
|
my $fmt = $$self{OPTIONS}{DateFormat};
|
6451
6434
|
my $shift = $$self{OPTIONS}{GlobalTimeShift};
|
6452
6435
|
if ($shift) {
|
6453
|
-
my $dir = ($shift =~ s/^([-+])// and $1 eq '-') ? -1 : 1;
|
6454
6436
|
my $offset = $$self{GLOBAL_TIME_OFFSET};
|
6455
|
-
$
|
6437
|
+
my ($g, $t, $dir, @matches);
|
6438
|
+
if ($shift =~ s/^((\d?[A-Z][-\w]*\w:)*)([A-Z][-\w]*\w)([-+])//i) {
|
6439
|
+
($g, $t, $dir) = ($1, $3, ($4 eq '-' ? -1 : 1));
|
6440
|
+
} else {
|
6441
|
+
$dir = ($shift =~ s/^([-+])// and $1 eq '-') ? -1 : 1;
|
6442
|
+
}
|
6443
|
+
unless ($offset) {
|
6444
|
+
$offset = $$self{GLOBAL_TIME_OFFSET} = { };
|
6445
|
+
# (see forum16692 for a discussion about why this code was added)
|
6446
|
+
if ($t) {
|
6447
|
+
# determine initial shift from specified tag
|
6448
|
+
@matches = sort grep(/^$t( \(|$)/i, keys %{$$self{VALUE}});
|
6449
|
+
if ($g and @matches) {
|
6450
|
+
$g =~ s/:$//;
|
6451
|
+
@matches = $self->GroupMatches($g, \@matches);
|
6452
|
+
}
|
6453
|
+
}
|
6454
|
+
if (not @matches and $$self{TAGS_FROM_FILE} and $$self{OPTIONS}{RequestTags}) {
|
6455
|
+
# determine initial shift from first requested date/time tag
|
6456
|
+
my @reqDate = grep /date/i, @{$$self{OPTIONS}{RequestTags}};
|
6457
|
+
while (@reqDate) {
|
6458
|
+
$t = shift @reqDate;
|
6459
|
+
@matches = sort grep(/^$t( \(|$)/i, keys %{$$self{VALUE}});
|
6460
|
+
my $ti = $$self{TAG_INFO};
|
6461
|
+
for (; @matches; shift @matches) {
|
6462
|
+
# select the first tag that calls this routine in its PrintConv
|
6463
|
+
next unless $$ti{$matches[0]}{PrintConv};
|
6464
|
+
next unless $$ti{$matches[0]}{PrintConv} =~ /ConvertDateTime/;
|
6465
|
+
undef @reqDate;
|
6466
|
+
last;
|
6467
|
+
}
|
6468
|
+
}
|
6469
|
+
}
|
6470
|
+
if (@matches) {
|
6471
|
+
my $val = $self->GetValue($matches[0], 'ValueConv');
|
6472
|
+
ShiftTime($val, $shift, $dir, $offset) if defined $val;
|
6473
|
+
}
|
6474
|
+
}
|
6456
6475
|
ShiftTime($date, $shift, $dir, $offset);
|
6457
6476
|
}
|
6458
6477
|
# only convert date if a format was specified and the date is recognizable
|
@@ -7952,6 +7971,10 @@ sub ProcessJPEG($$;$)
|
|
7952
7971
|
SetByteOrder('II');
|
7953
7972
|
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Isothermal');
|
7954
7973
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
7974
|
+
} elsif ($$segDataPt =~ /^SEAL\0/) {
|
7975
|
+
$dumpType = 'SEAL';
|
7976
|
+
DirStart(\%dirInfo, 5);
|
7977
|
+
$self->ProcessDirectory(\%dirInfo, GetTagTable("Image::ExifTool::XMP::SEAL"));
|
7955
7978
|
}
|
7956
7979
|
} elsif ($marker == 0xe9) { # APP9 (InfiRay, Media Jukebox)
|
7957
7980
|
if ($$segDataPt =~ /^Media Jukebox\0/ and $length > 22) {
|
@@ -7967,6 +7990,10 @@ sub ProcessJPEG($$;$)
|
|
7967
7990
|
SetByteOrder('II');
|
7968
7991
|
my $tagTablePtr = GetTagTable('Image::ExifTool::InfiRay::Sensor');
|
7969
7992
|
$self->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
7993
|
+
} elsif ($$segDataPt =~ /^SEAL\0/) {
|
7994
|
+
$dumpType = 'SEAL';
|
7995
|
+
DirStart(\%dirInfo, 5);
|
7996
|
+
$self->ProcessDirectory(\%dirInfo, GetTagTable("Image::ExifTool::XMP::SEAL"));
|
7970
7997
|
}
|
7971
7998
|
} elsif ($marker == 0xea) { # APP10 (PhotoStudio Unicode comments)
|
7972
7999
|
if ($$segDataPt =~ /^UNICODE\0/) {
|
@@ -8889,6 +8916,7 @@ sub GetTagInfo($$$;$$$)
|
|
8889
8916
|
my ($valPt, $format, $count);
|
8890
8917
|
|
8891
8918
|
my @infoArray = GetTagInfoList($tagTablePtr, $tagID);
|
8919
|
+
my $options = $$self{OPTIONS};
|
8892
8920
|
# evaluate condition
|
8893
8921
|
my $tagInfo;
|
8894
8922
|
foreach $tagInfo (@infoArray) {
|
@@ -8907,9 +8935,9 @@ sub GetTagInfo($$$;$$$)
|
|
8907
8935
|
}
|
8908
8936
|
}
|
8909
8937
|
# don't return Unknown tags unless that option is set (also see forum13716)
|
8910
|
-
if ($$tagInfo{Unknown} and not $$
|
8911
|
-
($$
|
8912
|
-
($$
|
8938
|
+
if ($$tagInfo{Unknown} and not $$options{Unknown} and not
|
8939
|
+
($$options{Verbose} or $$self{HTML_DUMP} or
|
8940
|
+
($$options{Validate} and not $$tagInfo{AddedUnknown})))
|
8913
8941
|
{
|
8914
8942
|
return undef;
|
8915
8943
|
}
|
@@ -8917,7 +8945,7 @@ sub GetTagInfo($$$;$$$)
|
|
8917
8945
|
return $tagInfo;
|
8918
8946
|
}
|
8919
8947
|
# generate information for unknown tags (numerical only) if required
|
8920
|
-
if (not $tagInfo and ($$
|
8948
|
+
if (not $tagInfo and ($$options{Unknown} or $$options{Verbose} or $$self{HTML_DUMP}) and
|
8921
8949
|
$tagID =~ /^\d+$/ and not $$self{NO_UNKNOWN})
|
8922
8950
|
{
|
8923
8951
|
my $printConv;
|
@@ -9102,6 +9130,7 @@ sub HandleTag($$$$;%)
|
|
9102
9130
|
Base => $parms{Base},
|
9103
9131
|
Multi => $$subdir{Multi},
|
9104
9132
|
TagInfo => $tagInfo,
|
9133
|
+
IgnoreProp => $$subdir{IgnoreProp},
|
9105
9134
|
RAF => $parms{RAF},
|
9106
9135
|
);
|
9107
9136
|
my $oldOrder = GetByteOrder();
|
data/bin/lib/Image/ExifTool.pod
CHANGED
@@ -809,8 +809,21 @@ Reference units for writing GPSSpeed when geotagging:
|
|
809
809
|
|
810
810
|
Time shift to apply to all extracted date/time PrintConv values. Does not
|
811
811
|
affect ValueConv values. Value is a date/time shift string (see
|
812
|
-
L<Image::ExifTool::Shift(3pm)|Image::ExifTool::Shift.pl>)
|
813
|
-
'-' for negative shifts
|
812
|
+
L<Image::ExifTool::Shift(3pm)|Image::ExifTool::Shift.pl>) with a leading
|
813
|
+
'-' for negative shifts, or a tag name with option group prefix followed
|
814
|
+
by '+' or '-' then the shift string. Default is undef.
|
815
|
+
|
816
|
+
Note: When specifying a number of months and/or years to shift, the tag for
|
817
|
+
the starting date should be specified so the number of days can be
|
818
|
+
determined unambiguously. For example:
|
819
|
+
|
820
|
+
'createdate-1:0:0 0:0:0' - shift back by the length of the
|
821
|
+
year before the CreateDate value
|
822
|
+
'xmp:createdate+0:2:0 0' - shift forward by the length of
|
823
|
+
the 2 months after XMP:CreateDate
|
824
|
+
|
825
|
+
If the starting tag is not specified, or the specified tag isn't available,
|
826
|
+
then the shift is calculated based on the first shifted tag.
|
814
827
|
|
815
828
|
=item Group#
|
816
829
|
|
@@ -2563,7 +2576,7 @@ Pentax, PhaseOne, PhotoCD, PhotoMechanic, Photoshop, PictureInfo,
|
|
2563
2576
|
PostScript, PreviewIFD, PrintIM, ProfileIFD, Qualcomm, QuickTime, RAF, RAF2,
|
2564
2577
|
RIFF, RMETA, RSRC, RTF, Radiance, Rawzor, Real, Real-CONT, Real-MDPR,
|
2565
2578
|
Real-PROP, Real-RA3, Real-RA4, Real-RA5, Real-RJMD, Reconyx, Red, Ricoh,
|
2566
|
-
SPIFF, SR2, SR2DataIFD, SR2SubIFD, SRF#, SVG, Samsung, Sanyo, Scalado,
|
2579
|
+
SEAL, SPIFF, SR2, SR2DataIFD, SR2SubIFD, SRF#, SVG, Samsung, Sanyo, Scalado,
|
2567
2580
|
Sigma, SigmaRaw, Sony, SonyIDC, Stim, SubIFD, System, Theora, Torrent,
|
2568
2581
|
Track#, UserData, VCalendar, VCard, VNote, Version0, Vorbis, WTV, XML, XMP,
|
2569
2582
|
XMP-DICOM, XMP-Device, XMP-GAudio, XMP-GCamera, XMP-GContainer,
|
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: 13.
|
4
|
+
version: 13.04.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: 2024-11-
|
12
|
+
date: 2024-11-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: exiftool
|