exiftool_vendored 12.68.0 → 12.72.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 +98 -15
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +10 -10
- data/bin/exiftool +32 -25
- data/bin/lib/Image/ExifTool/AAC.pm +175 -0
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +2 -1
- data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- data/bin/lib/Image/ExifTool/Canon.pm +87 -20
- data/bin/lib/Image/ExifTool/DJI.pm +3 -2
- data/bin/lib/Image/ExifTool/DNG.pm +25 -2
- data/bin/lib/Image/ExifTool/EXE.pm +54 -6
- data/bin/lib/Image/ExifTool/Exif.pm +204 -22
- data/bin/lib/Image/ExifTool/FujiFilm.pm +145 -20
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- data/bin/lib/Image/ExifTool/ID3.pm +76 -10
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/JSON.pm +4 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- data/bin/lib/Image/ExifTool/M2TS.pm +21 -16
- data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +213 -105
- data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
- data/bin/lib/Image/ExifTool/PNG.pm +8 -13
- data/bin/lib/Image/ExifTool/Panasonic.pm +15 -2
- data/bin/lib/Image/ExifTool/Pentax.pm +15 -6
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +60 -14
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +59 -11
- data/bin/lib/Image/ExifTool/README +14 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
- data/bin/lib/Image/ExifTool/Ricoh.pm +109 -1
- data/bin/lib/Image/ExifTool/Samsung.pm +3 -2
- data/bin/lib/Image/ExifTool/Sony.pm +177 -37
- data/bin/lib/Image/ExifTool/TagLookup.pm +6971 -6714
- data/bin/lib/Image/ExifTool/TagNames.pod +957 -372
- data/bin/lib/Image/ExifTool/Text.pm +4 -5
- data/bin/lib/Image/ExifTool/Validate.pm +23 -20
- data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +2 -2
- data/bin/lib/Image/ExifTool/WriteExif.pl +33 -8
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
- data/bin/lib/Image/ExifTool/Writer.pl +121 -28
- data/bin/lib/Image/ExifTool/XMP.pm +67 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
- data/bin/lib/Image/ExifTool.pm +94 -43
- data/bin/lib/Image/ExifTool.pod +28 -17
- data/bin/perl-Image-ExifTool.spec +9 -9
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +3 -2
@@ -122,9 +122,9 @@ my %writableType = (
|
|
122
122
|
XMP => [ undef, 'WriteXMP' ],
|
123
123
|
);
|
124
124
|
|
125
|
-
# RAW file types
|
125
|
+
# RAW file types (2 = raw file where we can delete maker notes from ExifIFD)
|
126
126
|
my %rawType = (
|
127
|
-
'3FR'=> 1, CR3 =>
|
127
|
+
'3FR'=> 1, CR3 => 2, IIQ => 1, NEF => 1, RW2 => 1,
|
128
128
|
ARQ => 1, CRW => 1, K25 => 1, NRW => 1, RWL => 1,
|
129
129
|
ARW => 1, DCR => 1, KDC => 1, ORF => 1, SR2 => 1,
|
130
130
|
ARW => 1, ERF => 1, MEF => 1, PEF => 1, SRF => 1,
|
@@ -278,6 +278,7 @@ my %ignorePrintConv = map { $_ => 1 } qw(OTHER BITMASK Notes);
|
|
278
278
|
# ListOnly => [internal use] set only list or non-list tags
|
279
279
|
# SetTags => [internal use] hash ref to return tagInfo refs of set tags
|
280
280
|
# Sanitized => [internal use] set to avoid double-sanitizing the value
|
281
|
+
# Fixup => [internal use] fixup information when writing maker notes
|
281
282
|
# Returns: number of tags set (plus error string in list context)
|
282
283
|
# Notes: For tag lists (like Keywords), call repeatedly with the same tag name for
|
283
284
|
# each value in the list. Internally, the new information is stored in
|
@@ -689,6 +690,12 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
689
690
|
$writeProc = $$src{WRITE_PROC} unless $writeProc;
|
690
691
|
}
|
691
692
|
{
|
693
|
+
# make sure module is loaded if the writeProc is a string
|
694
|
+
unless (ref $writeProc) {
|
695
|
+
my $module = $writeProc;
|
696
|
+
$module =~ s/::\w+$//;
|
697
|
+
eval "require $module";
|
698
|
+
}
|
692
699
|
no strict 'refs';
|
693
700
|
next unless $writeProc and &$writeProc();
|
694
701
|
}
|
@@ -1002,10 +1009,8 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
1002
1009
|
$$nvHash{NoReplace} = 1 if $$tagInfo{List} and not $options{Replace};
|
1003
1010
|
$$nvHash{WantGroup} = $wantGroup;
|
1004
1011
|
$$nvHash{EditOnly} = 1 if $editOnly;
|
1005
|
-
# save maker note information if writing maker notes
|
1006
|
-
if
|
1007
|
-
$$nvHash{MAKER_NOTE_FIXUP} = $$self{MAKER_NOTE_FIXUP};
|
1008
|
-
}
|
1012
|
+
# save maker note fixup information if writing maker notes
|
1013
|
+
$$nvHash{MAKER_NOTE_FIXUP} = $options{Fixup} if $$tagInfo{MakerNotes};
|
1009
1014
|
if ($createOnly) { # create only (never edit)
|
1010
1015
|
# empty item in DelValue list to never edit existing value
|
1011
1016
|
$$nvHash{DelValue} = [ '' ];
|
@@ -1272,6 +1277,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1272
1277
|
# +------------------------------------------+
|
1273
1278
|
$srcExifTool->Options(
|
1274
1279
|
Binary => 1,
|
1280
|
+
ByteUnit => $$options{ByteUnit},
|
1275
1281
|
Charset => $$options{Charset},
|
1276
1282
|
CharsetEXIF => $$options{CharsetEXIF},
|
1277
1283
|
CharsetFileName => $$options{CharsetFileName},
|
@@ -1372,8 +1378,8 @@ sub SetNewValuesFromFile($$;@)
|
|
1372
1378
|
#
|
1373
1379
|
unless (@setTags) {
|
1374
1380
|
# transfer maker note information to this object
|
1375
|
-
$$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
|
1376
1381
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
1382
|
+
my $tagExtra = $$srcExifTool{TAG_EXTRA};
|
1377
1383
|
foreach $tag (@tags) {
|
1378
1384
|
# don't try to set errors or warnings
|
1379
1385
|
next if $tag =~ /^(Error|Warning)\b/;
|
@@ -1381,10 +1387,13 @@ sub SetNewValuesFromFile($$;@)
|
|
1381
1387
|
if ($opts{SrcType} and $opts{SrcType} ne $srcType) {
|
1382
1388
|
$$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType});
|
1383
1389
|
}
|
1390
|
+
my $fixup = $$tagExtra{$tag}{Fixup};
|
1391
|
+
$opts{Fixup} = $fixup if $fixup;
|
1384
1392
|
# set value for this tag
|
1385
1393
|
my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts);
|
1386
1394
|
# delete this tag if we couldn't set it
|
1387
1395
|
$n or delete $$info{$tag};
|
1396
|
+
delete $opts{Fixup} if $fixup;
|
1388
1397
|
}
|
1389
1398
|
return $info;
|
1390
1399
|
}
|
@@ -1617,7 +1626,7 @@ SET: foreach $set (@setList) {
|
|
1617
1626
|
}
|
1618
1627
|
# transfer maker note information if setting this tag
|
1619
1628
|
if ($$srcExifTool{TAG_INFO}{$tag}{MakerNotes}) {
|
1620
|
-
$$
|
1629
|
+
$$opts{Fixup} = $$srcExifTool{TAG_EXTRA}{$tag}{Fixup};
|
1621
1630
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
1622
1631
|
}
|
1623
1632
|
if ($dstTag eq '*') {
|
@@ -1649,6 +1658,7 @@ SET: foreach $set (@setList) {
|
|
1649
1658
|
$rtnInfo{NextFreeTagKey(\%rtnInfo, 'Warning')} = $wrn;
|
1650
1659
|
$noWarn = 1;
|
1651
1660
|
}
|
1661
|
+
delete $$opts{Fixup};
|
1652
1662
|
$rtnInfo{$tag} = $val if $rtn; # tag was set successfully
|
1653
1663
|
}
|
1654
1664
|
}
|
@@ -3235,9 +3245,15 @@ sub InsertTagValues($$$;$$$)
|
|
3235
3245
|
$tag = $docGrp . ':' . $tag;
|
3236
3246
|
$lcTag = lc $tag;
|
3237
3247
|
}
|
3238
|
-
my $et = $self;
|
3248
|
+
my ($et, $fileTags) = ($self, $foundTags);
|
3239
3249
|
if ($tag =~ s/(\bfile\d+)://i) {
|
3240
|
-
$et = $$self{ALT_EXIFTOOL}{ucfirst lc $1}
|
3250
|
+
$et = $$self{ALT_EXIFTOOL}{ucfirst lc $1};
|
3251
|
+
if ($et) {
|
3252
|
+
$fileTags = $$et{FoundTags};
|
3253
|
+
} else {
|
3254
|
+
$et = $self;
|
3255
|
+
$tag = 'no_alt_file';
|
3256
|
+
}
|
3241
3257
|
}
|
3242
3258
|
if ($lcTag eq 'all') {
|
3243
3259
|
$val = 1; # always some tag available
|
@@ -3248,11 +3264,11 @@ sub InsertTagValues($$$;$$$)
|
|
3248
3264
|
($group, $tag) = ($1, $2);
|
3249
3265
|
if (lc $tag eq 'all') {
|
3250
3266
|
# see if any tag from the specified group exists
|
3251
|
-
my $match = $et->GroupMatches($group, $
|
3267
|
+
my $match = $et->GroupMatches($group, $fileTags);
|
3252
3268
|
$val = $match ? 1 : 0;
|
3253
3269
|
} else {
|
3254
3270
|
# find the specified tag
|
3255
|
-
my @matches = grep /^$tag(\s|$)/i, @$
|
3271
|
+
my @matches = grep /^$tag(\s|$)/i, @$fileTags;
|
3256
3272
|
@matches = $et->GroupMatches($group, \@matches);
|
3257
3273
|
foreach $tg (@matches) {
|
3258
3274
|
if (defined $val and $tg =~ / \((\d+)\)$/) {
|
@@ -3272,7 +3288,7 @@ sub InsertTagValues($$$;$$$)
|
|
3272
3288
|
$val = $et->GetValue($tag, $type);
|
3273
3289
|
unless (defined $val) {
|
3274
3290
|
# check for tag name with different case
|
3275
|
-
($tg) = grep /^$tag$/i, @$
|
3291
|
+
($tg) = grep /^$tag$/i, @$fileTags;
|
3276
3292
|
if (defined $tg) {
|
3277
3293
|
$val = $et->GetValue($tg, $type);
|
3278
3294
|
$tag = $tg;
|
@@ -3923,7 +3939,7 @@ sub RemoveNewValuesForGroup($$)
|
|
3923
3939
|
my $wgrp = $$nvHash{WriteGroup};
|
3924
3940
|
# use group1 if write group is not specific
|
3925
3941
|
$wgrp = $grp1 if $wgrp eq $grp0;
|
3926
|
-
if (grep /^($grp0|$wgrp)$/i, @groups) {
|
3942
|
+
if ($grp0 eq '*' or $wgrp eq '*' or grep /^($grp0|$wgrp)$/i, @groups) {
|
3927
3943
|
$out and print $out "Removed new value for $wgrp:$$tagInfo{Name}\n";
|
3928
3944
|
# remove from linked list
|
3929
3945
|
$self->RemoveNewValueHash($nvHash, $tagInfo);
|
@@ -4176,6 +4192,7 @@ sub WriteDirectory($$$;$)
|
|
4176
4192
|
$out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose};
|
4177
4193
|
# set directory name from default group0 name if not done already
|
4178
4194
|
my $dirName = $$dirInfo{DirName};
|
4195
|
+
my $parent = $$dirInfo{Parent} || '';
|
4179
4196
|
my $dataPt = $$dirInfo{DataPt};
|
4180
4197
|
my $grp0 = $$tagTablePtr{GROUPS}{0};
|
4181
4198
|
$dirName or $dirName = $$dirInfo{DirName} = $grp0;
|
@@ -4183,14 +4200,19 @@ sub WriteDirectory($$$;$)
|
|
4183
4200
|
my $delGroup = $$self{DEL_GROUP};
|
4184
4201
|
# delete entire directory if specified
|
4185
4202
|
my $grp1 = $dirName;
|
4186
|
-
$delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1})
|
4203
|
+
$delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1});
|
4204
|
+
if ($permanentDir{$grp0} and not ($$dirInfo{TagInfo} and $$dirInfo{TagInfo}{Deletable})) {
|
4205
|
+
undef $delFlag;
|
4206
|
+
}
|
4187
4207
|
# (never delete an entire QuickTime group)
|
4188
4208
|
if ($delFlag) {
|
4189
4209
|
if (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and
|
4190
4210
|
$self->IsRawType() and
|
4191
4211
|
# allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
|
4192
4212
|
(not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
|
4193
|
-
$$dirInfo{TagInfo}{Permanent})
|
4213
|
+
$$dirInfo{TagInfo}{Permanent}) and
|
4214
|
+
# allow MakerNotes to be deleted from ExifIFD of CR3 file
|
4215
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
4194
4216
|
{
|
4195
4217
|
$self->WarnOnce("Can't delete $1 from $$self{FileType}",1);
|
4196
4218
|
undef $grp1;
|
@@ -4226,7 +4248,6 @@ sub WriteDirectory($$$;$)
|
|
4226
4248
|
if ($delFlag == 2 and $right) {
|
4227
4249
|
# also check grandparent because some routines create 2 levels in 1
|
4228
4250
|
my $right2 = $$self{ADD_DIRS}{$right} || '';
|
4229
|
-
my $parent = $$dirInfo{Parent};
|
4230
4251
|
if (not $parent or $parent eq $right or $parent eq $right2) {
|
4231
4252
|
# prevent duplicate directories from being recreated at the same path
|
4232
4253
|
my $path = join '-', @{$$self{PATH}}, $dirName;
|
@@ -4284,10 +4305,27 @@ sub WriteDirectory($$$;$)
|
|
4284
4305
|
last unless $self->IsOverwriting($nvHash, $dataPt ? $$dataPt : '');
|
4285
4306
|
my $verb = 'Writing';
|
4286
4307
|
my $newVal = $self->GetNewValue($nvHash);
|
4287
|
-
|
4308
|
+
if (defined $newVal and length $newVal) {
|
4309
|
+
# hack to add back TIFF header when writing MakerNoteCanon to CMT3 in CR3 images
|
4310
|
+
if ($$tagInfo{Name} eq 'MakerNoteCanon') {
|
4311
|
+
require Image::ExifTool::Canon;
|
4312
|
+
if ($tagInfo eq $Image::ExifTool::Canon::uuid{CMT3}) {
|
4313
|
+
my $hdr;
|
4314
|
+
if (substr($newVal, 0, 1) eq "\0") {
|
4315
|
+
$hdr = "MM\0\x2a" . pack('N', 8);
|
4316
|
+
} else {
|
4317
|
+
$hdr = "II\x2a\0" . pack('V', 8);
|
4318
|
+
}
|
4319
|
+
$newVal = $hdr . $newVal;
|
4320
|
+
}
|
4321
|
+
}
|
4322
|
+
} else {
|
4288
4323
|
return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed
|
4289
4324
|
# don't allow MakerNotes to be removed from RAW files
|
4290
|
-
if ($blockName eq 'MakerNotes' and $
|
4325
|
+
if ($blockName eq 'MakerNotes' and $self->IsRawType() and
|
4326
|
+
# but allow MakerNotes to be deleted from ExifIFD of CR3 image (shouldn't be there)
|
4327
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
4328
|
+
{
|
4291
4329
|
$self->Warn("Can't delete MakerNotes from $$self{FileType}",1);
|
4292
4330
|
return undef;
|
4293
4331
|
}
|
@@ -4637,9 +4675,18 @@ sub DumpUnknownTrailer($$)
|
|
4637
4675
|
# account for preview/MPF image trailer
|
4638
4676
|
my $prePos = $$self{VALUE}{PreviewImageStart} || $$self{PreviewImageStart};
|
4639
4677
|
my $preLen = $$self{VALUE}{PreviewImageLength} || $$self{PreviewImageLength};
|
4678
|
+
my $hidPos = $$self{VALUE}{HiddenDataOffset};
|
4679
|
+
my $hidLen = $$self{VALUE}{HiddenDataLength};
|
4640
4680
|
my $tag = 'PreviewImage';
|
4641
4681
|
my $mpImageNum = 0;
|
4642
4682
|
my (%image, $lastOne);
|
4683
|
+
# add HiddenData to list of known trailer blocks
|
4684
|
+
if ($hidPos and $hidLen) {
|
4685
|
+
# call ReadHiddenData to validate hidden data and fix offset if necessary
|
4686
|
+
require Image::ExifTool::Sony;
|
4687
|
+
my $datPt = Image::ExifTool::Sony::ReadHiddenData($self, $hidPos, $hidLen);
|
4688
|
+
$image{$hidPos} = ['HiddenData', $hidLen] if $datPt;
|
4689
|
+
}
|
4643
4690
|
for (;;) {
|
4644
4691
|
# add to Preview block list if valid and in the trailer
|
4645
4692
|
$image{$prePos} = [$tag, $preLen] if $prePos and $preLen and $prePos+$preLen > $pos;
|
@@ -5754,13 +5801,16 @@ sub WriteJPEG($$)
|
|
5754
5801
|
}
|
5755
5802
|
}
|
5756
5803
|
# switch to buffered output if required
|
5757
|
-
if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}
|
5804
|
+
if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer} or $$self{HiddenData}) and
|
5805
|
+
not $oldOutfile)
|
5806
|
+
{
|
5758
5807
|
$writeBuffer = '';
|
5759
5808
|
$oldOutfile = $outfile;
|
5760
5809
|
$outfile = \$writeBuffer;
|
5761
5810
|
# account for segment, EXIF and TIFF headers
|
5762
5811
|
$$self{PREVIEW_INFO}{Fixup}{Start} += 18 if $$self{PREVIEW_INFO};
|
5763
5812
|
$$self{LeicaTrailer}{Fixup}{Start} += 18 if $$self{LeicaTrailer};
|
5813
|
+
$$self{HiddenData}{Fixup}{Start} += 18 if $$self{HiddenData};
|
5764
5814
|
}
|
5765
5815
|
# write as multi-segment
|
5766
5816
|
my $n = WriteMultiSegment($outfile, 0xe1, $exifAPP1hdr, \$buff, 'EXIF');
|
@@ -5906,7 +5956,9 @@ sub WriteJPEG($$)
|
|
5906
5956
|
my $delPreview = $$self{DEL_PREVIEW};
|
5907
5957
|
$trailInfo = IdentifyTrailer($raf) unless $$delGroup{Trailer};
|
5908
5958
|
my $nvTrail = $self->GetNewValueHash($Image::ExifTool::Extra{Trailer});
|
5909
|
-
unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer} or $nvTrail
|
5959
|
+
unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer} or $nvTrail or
|
5960
|
+
$$self{HiddenData})
|
5961
|
+
{
|
5910
5962
|
# blindly copy the rest of the file
|
5911
5963
|
while ($raf->Read($buff, 65536)) {
|
5912
5964
|
Write($outfile, $buff) or $err = 1, last;
|
@@ -5936,7 +5988,7 @@ sub WriteJPEG($$)
|
|
5936
5988
|
$endedWithFF = substr($buff, 65535, 1) eq "\xff" ? 1 : 0;
|
5937
5989
|
}
|
5938
5990
|
# remember position of last data copied
|
5939
|
-
$endPos = $raf->Tell() - length($buff);
|
5991
|
+
$endPos = $$self{TrailerStart} = $raf->Tell() - length($buff);
|
5940
5992
|
# write new trailer if specified
|
5941
5993
|
if ($nvTrail) {
|
5942
5994
|
# access new value directly to avoid copying a potentially very large data block
|
@@ -5950,6 +6002,34 @@ sub WriteJPEG($$)
|
|
5950
6002
|
}
|
5951
6003
|
last; # all done
|
5952
6004
|
}
|
6005
|
+
# copy HiddenData if necessary
|
6006
|
+
if ($$self{HiddenData}) {
|
6007
|
+
my $pad;
|
6008
|
+
my $hd = $$self{HiddenData};
|
6009
|
+
my $hdOff = $$hd{Offset} + $$hd{Base};
|
6010
|
+
require Image::ExifTool::Sony;
|
6011
|
+
# read HiddenData, updating $hdOff with actual offset if necessary
|
6012
|
+
my $dataPt = Image::ExifTool::Sony::ReadHiddenData($self, $hdOff, $$hd{Size});
|
6013
|
+
if ($dataPt) {
|
6014
|
+
# preserve padding to avoid invalidating MPF pointers (yuk!)
|
6015
|
+
my $padLen = $hdOff - $endPos;
|
6016
|
+
unless ($padLen >= 0 and $raf->Seek($endPos,0) and $raf->Read($pad,$padLen)==$padLen) {
|
6017
|
+
$self->Error('Error reading HiddenData padding',1);
|
6018
|
+
$pad = '';
|
6019
|
+
}
|
6020
|
+
$endPos += length($pad) + length($$dataPt); # update end position
|
6021
|
+
} else {
|
6022
|
+
$$dataPt = $pad = '';
|
6023
|
+
}
|
6024
|
+
my $fixup = $$self{HiddenData}{Fixup};
|
6025
|
+
# set MakerNote pointer and size (subtract 10 for segment and EXIF headers)
|
6026
|
+
$fixup->SetMarkerPointers($outfile, 'HiddenData', length($$outfile) + length($pad) - 10);
|
6027
|
+
# clean up and write the buffered data
|
6028
|
+
$outfile = $oldOutfile;
|
6029
|
+
undef $oldOutfile;
|
6030
|
+
Write($outfile, $writeBuffer, $pad, $$dataPt) or $err = 1;
|
6031
|
+
undef $writeBuffer;
|
6032
|
+
}
|
5953
6033
|
# rewrite existing trailers
|
5954
6034
|
if ($trailInfo) {
|
5955
6035
|
my $tbuf = '';
|
@@ -6059,7 +6139,7 @@ sub WriteJPEG($$)
|
|
6059
6139
|
$delPreview = 1; # remove old preview
|
6060
6140
|
}
|
6061
6141
|
}
|
6062
|
-
# copy over preview image if necessary
|
6142
|
+
# copy over preview image (or other data) if necessary
|
6063
6143
|
unless ($delPreview) {
|
6064
6144
|
my $extra;
|
6065
6145
|
if ($trailInfo) {
|
@@ -6226,13 +6306,16 @@ sub WriteJPEG($$)
|
|
6226
6306
|
}
|
6227
6307
|
}
|
6228
6308
|
# switch to buffered output if required
|
6229
|
-
if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}
|
6309
|
+
if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer} or $$self{HiddenData}) and
|
6310
|
+
not $oldOutfile)
|
6311
|
+
{
|
6230
6312
|
$writeBuffer = '';
|
6231
6313
|
$oldOutfile = $outfile;
|
6232
6314
|
$outfile = \$writeBuffer;
|
6233
6315
|
# must account for segment, EXIF and TIFF headers
|
6234
6316
|
$$self{PREVIEW_INFO}{Fixup}{Start} += 18 if $$self{PREVIEW_INFO};
|
6235
6317
|
$$self{LeicaTrailer}{Fixup}{Start} += 18 if $$self{LeicaTrailer};
|
6318
|
+
$$self{HiddenData}{Fixup}{Start} += 18 if $$self{HiddenData};
|
6236
6319
|
}
|
6237
6320
|
# write as multi-segment
|
6238
6321
|
my $n = WriteMultiSegment($outfile, $marker, $exifAPP1hdr, $segDataPt, 'EXIF');
|
@@ -7067,7 +7150,7 @@ sub WriteBinaryData($$$)
|
|
7067
7150
|
$newVal = length($data) if defined $data;
|
7068
7151
|
my $format = $$tagInfo{Format} || $$tagTablePtr{FORMAT} || 'int32u';
|
7069
7152
|
if ($format =~ /^int16/ and $newVal > 0xffff) {
|
7070
|
-
$self->Error("$$tagInfo{DataTag} is too large (64
|
7153
|
+
$self->Error("$$tagInfo{DataTag} is too large (64 KiB max. for this file)");
|
7071
7154
|
}
|
7072
7155
|
}
|
7073
7156
|
my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $entry);
|
@@ -7097,14 +7180,24 @@ sub WriteBinaryData($$$)
|
|
7097
7180
|
# ignore if offset is zero (eg. Ricoh DNG uses this to indicate no preview)
|
7098
7181
|
next unless $offset;
|
7099
7182
|
$fixup->AddFixup($entry, $$tagInfo{DataTag}, $format);
|
7100
|
-
|
7101
|
-
next unless $$self{FILE_TYPE} eq 'JPEG' and $$tagInfo{DataTag} and
|
7102
|
-
$$tagInfo{DataTag} eq 'PreviewImage' and defined $$tagInfo{OffsetPair};
|
7183
|
+
next unless $$tagInfo{DataTag} and defined $$tagInfo{OffsetPair};
|
7103
7184
|
# NOTE: here we assume there are no var-sized tags between the
|
7104
7185
|
# OffsetPair tags. If this ever becomes possible we must recalculate
|
7105
7186
|
# $varSize for the OffsetPair tag here!
|
7106
7187
|
$entry = $$tagInfo{OffsetPair} * $increment + $varSize;
|
7107
7188
|
my $size = ReadValue($dataPt, $entry, $format, 1, $dirLen-$entry);
|
7189
|
+
next unless defined $size;
|
7190
|
+
if ($$tagInfo{DataTag} eq 'HiddenData') {
|
7191
|
+
$$self{HiddenData} = {
|
7192
|
+
Offset => $offset,
|
7193
|
+
Size => $size,
|
7194
|
+
Fixup => new Image::ExifTool::Fixup,
|
7195
|
+
Base => $$dirInfo{Base},
|
7196
|
+
};
|
7197
|
+
next;
|
7198
|
+
}
|
7199
|
+
# handle the preview image now if this is a JPEG file
|
7200
|
+
next unless $$tagInfo{DataTag} eq 'PreviewImage' and $$self{FILE_TYPE} eq 'JPEG';
|
7108
7201
|
my $previewInfo = $$self{PREVIEW_INFO};
|
7109
7202
|
$previewInfo or $previewInfo = $$self{PREVIEW_INFO} = {
|
7110
7203
|
Fixup => new Image::ExifTool::Fixup,
|
@@ -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.61';
|
54
54
|
@ISA = qw(Exporter);
|
55
55
|
@EXPORT_OK = qw(EscapeXML UnescapeXML);
|
56
56
|
|
@@ -201,6 +201,8 @@ my %xmpNS = (
|
|
201
201
|
nine => 'http://ns.nikon.com/nine/1.0/',
|
202
202
|
hdr_metadata => 'http://ns.adobe.com/hdr-metadata/1.0/',
|
203
203
|
hdrgm => 'http://ns.adobe.com/hdr-gain-map/1.0/',
|
204
|
+
# Note: Not included due to namespace prefix conflict with Device:Container
|
205
|
+
# Container => 'http://ns.google.com/photos/1.0/container/',
|
204
206
|
);
|
205
207
|
|
206
208
|
# build reverse namespace lookup
|
@@ -479,7 +481,7 @@ my %sCorrRangeMask = (
|
|
479
481
|
LuminanceDepthSampleInfo => { },
|
480
482
|
);
|
481
483
|
# new LR2 crs structures (PH)
|
482
|
-
my %sCorrectionMask;
|
484
|
+
my %sCorrectionMask; # (must define this before assigning because it is self-referential)
|
483
485
|
%sCorrectionMask = (
|
484
486
|
STRUCT_NAME => 'CorrectionMask',
|
485
487
|
NAMESPACE => 'crs',
|
@@ -919,6 +921,11 @@ my %sRangeMask = (
|
|
919
921
|
Name => 'hdrgm',
|
920
922
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::hdrgm' },
|
921
923
|
},
|
924
|
+
# Note: Note included due to namespace prefix conflict with Device:Container
|
925
|
+
# Container => {
|
926
|
+
# Name => 'Container',
|
927
|
+
# SubDirectory => { TagTable => 'Image::ExifTool::XMP::Container' },
|
928
|
+
# },
|
922
929
|
);
|
923
930
|
|
924
931
|
# hack to allow XML containing Dublin Core metadata to be handled like XMP (eg. EPUB - see ZIP.pm)
|
@@ -1699,6 +1706,8 @@ my %sPantryItem = (
|
|
1699
1706
|
ToneCurvePV2012Red => { List => 'Seq' },
|
1700
1707
|
ToneCurvePV2012Green => { List => 'Seq' },
|
1701
1708
|
ToneCurvePV2012Blue => { List => 'Seq' },
|
1709
|
+
Highlights2012 => { },
|
1710
|
+
Shadows2012 => { },
|
1702
1711
|
},
|
1703
1712
|
},
|
1704
1713
|
}
|
@@ -1760,6 +1769,62 @@ my %sPantryItem = (
|
|
1760
1769
|
SDRShadows => { Writable => 'real' },
|
1761
1770
|
SDRWhites => { Writable => 'real' },
|
1762
1771
|
SDRBlend => { Writable => 'real' },
|
1772
|
+
# new for ACR 16 (ref forum15305)
|
1773
|
+
LensBlur => {
|
1774
|
+
Struct => {
|
1775
|
+
STRUCT_NAME => 'LensBlur',
|
1776
|
+
NAMESPACE => 'crs',
|
1777
|
+
# (Note: all the following 'real' values could be limited to 'integer')
|
1778
|
+
Active => { Writable => 'boolean' },
|
1779
|
+
BlurAmount => { FlatName => 'Amount', Writable => 'real' },
|
1780
|
+
BokehAspect => { Writable => 'real' },
|
1781
|
+
BokehRotation => { Writable => 'real' },
|
1782
|
+
BokehShape => { Writable => 'real' },
|
1783
|
+
BokehShapeDetail => { Writable => 'real' },
|
1784
|
+
CatEyeAmount => { Writable => 'real' },
|
1785
|
+
CatEyeScale => { Writable => 'real' },
|
1786
|
+
FocalRange => { }, # (eg. "-48 32 64 144")
|
1787
|
+
FocalRangeSource => { Writable => 'real' },
|
1788
|
+
HighlightsBoost => { Writable => 'real' },
|
1789
|
+
HighlightsThreshold => { Writable => 'real' },
|
1790
|
+
SampledArea => { }, # (eg. "0.500000 0.500000 0.500000 0.500000")
|
1791
|
+
SampledRange => { }, # (eg. "0 0")
|
1792
|
+
SphericalAberration => { Writable => 'real' },
|
1793
|
+
SubjectRange => { }, # (eg. "0 57");
|
1794
|
+
Version => { },
|
1795
|
+
},
|
1796
|
+
},
|
1797
|
+
DepthMapInfo => {
|
1798
|
+
Struct => {
|
1799
|
+
STRUCT_NAME => 'DepthMapInfo',
|
1800
|
+
NAMESPACE => 'crs',
|
1801
|
+
BaseHighlightGuideInputDigest => { },
|
1802
|
+
BaseHighlightGuideTable => { },
|
1803
|
+
BaseHighlightGuideVersion => { },
|
1804
|
+
BaseLayeredDepthInputDigest => { },
|
1805
|
+
BaseLayeredDepthTable => { },
|
1806
|
+
BaseLayeredDepthVersion => { },
|
1807
|
+
BaseRawDepthInputDigest => { },
|
1808
|
+
BaseRawDepthTable => { },
|
1809
|
+
BaseRawDepthVersion => { },
|
1810
|
+
DepthSource => { },
|
1811
|
+
},
|
1812
|
+
},
|
1813
|
+
DepthBasedCorrections => {
|
1814
|
+
List => 'Seq',
|
1815
|
+
FlatName => 'DepthBasedCorr',
|
1816
|
+
Struct => {
|
1817
|
+
STRUCT_NAME => 'DepthBasedCorr',
|
1818
|
+
NAMESPACE => 'crs',
|
1819
|
+
CorrectionActive => { Writable => 'boolean' },
|
1820
|
+
CorrectionAmount => { Writable => 'real' },
|
1821
|
+
CorrectionMasks => { FlatName => 'Mask', List => 'Seq', Struct => \%sCorrectionMask },
|
1822
|
+
CorrectionSyncID => { },
|
1823
|
+
LocalCorrectedDepth => { Writable => 'real' },
|
1824
|
+
LocalCurveRefineSaturation => { Writable => 'real' },
|
1825
|
+
What => { },
|
1826
|
+
},
|
1827
|
+
},
|
1763
1828
|
);
|
1764
1829
|
|
1765
1830
|
# Tiff namespace properties (tiff)
|
@@ -1873,6 +1873,10 @@ my %sSubVersion = (
|
|
1873
1873
|
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
1874
1874
|
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
1875
1875
|
},
|
1876
|
+
HdrPlusMakernote => {
|
1877
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
1878
|
+
ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)',
|
1879
|
+
},
|
1876
1880
|
);
|
1877
1881
|
|
1878
1882
|
# Google creations namespace (ref PH)
|
@@ -2037,6 +2041,37 @@ my %sSubVersion = (
|
|
2037
2041
|
},
|
2038
2042
|
);
|
2039
2043
|
|
2044
|
+
# Google container tags (ref https://developer.android.com/guide/topics/media/platform/hdr-image-format)
|
2045
|
+
# NOTE: Not included because these namespace prefixes conflict with Google's depth-map Device tags!
|
2046
|
+
# (see ../pics/GooglePixel8Pro.jpg sample image)
|
2047
|
+
# %Image::ExifTool::XMP::Container = (
|
2048
|
+
# %xmpTableDefaults,
|
2049
|
+
# GROUPS => { 1 => 'XMP-Container', 2 => 'Image' },
|
2050
|
+
# NAMESPACE => 'Container',
|
2051
|
+
# NOTES => 'Google Container namespace.',
|
2052
|
+
# Directory => {
|
2053
|
+
# Name => 'ContainerDirectory',
|
2054
|
+
# FlatName => 'Directory',
|
2055
|
+
# List => 'Seq',
|
2056
|
+
# Struct => {
|
2057
|
+
# STRUCT_NAME => 'Directory',
|
2058
|
+
# Item => {
|
2059
|
+
# Namespace => 'Container',
|
2060
|
+
# Struct => {
|
2061
|
+
# STRUCT_NAME => 'Item',
|
2062
|
+
# NAMESPACE => { Item => 'http://ns.google.com/photos/1.0/container/item/'},
|
2063
|
+
# Mime => { },
|
2064
|
+
# Semantic => { },
|
2065
|
+
# Length => { Writable => 'integer' },
|
2066
|
+
# Label => { },
|
2067
|
+
# Padding => { Writable => 'integer' },
|
2068
|
+
# URI => { },
|
2069
|
+
# },
|
2070
|
+
# },
|
2071
|
+
# },
|
2072
|
+
# },
|
2073
|
+
# );
|
2074
|
+
|
2040
2075
|
# Getty Images namespace (ref PH)
|
2041
2076
|
%Image::ExifTool::XMP::GettyImages = (
|
2042
2077
|
%xmpTableDefaults,
|