exiftool-vendored.pl 12.30.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.
- package/bin/Changes +129 -3
- package/bin/MANIFEST +2 -0
- package/bin/META.json +1 -1
- package/bin/META.yml +1 -1
- package/bin/README +2 -2
- package/bin/arg_files/xmp2exif.args +2 -1
- package/bin/config_files/example.config +1 -1
- package/bin/exiftool +88 -55
- package/bin/fmt_files/gpx.fmt +1 -1
- package/bin/fmt_files/gpx_wpt.fmt +1 -1
- package/bin/lib/Image/ExifTool/BuildTagLookup.pm +13 -3
- package/bin/lib/Image/ExifTool/CBOR.pm +331 -0
- package/bin/lib/Image/ExifTool/Canon.pm +175 -12
- package/bin/lib/Image/ExifTool/CanonCustom.pm +12 -2
- package/bin/lib/Image/ExifTool/Charset.pm +2 -0
- package/bin/lib/Image/ExifTool/DPX.pm +13 -2
- package/bin/lib/Image/ExifTool/DarwinCore.pm +2 -2
- package/bin/lib/Image/ExifTool/Exif.pm +109 -3
- package/bin/lib/Image/ExifTool/FLIR.pm +33 -8
- package/bin/lib/Image/ExifTool/GIF.pm +5 -1
- package/bin/lib/Image/ExifTool/GPS.pm +14 -10
- package/bin/lib/Image/ExifTool/Geotag.pm +13 -2
- package/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- package/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
- package/bin/lib/Image/ExifTool/JSON.pm +7 -3
- package/bin/lib/Image/ExifTool/Jpeg2000.pm +154 -24
- package/bin/lib/Image/ExifTool/M2TS.pm +27 -12
- package/bin/lib/Image/ExifTool/MacOS.pm +2 -2
- package/bin/lib/Image/ExifTool/Nikon.pm +1204 -96
- package/bin/lib/Image/ExifTool/NikonCustom.pm +5 -1
- package/bin/lib/Image/ExifTool/NikonSettings.pm +135 -71
- package/bin/lib/Image/ExifTool/Olympus.pm +5 -1
- package/bin/lib/Image/ExifTool/OpenEXR.pm +4 -2
- package/bin/lib/Image/ExifTool/PDF.pm +11 -12
- package/bin/lib/Image/ExifTool/PNG.pm +4 -1
- package/bin/lib/Image/ExifTool/Panasonic.pm +2 -2
- package/bin/lib/Image/ExifTool/Pentax.pm +2 -1
- package/bin/lib/Image/ExifTool/QuickTime.pm +69 -10
- package/bin/lib/Image/ExifTool/QuickTimeStream.pl +141 -111
- package/bin/lib/Image/ExifTool/README +9 -2
- package/bin/lib/Image/ExifTool/Sony.pm +56 -13
- package/bin/lib/Image/ExifTool/TagInfoXML.pm +9 -4
- package/bin/lib/Image/ExifTool/TagLookup.pm +6473 -5827
- package/bin/lib/Image/ExifTool/TagNames.pod +1401 -54
- package/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
- package/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
- package/bin/lib/Image/ExifTool/WriteQuickTime.pl +10 -0
- package/bin/lib/Image/ExifTool/WriteXMP.pl +10 -11
- package/bin/lib/Image/ExifTool/Writer.pl +50 -5
- package/bin/lib/Image/ExifTool/XMP.pm +125 -31
- package/bin/lib/Image/ExifTool/XMP2.pl +3 -1
- package/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
- package/bin/lib/Image/ExifTool.pm +89 -22
- package/bin/lib/Image/ExifTool.pod +21 -13
- package/bin/perl-Image-ExifTool.spec +1 -1
- package/bin/pp_build_exe.args +5 -4
- package/package.json +3 -3
|
@@ -293,6 +293,7 @@ sub WritePDF($$)
|
|
|
293
293
|
my $newTool = new Image::ExifTool;
|
|
294
294
|
$newTool->Options(List => 1);
|
|
295
295
|
$newTool->Options(Password => $et->Options('Password'));
|
|
296
|
+
$newTool->Options(NoPDFList => $et->Options('NoPDFList'));
|
|
296
297
|
$$newTool{PDF_CAPTURE} = \%capture;
|
|
297
298
|
my $info = $newTool->ImageInfo($raf, 'XMP', 'PDF:*', 'Error', 'Warning');
|
|
298
299
|
# not a valid PDF file unless we got a version number
|
|
@@ -179,6 +179,8 @@ sub BuildTextChunk($$$$$)
|
|
|
179
179
|
$tag =~ s/-$lang$//; # remove language code from tagID
|
|
180
180
|
} elsif ($$et{OPTIONS}{Charset} ne 'Latin' and $val =~ /[\x80-\xff]/) {
|
|
181
181
|
$iTXt = 1; # write as iTXt if it contains non-Latin special characters
|
|
182
|
+
} elsif ($$tagInfo{iTXt}) {
|
|
183
|
+
$iTXt = 1; # write as iTXt if specified in user-defined tag
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
if ($comp) {
|
|
@@ -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.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
|
-
|
|
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 = (
|
|
@@ -1533,6 +1598,9 @@ my %sPantryItem = (
|
|
|
1533
1598
|
CameraProfile => { },
|
|
1534
1599
|
LookTable => { },
|
|
1535
1600
|
ToneCurvePV2012 => { List => 'Seq' },
|
|
1601
|
+
ToneCurvePV2012Red => { List => 'Seq' },
|
|
1602
|
+
ToneCurvePV2012Green => { List => 'Seq' },
|
|
1603
|
+
ToneCurvePV2012Blue => { List => 'Seq' },
|
|
1536
1604
|
},
|
|
1537
1605
|
},
|
|
1538
1606
|
}
|
|
@@ -1578,6 +1646,14 @@ my %sPantryItem = (
|
|
|
1578
1646
|
AutoToneDigestNoSat => { },
|
|
1579
1647
|
ToggleStyleDigest => { },
|
|
1580
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' },
|
|
1581
1657
|
);
|
|
1582
1658
|
|
|
1583
1659
|
# Tiff namespace properties (tiff)
|
|
@@ -1669,7 +1745,7 @@ my %sPantryItem = (
|
|
|
1669
1745
|
Software => { },
|
|
1670
1746
|
Artist => { Groups => { 2 => 'Author' } },
|
|
1671
1747
|
Copyright => { Groups => { 2 => 'Author' }, Writable => 'lang-alt' },
|
|
1672
|
-
NativeDigest => { }, #PH
|
|
1748
|
+
NativeDigest => { Avoid => 1 }, #PH
|
|
1673
1749
|
);
|
|
1674
1750
|
|
|
1675
1751
|
# Exif namespace properties (exif)
|
|
@@ -2058,8 +2134,8 @@ my %sPantryItem = (
|
|
|
2058
2134
|
Groups => { 2 => 'Location' },
|
|
2059
2135
|
Writable => 'integer',
|
|
2060
2136
|
PrintConv => {
|
|
2061
|
-
2 => '2-Dimensional',
|
|
2062
|
-
3 => '3-Dimensional',
|
|
2137
|
+
2 => '2-Dimensional Measurement',
|
|
2138
|
+
3 => '3-Dimensional Measurement',
|
|
2063
2139
|
},
|
|
2064
2140
|
},
|
|
2065
2141
|
GPSDOP => { Groups => { 2 => 'Location' }, Writable => 'rational' },
|
|
@@ -2139,8 +2215,8 @@ my %sPantryItem = (
|
|
|
2139
2215
|
NAMESPACE => 'exifEX',
|
|
2140
2216
|
PRIORITY => 0, # not as reliable as actual EXIF tags
|
|
2141
2217
|
NOTES => q{
|
|
2142
|
-
EXIF tags added by the EXIF 2.
|
|
2143
|
-
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>).
|
|
2144
2220
|
},
|
|
2145
2221
|
Gamma => { Writable => 'rational' },
|
|
2146
2222
|
PhotographicSensitivity => { Writable => 'integer' },
|
|
@@ -2304,6 +2380,7 @@ my %sPantryItem = (
|
|
|
2304
2380
|
VignetteCorrectionAlreadyApplied => { Writable => 'boolean' },
|
|
2305
2381
|
LateralChromaticAberrationCorrectionAlreadyApplied => { Writable => 'boolean' },
|
|
2306
2382
|
LensDistortInfo => { }, # (LR 7.5.1, 4 signed rational values)
|
|
2383
|
+
NeutralDensityFactor => { }, # (LR 11.0 - rational value, but denominator seems significant)
|
|
2307
2384
|
);
|
|
2308
2385
|
|
|
2309
2386
|
# IPTC Core namespace properties (Iptc4xmpCore) (ref 4)
|
|
@@ -2346,6 +2423,9 @@ my %sPantryItem = (
|
|
|
2346
2423
|
Scene => { Groups => { 2 => 'Other' }, List => 'Bag' },
|
|
2347
2424
|
SubjectCode => { Groups => { 2 => 'Other' }, List => 'Bag' },
|
|
2348
2425
|
# Copyright - have seen this in a sample (Jan 2021), but I think it is non-standard
|
|
2426
|
+
# new IPTC Core 1.3 properties
|
|
2427
|
+
AltTextAccessibility => { Groups => { 2 => 'Other' }, Writable => 'lang-alt' },
|
|
2428
|
+
ExtDescrAccessibility => { Groups => { 2 => 'Other' }, Writable => 'lang-alt' },
|
|
2349
2429
|
);
|
|
2350
2430
|
|
|
2351
2431
|
# Adobe Lightroom namespace properties (lr) (ref PH)
|
|
@@ -2357,6 +2437,7 @@ my %sPantryItem = (
|
|
|
2357
2437
|
NOTES => 'Adobe Lightroom "lr" namespace tags.',
|
|
2358
2438
|
privateRTKInfo => { },
|
|
2359
2439
|
hierarchicalSubject => { List => 'Bag' },
|
|
2440
|
+
weightedFlatSubject => { List => 'Bag' },
|
|
2360
2441
|
);
|
|
2361
2442
|
|
|
2362
2443
|
# Adobe Album namespace properties (album) (ref PH)
|
|
@@ -3499,6 +3580,17 @@ sub ParseXMPElement($$$;$$$$)
|
|
|
3499
3580
|
}
|
|
3500
3581
|
$start = pos($$dataPt); # start from here the next time around
|
|
3501
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
|
+
|
|
3502
3594
|
# extract property attributes
|
|
3503
3595
|
my ($parseResource, %attrs, @attrs);
|
|
3504
3596
|
while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) {
|
|
@@ -3596,9 +3688,9 @@ sub ParseXMPElement($$$;$$$$)
|
|
|
3596
3688
|
if ($nItems == 1000) {
|
|
3597
3689
|
my ($tg,$ns) = GetXMPTagID($propList);
|
|
3598
3690
|
if ($isWriting) {
|
|
3599
|
-
$et->
|
|
3691
|
+
$et->WarnOnce("Excessive number of items for $ns:$tg. Processing may be slow", 1);
|
|
3600
3692
|
} elsif (not $$et{OPTIONS}{IgnoreMinorErrors}) {
|
|
3601
|
-
$et->
|
|
3693
|
+
$et->WarnOnce("Extracted only 1000 $ns:$tg items. Ignore minor errors to extract all", 2);
|
|
3602
3694
|
last;
|
|
3603
3695
|
}
|
|
3604
3696
|
}
|
|
@@ -3960,7 +4052,7 @@ sub ProcessXMP($$;$)
|
|
|
3960
4052
|
} elsif ($1 eq 'REDXIF') {
|
|
3961
4053
|
$type = 'RMD';
|
|
3962
4054
|
$mime = 'application/xml';
|
|
3963
|
-
}
|
|
4055
|
+
} elsif ($1 ne 'fcpxml') { # Final Cut Pro XML
|
|
3964
4056
|
return 0;
|
|
3965
4057
|
}
|
|
3966
4058
|
} elsif ($buf2 =~ /<svg[\s>]/) {
|
|
@@ -3970,14 +4062,16 @@ sub ProcessXMP($$;$)
|
|
|
3970
4062
|
} elsif ($buf2 =~ /<plist[\s>]/) {
|
|
3971
4063
|
$type = 'PLIST';
|
|
3972
4064
|
}
|
|
3973
|
-
if ($isSVG and $$et{XMP_CAPTURE}) {
|
|
3974
|
-
$et->Error("ExifTool does not yet support writing of SVG images");
|
|
3975
|
-
return 0;
|
|
3976
|
-
}
|
|
3977
4065
|
}
|
|
3978
4066
|
$isXML = 1;
|
|
3979
4067
|
} elsif ($2 eq '<rdf:RDF') {
|
|
3980
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;
|
|
3981
4075
|
}
|
|
3982
4076
|
if ($buff =~ /^\0\0/) {
|
|
3983
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,6 +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
|
+
# new Extension 1.6 property
|
|
801
|
+
EventId => { Name => 'EventID', List => 'Bag' },
|
|
800
802
|
);
|
|
801
803
|
|
|
802
804
|
#------------------------------------------------------------------------------
|
|
@@ -32,7 +32,9 @@ sub SerializeStruct($;$)
|
|
|
32
32
|
my ($key, $val, @vals, $rtnVal);
|
|
33
33
|
|
|
34
34
|
if (ref $obj eq 'HASH') {
|
|
35
|
-
|
|
35
|
+
# support hashes with ordered keys
|
|
36
|
+
my @keys = $$obj{_ordered_keys_} ? @{$$obj{_ordered_keys_}} : sort keys %$obj;
|
|
37
|
+
foreach $key (@keys) {
|
|
36
38
|
push @vals, $key . '=' . SerializeStruct($$obj{$key}, '}');
|
|
37
39
|
}
|
|
38
40
|
$rtnVal = '{' . join(',', @vals) . '}';
|