exiftool_vendored 12.33.0 → 12.37.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/bin/Changes +66 -0
  3. data/bin/META.json +1 -1
  4. data/bin/META.yml +1 -1
  5. data/bin/README +2 -2
  6. data/bin/exiftool +65 -37
  7. data/bin/lib/Image/ExifTool/BuildTagLookup.pm +11 -2
  8. data/bin/lib/Image/ExifTool/Canon.pm +156 -10
  9. data/bin/lib/Image/ExifTool/Charset.pm +2 -0
  10. data/bin/lib/Image/ExifTool/DarwinCore.pm +2 -2
  11. data/bin/lib/Image/ExifTool/Exif.pm +13 -1
  12. data/bin/lib/Image/ExifTool/FLIR.pm +33 -8
  13. data/bin/lib/Image/ExifTool/GIF.pm +5 -1
  14. data/bin/lib/Image/ExifTool/GPS.pm +14 -10
  15. data/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
  16. data/bin/lib/Image/ExifTool/Jpeg2000.pm +108 -11
  17. data/bin/lib/Image/ExifTool/Nikon.pm +992 -18
  18. data/bin/lib/Image/ExifTool/NikonCustom.pm +5 -1
  19. data/bin/lib/Image/ExifTool/NikonSettings.pm +135 -71
  20. data/bin/lib/Image/ExifTool/PDF.pm +5 -3
  21. data/bin/lib/Image/ExifTool/PNG.pm +1 -0
  22. data/bin/lib/Image/ExifTool/QuickTime.pm +17 -3
  23. data/bin/lib/Image/ExifTool/QuickTimeStream.pl +26 -1
  24. data/bin/lib/Image/ExifTool/README +4 -0
  25. data/bin/lib/Image/ExifTool/Sony.pm +29 -11
  26. data/bin/lib/Image/ExifTool/TagInfoXML.pm +9 -4
  27. data/bin/lib/Image/ExifTool/TagLookup.pm +6437 -5843
  28. data/bin/lib/Image/ExifTool/TagNames.pod +1292 -46
  29. data/bin/lib/Image/ExifTool/WriteQuickTime.pl +10 -0
  30. data/bin/lib/Image/ExifTool/WriteXMP.pl +10 -11
  31. data/bin/lib/Image/ExifTool/Writer.pl +50 -5
  32. data/bin/lib/Image/ExifTool/XMP.pm +119 -30
  33. data/bin/lib/Image/ExifTool/XMP2.pl +3 -2
  34. data/bin/lib/Image/ExifTool.pm +71 -8
  35. data/bin/lib/Image/ExifTool.pod +9 -1
  36. data/bin/perl-Image-ExifTool.spec +1 -1
  37. data/lib/exiftool_vendored/version.rb +1 -1
  38. metadata +2 -2
@@ -1067,6 +1067,9 @@ sub WriteQuickTime($$$)
1067
1067
  # 3=optional base offset, 4=optional item ID)
1068
1068
  ChunkOffset => \@chunkOffset,
1069
1069
  );
1070
+ # set InPlace flag so XMP will be padded properly when
1071
+ # QuickTimePad is used if this is an XMP directory
1072
+ $subdirInfo{InPlace} = 2 if $et->Options('QuickTimePad');
1070
1073
  # pass the header pointer if necessary (for EXIF IFD's
1071
1074
  # where the Base offset is at the end of the header)
1072
1075
  if ($hdrLen and $hdrLen < $size) {
@@ -1331,6 +1334,13 @@ sub WriteQuickTime($$$)
1331
1334
  }
1332
1335
  # write the new atom if it was modified
1333
1336
  if (defined $newData) {
1337
+ my $sizeDiff = length($buff) - length($newData);
1338
+ if ($sizeDiff > 0 and $$tagInfo{PreservePadding} and $et->Options('QuickTimePad')) {
1339
+ $newData .= "\0" x $sizeDiff;
1340
+ $et->VPrint(1, " ($$tagInfo{Name} padded to original size)");
1341
+ } elsif ($sizeDiff) {
1342
+ $et->VPrint(1, " ($$tagInfo{Name} changed size)");
1343
+ }
1334
1344
  my $len = length($newData) + 8;
1335
1345
  $len > 0x7fffffff and $et->Error("$$tagInfo{Name} to large to write"), last;
1336
1346
  # update size in ChunkOffset list for modified 'uuid' atom
@@ -1418,9 +1418,15 @@ sub WriteXMP($$;$)
1418
1418
  unless ($uri) {
1419
1419
  $uri = $nsURI{$1}; # we must have added a namespace
1420
1420
  unless ($uri) {
1421
- # (namespace may be empty if trying to write empty XMP structure, forum12384)
1422
- $xmpErr = "Undefined XMP namespace: $1" if length $uri;
1423
- next;
1421
+ # (namespace prefix may be empty if trying to write empty XMP structure, forum12384)
1422
+ if (length $1) {
1423
+ my $err = "Undefined XMP namespace: $1";
1424
+ if (not $xmpErr or $err ne $xmpErr) {
1425
+ $xmpFile ? $et->Error($err) : $et->Warn($err);
1426
+ $xmpErr = $err;
1427
+ }
1428
+ }
1429
+ next;
1424
1430
  }
1425
1431
  }
1426
1432
  $nsNew{$1} = $uri;
@@ -1586,14 +1592,7 @@ sub WriteXMP($$;$)
1586
1592
  unless (%capture or $xmpFile or $$dirInfo{InPlace} or $$dirInfo{NoDelete}) {
1587
1593
  $long[-2] = '';
1588
1594
  }
1589
- if ($xmpErr) {
1590
- if ($xmpFile) {
1591
- $et->Error($xmpErr);
1592
- return -1;
1593
- }
1594
- $et->Warn($xmpErr);
1595
- return undef;
1596
- }
1595
+ return($xmpFile ? -1 : undef) if $xmpErr;
1597
1596
  $$et{CHANGED} += $changed;
1598
1597
  $debug > 1 and $long[-2] and print $long[-2],"\n";
1599
1598
  return $long[-2] unless $xmpFile;
@@ -154,7 +154,7 @@ my %delMore = (
154
154
  );
155
155
 
156
156
  # family 0 groups where directories should never be deleted
157
- my %permanentDir = ( QuickTime => 1 );
157
+ my %permanentDir = ( QuickTime => 1, Jpeg2000 => 1 );
158
158
 
159
159
  # lookup for all valid family 2 groups (lower case)
160
160
  my %family2groups = map { lc $_ => 1 } @delGroup2, 'Unknown';
@@ -1400,7 +1400,10 @@ sub SetNewValuesFromFile($$;@)
1400
1400
  }
1401
1401
  }
1402
1402
  # validate tag name(s)
1403
- $$opts{EXPR} or ValidTagName($tag) or $self->Warn("Invalid tag name '${tag}'"), next;
1403
+ unless ($$opts{EXPR} or ValidTagName($tag)) {
1404
+ $self->Warn("Invalid tag name '${tag}'. Use '=' not '<' to assign a tag value");
1405
+ next;
1406
+ }
1404
1407
  ValidTagName($dstTag) or $self->Warn("Invalid tag name '${dstTag}'"), next;
1405
1408
  # translate '+' and '-' to appropriate SetNewValue option
1406
1409
  if ($opt) {
@@ -2074,6 +2077,46 @@ sub SetSystemTags($$)
2074
2077
  last;
2075
2078
  }
2076
2079
  }
2080
+ # delete Windows Zone.Identifier if specified
2081
+ my $zhash = $self->GetNewValueHash($Image::ExifTool::Extra{ZoneIdentifier});
2082
+ if ($zhash) {
2083
+ my $res = -1;
2084
+ if ($^O ne 'MSWin32') {
2085
+ $self->Warn('ZoneIdentifer is a Windows-only tag');
2086
+ } elsif (ref $file) {
2087
+ $self->Warn('Writing ZoneIdentifer requires a file name');
2088
+ } elsif (defined $self->GetNewValue('ZoneIdentifier', \$zhash)) {
2089
+ $self->Warn('ZoneIndentifier may only be delted');
2090
+ } elsif (not eval { require Win32API::File }) {
2091
+ $self->Warn('Install Win32API::File to write ZoneIdentifier');
2092
+ } else {
2093
+ my ($wattr, $wide);
2094
+ my $zfile = "${file}:Zone.Identifier";
2095
+ if ($self->EncodeFileName($zfile)) {
2096
+ $wide = 1;
2097
+ $wattr = eval { Win32API::File::GetFileAttributesW($zfile) };
2098
+ } else {
2099
+ $wattr = eval { Win32API::File::GetFileAttributes($zfile) };
2100
+ }
2101
+ if ($wattr == Win32API::File::INVALID_FILE_ATTRIBUTES()) {
2102
+ $res = 0; # file doesn't exist, nothing to do
2103
+ } elsif ($wattr & Win32API::File::FILE_ATTRIBUTE_READONLY()) {
2104
+ $self->Warn('Zone.Identifier stream is read-only');
2105
+ } else {
2106
+ if ($wide) {
2107
+ $res = 1 if eval { Win32API::File::DeleteFileW($zfile) };
2108
+ } else {
2109
+ $res = 1 if eval { Win32API::File::DeleteFile($zfile) };
2110
+ }
2111
+ if ($res > 0) {
2112
+ $self->VPrint(0, " Deleting Zone.Identifier stream\n");
2113
+ } else {
2114
+ $self->Warn('Error deleting Zone.Identifier stream');
2115
+ }
2116
+ }
2117
+ }
2118
+ $result = $res if $res == 1 or not $result;
2119
+ }
2077
2120
  return $result;
2078
2121
  }
2079
2122
 
@@ -4735,7 +4778,7 @@ sub InverseDateTime($$;$$)
4735
4778
  my ($rtnVal, $tz);
4736
4779
  my $fmt = $$self{OPTIONS}{DateFormat};
4737
4780
  # strip off timezone first if it exists
4738
- if (not $fmt and $val =~ s/([+-])(\d{1,2}):?(\d{2})\s*(DST)?$//i) {
4781
+ if (not $fmt and $val =~ s/([-+])(\d{1,2}):?(\d{2})\s*(DST)?$//i) {
4739
4782
  $tz = sprintf("$1%.2d:$3", $2);
4740
4783
  } elsif (not $fmt and $val =~ s/Z$//i) {
4741
4784
  $tz = 'Z';
@@ -4758,6 +4801,8 @@ sub InverseDateTime($$;$$)
4758
4801
  $strptimeLib = '';
4759
4802
  }
4760
4803
  }
4804
+ # handle factional seconds (%f), but only at the end of the string
4805
+ my $fs = ($fmt =~ s/%f$// and $val =~ s/(\.\d+)\s*$//) ? $1 : '';
4761
4806
  my ($lib, $wrn, @a);
4762
4807
  TryLib: for ($lib=$strptimeLib; ; $lib='') {
4763
4808
  if (not $lib) {
@@ -4794,10 +4839,10 @@ TryLib: for ($lib=$strptimeLib; ; $lib='') {
4794
4839
  next TryLib;
4795
4840
  }
4796
4841
  } elsif (length($a[$i]) < 2) {
4797
- $$a[$i] = "0$a[$i]";# pad to 2 digits if necessary
4842
+ $a[$i] = "0$a[$i]"; # pad to 2 digits if necessary
4798
4843
  }
4799
4844
  }
4800
- $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]);
4845
+ $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]) . $fs;
4801
4846
  last;
4802
4847
  }
4803
4848
  }
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
50
50
  use Image::ExifTool::GPS;
51
51
  require Exporter;
52
52
 
53
- $VERSION = '3.46';
53
+ $VERSION = '3.49';
54
54
  @ISA = qw(Exporter);
55
55
  @EXPORT_OK = qw(EscapeXML UnescapeXML);
56
56
 
@@ -436,9 +436,38 @@ my %sOECF = (
436
436
  Names => { List => 'Seq' },
437
437
  Values => { List => 'Seq', Writable => 'rational' },
438
438
  );
439
-
439
+ my %sAreaModels = (
440
+ STRUCT_NAME => 'AreaModels',
441
+ NAMESPACE => 'crs',
442
+ ColorRangeMaskAreaSampleInfo => { FlatName => 'ColorSampleInfo' },
443
+ AreaComponents => { FlatName => 'Components', List => 'Seq' },
444
+ );
445
+ my %sCorrRangeMask = (
446
+ STRUCT_NAME => 'CorrRangeMask',
447
+ NAMESPACE => 'crs',
448
+ NOTES => 'Called CorrectionRangeMask by the spec.',
449
+ Version => { },
450
+ Type => { },
451
+ ColorAmount => { Writable => 'real' },
452
+ LumMin => { Writable => 'real' },
453
+ LumMax => { Writable => 'real' },
454
+ LumFeather => { Writable => 'real' },
455
+ DepthMin => { Writable => 'real' },
456
+ DepthMax => { Writable => 'real' },
457
+ DepthFeather=> { Writable => 'real' },
458
+ # new in LR 11.0
459
+ Invert => { Writable => 'boolean' },
460
+ SampleType => { Writable => 'integer' },
461
+ AreaModels => {
462
+ List => 'Seq',
463
+ Struct => \%sAreaModels,
464
+ },
465
+ LumRange => { },
466
+ LuminanceDepthSampleInfo => { },
467
+ );
440
468
  # new LR2 crs structures (PH)
441
- my %sCorrectionMask = (
469
+ my %sCorrectionMask;
470
+ %sCorrectionMask = (
442
471
  STRUCT_NAME => 'CorrectionMask',
443
472
  NAMESPACE => 'crs',
444
473
  # disable List behaviour of flattened Gradient/PaintBasedCorrections
@@ -473,19 +502,26 @@ my %sCorrectionMask = (
473
502
  Alpha => { Writable => 'real', List => 0 },
474
503
  CenterValue => { Writable => 'real', List => 0 },
475
504
  PerimeterValue=>{ Writable => 'real', List => 0 },
476
- );
477
- my %sCorrectionRangeMask = (
478
- STRUCT_NAME => 'CorrectionRangeMask',
479
- NAMESPACE => 'crs',
480
- Version => { },
481
- Type => { },
482
- ColorAmount => { Writable => 'real' },
483
- LumMin => { Writable => 'real' },
484
- LumMax => { Writable => 'real' },
485
- LumFeather => { Writable => 'real' },
486
- DepthMin => { Writable => 'real' },
487
- DepthMax => { Writable => 'real' },
488
- DepthFeather=> { Writable => 'real' },
505
+ # new in LR 11.0 MaskGroupBasedCorrections
506
+ MaskActive => { Writable => 'boolean', List => 0 },
507
+ MaskName => { List => 0 },
508
+ MaskBlendMode=> { Writable => 'integer', List => 0 },
509
+ MaskInverted => { Writable => 'boolean', List => 0 },
510
+ MaskSyncID => { List => 0 },
511
+ MaskVersion => { List => 0 },
512
+ MaskSubType => { List => 0 },
513
+ ReferencePoint => { List => 0 },
514
+ InputDigest => { List => 0 },
515
+ MaskDigest => { List => 0 },
516
+ WholeImageArea => { List => 0 },
517
+ Origin => { List => 0 },
518
+ Masks => { Struct => \%sCorrectionMask, NoSubStruct => 1 },
519
+ CorrectionRangeMask => {
520
+ Name => 'CorrRangeMask',
521
+ Notes => 'called CorrectionRangeMask by the spec',
522
+ FlatName => 'Range',
523
+ Struct => \%sCorrRangeMask,
524
+ },
489
525
  );
490
526
  my %sCorrection = (
491
527
  STRUCT_NAME => 'Correction',
@@ -499,8 +535,8 @@ my %sCorrection = (
499
535
  LocalClarity => { FlatName => 'Clarity', Writable => 'real', List => 0 },
500
536
  LocalSharpness => { FlatName => 'Sharpness', Writable => 'real', List => 0 },
501
537
  LocalBrightness => { FlatName => 'Brightness', Writable => 'real', List => 0 },
502
- LocalToningHue => { FlatName => 'Hue', Writable => 'real', List => 0 },
503
- LocalToningSaturation => { FlatName => 'Saturation', Writable => 'real', List => 0 },
538
+ LocalToningHue => { FlatName => 'ToningHue', Writable => 'real', List => 0 },
539
+ LocalToningSaturation => { FlatName => 'ToningSaturation', Writable => 'real', List => 0 },
504
540
  LocalExposure2012 => { FlatName => 'Exposure2012', Writable => 'real', List => 0 },
505
541
  LocalContrast2012 => { FlatName => 'Contrast2012', Writable => 'real', List => 0 },
506
542
  LocalHighlights2012 => { FlatName => 'Highlights2012', Writable => 'real', List => 0 },
@@ -516,15 +552,20 @@ my %sCorrection = (
516
552
  LocalBlacks2012 => { FlatName => 'Blacks2012', Writable => 'real', List => 0 },
517
553
  LocalDehaze => { FlatName => 'Dehaze', Writable => 'real', List => 0 },
518
554
  LocalTexture => { FlatName => 'Texture', Writable => 'real', List => 0 },
555
+ # new in LR 11.0
519
556
  CorrectionRangeMask => {
557
+ Name => 'CorrRangeMask',
558
+ Notes => 'called CorrectionRangeMask by the spec',
520
559
  FlatName => 'RangeMask',
521
- Struct => \%sCorrectionRangeMask,
560
+ Struct => \%sCorrRangeMask,
522
561
  },
523
562
  CorrectionMasks => {
524
563
  FlatName => 'Mask',
525
564
  Struct => \%sCorrectionMask,
526
565
  List => 'Seq',
527
566
  },
567
+ CorrectionName => { },
568
+ CorrectionSyncID => { },
528
569
  );
529
570
  my %sRetouchArea = (
530
571
  STRUCT_NAME => 'RetouchArea',
@@ -543,6 +584,30 @@ my %sRetouchArea = (
543
584
  List => 'Seq',
544
585
  },
545
586
  );
587
+ my %sMapInfo = (
588
+ STRUCT_NAME => 'MapInfo',
589
+ NAMESPACE => 'crs',
590
+ NOTES => q{
591
+ Called RangeMaskMapInfo by the specification, the same as the containing
592
+ structure.
593
+ },
594
+ RGBMin => { },
595
+ RGBMax => { },
596
+ LabMin => { },
597
+ LabMax => { },
598
+ LumEq => { List => 'Seq' },
599
+ );
600
+ my %sRangeMask = (
601
+ STRUCT_NAME => 'RangeMask',
602
+ NAMESPACE => 'crs',
603
+ NOTES => q{
604
+ This structure is actually called RangeMaskMapInfo, but it only contains one
605
+ element which is a RangeMaskMapInfo structure (Yes, really!). So these are
606
+ renamed to RangeMask and MapInfo respectively to avoid confusion and
607
+ redundancy in the tag names.
608
+ },
609
+ RangeMaskMapInfo => { FlatName => 'MapInfo', Struct => \%sMapInfo },
610
+ );
546
611
 
547
612
  # main XMP tag table (tag ID's are used for the family 1 group names)
548
613
  %Image::ExifTool::XMP::Main = (
@@ -1581,6 +1646,14 @@ my %sPantryItem = (
1581
1646
  AutoToneDigestNoSat => { },
1582
1647
  ToggleStyleDigest => { },
1583
1648
  ToggleStyleAmount => { Writable => 'integer' },
1649
+ # new for LightRoom 11.0
1650
+ CompatibleVersion => { },
1651
+ MaskGroupBasedCorrections => {
1652
+ FlatName => 'MaskGroupBasedCorr',
1653
+ Struct => \%sCorrection,
1654
+ List => 'Seq',
1655
+ },
1656
+ RangeMaskMapInfo => { Name => 'RangeMask', Struct => \%sRangeMask, FlatName => 'RangeMask' },
1584
1657
  );
1585
1658
 
1586
1659
  # Tiff namespace properties (tiff)
@@ -1672,7 +1745,7 @@ my %sPantryItem = (
1672
1745
  Software => { },
1673
1746
  Artist => { Groups => { 2 => 'Author' } },
1674
1747
  Copyright => { Groups => { 2 => 'Author' }, Writable => 'lang-alt' },
1675
- NativeDigest => { }, #PH
1748
+ NativeDigest => { Avoid => 1 }, #PH
1676
1749
  );
1677
1750
 
1678
1751
  # Exif namespace properties (exif)
@@ -2142,8 +2215,8 @@ my %sPantryItem = (
2142
2215
  NAMESPACE => 'exifEX',
2143
2216
  PRIORITY => 0, # not as reliable as actual EXIF tags
2144
2217
  NOTES => q{
2145
- EXIF tags added by the EXIF 2.31 for XMP specification (see
2146
- L<http://www.cipa.jp/std/documents/e/DC-X010-2017.pdf>).
2218
+ EXIF tags added by the EXIF 2.32 for XMP specification (see
2219
+ L<https://cipa.jp/std/documents/download_e.html?DC-010-2020_E>).
2147
2220
  },
2148
2221
  Gamma => { Writable => 'rational' },
2149
2222
  PhotographicSensitivity => { Writable => 'integer' },
@@ -2307,6 +2380,7 @@ my %sPantryItem = (
2307
2380
  VignetteCorrectionAlreadyApplied => { Writable => 'boolean' },
2308
2381
  LateralChromaticAberrationCorrectionAlreadyApplied => { Writable => 'boolean' },
2309
2382
  LensDistortInfo => { }, # (LR 7.5.1, 4 signed rational values)
2383
+ NeutralDensityFactor => { }, # (LR 11.0 - rational value, but denominator seems significant)
2310
2384
  );
2311
2385
 
2312
2386
  # IPTC Core namespace properties (Iptc4xmpCore) (ref 4)
@@ -2349,8 +2423,9 @@ my %sPantryItem = (
2349
2423
  Scene => { Groups => { 2 => 'Other' }, List => 'Bag' },
2350
2424
  SubjectCode => { Groups => { 2 => 'Other' }, List => 'Bag' },
2351
2425
  # Copyright - have seen this in a sample (Jan 2021), but I think it is non-standard
2352
- AltTextAccessibility =>{ Groups => { 2 => 'Other' }, Writable => 'lang-alt' }, # added 2021-10-13
2353
- ExtDescrAccessibility=>{ Groups => { 2 => 'Other' }, Writable => 'lang-alt' }, # added 2021-10-13
2426
+ # new IPTC Core 1.3 properties
2427
+ AltTextAccessibility => { Groups => { 2 => 'Other' }, Writable => 'lang-alt' },
2428
+ ExtDescrAccessibility => { Groups => { 2 => 'Other' }, Writable => 'lang-alt' },
2354
2429
  );
2355
2430
 
2356
2431
  # Adobe Lightroom namespace properties (lr) (ref PH)
@@ -2362,6 +2437,7 @@ my %sPantryItem = (
2362
2437
  NOTES => 'Adobe Lightroom "lr" namespace tags.',
2363
2438
  privateRTKInfo => { },
2364
2439
  hierarchicalSubject => { List => 'Bag' },
2440
+ weightedFlatSubject => { List => 'Bag' },
2365
2441
  );
2366
2442
 
2367
2443
  # Adobe Album namespace properties (album) (ref PH)
@@ -3504,6 +3580,17 @@ sub ParseXMPElement($$$;$$$$)
3504
3580
  }
3505
3581
  $start = pos($$dataPt); # start from here the next time around
3506
3582
 
3583
+ # ignore specified XMP namespaces/properties
3584
+ if ($$et{EXCL_XMP_LOOKUP} and not $isWriting and $prop =~ /^(.+):(.*)/) {
3585
+ my ($ns, $nm) = (lc($stdXlatNS{$1} || $1), lc($2));
3586
+ if ($$et{EXCL_XMP_LOOKUP}{"xmp-$ns:all"} or $$et{EXCL_XMP_LOOKUP}{"xmp-$ns:$nm"} or
3587
+ $$et{EXCL_XMP_LOOKUP}{"xmp-all:$nm"})
3588
+ {
3589
+ ++$count; # (pretend we found something so we don't store as a tag value)
3590
+ next;
3591
+ }
3592
+ }
3593
+
3507
3594
  # extract property attributes
3508
3595
  my ($parseResource, %attrs, @attrs);
3509
3596
  while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) {
@@ -3601,9 +3688,9 @@ sub ParseXMPElement($$$;$$$$)
3601
3688
  if ($nItems == 1000) {
3602
3689
  my ($tg,$ns) = GetXMPTagID($propList);
3603
3690
  if ($isWriting) {
3604
- $et->Warn("Excessive number of items for $ns:$tg. Processing may be slow", 1);
3691
+ $et->WarnOnce("Excessive number of items for $ns:$tg. Processing may be slow", 1);
3605
3692
  } elsif (not $$et{OPTIONS}{IgnoreMinorErrors}) {
3606
- $et->Warn("Extracted only 1000 $ns:$tg items. Ignore minor errors to extract all", 2);
3693
+ $et->WarnOnce("Extracted only 1000 $ns:$tg items. Ignore minor errors to extract all", 2);
3607
3694
  last;
3608
3695
  }
3609
3696
  }
@@ -3975,14 +4062,16 @@ sub ProcessXMP($$;$)
3975
4062
  } elsif ($buf2 =~ /<plist[\s>]/) {
3976
4063
  $type = 'PLIST';
3977
4064
  }
3978
- if ($isSVG and $$et{XMP_CAPTURE}) {
3979
- $et->Error("ExifTool does not yet support writing of SVG images");
3980
- return 0;
3981
- }
3982
4065
  }
3983
4066
  $isXML = 1;
3984
4067
  } elsif ($2 eq '<rdf:RDF') {
3985
4068
  $isRDF = 1; # recognize XMP without x:xmpmeta element
4069
+ } elsif ($2 eq '<svg') {
4070
+ $isSVG = $isXML = 1;
4071
+ }
4072
+ if ($isSVG and $$et{XMP_CAPTURE}) {
4073
+ $et->Error("ExifTool does not yet support writing of SVG images");
4074
+ return 0;
3986
4075
  }
3987
4076
  if ($buff =~ /^\0\0/) {
3988
4077
  $fmt = 'N'; # UTF-32 MM with or without BOM
@@ -537,7 +537,7 @@ my %sImageRegion = ( # new in 1.5
537
537
  NAMESPACE => 'Iptc4xmpExt',
538
538
  TABLE_DESC => 'XMP IPTC Extension',
539
539
  NOTES => q{
540
- This table contains tags defined by the IPTC Extension schema version 1.5.
540
+ This table contains tags defined by the IPTC Extension schema version 1.6.
541
541
  The actual namespace prefix is "Iptc4xmpExt", but ExifTool shortens this for
542
542
  the family 1 group name. (see
543
543
  L<http://www.iptc.org/standards/photo-metadata/iptc-standard/>)
@@ -797,7 +797,8 @@ my %sImageRegion = ( # new in 1.5
797
797
  audioBitsPerSample => { Groups => { 2 => 'Audio' }, Writable => 'integer' },
798
798
  # new IPTC Extension schema 1.5 property
799
799
  ImageRegion => { Groups => { 2 => 'Image' }, List => 'Bag', Struct => \%sImageRegion },
800
- EventID => { List => 'Bag' }, # added 2021-10-13
800
+ # new Extension 1.6 property
801
+ EventId => { Name => 'EventID', List => 'Bag' },
801
802
  );
802
803
 
803
804
  #------------------------------------------------------------------------------
@@ -26,10 +26,10 @@ use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes
26
26
  $psAPP13hdr $psAPP13old @loadAllTables %UserDefined $evalWarning
27
27
  %noWriteFile %magicNumber @langs $defaultLang %langName %charsetName
28
28
  %mimeType $swapBytes $swapWords $currentByteOrder %unpackStd
29
- %jpegMarker %specialTags %fileTypeLookup $testLen $exePath
29
+ %jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
30
30
  %static_vars);
31
31
 
32
- $VERSION = '12.33';
32
+ $VERSION = '12.37';
33
33
  $RELEASE = '';
34
34
  @ISA = qw(Exporter);
35
35
  %EXPORT_TAGS = (
@@ -909,7 +909,7 @@ $testLen = 1024; # number of bytes to read when testing for magic number
909
909
  GZIP => '\x1f\x8b\x08',
910
910
  HDR => '#\?(RADIANCE|RGBE)\x0a',
911
911
  HTML => '(\xef\xbb\xbf)?\s*(?i)<(!DOCTYPE\s+HTML|HTML|\?xml)', # (case insensitive)
912
- ICC => '.{12}(scnr|mntr|prtr|link|spac|abst|nmcl|nkpf)(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR){2}',
912
+ ICC => '.{12}(scnr|mntr|prtr|link|spac|abst|nmcl|nkpf|cenc|mid |mlnk|mvis)(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR|nc..|\0{4}){2}',
913
913
  IND => '\x06\x06\xed\xf5\xd8\x1d\x46\xe5\xbd\x31\xef\xe7\xfe\x74\xb7\x1d',
914
914
  # ISO => signature is at byte 32768
915
915
  ITC => '.{4}itch',
@@ -1208,6 +1208,18 @@ my %systemTagsNotes = (
1208
1208
  },
1209
1209
  PrintConv => \&ConvertFileSize,
1210
1210
  },
1211
+ ZoneIdentifier => {
1212
+ Groups => { 1 => 'System', 2 => 'Other' },
1213
+ Notes => q{
1214
+ Windows only. Existence indicates that the file has a Zone.Identifier
1215
+ alternate data stream, which is used by some Windows browsers to mark
1216
+ downloaded files as possibly unsafe to run. May be deleted to remove this
1217
+ stream. Requires Win32API::File
1218
+ },
1219
+ Writable => 1,
1220
+ WritePseudo => 1,
1221
+ Protected => 1,
1222
+ },
1211
1223
  FileType => {
1212
1224
  Groups => { 2 => 'Other' },
1213
1225
  Notes => q{
@@ -2320,6 +2332,7 @@ sub ClearOptions($)
2320
2332
  Password => undef, # password for password-protected PDF documents
2321
2333
  PrintConv => 1, # flag to enable print conversion
2322
2334
  QuickTimeHandler => 1, # flag to add mdir Handler to newly created Meta box
2335
+ QuickTimePad=> undef, # flag to preserve padding of QuickTime CR3 tags
2323
2336
  QuickTimeUTC=> undef, # assume that QuickTime date/time tags are stored as UTC
2324
2337
  RequestAll => undef, # extract all tags that must be specifically requested
2325
2338
  RequestTags => undef, # extra tags to request (on top of those in the tag list)
@@ -2369,7 +2382,7 @@ sub ExtractInfo($;@)
2369
2382
  my $fast = $$options{FastScan} || 0;
2370
2383
  my $req = $$self{REQ_TAG_LOOKUP};
2371
2384
  my $reqAll = $$options{RequestAll} || 0;
2372
- my (%saveOptions, $reEntry, $rsize, $type, @startTime, $saveOrder, $isDir);
2385
+ my (%saveOptions, $reEntry, $rsize, $zid, $type, @startTime, $saveOrder, $isDir);
2373
2386
 
2374
2387
  # check for internal ReEntry option to allow recursive calls to ExtractInfo
2375
2388
  if (ref $_[1] eq 'HASH' and $_[1]{ReEntry} and
@@ -2461,6 +2474,17 @@ sub ExtractInfo($;@)
2461
2474
  }
2462
2475
  # get size of resource fork on Mac OS
2463
2476
  $rsize = -s "$filename/..namedfork/rsrc" if $^O eq 'darwin' and not $$self{IN_RESOURCE};
2477
+ # check to see if Zone.Identifier file exists in Windows
2478
+ if ($^O eq 'MSWin32' and eval { require Win32API::File }) {
2479
+ my $wattr;
2480
+ my $zfile = "${filename}:Zone.Identifier";
2481
+ if ($self->EncodeFileName($zfile)) {
2482
+ $wattr = eval { Win32API::File::GetFileAttributesW($zfile) };
2483
+ } else {
2484
+ $wattr = eval { Win32API::File::GetFileAttributes($zfile) };
2485
+ }
2486
+ $zid = 1 unless $wattr == Win32API::File::INVALID_FILE_ATTRIBUTES();
2487
+ }
2464
2488
  }
2465
2489
  # open the file
2466
2490
  if ($self->Open(\*EXIFTOOL_FILE, $filename)) {
@@ -2503,6 +2527,7 @@ sub ExtractInfo($;@)
2503
2527
  my $fileSize = $stat[7];
2504
2528
  $self->FoundTag('FileSize', $stat[7]) if defined $stat[7];
2505
2529
  $self->FoundTag('ResourceForkSize', $rsize) if $rsize;
2530
+ $self->FoundTag('ZoneIdentifier', 'Exists') if $zid;
2506
2531
  $self->FoundTag('FileModifyDate', $stat[9]) if defined $stat[9];
2507
2532
  $self->FoundTag('FileAccessDate', $stat[8]) if defined $stat[8];
2508
2533
  my $cTag = $^O eq 'MSWin32' ? 'FileCreateDate' : 'FileInodeChangeDate';
@@ -4227,6 +4252,7 @@ sub ParseArguments($;@)
4227
4252
  $$self{REQ_TAG_LOOKUP} = { };
4228
4253
  $$self{EXCL_TAG_LOOKUP} = { };
4229
4254
  $$self{IO_TAG_LIST} = undef;
4255
+ delete $$self{EXCL_XMP_LOOKUP};
4230
4256
 
4231
4257
  # handle our input arguments
4232
4258
  while (@_) {
@@ -4310,7 +4336,11 @@ sub ParseArguments($;@)
4310
4336
  # generate lookup for excluded tags
4311
4337
  if ($$options{Exclude}) {
4312
4338
  foreach (@{$$options{Exclude}}) {
4313
- /([-\w]+)#?$/ and $$self{EXCL_TAG_LOOKUP}{lc($1)} = 1;
4339
+ /([-\w]+)#?$/ and $$self{EXCL_TAG_LOOKUP}{lc $1} = 1;
4340
+ if (/(xmp-.*:[-\w]+)#?/i) {
4341
+ $$self{EXCL_XMP_LOOKUP} or $$self{EXCL_XMP_LOOKUP} = { };
4342
+ $$self{EXCL_XMP_LOOKUP}{lc $1} = 1;
4343
+ }
4314
4344
  }
4315
4345
  # exclude list is used only for EXCL_TAG_LOOKUP when TAGS_FROM_FILE is set
4316
4346
  undef $$options{Exclude} if $$self{TAGS_FROM_FILE};
@@ -5652,6 +5682,38 @@ sub ConvertDateTime($$)
5652
5682
  unshift @a, 1 while @a < 3; # add month and day if necessary
5653
5683
  unshift @a, 0 while @a < 6; # add h,m,s if necessary
5654
5684
  $a[4] -= 1; # base month is 1
5685
+ # parse our %f fractional seconds first (and round up seconds if necessary)
5686
+ # - if there are multiple %f codes, they all get the same number of digits as the first
5687
+ if ($fmt =~ /%\.?(\d*)f/) {
5688
+ my $dig = $1;
5689
+ my $frac = $date =~ /(\.\d+)/ ? $1 : '';
5690
+ if (not $frac) {
5691
+ $frac = '.' . ('0' x $dig) if $dig;
5692
+ } elsif (length $dig) {
5693
+ if ($dig+1 > length($frac)) {
5694
+ $frac .= '0' x ($dig+1-length($frac));
5695
+ } elsif ($dig+1 < length($frac)) {
5696
+ $frac = sprintf("%.${dig}f", $frac);
5697
+ while ($frac =~ s/^(\d)// and $1 ne '0') {
5698
+ # this is a pain, but we must round up to the next second
5699
+ ++$a[0] < 60 and last;
5700
+ $a[0] = 0;
5701
+ ++$a[1] < 60 and last;
5702
+ $a[1] = 0;
5703
+ ++$a[2] < 24 and last;
5704
+ $a[2] = 0;
5705
+ require 'Image/ExifTool/Shift.pl';
5706
+ ++$a[3] <= DaysInMonth($a[4]+1, $a[5]) and last;
5707
+ $a[3] = 1;
5708
+ ++$a[4] < 12 and last;
5709
+ $a[4] = 0;
5710
+ ++$a[5];
5711
+ last; # (this was a goto)
5712
+ }
5713
+ }
5714
+ }
5715
+ $fmt =~ s/(^|[^%])((%%)*)%\.?\d*f/$1$2$frac/g;
5716
+ }
5655
5717
  # parse %z and %s ourself (to handle time zones properly)
5656
5718
  if ($fmt =~ /%[sz]/) {
5657
5719
  # use system time zone unless otherwise specified
@@ -6252,7 +6314,7 @@ sub ProcessJPEG($$)
6252
6314
  my $markerName = JpegMarkerName($marker);
6253
6315
  $$path[$pn] = $markerName;
6254
6316
  # issue warning if we skipped some garbage
6255
- if ($skipped and not $foundSOS) {
6317
+ if ($skipped and not $foundSOS and $markerName ne 'SOS') {
6256
6318
  $self->Warn("Skipped unknown $skipped bytes after JPEG $markerName segment", 1);
6257
6319
  if ($htmlDump) {
6258
6320
  $self->HDump($nextSegPos-4-$skipped, $skipped, "[unknown $skipped bytes]", undef, 0x08);
@@ -8711,6 +8773,7 @@ sub ProcessBinaryData($$$)
8711
8773
  # read value now if necessary
8712
8774
  unless (defined $val and not $$tagInfo{SubDirectory}) {
8713
8775
  $val = ReadValue($dataPt, $entry+$offset, $format, $count, $more, \$rational);
8776
+ next unless defined $val;
8714
8777
  $mask = $$tagInfo{Mask};
8715
8778
  $val = ($val & $mask) >> $$tagInfo{BitShift} if $mask;
8716
8779
  }
@@ -8812,8 +8875,8 @@ until ($Image::ExifTool::noConfig) {
8812
8875
  $file = $config;
8813
8876
  }
8814
8877
  # also check executable directory unless path is absolute
8815
- $exePath = $0 unless defined $exePath; # (undocumented $exePath setting)
8816
- -r $file or $config =~ /^\// or $file = ($exePath =~ /(.*[\\\/])/ ? $1 : './') . $config;
8878
+ $exeDir = ($0 =~ /(.*)[\\\/]/) ? $1 : '.' unless defined $exeDir;
8879
+ -r $file or $config =~ /^\// or $file = "$exeDir/$config";
8817
8880
  unless (-r $file) {
8818
8881
  warn("Config file not found\n") if defined $Image::ExifTool::configFile;
8819
8882
  last;
@@ -860,6 +860,14 @@ commonly found in samples from other software, and it has been reported that
860
860
  Apple QuickTime Player and Photos.apps will ignore ItemList tags if this is
861
861
  missing. Default is 1.
862
862
 
863
+ =item QuickTimePad
864
+
865
+ Flag to preserve the padding of some QuickTime atoms when writing.
866
+ QuickTime-based Canon CR3 files pad the values of container atoms with null
867
+ bytes. This padding is removed by default when the file is rewritten, but
868
+ setting this option to 1 adds padding to preserve the original atom size if
869
+ the new atom would be smaller than the original. Default is undef.
870
+
863
871
  =item QuickTimeUTC
864
872
 
865
873
  Flag set to assume that QuickTime date/time values are stored as UTC,
@@ -1236,7 +1244,7 @@ The following ExifTool options are effective in the call to L</WriteInfo>:
1236
1244
 
1237
1245
  ByteOrder, Charset, CharsetEXIF, CharsetFileName, CharsetIPTC, Compact,
1238
1246
  Compress, FixBase, IgnoreMinorErrors, NoMultiExif, NoPDFList, Password,
1239
- QuickTimeHandler, Verbose and WriteMode.
1247
+ QuickTimeHandler, QuickTimePad, Verbose and WriteMode.
1240
1248
 
1241
1249
  =head2 GetTagList
1242
1250
 
@@ -1,6 +1,6 @@
1
1
  Summary: perl module for image data extraction
2
2
  Name: perl-Image-ExifTool
3
- Version: 12.33
3
+ Version: 12.37
4
4
  Release: 1
5
5
  License: Artistic/GPL
6
6
  Group: Development/Libraries/Perl
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExiftoolVendored
4
- VERSION = Gem::Version.new('12.33.0')
4
+ VERSION = Gem::Version.new('12.37.0')
5
5
  end