exiftool_vendored 13.02.0 → 13.03.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 +23 -3
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +53 -24
- data/bin/lib/Image/ExifTool/Apple.pm +2 -2
- data/bin/lib/Image/ExifTool/Exif.pm +8 -1
- data/bin/lib/Image/ExifTool/GIF.pm +143 -92
- data/bin/lib/Image/ExifTool/JPEG.pm +9 -1
- data/bin/lib/Image/ExifTool/Matroska.pm +10 -2
- 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/QuickTime.pm +6 -1
- data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
- data/bin/lib/Image/ExifTool/TagLookup.pm +5594 -5583
- data/bin/lib/Image/ExifTool/TagNames.pod +43 -4
- 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 +60 -0
- data/bin/lib/Image/ExifTool.pm +94 -67
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: beee9d5cf55d8f0cdbe040a87bcccb203cb39721065957785486ef6bc02380ca
|
4
|
+
data.tar.gz: b5023cb0b5f82e8c4798256b34ea31bc3e99dc805af96d7595f2727ef1b9ce90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e8b38e7fa81625bb834f7f419100eb4116514d6e3f667b80b486e449b36f849ee26dfb9878caab0b0d937b59a803e1177ed459cbf0e6df4a949427b7e87347d
|
7
|
+
data.tar.gz: 36865cb5c13daac876f068af94f9d7b50b16338b0159fadcdd365bb15bf98791956bfe5c2fb25d6ab9521f02126bfc918184f4d12b264e54a24718ab93808f53
|
data/bin/Changes
CHANGED
@@ -7,6 +7,25 @@ RSS feed: https://exiftool.org/rss.xml
|
|
7
7
|
Note: The most recent production release is Version 13.00. (Other versions are
|
8
8
|
considered development releases, and are not uploaded to MetaCPAN.)
|
9
9
|
|
10
|
+
Nov. 12, 2024 - Version 13.03
|
11
|
+
|
12
|
+
- Added ability to include or exclude tags from CSV and JSON imports
|
13
|
+
(-csv=CSVFILE and -json=JSONFILE) by adding -TAG or --TAG options
|
14
|
+
- Added read/delete support for SEAL metadata in JPG, TIFF, XMP, PNG, WEBP,
|
15
|
+
HEIC, PPM, MOV and MP4 files, and read support in PDF, MKV and WAV files
|
16
|
+
- Added support for user-defined application extensions in GIF images
|
17
|
+
- Added print conversion for QuickTime VideoFullRangeFlag
|
18
|
+
- Apply API LimitLongValues option to hex field in -j output
|
19
|
+
- Avoid extracting some large AES-encrypted data from PDF files for
|
20
|
+
performance reasons unless the -m option is used (current limits are 100 kB
|
21
|
+
for XMP and 10 kB for everything else)
|
22
|
+
- Fixed WindowsLongPath option to support wide characters (thanks Frank B)
|
23
|
+
- Fixed problem writing ICC_Profile to a GIF image which already had one
|
24
|
+
- Fixed problem writing Apple:FocusDistanceRange
|
25
|
+
- API Changes:
|
26
|
+
- Enchanced GlobalTimeShift option to allow the base tag to be specified,
|
27
|
+
otherwise use the first specified source date/time tag when copying tags
|
28
|
+
|
10
29
|
Nov. 5, 2024 - Version 13.02
|
11
30
|
|
12
31
|
- Enhanced -j -l output to add optional "fmt" and "hex" fields
|
@@ -20,11 +39,12 @@ Nov. 5, 2024 - Version 13.02
|
|
20
39
|
- Patched to avoid using Encode module in Windows because it can hang if run
|
21
40
|
from a working directory with a long path name
|
22
41
|
- Patched to use -csv output if -j also used
|
23
|
-
- Fixed
|
24
|
-
|
42
|
+
- Fixed a few problems with the new WindowsLongPath option
|
43
|
+
- Fixed problem setting FileCreateDate with Xcode 16 command line tools if the
|
44
|
+
date/time contains a time zone
|
25
45
|
- Fixed problem in -csv output when combined with -g
|
26
46
|
- API Changes:
|
27
|
-
- Added
|
47
|
+
- Added SaveBin option
|
28
48
|
|
29
49
|
Nov. 1, 2024 - Version 13.01
|
30
50
|
|
data/bin/META.json
CHANGED
data/bin/META.yml
CHANGED
data/bin/README
CHANGED
@@ -109,8 +109,8 @@ your home directory, then you would type the following commands in a
|
|
109
109
|
terminal window to extract and run ExifTool:
|
110
110
|
|
111
111
|
cd ~/Desktop
|
112
|
-
gzip -dc Image-ExifTool-13.
|
113
|
-
cd Image-ExifTool-13.
|
112
|
+
gzip -dc Image-ExifTool-13.03.tar.gz | tar -xf -
|
113
|
+
cd Image-ExifTool-13.03
|
114
114
|
./exiftool t/images/ExifTool.jpg
|
115
115
|
|
116
116
|
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 = '13.
|
14
|
+
my $version = '13.03';
|
15
15
|
|
16
16
|
# add our 'lib' directory to the include list BEFORE 'use Image::ExifTool'
|
17
17
|
my $exePath;
|
@@ -1777,7 +1777,7 @@ if ($isWriting) {
|
|
1777
1777
|
if (defined $diff) {
|
1778
1778
|
Error "Can't use -diff option when writing tags\n";
|
1779
1779
|
next;
|
1780
|
-
} elsif (@tags and not $outOpt) {
|
1780
|
+
} elsif (@tags and not $outOpt and not $csv) {
|
1781
1781
|
my ($tg, $s) = @tags > 1 ? ("$tags[0] ...", 's') : ($tags[0], '');
|
1782
1782
|
Warn "Ignored superfluous tag name$s or invalid option$s: -$tg\n";
|
1783
1783
|
}
|
@@ -2852,8 +2852,16 @@ TAG: foreach $tag (@foundTags) {
|
|
2852
2852
|
$$val{num} = $num if defined $num and not IsEqual($num, $$val{val});
|
2853
2853
|
}
|
2854
2854
|
my $ex = $$et{TAG_EXTRA}{$tag};
|
2855
|
-
$$val{'hex'} = join ' ', unpack '(H2)*', $$ex{BinVal} if defined $$ex{BinVal};
|
2856
2855
|
$$val{'fmt'} = $$ex{G6} if defined $$ex{G6};
|
2856
|
+
if (defined $$ex{BinVal}) {
|
2857
|
+
my $max = ($$et{OPTIONS}{LimitLongValues} - 5) / 3;
|
2858
|
+
if ($max >= 0 and length($$ex{BinVal}) > int($max)) {
|
2859
|
+
$max = int $max;
|
2860
|
+
$$val{'hex'} = join ' ', unpack("(H2)$max", $$ex{BinVal}), '[...]';
|
2861
|
+
} else {
|
2862
|
+
$$val{'hex'} = join ' ', unpack '(H2)*', $$ex{BinVal};
|
2863
|
+
}
|
2864
|
+
}
|
2857
2865
|
}
|
2858
2866
|
}
|
2859
2867
|
FormatJSON($fp, $val, $ind, $quote);
|
@@ -3148,9 +3156,15 @@ sub SetImageInfo($$$)
|
|
3148
3156
|
next unless defined $absPath and $csvInfo = $database{$absPath};
|
3149
3157
|
}
|
3150
3158
|
$found = 1;
|
3151
|
-
$verbose
|
3159
|
+
if ($verbose) {
|
3160
|
+
print $vout "Setting new values from $csv database\n";
|
3161
|
+
print $vout 'Including tags: ',join(' ',@tags),"\n" if @tags;
|
3162
|
+
print $vout 'Excluding tags: ',join(' ',@exclude),"\n" if @exclude;
|
3163
|
+
}
|
3152
3164
|
foreach $tag (OrderedKeys($csvInfo)) {
|
3153
3165
|
next if $tag =~ /\b(SourceFile|Directory|FileName)$/i; # don't write these
|
3166
|
+
next if @tags and not grep /^\Q$tag\E$/i, @tags;
|
3167
|
+
next if @exclude and grep /^\Q$tag\E$/i, @exclude;
|
3154
3168
|
my ($rtn, $wrn) = $et->SetNewValue($tag, $$csvInfo{$tag},
|
3155
3169
|
Protected => 1, AddValue => $csvAdd,
|
3156
3170
|
ProtectSaved => $csvSaveCount);
|
@@ -5143,7 +5157,7 @@ information. Use the B<-s> option to see the tag names instead.
|
|
5143
5157
|
=item B<-->I<TAG>
|
5144
5158
|
|
5145
5159
|
Exclude specified tag from extracted information. Same as the B<-x> option.
|
5146
|
-
Group names and wildcards are permitted as described above for B
|
5160
|
+
Group names and wildcards are permitted as described above for B<->I<TAG>.
|
5147
5161
|
Once excluded from the output, a tag may not be re-included by a subsequent
|
5148
5162
|
option. May also be used following a B<-tagsFromFile> option to exclude
|
5149
5163
|
tags from being copied (when redirecting to another tag, it is the source
|
@@ -5574,7 +5588,9 @@ deleted). Also, FileName and Directory columns are ignored if they exist
|
|
5574
5588
|
all other columns are imported. To force a tag to be deleted, use the B<-f>
|
5575
5589
|
option and set the value to "-" in the CSV file (or to the MissingTagValue
|
5576
5590
|
if this API option was used). Multiple databases may be imported in a
|
5577
|
-
single command.
|
5591
|
+
single command. Specific tags may be imported from the database by adding
|
5592
|
+
B<->I<TAG> options to the command, or excluded with B<-->I<TAG> options.
|
5593
|
+
If no tags are specified, then all except FileName and Directory are used.
|
5578
5594
|
|
5579
5595
|
When exporting a CSV file, the B<-g> or B<-G> option adds group names to the
|
5580
5596
|
tag headings. If the B<-a> option is used to allow duplicate tag names, the
|
@@ -5710,19 +5726,28 @@ preserved with the B<-struct> option (this also causes all list-type XMP
|
|
5710
5726
|
tags to be output as JSON arrays, otherwise single-item lists would be
|
5711
5727
|
output as simple strings). The B<-a> option is implied when B<-json> is
|
5712
5728
|
used, but entries with identical JSON names are suppressed in the output.
|
5713
|
-
(B<-G4> may be used to ensure that all tags have unique JSON names.)
|
5714
|
-
|
5715
|
-
|
5716
|
-
|
5717
|
-
|
5718
|
-
|
5719
|
-
|
5720
|
-
|
5721
|
-
|
5722
|
-
|
5723
|
-
|
5724
|
-
|
5725
|
-
|
5729
|
+
(B<-G4> may be used to ensure that all tags have unique JSON names.)
|
5730
|
+
|
5731
|
+
Adding the B<-D> or B<-H> option changes tag values to JSON objects with
|
5732
|
+
"val" and "id" fields. Adding B<-l> adds a "desc" field, and a "num" field
|
5733
|
+
if the numerical value is different from the converted "val", and "fmt" and
|
5734
|
+
"hex" fields for EXIF metadata if the API SaveFormat and SaveBin options are
|
5735
|
+
set respectively, and the length of the "hex" output is limited by the API
|
5736
|
+
LimitLongValues setting. The B<-b> option may be added to output binary
|
5737
|
+
data, encoded in base64 if necessary (indicated by ASCII "base64:" as the
|
5738
|
+
first 7 bytes of the value), and B<-t> may be added to include tag table
|
5739
|
+
information (see B<-t> for details). The JSON output is UTF-8 regardless of
|
5740
|
+
any B<-L> or B<-charset> option setting, but the UTF-8 validation is
|
5741
|
+
disabled if a character set other than UTF-8 is specified.
|
5742
|
+
|
5743
|
+
Note that ExifTool quotes JSON values only if they don't look like numbers
|
5744
|
+
(regardless of the original storage format or the relevant metadata
|
5745
|
+
specification). This may be a problem when reading the JSON via a strongly
|
5746
|
+
typed language. However, the API StructFormat option may be set to "JSONQ"
|
5747
|
+
to force quoting of numbers. As well, the B<-sep> option may be used to
|
5748
|
+
convert arrays into strings. For example:
|
5749
|
+
|
5750
|
+
exiftool -j -api structformat=jsonq -sep ", " ...
|
5726
5751
|
|
5727
5752
|
If I<JSONFILE> is specified, the file is imported and the tag definitions
|
5728
5753
|
from the file are used to set tag values on a per-file basis. The special
|
@@ -5735,7 +5760,9 @@ that options exporting JSON objects instead of simple values are not
|
|
5735
5760
|
compatible with the import file format (ie. export with B<-D>, B<-H>, B<-l>,
|
5736
5761
|
or B<-T> is not compatible, and use B<-G> instead of B<-g>). Additionally,
|
5737
5762
|
tag names in the input JSON file may be suffixed with a C<#> to disable
|
5738
|
-
print conversion.
|
5763
|
+
print conversion. Specific tags may be imported from the database by adding
|
5764
|
+
B<->I<TAG> options to the command, or excluded with B<-->I<TAG> options.
|
5765
|
+
If no tags are specified, then all except FileName and Directory are used.
|
5739
5766
|
|
5740
5767
|
Unlike CSV import, empty values are not ignored, and will cause an empty
|
5741
5768
|
value to be written if supported by the specific metadata type. Tags are
|
@@ -5876,7 +5903,7 @@ with this command:
|
|
5876
5903
|
|
5877
5904
|
produces output like this:
|
5878
5905
|
|
5879
|
-
-- Generated by ExifTool 13.
|
5906
|
+
-- Generated by ExifTool 13.03 --
|
5880
5907
|
File: a.jpg - 2003:10:31 15:44:19
|
5881
5908
|
(f/5.6, 1/60s, ISO 100)
|
5882
5909
|
File: b.jpg - 2006:05:23 11:57:38
|
@@ -6305,7 +6332,8 @@ ExifTool will not scan to the end of a JPEG image to check for an AFCP or
|
|
6305
6332
|
PreviewImage trailer, or past the first comment in GIF images or the
|
6306
6333
|
audio/video data in WAV/AVI files to search for additional metadata. These
|
6307
6334
|
speed benefits are small when reading images directly from disk, but can be
|
6308
|
-
substantial if piping images through a network connection.
|
6335
|
+
substantial if piping images through a network connection. Also bypasses
|
6336
|
+
CRC validation when writing PNG images which can be very slow. For more
|
6309
6337
|
substantial speed benefits, B<-fast2> also causes exiftool to avoid
|
6310
6338
|
extracting any EXIF MakerNote information, and to stop processing at the
|
6311
6339
|
IDAT chunk of PNG images and the mdat atom of QuickTime-format files (but
|
@@ -6716,8 +6744,9 @@ names, even if they begin with a dash (C<->).
|
|
6716
6744
|
Compare metadata in I<FILE> with I<FILE2>. The I<FILE2> name may include
|
6717
6745
|
filename formatting codes (see the B<-w> option). All extracted tags from
|
6718
6746
|
the files are compared, but the extracted tags may be controlled by adding
|
6719
|
-
B
|
6720
|
-
the same-named files in two different directories, ignoring the
|
6747
|
+
B<->I<TAG> or B<-->I<TAG> options. For example, below is a command to
|
6748
|
+
compare all the same-named files in two different directories, ignoring the
|
6749
|
+
System tags:
|
6721
6750
|
|
6722
6751
|
exiftool DIR1 -diff DIR2/%f.%e --system:all
|
6723
6752
|
|
@@ -16,7 +16,7 @@ use vars qw($VERSION);
|
|
16
16
|
use Image::ExifTool::Exif;
|
17
17
|
use Image::ExifTool::PLIST;
|
18
18
|
|
19
|
-
$VERSION = '1.
|
19
|
+
$VERSION = '1.13';
|
20
20
|
|
21
21
|
sub ConvertPLIST($$);
|
22
22
|
|
@@ -99,7 +99,7 @@ sub ConvertPLIST($$);
|
|
99
99
|
my @a = split ' ', $val;
|
100
100
|
sprintf('%.2f - %.2f m', $a[0] <= $a[1] ? @a : reverse @a);
|
101
101
|
},
|
102
|
-
PrintConvInv => '$val =~ s/ -
|
102
|
+
PrintConvInv => '$val =~ s/ - / /; $val =~ s/ ?m$//; $val',
|
103
103
|
},
|
104
104
|
# 0x000d - int32s: 0,1,6,20,24,32,40 (SphereHealthAverageCurrent, ref 2)
|
105
105
|
# 0x000e - int32s: 0,1,4,12 (Orientation? 0=landscape? 4=portrait? ref 1) (SphereMotionDataStatus, ref 2)
|
@@ -57,7 +57,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
|
|
57
57
|
use Image::ExifTool qw(:DataAccess :Utils);
|
58
58
|
use Image::ExifTool::MakerNotes;
|
59
59
|
|
60
|
-
$VERSION = '4.
|
60
|
+
$VERSION = '4.54';
|
61
61
|
|
62
62
|
sub ProcessExif($$$);
|
63
63
|
sub WriteExif($$$);
|
@@ -4421,6 +4421,13 @@ my %opcodeInfo = (
|
|
4421
4421
|
Writable => 'int32u',
|
4422
4422
|
WriteGroup => 'IFD0',
|
4423
4423
|
},
|
4424
|
+
0xcea1 => {
|
4425
|
+
Name => 'SEAL', # (writable directory!)
|
4426
|
+
Writable => 'string',
|
4427
|
+
WriteGroup => 'IFD0',
|
4428
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
|
4429
|
+
WriteCheck => 'return "Can only delete"', # (don't allow writing)
|
4430
|
+
},
|
4424
4431
|
0xea1c => { #13
|
4425
4432
|
Name => 'Padding',
|
4426
4433
|
Binary => 1,
|
@@ -20,7 +20,7 @@ use strict;
|
|
20
20
|
use vars qw($VERSION);
|
21
21
|
use Image::ExifTool qw(:DataAccess :Utils);
|
22
22
|
|
23
|
-
$VERSION = '1.
|
23
|
+
$VERSION = '1.21';
|
24
24
|
|
25
25
|
# road map of directory locations in GIF images
|
26
26
|
my %gifMap = (
|
@@ -28,6 +28,9 @@ my %gifMap = (
|
|
28
28
|
ICC_Profile => 'GIF',
|
29
29
|
);
|
30
30
|
|
31
|
+
# application extensions that we can write, and the order they are written
|
32
|
+
my @appExtensions = ( 'XMP Data/XMP', 'ICCRGBG1/012' );
|
33
|
+
|
31
34
|
%Image::ExifTool::GIF::Main = (
|
32
35
|
GROUPS => { 2 => 'Image' },
|
33
36
|
VARS => { NO_ID => 1 },
|
@@ -61,19 +64,26 @@ my %gifMap = (
|
|
61
64
|
%Image::ExifTool::GIF::Extensions = (
|
62
65
|
GROUPS => { 2 => 'Image' },
|
63
66
|
NOTES => 'Tags extracted from GIF89a application extensions.',
|
67
|
+
WRITE_PROC => sub { return 1 }, # (dummy proc to facilitate writable directories)
|
64
68
|
'NETSCAPE/2.0' => { #3
|
65
69
|
Name => 'Animation',
|
66
70
|
SubDirectory => { TagTable => 'Image::ExifTool::GIF::Animation' },
|
67
71
|
},
|
68
72
|
'XMP Data/XMP' => { #2
|
69
73
|
Name => 'XMP',
|
70
|
-
IncludeLengthBytes
|
71
|
-
|
74
|
+
# IncludeLengthBytes indicates the length bytes are part of the data value...
|
75
|
+
# undef = data may contain nulls and is split into 255-byte blocks
|
76
|
+
# 1 = data may not contain nulls and is not split; NULL padding is added as necessary
|
77
|
+
# 2 = data is not split and may be edited in place; 257-byte landing zone is added
|
78
|
+
# (Terminator may be specified for a value of 1 above, but must be specified for 2)
|
79
|
+
IncludeLengthBytes => 2,
|
80
|
+
Terminator => q(<\\?xpacket end=['"][wr]['"]\\?>), # (regex to match end of valid data)
|
81
|
+
Writable => 2, # (writable directory!)
|
72
82
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
73
83
|
},
|
74
84
|
'ICCRGBG1/012' => { #4
|
75
85
|
Name => 'ICC_Profile',
|
76
|
-
Writable => 2,
|
86
|
+
Writable => 2, # (writable directory!)
|
77
87
|
SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
|
78
88
|
},
|
79
89
|
'MIDICTRL/Jon' => { #5
|
@@ -162,7 +172,7 @@ my %gifMap = (
|
|
162
172
|
);
|
163
173
|
|
164
174
|
#------------------------------------------------------------------------------
|
165
|
-
#
|
175
|
+
# Read/write meta information in GIF image
|
166
176
|
# Inputs: 0) ExifTool object reference, 1) Directory information ref
|
167
177
|
# Returns: 1 on success, 0 if this wasn't a valid GIF file, or -1 if
|
168
178
|
# an output file was specified and a write error occurred
|
@@ -174,7 +184,7 @@ sub ProcessGIF($$)
|
|
174
184
|
my $verbose = $et->Options('Verbose');
|
175
185
|
my $out = $et->Options('TextOut');
|
176
186
|
my ($a, $s, $ch, $length, $buff);
|
177
|
-
my ($err, $newComment, $setComment, $nvComment);
|
187
|
+
my ($err, $newComment, $setComment, $nvComment, $newExt);
|
178
188
|
my ($addDirs, %doneDir);
|
179
189
|
my ($frameCount, $delayTime) = (0, 0);
|
180
190
|
|
@@ -186,9 +196,19 @@ sub ProcessGIF($$)
|
|
186
196
|
my $ver = $1;
|
187
197
|
my $rtnVal = 0;
|
188
198
|
my $tagTablePtr = GetTagTable('Image::ExifTool::GIF::Main');
|
199
|
+
my $extTable = GetTagTable('Image::ExifTool::GIF::Extensions');
|
189
200
|
SetByteOrder('II');
|
190
201
|
|
191
202
|
if ($outfile) {
|
203
|
+
# add any user-defined writable app extensions to the list
|
204
|
+
my $ext;
|
205
|
+
foreach $ext (sort keys %$extTable) {
|
206
|
+
next unless ref $$extTable{$ext} eq 'HASH';
|
207
|
+
my $extInfo = $$extTable{$ext};
|
208
|
+
next unless $$extInfo{SubDirectory} and $$extInfo{Writable} and not $gifMap{$$extInfo{Name}};
|
209
|
+
$gifMap{$$extInfo{Name}} = 'GIF';
|
210
|
+
push @appExtensions, $ext;
|
211
|
+
}
|
192
212
|
$et->InitWriteDirs(\%gifMap, 'XMP'); # make XMP the preferred group for GIF
|
193
213
|
$addDirs = $$et{ADD_DIRS};
|
194
214
|
# determine if we are editing the File:Comment tag
|
@@ -196,8 +216,9 @@ sub ProcessGIF($$)
|
|
196
216
|
$newComment = $et->GetNewValue('Comment', \$nvComment);
|
197
217
|
$setComment = 1 if $nvComment or $$delGroup{File};
|
198
218
|
# change to GIF 89a if adding comment, XMP or ICC_Profile
|
199
|
-
$buff = 'GIF89a' if
|
219
|
+
$buff = 'GIF89a' if %$addDirs or defined $newComment;
|
200
220
|
Write($outfile, $buff, $s) or $err = 1;
|
221
|
+
$newExt = $et->GetNewTagInfoHash($extTable);
|
201
222
|
} else {
|
202
223
|
$et->SetFileType(); # set file type
|
203
224
|
$et->HandleTag($tagTablePtr, 'GIFVersion', $ver);
|
@@ -238,45 +259,50 @@ Block:
|
|
238
259
|
undef $nvComment; # delete any other extraneous comments
|
239
260
|
++$$et{CHANGED}; # increment file changed flag
|
240
261
|
}
|
241
|
-
# add application
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
my $
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
262
|
+
# add application extensions if necessary
|
263
|
+
my $ext;
|
264
|
+
my @new = sort keys %$newExt;
|
265
|
+
foreach $ext (@appExtensions, @new) {
|
266
|
+
my $extInfo = $$extTable{$ext};
|
267
|
+
my $name = $$extInfo{Name};
|
268
|
+
if ($$newExt{$ext}) {
|
269
|
+
delete $$newExt{$ext};
|
270
|
+
$doneDir{$name} = 1; # (we wrote this as a block instead)
|
271
|
+
$buff = $et->GetNewValue($extInfo);
|
272
|
+
$et->VerboseValue("+ GIF:$name", $buff);
|
273
|
+
} elsif (exists $$addDirs{$name} and not defined $doneDir{$name}) {
|
274
|
+
$doneDir{$name} = 1;
|
275
|
+
my $tbl = GetTagTable($$extInfo{SubDirectory}{TagTable});
|
276
|
+
my %dirInfo = ( Parent => 'GIF' );
|
277
|
+
$verbose and print $out "Creating $name application extension block:\n";
|
278
|
+
$buff = $et->WriteDirectory(\%dirInfo, $tbl);
|
254
279
|
} else {
|
255
|
-
|
280
|
+
next;
|
256
281
|
}
|
257
|
-
}
|
258
|
-
# add application extension containing ICC_Profile if necessary
|
259
|
-
if (exists $$addDirs{ICC_Profile} and not defined $doneDir{ICC_Profile}) {
|
260
|
-
$doneDir{ICC_Profile} = 1;
|
261
|
-
# write new ICC_Profile
|
262
|
-
my $iccTable = GetTagTable('Image::ExifTool::ICC_Profile::Main');
|
263
|
-
my %dirInfo = ( Parent => 'GIF' );
|
264
|
-
$verbose and print $out "Creating ICC_Profile application extension block:\n";
|
265
|
-
$buff = $et->WriteDirectory(\%dirInfo, $iccTable);
|
266
282
|
if (defined $buff and length $buff) {
|
283
|
+
++$$et{CHANGED};
|
284
|
+
Write($outfile, "\x21\xff\x0b", substr($ext,0,8), substr($ext,9,3)) or $err = 1;
|
267
285
|
my $pos = 0;
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
286
|
+
if (not $$extTable{$ext}{IncludeLengthBytes}) {
|
287
|
+
my $len = length $buff;
|
288
|
+
while ($pos < length $buff) {
|
289
|
+
my $n = length($buff) - $pos;
|
290
|
+
$n = 255 if $n > 255;
|
291
|
+
Write($outfile, chr($n), substr($buff, $pos, $n)) or $err = 1;
|
292
|
+
$pos += $n;
|
293
|
+
}
|
294
|
+
Write($outfile, "\0") or $err = 1; # write null terminator
|
295
|
+
} elsif ($$extTable{$ext}{IncludeLengthBytes} < 2) {
|
296
|
+
$pos += ord(substr($buff,$pos,1)) + 1 while $pos < length $buff;
|
297
|
+
# write data, null padding and terminator
|
298
|
+
Write($outfile, $buff, "\0" x ($pos - length($buff) + 1)) or $err = 1;
|
299
|
+
} else {
|
300
|
+
# write data, landing zone and null terminator
|
301
|
+
Write($outfile, $buff, pack('C*',1,reverse(0..255),0)) or $err = 1;
|
275
302
|
}
|
276
|
-
|
277
|
-
++$doneDir{ICC_Profile}; # set to 2 to indicate we added a new profile
|
303
|
+
++$doneDir{$name}; # set to 2 to indicate we added it
|
278
304
|
} else {
|
279
|
-
$verbose and print $out " -> no
|
305
|
+
$verbose and print $out " -> no $name to add\n";
|
280
306
|
}
|
281
307
|
}
|
282
308
|
}
|
@@ -286,7 +312,7 @@ Block:
|
|
286
312
|
# image descriptor
|
287
313
|
last unless $raf->Read($buff, 8) == 8 and $raf->Read($ch, 1);
|
288
314
|
Write($outfile, $buff, $ch) or $err = 1 if $outfile;
|
289
|
-
if ($verbose) {
|
315
|
+
if ($verbose and not $outfile) {
|
290
316
|
my ($left, $top, $w, $h) = unpack('v*', $buff);
|
291
317
|
print $out "Image: left=$left top=$top width=$w height=$h\n";
|
292
318
|
}
|
@@ -352,9 +378,9 @@ Block:
|
|
352
378
|
}
|
353
379
|
if ($isOverwriting) {
|
354
380
|
++$$et{CHANGED}; # increment file changed flag
|
355
|
-
$et->VerboseValue('- Comment', $comment);
|
381
|
+
$et->VerboseValue('- GIF:Comment', $comment);
|
356
382
|
$comment = $newComment;
|
357
|
-
$et->VerboseValue('+ Comment', $comment) if defined $comment;
|
383
|
+
$et->VerboseValue('+ GIF:Comment', $comment) if defined $comment;
|
358
384
|
undef $nvComment; # just delete remaining comments
|
359
385
|
} else {
|
360
386
|
undef $setComment; # leave remaining comments alone
|
@@ -393,14 +419,19 @@ Block:
|
|
393
419
|
$tag =~ tr/\0-\x1f//d; # remove nulls and control characters
|
394
420
|
$verbose and print $out "Application Extension: $tag\n";
|
395
421
|
|
396
|
-
my $extTable = GetTagTable('Image::ExifTool::GIF::Extensions');
|
397
422
|
my $extInfo = $$extTable{$tag};
|
398
|
-
my ($subdir, $inclLen, $justCopy);
|
423
|
+
my ($subdir, $inclLen, $justCopy, $name);
|
399
424
|
if ($extInfo) {
|
400
|
-
$
|
425
|
+
if ($outfile and $$newExt{$$extInfo{TagID}}) {
|
426
|
+
delete $$newExt{$$extInfo{TagID}}; # don't create again
|
427
|
+
# (write as a block -- don't define $subdir)
|
428
|
+
} else {
|
429
|
+
$subdir = $$extInfo{SubDirectory};
|
430
|
+
}
|
401
431
|
$inclLen = $$extInfo{IncludeLengthBytes};
|
402
|
-
|
403
|
-
|
432
|
+
$name = $$extInfo{Name};
|
433
|
+
# rewrite as-is unless this is a writable
|
434
|
+
$justCopy = 1 if $outfile and not $$extInfo{Writable};
|
404
435
|
} else {
|
405
436
|
$justCopy = 1 if $outfile;
|
406
437
|
}
|
@@ -415,62 +446,82 @@ Block:
|
|
415
446
|
Write($outfile, $ch, $buff) or $err = 1 if $justCopy;
|
416
447
|
$dat .= $inclLen ? $ch . $buff : $buff;
|
417
448
|
}
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
if ($
|
424
|
-
|
425
|
-
|
426
|
-
$
|
449
|
+
if ($justCopy) {
|
450
|
+
Write($outfile, "\0") or $err = 1;
|
451
|
+
next;
|
452
|
+
} elsif ($inclLen) {
|
453
|
+
# remove landing zone or padding
|
454
|
+
if ($$extInfo{Terminator} and $dat =~ /$$extInfo{Terminator}/g) {
|
455
|
+
$dat = substr($dat, 0, pos($dat));
|
456
|
+
} elsif ($dat =~ /\0/g) {
|
457
|
+
$dat = substr($dat, 0, pos($dat) - 1);
|
427
458
|
}
|
459
|
+
}
|
460
|
+
if ($subdir) {
|
428
461
|
my %dirInfo = (
|
429
462
|
DataPt => \$dat,
|
430
463
|
DataLen => length $dat,
|
431
|
-
DirLen => $
|
464
|
+
DirLen => length $dat,
|
432
465
|
DirName => $name,
|
433
466
|
Parent => 'GIF',
|
434
467
|
);
|
435
468
|
my $subTable = GetTagTable($$subdir{TagTable});
|
436
|
-
|
469
|
+
unless ($outfile) {
|
437
470
|
$et->ProcessDirectory(\%dirInfo, $subTable);
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
$
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
my $pos = 0;
|
461
|
-
my $len = length $dat;
|
462
|
-
while ($pos < $len) {
|
463
|
-
my $n = $len - $pos;
|
464
|
-
$n = 255 if $n > 255;
|
465
|
-
Write($outfile, chr($n), substr($dat, $pos, $n)) or $err = 1;
|
466
|
-
$pos += $n;
|
467
|
-
}
|
468
|
-
}
|
469
|
-
Write($outfile, "\0") or $err = 1; # write null terminator
|
471
|
+
next;
|
472
|
+
}
|
473
|
+
next if $justCopy;
|
474
|
+
if ($doneDir{$name} and $doneDir{$name} > 1) {
|
475
|
+
$et->Warn("Duplicate $name block created");
|
476
|
+
}
|
477
|
+
$buff = $et->WriteDirectory(\%dirInfo, $subTable);
|
478
|
+
if (defined $buff) {
|
479
|
+
next unless length $buff; # delete this extension if length is zero
|
480
|
+
$dat = $buff;
|
481
|
+
}
|
482
|
+
$doneDir{$name} = 1;
|
483
|
+
} elsif ($outfile and not $justCopy) {
|
484
|
+
my $nvHash = $et->GetNewValueHash($extInfo);
|
485
|
+
if ($nvHash and $et->IsOverwriting($nvHash, $dat)) {
|
486
|
+
++$$et{CHANGED};
|
487
|
+
my $val = $et->GetNewValue($extInfo);
|
488
|
+
$et->VerboseValue("- GIF:$name", $dat);
|
489
|
+
next unless defined $val and length $val;
|
490
|
+
$dat = $val;
|
491
|
+
$et->VerboseValue("+ GIF:$name", $dat);
|
492
|
+
$doneDir{$name} = 1; # (possibly wrote dir as a block)
|
470
493
|
}
|
471
494
|
} elsif (not $outfile) {
|
472
495
|
$et->HandleTag($extTable, $tag, $dat);
|
496
|
+
next;
|
497
|
+
}
|
498
|
+
Write($outfile, $hdr) or $err = 1; # write extension header
|
499
|
+
if ($inclLen) {
|
500
|
+
# check for null just to be safe
|
501
|
+
$et->Error("$name contained NULL character") if $inclLen and $dat =~ /\0/;
|
502
|
+
if ($inclLen > 1) {
|
503
|
+
# add landing zone (without terminator, which will be added later)
|
504
|
+
$dat .= pack('C*',1,reverse(0..255)) if $inclLen;
|
505
|
+
} else {
|
506
|
+
# pad with nulls as required
|
507
|
+
my $pos = 0;
|
508
|
+
$pos += ord(substr($dat,$pos,1)) + 1 while $pos < length $dat;
|
509
|
+
$dat .= "\0" x ($pos - length($dat));
|
510
|
+
}
|
511
|
+
# write data and landing zone
|
512
|
+
Write($outfile, $dat) or $err = 1;
|
513
|
+
} else {
|
514
|
+
# write as sub-blocks
|
515
|
+
my $pos = 0;
|
516
|
+
my $len = length $dat;
|
517
|
+
while ($pos < $len) {
|
518
|
+
my $n = $len - $pos;
|
519
|
+
$n = 255 if $n > 255;
|
520
|
+
Write($outfile, chr($n), substr($dat, $pos, $n)) or $err = 1;
|
521
|
+
$pos += $n;
|
522
|
+
}
|
473
523
|
}
|
524
|
+
Write($outfile, "\0") or $err = 1; # write null terminator
|
474
525
|
next;
|
475
526
|
|
476
527
|
} elsif ($a == 0xf9 and $length == 4) { # graphic control extension
|
@@ -489,7 +540,7 @@ Block:
|
|
489
540
|
|
490
541
|
last unless $raf->Read($buff, $length) == $length;
|
491
542
|
Write($outfile, $ch, $s, $buff) or $err = 1 if $outfile;
|
492
|
-
if ($verbose) {
|
543
|
+
if ($verbose and not $outfile) {
|
493
544
|
my ($left, $top, $w, $h) = unpack('v4', $buff);
|
494
545
|
print $out "Text: left=$left top=$top width=$w height=$h\n";
|
495
546
|
}
|