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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b02d7fc208b8d2296a64a11ab1c08e1a82eb9d2f3e04443dcef0b2c0cd0a7d6
4
- data.tar.gz: 02d7d674c3975c9462c8adfc139e81c692c5f4a1d5dc298a5b83e1f9c1a4def0
3
+ metadata.gz: beee9d5cf55d8f0cdbe040a87bcccb203cb39721065957785486ef6bc02380ca
4
+ data.tar.gz: b5023cb0b5f82e8c4798256b34ea31bc3e99dc805af96d7595f2727ef1b9ce90
5
5
  SHA512:
6
- metadata.gz: 04f78c57d35f72c974d88c53b3a900ccd3f25528b5506e6b5b6fb4f9f9b73f509d01b740184e24bc9f445cee9cde5cfd0fefa71b628497bbbf2c20ef142fe723
7
- data.tar.gz: 8db5ada7fdd6e765139fbda15720cf1bbf5fb61b015055a9249d18270bc05849aa79ddf20d4107e5de1d4260e68ece57a05d730449cb0b5c3aa1f3fb8b5fbc40
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 problem setting FileCreateDate on MacOS Sequoia if the date/time
24
- contains a time zone
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 BinVal option
47
+ - Added SaveBin option
28
48
 
29
49
  Nov. 1, 2024 - Version 13.01
30
50
 
data/bin/META.json CHANGED
@@ -50,5 +50,5 @@
50
50
  }
51
51
  },
52
52
  "release_status" : "stable",
53
- "version" : "13.02"
53
+ "version" : "13.03"
54
54
  }
data/bin/META.yml CHANGED
@@ -31,4 +31,4 @@ recommends:
31
31
  Time::HiRes: '0'
32
32
  requires:
33
33
  perl: '5.004'
34
- version: '13.02'
34
+ version: '13.03'
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.02.tar.gz | tar -xf -
113
- cd Image-ExifTool-13.02
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.02';
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 and print $vout "Setting new values from $csv database\n";
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<-TAG>.
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.) Adding
5714
- the B<-D> or B<-H> option changes tag values to JSON objects with "val" and
5715
- "id" fields. Adding B<-l> adds a "desc" field, and a "num" field if the
5716
- numerical value is different from the converted "val", and "fmt" and "hex"
5717
- fields for EXIF metadata if the API SaveFormat and SaveBin options are set
5718
- respectively. The B<-b> option may be added to output binary data, encoded
5719
- in base64 if necessary (indicated by ASCII "base64:" as the first 7 bytes of
5720
- the value), and B<-t> may be added to include tag table information (see
5721
- B<-t> for details). The JSON output is UTF-8 regardless of any B<-L> or
5722
- B<-charset> option setting, but the UTF-8 validation is disabled if a
5723
- character set other than UTF-8 is specified. Note that ExifTool quotes JSON
5724
- values only if they don't look like numbers (regardless of the original
5725
- storage format or the relevant metadata specification).
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.02 --
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. For more
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<-TAG> or B<--TAG> options. For example, below is a command to compare all
6720
- the same-named files in two different directories, ignoring the System tags:
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.12';
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/ - //; $val =~ s/ ?m$//; $val',
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.53';
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.20';
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 => 1, # length bytes are included in the data
71
- Writable => 2,
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
- # Process meta information in GIF image
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 $$addDirs{XMP} or $$addDirs{ICC_Profile} or defined $newComment;
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 extension containing XMP block if necessary
242
- # (this will place XMP before the first non-extension block)
243
- if (exists $$addDirs{XMP} and not defined $doneDir{XMP}) {
244
- $doneDir{XMP} = 1;
245
- # write new XMP data
246
- my $xmpTable = GetTagTable('Image::ExifTool::XMP::Main');
247
- my %dirInfo = ( Parent => 'GIF' );
248
- $verbose and print $out "Creating XMP application extension block:\n";
249
- $buff = $et->WriteDirectory(\%dirInfo, $xmpTable);
250
- if (defined $buff and length $buff) {
251
- my $lz = pack('C*',1,reverse(0..255),0);
252
- Write($outfile, "\x21\xff\x0bXMP DataXMP", $buff, $lz) or $err = 1;
253
- ++$doneDir{XMP}; # set to 2 to indicate we added XMP
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
- $verbose and print $out " -> no XMP to add\n";
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
- Write($outfile, "\x21\xff\x0bICCRGBG1012") or $err = 1;
269
- my $len = length $buff;
270
- while ($pos < $len) {
271
- my $n = $len - $pos;
272
- $n = 255 if $n > 255;
273
- Write($outfile, chr($n), substr($buff, $pos, $n)) or $err = 1;
274
- $pos += $n;
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
- Write($outfile, "\0") or $err = 1; # write null terminator
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 ICC_Profile to add\n";
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
- $subdir = $$extInfo{SubDirectory};
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
- # rewrite as-is unless this is a writable subdirectory
403
- $justCopy = 1 if $outfile and (not $subdir or not $$extInfo{Writable});
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
- Write($outfile, "\0") if $justCopy;
419
-
420
- if ($subdir) {
421
- my $dirLen = length $dat;
422
- my $name = $$extInfo{Name};
423
- if ($name eq 'XMP') {
424
- # get length of XMP without landing zone data
425
- # (note that LZ data may not be exactly the same as what we use)
426
- $dirLen = pos($dat) if $dat =~ /<\?xpacket end=['"][wr]['"]\?>/g;
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 => $dirLen,
464
+ DirLen => length $dat,
432
465
  DirName => $name,
433
466
  Parent => 'GIF',
434
467
  );
435
468
  my $subTable = GetTagTable($$subdir{TagTable});
436
- if (not $outfile) {
469
+ unless ($outfile) {
437
470
  $et->ProcessDirectory(\%dirInfo, $subTable);
438
- } elsif ($$extInfo{Writable}) {
439
- if ($doneDir{$name} and $doneDir{$name} > 1) {
440
- $et->Warn("Duplicate $name block created");
441
- }
442
- $buff = $et->WriteDirectory(\%dirInfo, $subTable);
443
- if (defined $buff) {
444
- next unless length $buff; # delete this extension if length is zero
445
- # check for null just to be safe
446
- $et->Error("$name contained NULL character") if $buff =~ /\0/;
447
- $dat = $buff;
448
- # add landing zone (without terminator, which will be added later)
449
- $dat .= pack('C*',1,reverse(0..255)) if $$extInfo{IncludeLengthBytes};
450
- } # (else rewrite original data)
451
-
452
- $doneDir{$name} = 1;
453
-
454
- if ($$extInfo{IncludeLengthBytes}) {
455
- # write data and landing zone
456
- Write($outfile, $hdr, $dat) or $err = 1;
457
- } else {
458
- # write as sub-blocks
459
- Write($outfile, $hdr) or $err = 1;
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
  }