exiftool_vendored 10.58.0 → 10.65.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of exiftool_vendored might be problematic. Click here for more details.

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +100 -1
  3. data/bin/MANIFEST +2 -0
  4. data/bin/META.json +1 -1
  5. data/bin/META.yml +1 -1
  6. data/bin/README +39 -38
  7. data/bin/arg_files/exif2iptc.args +3 -0
  8. data/bin/arg_files/iptc2exif.args +3 -0
  9. data/bin/config_files/example.config +16 -14
  10. data/bin/config_files/photoshop_paths.config +10 -0
  11. data/bin/exiftool +71 -65
  12. data/bin/lib/Image/ExifTool/APE.pm +5 -0
  13. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +31 -15
  14. data/bin/lib/Image/ExifTool/Canon.pm +18 -4
  15. data/bin/lib/Image/ExifTool/CanonCustom.pm +3 -0
  16. data/bin/lib/Image/ExifTool/Charset/DOSLatin1.pm +49 -0
  17. data/bin/lib/Image/ExifTool/Charset/DOSLatinUS.pm +49 -0
  18. data/bin/lib/Image/ExifTool/Charset.pm +8 -5
  19. data/bin/lib/Image/ExifTool/Exif.pm +37 -18
  20. data/bin/lib/Image/ExifTool/FLAC.pm +47 -37
  21. data/bin/lib/Image/ExifTool/FLIR.pm +3 -3
  22. data/bin/lib/Image/ExifTool/FujiFilm.pm +5 -2
  23. data/bin/lib/Image/ExifTool/GPS.pm +6 -6
  24. data/bin/lib/Image/ExifTool/Geotag.pm +1 -1
  25. data/bin/lib/Image/ExifTool/H264.pm +2 -0
  26. data/bin/lib/Image/ExifTool/ID3.pm +8 -3
  27. data/bin/lib/Image/ExifTool/IPTC.pm +1 -1
  28. data/bin/lib/Image/ExifTool/Import.pm +4 -1
  29. data/bin/lib/Image/ExifTool/InDesign.pm +11 -7
  30. data/bin/lib/Image/ExifTool/Kodak.pm +4 -1
  31. data/bin/lib/Image/ExifTool/Lang/de.pm +31 -31
  32. data/bin/lib/Image/ExifTool/MWG.pm +12 -4
  33. data/bin/lib/Image/ExifTool/MakerNotes.pm +3 -3
  34. data/bin/lib/Image/ExifTool/Matroska.pm +2 -1
  35. data/bin/lib/Image/ExifTool/Microsoft.pm +3 -3
  36. data/bin/lib/Image/ExifTool/Minolta.pm +71 -61
  37. data/bin/lib/Image/ExifTool/Nikon.pm +286 -43
  38. data/bin/lib/Image/ExifTool/NikonCustom.pm +1049 -0
  39. data/bin/lib/Image/ExifTool/Olympus.pm +4 -1
  40. data/bin/lib/Image/ExifTool/PNG.pm +4 -7
  41. data/bin/lib/Image/ExifTool/PanasonicRaw.pm +24 -1
  42. data/bin/lib/Image/ExifTool/Pentax.pm +20 -6
  43. data/bin/lib/Image/ExifTool/Photoshop.pm +24 -3
  44. data/bin/lib/Image/ExifTool/QuickTime.pm +545 -14
  45. data/bin/lib/Image/ExifTool/README +16 -9
  46. data/bin/lib/Image/ExifTool/RIFF.pm +8 -1
  47. data/bin/lib/Image/ExifTool/Samsung.pm +5 -4
  48. data/bin/lib/Image/ExifTool/Sigma.pm +9 -1
  49. data/bin/lib/Image/ExifTool/Sony.pm +327 -153
  50. data/bin/lib/Image/ExifTool/TagLookup.pm +3273 -3220
  51. data/bin/lib/Image/ExifTool/TagNames.pod +317 -38
  52. data/bin/lib/Image/ExifTool/Validate.pm +15 -1
  53. data/bin/lib/Image/ExifTool/WriteExif.pl +5 -0
  54. data/bin/lib/Image/ExifTool/WriteIPTC.pl +23 -1
  55. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +8 -2
  56. data/bin/lib/Image/ExifTool/WriteXMP.pl +7 -0
  57. data/bin/lib/Image/ExifTool/Writer.pl +96 -18
  58. data/bin/lib/Image/ExifTool/XMP.pm +20 -11
  59. data/bin/lib/Image/ExifTool/XMP2.pl +634 -583
  60. data/bin/lib/Image/ExifTool.pm +124 -17
  61. data/bin/lib/Image/ExifTool.pod +86 -82
  62. data/bin/perl-Image-ExifTool.spec +38 -37
  63. data/lib/exiftool_vendored/version.rb +1 -1
  64. metadata +4 -2
@@ -11,7 +11,7 @@ package Image::ExifTool::Validate;
11
11
  use strict;
12
12
  use vars qw($VERSION %exifSpec);
13
13
 
14
- $VERSION = '1.02';
14
+ $VERSION = '1.03';
15
15
 
16
16
  use Image::ExifTool qw(:Utils);
17
17
  use Image::ExifTool::Exif;
@@ -285,6 +285,20 @@ sub FinishValidate($$)
285
285
  }
286
286
  }
287
287
  }
288
+ # validate file extension
289
+ if ($$et{FILENAME} ne '') {
290
+ my $fileExt = ($$et{FILENAME} =~ /^.*\.([^.]+)$/s) ? uc($1) : '';
291
+ my $extFileType = Image::ExifTool::GetFileType($fileExt);
292
+ if ($extFileType and $extFileType ne $fileType) {
293
+ my $normExt = $$et{VALUE}{FileTypeExtension};
294
+ if ($normExt and $normExt ne $fileExt) {
295
+ my $lkup = $Image::ExifTool::fileTypeLookup{$fileExt};
296
+ if (ref $lkup or $lkup ne $normExt) {
297
+ $et->Warn("File has wrong extension (should be $normExt, not $fileExt)");
298
+ }
299
+ }
300
+ }
301
+ }
288
302
  MakeValidateTag($et) if $mkTag;
289
303
  }
290
304
 
@@ -563,6 +563,8 @@ sub WriteExif($$$)
563
563
  # update local variables from fixed values
564
564
  $base = $$dirInfo{Base};
565
565
  $dataPos = $$dirInfo{DataPos};
566
+ # changed if ForceWrite tag was was set to "FixBase"
567
+ ++$$et{CHANGED} if $$et{FORCE_WRITE}{FixBase};
566
568
  }
567
569
 
568
570
  # initialize variables to handle mandatory tags
@@ -2451,6 +2453,9 @@ NoOverwrite: next if $isNew > 0;
2451
2453
  # (could be up to 10 bytes and still be empty)
2452
2454
  $newData = '' if defined $newData and length($newData) < 12;
2453
2455
 
2456
+ # set changed if ForceWrite tag was set to "EXIF"
2457
+ ++$$et{CHANGED} if defined $newData and length $newData and $$et{FORCE_WRITE}{EXIF};
2458
+
2454
2459
  return $newData; # return our directory data
2455
2460
  }
2456
2461
 
@@ -127,7 +127,7 @@ sub CheckIPTC($$$)
127
127
  $len = $minlen;
128
128
  }
129
129
  }
130
- if (defined $minlen) {
130
+ if (defined $minlen and $fmt ne 'string') { # (must truncate strings later, after recoding)
131
131
  $maxlen or $maxlen = $minlen;
132
132
  if ($len < $minlen) {
133
133
  unless ($$et{OPTIONS}{IgnoreMinorErrors}) {
@@ -185,6 +185,26 @@ sub FormatIPTC($$$$$;$)
185
185
  } elsif ($$xlatPtr and $rec < 7 and $$valPtr =~ /[\x80-\xff]/) {
186
186
  TranslateCodedString($et, $valPtr, $xlatPtr, $read);
187
187
  }
188
+ # must check length now (after any string recoding)
189
+ if (not $read and $format =~ /^string\[(\d+),?(\d*)\]$/) {
190
+ my ($minlen, $maxlen) = ($1, $2);
191
+ my $len = length $$valPtr;
192
+ $maxlen or $maxlen = $minlen;
193
+ if ($len < $minlen) {
194
+ if ($et->Warn("String to short for IPTC:$$tagInfo{Name} (padded)", 2)) {
195
+ $$valPtr .= ' ' x ($minlen - $len);
196
+ }
197
+ } elsif ($len > $maxlen) {
198
+ if ($et->Warn("IPTC:$$tagInfo{Name} exceeds length limit (truncated)", 2)) {
199
+ $$valPtr = substr($$valPtr, 0, $maxlen);
200
+ # make sure UTF-8 is still valid
201
+ if (($$xlatPtr || $et->Options('Charset')) eq 'UTF8') {
202
+ require Image::ExifTool::XMP;
203
+ Image::ExifTool::XMP::FixUTF8($valPtr,'.');
204
+ }
205
+ }
206
+ }
207
+ }
188
208
  }
189
209
  }
190
210
 
@@ -670,6 +690,8 @@ sub WriteIPTC($$$)
670
690
  }
671
691
  last;
672
692
  }
693
+ # set changed if ForceWrite tag was set to "IPTC"
694
+ ++$$et{CHANGED} if defined $newData and length $newData and $$et{FORCE_WRITE}{IPTC};
673
695
  return $newData;
674
696
  }
675
697
 
@@ -23,6 +23,7 @@ my %mp4Map = (
23
23
  my %dirMap = (
24
24
  MOV => \%movMap,
25
25
  MP4 => \%mp4Map,
26
+ HEIC => { }, # can't currently write XMP to HEIC files
26
27
  );
27
28
 
28
29
  #------------------------------------------------------------------------------
@@ -135,7 +136,7 @@ sub WriteQuickTime($$$)
135
136
  undef $tagInfo;
136
137
  }
137
138
  }
138
- if ($tagInfo) {
139
+ if ($tagInfo and (not defined $$tagInfo{Writable} or $$tagInfo{Writable})) {
139
140
  # read the atom data
140
141
  $raf->Read($buff, $size) == $size or $et->Error("Error reading $tag data"), last;
141
142
  my $subdir = $$tagInfo{SubDirectory};
@@ -310,7 +311,12 @@ sub WriteMOV($$)
310
311
  $buff !~ /^(....)+(qt )/s)
311
312
  {
312
313
  # file is MP4 format if 'ftyp' exists without 'qt ' as a compatible brand
313
- $ftype = 'MP4';
314
+ if ($buff =~ /^(heic|mif1|msf1|heix|hevc|hevx)/) {
315
+ $ftype = 'HEIC';
316
+ $et->Error("Can't currently write HEIC/HEIF files");
317
+ } else {
318
+ $ftype = 'MP4';
319
+ }
314
320
  } else {
315
321
  $ftype = 'MOV';
316
322
  }
@@ -688,6 +688,12 @@ sub WriteXMP($$;$)
688
688
  }
689
689
  delete $$et{XMP_ERROR};
690
690
  delete $$et{XMP_ABOUT};
691
+
692
+ # call InitWriteDirs to initialize FORCE_WRITE flags if necessary
693
+ $et->InitWriteDirs({}, 'XMP') if $xmpFile and $et->GetNewValue('ForceWrite');
694
+ # set changed if we are ForceWrite tag was set to "XMP"
695
+ ++$changed if $$et{FORCE_WRITE}{XMP};
696
+
691
697
  } elsif (defined $about) {
692
698
  $et->VerboseValue('+ XMP-rdf:About', $about);
693
699
  $about = EscapeXML($about); # must escape for XML
@@ -1116,6 +1122,7 @@ sub WriteXMP($$;$)
1116
1122
  my $maxDataLen = $$dirInfo{MaxDataLen};
1117
1123
  # get DataPt again because it may have been set by ProcessXMP
1118
1124
  $dataPt = $$dirInfo{DataPt};
1125
+
1119
1126
  # return now if we didn't change anything
1120
1127
  unless ($changed or ($maxDataLen and $dataPt and defined $$dataPt and
1121
1128
  length($$dataPt) > $maxDataLen))
@@ -268,7 +268,7 @@ my %ignorePrintConv = map { $_ => 1 } qw(OTHER BITMASK Notes);
268
268
  # WriteGroup - group name where information is being written (correct case)
269
269
  # WantGroup - group name as specified in call to function (case insensitive)
270
270
  # Next - pointer to next new value hash (if more than one)
271
- # NoReplace - set for List-type tag if value was created with Replace=0
271
+ # NoReplace - set if value was created with Replace=0
272
272
  # AddBefore - number of list items added by a subsequent Replace=0 call
273
273
  # IsNVH - Flag indicating this is a new value hash
274
274
  # Shift - shift value
@@ -900,7 +900,7 @@ TAG: foreach $tagInfo (@matchingTags) {
900
900
  my $nvHash = $self->GetNewValueHash($tagInfo, $writeGroup, 'create', $options{ProtectSaved});
901
901
  # ignore new values protected with ProtectSaved
902
902
  $nvHash or ++$numSet, next; # (increment $numSet to avoid warning)
903
- $$nvHash{NoReplace} = 1 if $$tagInfo{List} and not $options{Replace};
903
+ $$nvHash{NoReplace} = 1 unless $options{Replace};
904
904
  $$nvHash{WantGroup} = $wantGroup;
905
905
  $$nvHash{EditOnly} = 1 if $editOnly;
906
906
  # save maker note information if writing maker notes
@@ -1619,7 +1619,7 @@ sub CountNewValues($)
1619
1619
  # Save new values for subsequent restore
1620
1620
  # Inputs: 0) ExifTool object reference
1621
1621
  # Returns: Number of times new values have been saved
1622
- # Notes: increments Save flag each time routine is called
1622
+ # Notes: increments SAVE_COUNT flag each time routine is called
1623
1623
  sub SaveNewValues($)
1624
1624
  {
1625
1625
  my $self = shift;
@@ -2820,7 +2820,7 @@ sub InsertTagValues($$$;$)
2820
2820
  }
2821
2821
  # allow trailing '#' to indicate ValueConv value
2822
2822
  $type = 'ValueConv' if $line =~ s/^#//;
2823
- # (and undocumented feature to allow '@' to evaluate values separately, but only in braces)
2823
+ # (undocumented feature to allow '@' to evaluate values separately, but only in braces)
2824
2824
  if ($bra and $line =~ s/^\@(#)?//) {
2825
2825
  $asList = 1;
2826
2826
  $type = 'ValueConv' if $1;
@@ -2933,7 +2933,7 @@ sub InsertTagValues($$$;$)
2933
2933
  #### eval advanced formatting expression ($_, $self, @val, $advFmtSelf)
2934
2934
  eval $expr;
2935
2935
  $@ and $evalWarning = $@;
2936
- $val = $_;
2936
+ $val = ref $_ eq 'ARRAY' ? join($$self{OPTIONS}{ListSep}, @$_): $_;
2937
2937
  }
2938
2938
  if ($evalWarning) {
2939
2939
  my $str = CleanWarning() . " for '$var'";
@@ -3223,8 +3223,27 @@ sub IsOverwriting($$;$)
3223
3223
  my $shiftType = $$tagInfo{Shift};
3224
3224
  unless ($shiftType and $shiftType eq 'Time') {
3225
3225
  unless (IsFloat($val)) {
3226
- $self->Warn("Can't shift $$tagInfo{Name} (not a number)");
3227
- return 0;
3226
+ # do the ValueConv to try to get a number
3227
+ my $conv = $$tagInfo{ValueConv};
3228
+ if (defined $conv) {
3229
+ local $SIG{'__WARN__'} = \&SetWarning;
3230
+ undef $evalWarning;
3231
+ if (ref $conv eq 'CODE') {
3232
+ $val = &$conv($val, $self);
3233
+ } elsif (not ref $conv) {
3234
+ #### eval ValueConv ($val, $self)
3235
+ $val = eval $conv;
3236
+ $@ and $evalWarning = $@;
3237
+ }
3238
+ if ($evalWarning) {
3239
+ $self->Warn("ValueConv $$tagInfo{Name}: " . CleanWarning());
3240
+ return 0;
3241
+ }
3242
+ }
3243
+ unless (defined $val and IsFloat($val)) {
3244
+ $self->Warn("Can't shift $$tagInfo{Name} (not a number)");
3245
+ return 0;
3246
+ }
3228
3247
  }
3229
3248
  $shiftType = 'Number'; # allow any number to be shifted
3230
3249
  }
@@ -3558,11 +3577,13 @@ sub GetLangInfo($$)
3558
3577
 
3559
3578
  #------------------------------------------------------------------------------
3560
3579
  # initialize ADD_DIRS and EDIT_DIRS hashes for all directories that need
3561
- # need to be created or will have tags changed in them
3580
+ # to be created or will have tags changed in them
3562
3581
  # Inputs: 0) ExifTool object reference, 1) file type string (or map hash ref)
3563
3582
  # 2) preferred family 0 group name for creating tags
3564
- # Notes: The ADD_DIRS and EDIT_DIRS keys are the directory names, and the values
3565
- # are the names of the parent directories (undefined for a top-level directory)
3583
+ # Notes:
3584
+ # - the ADD_DIRS and EDIT_DIRS keys are the directory names, and the values
3585
+ # are the names of the parent directories (undefined for a top-level directory)
3586
+ # - also initializes FORCE_WRITE lookup
3566
3587
  sub InitWriteDirs($$;$)
3567
3588
  {
3568
3589
  my ($self, $fileType, $preferredGroup) = @_;
@@ -3605,6 +3626,19 @@ sub InitWriteDirs($$;$)
3605
3626
  $dirName = 'MIE' . ($1 || '');
3606
3627
  }
3607
3628
  my @dirNames;
3629
+ # allow a group name of '*' to force writing EXIF/IPTC/XMP (ForceWrite tag)
3630
+ if ($dirName eq '*' and $$nvHash{Value}) {
3631
+ my $val = $$nvHash{Value}[0];
3632
+ if ($val) {
3633
+ foreach (qw(EXIF IPTC XMP FixBase)) {
3634
+ next unless $val =~ /\b($_|All)\b/i;
3635
+ push @dirNames, $_;
3636
+ push @dirNames, 'EXIF' if $_ eq 'FixBase';
3637
+ $$self{FORCE_WRITE}{$_} = 1;
3638
+ }
3639
+ }
3640
+ $dirName = shift @dirNames;
3641
+ }
3608
3642
  while ($dirName) {
3609
3643
  my $parent = $$fileDirs{$dirName};
3610
3644
  if (ref $parent) {
@@ -4278,6 +4312,58 @@ sub NewGUID()
4278
4312
  $$ & 0xffff, rand(0x10000), rand(0x10000), rand(0x10000));
4279
4313
  }
4280
4314
 
4315
+ #------------------------------------------------------------------------------
4316
+ # Make TIFF header for raw data
4317
+ # Inputs: 0) width, 1) height, 2) num colour components, 3) bits, 4) resolution
4318
+ # 5) color-map data for palette-color image (8 or 16 bit)
4319
+ # Returns: TIFF header
4320
+ # Notes: Multi-byte data must be little-endian
4321
+ sub MakeTiffHeader($$$$;$$)
4322
+ {
4323
+ my ($w, $h, $cols, $bits, $res, $cmap) = @_;
4324
+ $res or $res = 72;
4325
+ my $saveOrder = GetByteOrder();
4326
+ SetByteOrder('II');
4327
+ if (not $cmap) {
4328
+ $cmap = '';
4329
+ } elsif (length $cmap == 3 * 2**$bits) {
4330
+ # convert to short
4331
+ $cmap = pack 'v*', map { $_ | ($_<<8) } unpack 'C*', $cmap;
4332
+ } elsif (length $cmap != 6 * 2**$bits) {
4333
+ $cmap = '';
4334
+ }
4335
+ my $cmo = $cmap ? 12 : 0; # offset due to ColorMap IFD entry
4336
+ my $hdr =
4337
+ "\x49\x49\x2a\0\x08\0\0\0\x0e\0" . # 0x00 14 menu entries:
4338
+ "\xfe\x00\x04\0\x01\0\0\0\x00\0\0\0" . # 0x0a SubfileType = 0
4339
+ "\x00\x01\x04\0\x01\0\0\0" . Set32u($w) . # 0x16 ImageWidth
4340
+ "\x01\x01\x04\0\x01\0\0\0" . Set32u($h) . # 0x22 ImageHeight
4341
+ "\x02\x01\x03\0" . Set32u($cols) . # 0x2e BitsPerSample
4342
+ Set32u($cols == 1 ? $bits : 0xb6 + $cmo) .
4343
+ "\x03\x01\x03\0\x01\0\0\0\x01\0\0\0" . # 0x3a Compression = 1
4344
+ "\x06\x01\x03\0\x01\0\0\0" . # 0x46 PhotometricInterpretation
4345
+ Set32u($cmap ? 3 : $cols == 1 ? 1 : 2) .
4346
+ "\x11\x01\x04\0\x01\0\0\0" . # 0x52 StripOffsets
4347
+ Set32u(0xcc + $cmo + length($cmap)) .
4348
+ "\x15\x01\x03\0\x01\0\0\0" . Set32u($cols) . # 0x5e SamplesPerPixel
4349
+ "\x16\x01\x04\0\x01\0\0\0" . Set32u($h) . # 0x6a RowsPerStrip
4350
+ "\x17\x01\x04\0\x01\0\0\0" . # 0x76 StripByteCounts
4351
+ Set32u($w * $h * $cols * int(($bits+7)/8)) .
4352
+ "\x1a\x01\x05\0\x01\0\0\0" . Set32u(0xbc + $cmo) . # 0x82 XResolution
4353
+ "\x1b\x01\x05\0\x01\0\0\0" . Set32u(0xc4 + $cmo) . # 0x8e YResolution
4354
+ "\x1c\x01\x03\0\x01\0\0\0\x01\0\0\0" . # 0x9a PlanarConfiguration = 1
4355
+ "\x28\x01\x03\0\x01\0\0\0\x02\0\0\0" . # 0xa6 ResolutionUnit = 2
4356
+ ($cmap ? # 0xb2 ColorMap [optional]
4357
+ "\x40\x01\x03\0" . Set32u(3 * 2**$bits) . "\xd8\0\0\0" : '') .
4358
+ "\0\0\0\0" . # 0xb2+$cmo (no IFD1)
4359
+ (Set16u($bits) x 3) . # 0xb6+$cmo BitsPerSample value
4360
+ Set32u($res) . "\x01\0\0\0" . # 0xbc+$cmo XResolution = 72
4361
+ Set32u($res) . "\x01\0\0\0" . # 0xc4+$cmo YResolution = 72
4362
+ $cmap; # 0xcc or 0xd8 (cmap and data go here)
4363
+ SetByteOrder($saveOrder);
4364
+ return $hdr;
4365
+ }
4366
+
4281
4367
  #------------------------------------------------------------------------------
4282
4368
  # Return current time in EXIF format
4283
4369
  # Inputs: 0) flag to include timezone (0 to disable, undef or 1 to include)
@@ -5456,7 +5542,6 @@ sub WriteJPEG($$)
5456
5542
  # rewrite this segment only if we are changing a tag which is contained in its
5457
5543
  # directory (or deleting '*', in which case we need to identify the segment type)
5458
5544
  while (exists $$editDirs{$markerName} or $$delGroup{'*'}) {
5459
- my $oldChanged = $$self{CHANGED};
5460
5545
  if ($marker == 0xe0) { # APP0 (JFIF, CIFF)
5461
5546
  if ($$segDataPt =~ /^JFIF\0/) {
5462
5547
  $segType = 'JFIF';
@@ -5535,7 +5620,6 @@ sub WriteJPEG($$)
5535
5620
  $$segDataPt = $exifAPP1hdr . $buff;
5536
5621
  } else {
5537
5622
  last Marker unless $self->Options('IgnoreMinorErrors');
5538
- $$self{CHANGED} = $oldChanged; # nothing changed
5539
5623
  }
5540
5624
  # switch to buffered output if required
5541
5625
  if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) {
@@ -5653,7 +5737,6 @@ sub WriteJPEG($$)
5653
5737
  $$segDataPt = ''; # delete the XMP
5654
5738
  }
5655
5739
  } else {
5656
- $$self{CHANGED} = $oldChanged;
5657
5740
  $verbose and print $out " [XMP rewritten with no changes]\n";
5658
5741
  if ($doneDir{XMP} > 1) {
5659
5742
  # re-write original multi-segment XMP
@@ -5777,7 +5860,6 @@ sub WriteJPEG($$)
5777
5860
  $$segDataPt = substr($$segDataPt,0,6) . $buff;
5778
5861
  } else {
5779
5862
  last Marker unless $self->Options('IgnoreMinorErrors');
5780
- $$self{CHANGED} = $oldChanged; # nothing changed
5781
5863
  }
5782
5864
  # delete segment if IFD contains no entries
5783
5865
  $del = 1 unless length($$segDataPt) > 6;
@@ -5809,8 +5891,6 @@ sub WriteJPEG($$)
5809
5891
  # add header to new segment unless empty
5810
5892
  $newData = 'Ducky' . $newData if length $newData;
5811
5893
  $segDataPt = \$newData;
5812
- } else {
5813
- $$self{CHANGED} = $oldChanged;
5814
5894
  }
5815
5895
  $del = 1 unless length $$segDataPt;
5816
5896
  }
@@ -5850,8 +5930,6 @@ sub WriteJPEG($$)
5850
5930
  if (defined $newData) {
5851
5931
  undef $$segDataPt; # free the old buffer
5852
5932
  $segDataPt = \$newData;
5853
- } else {
5854
- $$self{CHANGED} = $oldChanged;
5855
5933
  }
5856
5934
  length $$segDataPt or $del = 1, last;
5857
5935
  # write as multi-segment
@@ -48,7 +48,7 @@ use Image::ExifTool::Exif;
48
48
  use Image::ExifTool::GPS;
49
49
  require Exporter;
50
50
 
51
- $VERSION = '3.04';
51
+ $VERSION = '3.07';
52
52
  @ISA = qw(Exporter);
53
53
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
54
54
 
@@ -172,6 +172,7 @@ my %xmpNS = (
172
172
  GImage => 'http://ns.google.com/photos/1.0/image/',
173
173
  GPano => 'http://ns.google.com/photos/1.0/panorama/',
174
174
  GSpherical=> 'http://ns.google.com/videos/1.0/spherical/',
175
+ GDepth => 'http://ns.google.com/photos/1.0/depthmap/',
175
176
  dwc => 'http://rs.tdwg.org/dwc/index.htm',
176
177
  GettyImagesGIFT => 'http://xmp.gettyimages.com/gift/1.0/',
177
178
  );
@@ -732,6 +733,10 @@ my %sRetouchArea = (
732
733
  Name => 'GSpherical',
733
734
  SubDirectory => { TagTable => 'Image::ExifTool::XMP::GSpherical' },
734
735
  },
736
+ GDepth => {
737
+ Name => 'GDepth',
738
+ SubDirectory => { TagTable => 'Image::ExifTool::XMP::GDepth' },
739
+ },
735
740
  dwc => {
736
741
  Name => 'dwc',
737
742
  SubDirectory => { TagTable => 'Image::ExifTool::DarwinCore::Main' },
@@ -2042,9 +2047,8 @@ my %sPantryItem = (
2042
2047
  PrintConv => \&Image::ExifTool::Exif::PrintLensInfo,
2043
2048
  PrintConvInv => \&Image::ExifTool::Exif::ConvertLensInfo,
2044
2049
  Notes => q{
2045
- called LensSpecification by the spec. Unfortunately the EXIF 2.3 for XMP
2046
- specification defined this new tag instead of using the existing
2047
- XMP-aux:LensInfo
2050
+ unfortunately the EXIF 2.3 for XMP specification defined this new tag
2051
+ instead of using the existing XMP-aux:LensInfo
2048
2052
  },
2049
2053
  },
2050
2054
  LensMake => { },
@@ -2398,12 +2402,13 @@ sub IsUTF8($)
2398
2402
  }
2399
2403
 
2400
2404
  #------------------------------------------------------------------------------
2401
- # Fix malformed UTF8 (by replacing bad bytes with '?')
2402
- # Inputs: 0) string reference
2405
+ # Fix malformed UTF8 (by replacing bad bytes with specified character)
2406
+ # Inputs: 0) string reference, 1) string to replace each bad byte,
2407
+ # may be '' to delete bad bytes, or undef to use '?'
2403
2408
  # Returns: true if string was fixed, and updates string
2404
- sub FixUTF8($)
2409
+ sub FixUTF8($;$)
2405
2410
  {
2406
- my $strPt = shift;
2411
+ my ($strPt, $bad) = @_;
2407
2412
  my $fixed;
2408
2413
  pos($$strPt) = 0; # start at beginning of string
2409
2414
  for (;;) {
@@ -2415,9 +2420,11 @@ sub FixUTF8($)
2415
2420
  my $n = $ch < 0xe0 ? 1 : ($ch < 0xf0 ? 2 : 3);
2416
2421
  next if $$strPt =~ /\G[\x80-\xbf]{$n}/g;
2417
2422
  }
2418
- # replace bad character with '?'
2419
- substr($$strPt, $pos-1, 1) = '?';
2420
- pos($$strPt) = $fixed = $pos;
2423
+ # replace bad character
2424
+ $bad = '?' unless defined $bad;
2425
+ substr($$strPt, $pos-1, 1) = $bad;
2426
+ pos($$strPt) = $pos-1 + length $bad;
2427
+ $fixed = 1;
2421
2428
  }
2422
2429
  return $fixed;
2423
2430
  }
@@ -3610,6 +3617,8 @@ sub ProcessXMP($$;$)
3610
3617
  $isSVG = 1;
3611
3618
  } elsif ($1 eq 'plist') {
3612
3619
  $type = 'PLIST';
3620
+ } elsif ($1 eq 'REDXIF') {
3621
+ $type = 'RMD';
3613
3622
  } else {
3614
3623
  return 0;
3615
3624
  }