exiftool_vendored 13.02.0 → 13.03.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.
- 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
|
}
|