exiftool_vendored 12.33.0 → 12.37.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.
- 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
|
|