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.
- checksums.yaml +4 -4
- data/bin/Changes +66 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +2 -2
- data/bin/exiftool +65 -37
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +11 -2
- data/bin/lib/Image/ExifTool/Canon.pm +156 -10
- data/bin/lib/Image/ExifTool/Charset.pm +2 -0
- data/bin/lib/Image/ExifTool/DarwinCore.pm +2 -2
- data/bin/lib/Image/ExifTool/Exif.pm +13 -1
- data/bin/lib/Image/ExifTool/FLIR.pm +33 -8
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/GPS.pm +14 -10
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +108 -11
- data/bin/lib/Image/ExifTool/Nikon.pm +992 -18
- data/bin/lib/Image/ExifTool/NikonCustom.pm +5 -1
- data/bin/lib/Image/ExifTool/NikonSettings.pm +135 -71
- data/bin/lib/Image/ExifTool/PDF.pm +5 -3
- data/bin/lib/Image/ExifTool/PNG.pm +1 -0
- data/bin/lib/Image/ExifTool/QuickTime.pm +17 -3
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +26 -1
- data/bin/lib/Image/ExifTool/README +4 -0
- data/bin/lib/Image/ExifTool/Sony.pm +29 -11
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +9 -4
- data/bin/lib/Image/ExifTool/TagLookup.pm +6437 -5843
- data/bin/lib/Image/ExifTool/TagNames.pod +1292 -46
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +10 -0
- data/bin/lib/Image/ExifTool/WriteXMP.pl +10 -11
- data/bin/lib/Image/ExifTool/Writer.pl +50 -5
- data/bin/lib/Image/ExifTool/XMP.pm +119 -30
- data/bin/lib/Image/ExifTool/XMP2.pl +3 -2
- data/bin/lib/Image/ExifTool.pm +71 -8
- data/bin/lib/Image/ExifTool.pod +9 -1
- data/bin/perl-Image-ExifTool.spec +1 -1
- data/lib/exiftool_vendored/version.rb +1 -1
- 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
|
-
|
1423
|
-
|
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
|
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)
|
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/([
|
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
|
-
|
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.
|
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
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
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 => '
|
503
|
-
LocalToningSaturation => { FlatName => '
|
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 => \%
|
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.
|
2146
|
-
L<
|
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
|
-
|
2353
|
-
|
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->
|
3691
|
+
$et->WarnOnce("Excessive number of items for $ns:$tg. Processing may be slow", 1);
|
3605
3692
|
} elsif (not $$et{OPTIONS}{IgnoreMinorErrors}) {
|
3606
|
-
$et->
|
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.
|
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
|
-
|
800
|
+
# new Extension 1.6 property
|
801
|
+
EventId => { Name => 'EventID', List => 'Bag' },
|
801
802
|
);
|
802
803
|
|
803
804
|
#------------------------------------------------------------------------------
|
data/bin/lib/Image/ExifTool.pm
CHANGED
@@ -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 $
|
29
|
+
%jpegMarker %specialTags %fileTypeLookup $testLen $exeDir
|
30
30
|
%static_vars);
|
31
31
|
|
32
|
-
$VERSION = '12.
|
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
|
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
|
-
$
|
8816
|
-
-r $file or $config =~ /^\// or $file =
|
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;
|
data/bin/lib/Image/ExifTool.pod
CHANGED
@@ -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
|
|