exiftool-vendored.exe 12.34.0 → 12.38.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.
Files changed (30) hide show
  1. package/bin/exiftool_files/Changes +61 -2
  2. package/bin/exiftool_files/README +2 -2
  3. package/bin/exiftool_files/exiftool.pl +63 -35
  4. package/bin/exiftool_files/lib/Image/ExifTool/BuildTagLookup.pm +6 -2
  5. package/bin/exiftool_files/lib/Image/ExifTool/Canon.pm +143 -9
  6. package/bin/exiftool_files/lib/Image/ExifTool/CanonCustom.pm +12 -2
  7. package/bin/exiftool_files/lib/Image/ExifTool/DarwinCore.pm +2 -2
  8. package/bin/exiftool_files/lib/Image/ExifTool/Exif.pm +13 -1
  9. package/bin/exiftool_files/lib/Image/ExifTool/FLIR.pm +33 -8
  10. package/bin/exiftool_files/lib/Image/ExifTool/GIF.pm +5 -1
  11. package/bin/exiftool_files/lib/Image/ExifTool/GPS.pm +14 -10
  12. package/bin/exiftool_files/lib/Image/ExifTool/ICC_Profile.pm +3 -3
  13. package/bin/exiftool_files/lib/Image/ExifTool/Jpeg2000.pm +108 -11
  14. package/bin/exiftool_files/lib/Image/ExifTool/Nikon.pm +1203 -96
  15. package/bin/exiftool_files/lib/Image/ExifTool/NikonCustom.pm +5 -1
  16. package/bin/exiftool_files/lib/Image/ExifTool/NikonSettings.pm +135 -71
  17. package/bin/exiftool_files/lib/Image/ExifTool/OpenEXR.pm +4 -2
  18. package/bin/exiftool_files/lib/Image/ExifTool/PNG.pm +1 -0
  19. package/bin/exiftool_files/lib/Image/ExifTool/QuickTime.pm +14 -2
  20. package/bin/exiftool_files/lib/Image/ExifTool/QuickTimeStream.pl +26 -1
  21. package/bin/exiftool_files/lib/Image/ExifTool/Sony.pm +3 -1
  22. package/bin/exiftool_files/lib/Image/ExifTool/TagInfoXML.pm +9 -4
  23. package/bin/exiftool_files/lib/Image/ExifTool/TagLookup.pm +6363 -5846
  24. package/bin/exiftool_files/lib/Image/ExifTool/TagNames.pod +1215 -39
  25. package/bin/exiftool_files/lib/Image/ExifTool/WriteXMP.pl +10 -11
  26. package/bin/exiftool_files/lib/Image/ExifTool/Writer.pl +10 -5
  27. package/bin/exiftool_files/lib/Image/ExifTool/XMP.pm +110 -24
  28. package/bin/exiftool_files/lib/Image/ExifTool/XMP2.pl +1 -1
  29. package/bin/exiftool_files/lib/Image/ExifTool.pm +51 -12
  30. package/package.json +2 -2
@@ -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) {
@@ -4775,7 +4778,7 @@ sub InverseDateTime($$;$$)
4775
4778
  my ($rtnVal, $tz);
4776
4779
  my $fmt = $$self{OPTIONS}{DateFormat};
4777
4780
  # strip off timezone first if it exists
4778
- 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) {
4779
4782
  $tz = sprintf("$1%.2d:$3", $2);
4780
4783
  } elsif (not $fmt and $val =~ s/Z$//i) {
4781
4784
  $tz = 'Z';
@@ -4798,6 +4801,8 @@ sub InverseDateTime($$;$$)
4798
4801
  $strptimeLib = '';
4799
4802
  }
4800
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 : '';
4801
4806
  my ($lib, $wrn, @a);
4802
4807
  TryLib: for ($lib=$strptimeLib; ; $lib='') {
4803
4808
  if (not $lib) {
@@ -4834,10 +4839,10 @@ TryLib: for ($lib=$strptimeLib; ; $lib='') {
4834
4839
  next TryLib;
4835
4840
  }
4836
4841
  } elsif (length($a[$i]) < 2) {
4837
- $$a[$i] = "0$a[$i]";# pad to 2 digits if necessary
4842
+ $a[$i] = "0$a[$i]"; # pad to 2 digits if necessary
4838
4843
  }
4839
4844
  }
4840
- $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]);
4845
+ $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]) . $fs;
4841
4846
  last;
4842
4847
  }
4843
4848
  }
@@ -50,7 +50,7 @@ use Image::ExifTool::Exif;
50
50
  use Image::ExifTool::GPS;
51
51
  require Exporter;
52
52
 
53
- $VERSION = '3.47';
53
+ $VERSION = '3.50';
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)
@@ -2061,8 +2134,8 @@ my %sPantryItem = (
2061
2134
  Groups => { 2 => 'Location' },
2062
2135
  Writable => 'integer',
2063
2136
  PrintConv => {
2064
- 2 => '2-Dimensional',
2065
- 3 => '3-Dimensional',
2137
+ 2 => '2-Dimensional Measurement',
2138
+ 3 => '3-Dimensional Measurement',
2066
2139
  },
2067
2140
  },
2068
2141
  GPSDOP => { Groups => { 2 => 'Location' }, Writable => 'rational' },
@@ -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)
@@ -2363,6 +2437,7 @@ my %sPantryItem = (
2363
2437
  NOTES => 'Adobe Lightroom "lr" namespace tags.',
2364
2438
  privateRTKInfo => { },
2365
2439
  hierarchicalSubject => { List => 'Bag' },
2440
+ weightedFlatSubject => { List => 'Bag' },
2366
2441
  );
2367
2442
 
2368
2443
  # Adobe Album namespace properties (album) (ref PH)
@@ -3505,6 +3580,17 @@ sub ParseXMPElement($$$;$$$$)
3505
3580
  }
3506
3581
  $start = pos($$dataPt); # start from here the next time around
3507
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
+
3508
3594
  # extract property attributes
3509
3595
  my ($parseResource, %attrs, @attrs);
3510
3596
  while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) {
@@ -3602,9 +3688,9 @@ sub ParseXMPElement($$$;$$$$)
3602
3688
  if ($nItems == 1000) {
3603
3689
  my ($tg,$ns) = GetXMPTagID($propList);
3604
3690
  if ($isWriting) {
3605
- $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);
3606
3692
  } elsif (not $$et{OPTIONS}{IgnoreMinorErrors}) {
3607
- $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);
3608
3694
  last;
3609
3695
  }
3610
3696
  }
@@ -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/>)
@@ -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.34';
32
+ $VERSION = '12.38';
33
33
  $RELEASE = '';
34
34
  @ISA = qw(Exporter);
35
35
  %EXPORT_TAGS = (
@@ -1211,10 +1211,10 @@ my %systemTagsNotes = (
1211
1211
  ZoneIdentifier => {
1212
1212
  Groups => { 1 => 'System', 2 => 'Other' },
1213
1213
  Notes => q{
1214
- Windows only. Used to indicate that a file has a Zone.Identifier alternate
1215
- data stream, which is used by some Windows browsers to mark downloaded files
1216
- as possibly unsafe to run. May be deleted to remove this stream. Requires
1217
- Win32API::File
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
1218
  },
1219
1219
  Writable => 1,
1220
1220
  WritePseudo => 1,
@@ -4088,8 +4088,9 @@ sub Open($*$;$)
4088
4088
  my ($self, $fh, $file, $mode) = @_;
4089
4089
 
4090
4090
  $file =~ s/^([\s&])/.\/$1/; # protect leading whitespace or ampersand
4091
- # default to read mode ('<') unless input is a pipe
4092
- $mode = ($file =~ /\|$/ ? '' : '<') unless $mode;
4091
+ # default to read mode ('<') unless input is a trusted pipe
4092
+ $mode = (($file =~ /\|$/ and $$self{TRUST_PIPE}) ? '' : '<') unless $mode;
4093
+ undef $$self{TRUST_PIPE};
4093
4094
  if ($mode) {
4094
4095
  if ($self->EncodeFileName($file)) {
4095
4096
  # handle Windows Unicode file name
@@ -4252,6 +4253,7 @@ sub ParseArguments($;@)
4252
4253
  $$self{REQ_TAG_LOOKUP} = { };
4253
4254
  $$self{EXCL_TAG_LOOKUP} = { };
4254
4255
  $$self{IO_TAG_LIST} = undef;
4256
+ delete $$self{EXCL_XMP_LOOKUP};
4255
4257
 
4256
4258
  # handle our input arguments
4257
4259
  while (@_) {
@@ -4335,7 +4337,11 @@ sub ParseArguments($;@)
4335
4337
  # generate lookup for excluded tags
4336
4338
  if ($$options{Exclude}) {
4337
4339
  foreach (@{$$options{Exclude}}) {
4338
- /([-\w]+)#?$/ and $$self{EXCL_TAG_LOOKUP}{lc($1)} = 1;
4340
+ /([-\w]+)#?$/ and $$self{EXCL_TAG_LOOKUP}{lc $1} = 1;
4341
+ if (/(xmp-.*:[-\w]+)#?/i) {
4342
+ $$self{EXCL_XMP_LOOKUP} or $$self{EXCL_XMP_LOOKUP} = { };
4343
+ $$self{EXCL_XMP_LOOKUP}{lc $1} = 1;
4344
+ }
4339
4345
  }
4340
4346
  # exclude list is used only for EXCL_TAG_LOOKUP when TAGS_FROM_FILE is set
4341
4347
  undef $$options{Exclude} if $$self{TAGS_FROM_FILE};
@@ -5677,6 +5683,38 @@ sub ConvertDateTime($$)
5677
5683
  unshift @a, 1 while @a < 3; # add month and day if necessary
5678
5684
  unshift @a, 0 while @a < 6; # add h,m,s if necessary
5679
5685
  $a[4] -= 1; # base month is 1
5686
+ # parse our %f fractional seconds first (and round up seconds if necessary)
5687
+ # - if there are multiple %f codes, they all get the same number of digits as the first
5688
+ if ($fmt =~ /%\.?(\d*)f/) {
5689
+ my $dig = $1;
5690
+ my $frac = $date =~ /(\.\d+)/ ? $1 : '';
5691
+ if (not $frac) {
5692
+ $frac = '.' . ('0' x $dig) if $dig;
5693
+ } elsif (length $dig) {
5694
+ if ($dig+1 > length($frac)) {
5695
+ $frac .= '0' x ($dig+1-length($frac));
5696
+ } elsif ($dig+1 < length($frac)) {
5697
+ $frac = sprintf("%.${dig}f", $frac);
5698
+ while ($frac =~ s/^(\d)// and $1 ne '0') {
5699
+ # this is a pain, but we must round up to the next second
5700
+ ++$a[0] < 60 and last;
5701
+ $a[0] = 0;
5702
+ ++$a[1] < 60 and last;
5703
+ $a[1] = 0;
5704
+ ++$a[2] < 24 and last;
5705
+ $a[2] = 0;
5706
+ require 'Image/ExifTool/Shift.pl';
5707
+ ++$a[3] <= DaysInMonth($a[4]+1, $a[5]) and last;
5708
+ $a[3] = 1;
5709
+ ++$a[4] < 12 and last;
5710
+ $a[4] = 0;
5711
+ ++$a[5];
5712
+ last; # (this was a goto)
5713
+ }
5714
+ }
5715
+ }
5716
+ $fmt =~ s/(^|[^%])((%%)*)%\.?\d*f/$1$2$frac/g;
5717
+ }
5680
5718
  # parse %z and %s ourself (to handle time zones properly)
5681
5719
  if ($fmt =~ /%[sz]/) {
5682
5720
  # use system time zone unless otherwise specified
@@ -6277,7 +6315,7 @@ sub ProcessJPEG($$)
6277
6315
  my $markerName = JpegMarkerName($marker);
6278
6316
  $$path[$pn] = $markerName;
6279
6317
  # issue warning if we skipped some garbage
6280
- if ($skipped and not $foundSOS) {
6318
+ if ($skipped and not $foundSOS and $markerName ne 'SOS') {
6281
6319
  $self->Warn("Skipped unknown $skipped bytes after JPEG $markerName segment", 1);
6282
6320
  if ($htmlDump) {
6283
6321
  $self->HDump($nextSegPos-4-$skipped, $skipped, "[unknown $skipped bytes]", undef, 0x08);
@@ -8736,6 +8774,7 @@ sub ProcessBinaryData($$$)
8736
8774
  # read value now if necessary
8737
8775
  unless (defined $val and not $$tagInfo{SubDirectory}) {
8738
8776
  $val = ReadValue($dataPt, $entry+$offset, $format, $count, $more, \$rational);
8777
+ next unless defined $val;
8739
8778
  $mask = $$tagInfo{Mask};
8740
8779
  $val = ($val & $mask) >> $$tagInfo{BitShift} if $mask;
8741
8780
  }
@@ -8837,8 +8876,8 @@ until ($Image::ExifTool::noConfig) {
8837
8876
  $file = $config;
8838
8877
  }
8839
8878
  # also check executable directory unless path is absolute
8840
- $exePath = $^X unless defined $exePath; # (undocumented $exePath setting)
8841
- -r $file or $config =~ /^\// or $file = ($exePath =~ /(.*[\\\/])/ ? $1 : './') . $config;
8879
+ $exeDir = ($0 =~ /(.*)[\\\/]/) ? $1 : '.' unless defined $exeDir;
8880
+ -r $file or $config =~ /^\// or $file = "$exeDir/$config";
8842
8881
  unless (-r $file) {
8843
8882
  warn("Config file not found\n") if defined $Image::ExifTool::configFile;
8844
8883
  last;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exiftool-vendored.exe",
3
- "version": "12.34.0",
3
+ "version": "12.38.0",
4
4
  "description": "Vendored win32 ExifTool for Node.js",
5
5
  "main": "./index.js",
6
6
  "homepage": "https://github.com/mceachen/exiftool-vendored.exe#readme",
@@ -31,6 +31,6 @@
31
31
  },
32
32
  "devDependencies": {
33
33
  "mocha": "^9.1.3",
34
- "prettier": "^2.4.1"
34
+ "prettier": "^2.5.1"
35
35
  }
36
36
  }