exiftool_vendored 12.67.0 → 12.70.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 +79 -10
- data/bin/MANIFEST +5 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +7 -7
- data/bin/exiftool +32 -27
- data/bin/lib/Image/ExifTool/CBOR.pm +18 -2
- data/bin/lib/Image/ExifTool/Canon.pm +87 -16
- 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 +175 -14
- data/bin/lib/Image/ExifTool/FujiFilm.pm +158 -20
- data/bin/lib/Image/ExifTool/GIF.pm +5 -1
- data/bin/lib/Image/ExifTool/Geotag.pm +16 -11
- data/bin/lib/Image/ExifTool/ID3.pm +70 -7
- data/bin/lib/Image/ExifTool/InDesign.pm +1 -1
- data/bin/lib/Image/ExifTool/JPEG.pm +1 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +30 -15
- data/bin/lib/Image/ExifTool/MakerNotes.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +82 -22
- data/bin/lib/Image/ExifTool/Olympus.pm +7 -1
- data/bin/lib/Image/ExifTool/PNG.pm +3 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +22 -9
- data/bin/lib/Image/ExifTool/Pentax.pm +6 -1
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +2 -1
- data/bin/lib/Image/ExifTool/QuickTime.pm +92 -55
- data/bin/lib/Image/ExifTool/README +14 -5
- data/bin/lib/Image/ExifTool/RIFF.pm +60 -10
- data/bin/lib/Image/ExifTool/Sony.pm +152 -46
- data/bin/lib/Image/ExifTool/TagLookup.pm +6955 -6713
- data/bin/lib/Image/ExifTool/TagNames.pod +878 -334
- 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 +14 -4
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +3 -0
- data/bin/lib/Image/ExifTool/WriteRIFF.pl +31 -6
- data/bin/lib/Image/ExifTool/Writer.pl +40 -14
- data/bin/lib/Image/ExifTool/XISF.pm +185 -0
- data/bin/lib/Image/ExifTool/XMP.pm +67 -2
- data/bin/lib/Image/ExifTool/XMP2.pl +35 -0
- data/bin/lib/Image/ExifTool.pm +92 -45
- data/bin/lib/Image/ExifTool.pod +14 -8
- data/bin/perl-Image-ExifTool.spec +6 -6
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +4 -3
@@ -25,11 +25,10 @@ $VERSION = '1.04';
|
|
25
25
|
Although basic text files contain no metadata, the following tags are
|
26
26
|
determined from a simple analysis of the data in TXT and CSV files.
|
27
27
|
Statistics are generated only for 8-bit encodings, but the L<FastScan|../ExifTool.html#FastScan> (-fast)
|
28
|
-
option may be used to limit processing to the first 64
|
29
|
-
tags are not produced. To avoid long processing delays, ExifTool will
|
30
|
-
a minor warning and process only the first 64
|
31
|
-
|
32
|
-
option is used.
|
28
|
+
option may be used to limit processing to the first 64 KiB in which case
|
29
|
+
some tags are not produced. To avoid long processing delays, ExifTool will
|
30
|
+
issue a minor warning and process only the first 64 KiB of any file larger
|
31
|
+
than 20 MiB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m) option is used.
|
33
32
|
},
|
34
33
|
MIMEEncoding => { Groups => { 2 => 'Other' } },
|
35
34
|
Newlines => {
|
@@ -17,7 +17,7 @@ package Image::ExifTool::Validate;
|
|
17
17
|
use strict;
|
18
18
|
use vars qw($VERSION %exifSpec);
|
19
19
|
|
20
|
-
$VERSION = '1.
|
20
|
+
$VERSION = '1.23';
|
21
21
|
|
22
22
|
use Image::ExifTool qw(:Utils);
|
23
23
|
use Image::ExifTool::Exif;
|
@@ -86,7 +86,7 @@ my %verCheck = (
|
|
86
86
|
GPS => { GPSVersionID => \%gpsVer },
|
87
87
|
);
|
88
88
|
|
89
|
-
# tags standard in various RAW file formats
|
89
|
+
# tags standard in various RAW file formats or IFD's
|
90
90
|
my %otherSpec = (
|
91
91
|
CR2 => { 0xc5d8 => 1, 0xc5d9 => 1, 0xc5e0 => 1, 0xc640 => 1, 0xc6dc => 1, 0xc6dd => 1 },
|
92
92
|
NEF => { 0x9216 => 1, 0x9217 => 1 },
|
@@ -103,6 +103,7 @@ my %otherSpec = (
|
|
103
103
|
SRW => { 0xa010 => 1, 0xa011 => 1, 0xa101 => 1, 0xa102 => 1 },
|
104
104
|
NRW => { 0x9216 => 1, 0x9217 => 1 },
|
105
105
|
X3F => { 0xa500 => 1 },
|
106
|
+
CameraIFD => { All => 1 }, # (exists in JPG and DNG of Leica Q3 images)
|
106
107
|
);
|
107
108
|
|
108
109
|
# standard format for tags (not necessary for exifSpec or GPS tags where Writable is defined)
|
@@ -142,20 +143,22 @@ my %stdFormat = (
|
|
142
143
|
# GeoTiff tags:
|
143
144
|
0x830e => 'double', 0x8482 => 'double', 0x87af => 'int16u', 0x87b1 => 'string',
|
144
145
|
0x8480 => 'double', 0x85d8 => 'double', 0x87b0 => 'double',
|
145
|
-
# DNG tags:
|
146
|
-
0xc615 => '(string|int8u)',
|
147
|
-
0xc61a => '(int16u|int32u|rational64u)',
|
148
|
-
0xc61d => 'int(16|32)u',
|
149
|
-
0xc61f => '(int16u|int32u|rational64u)',
|
150
|
-
0xc620 => '(int16u|int32u|rational64u)',
|
151
|
-
0xc628 => '(int16u|rational64u)',
|
152
|
-
0xc634 => 'int8u',
|
153
|
-
0xc640 => '',
|
154
|
-
0xc660 => '',
|
155
|
-
0xc68b => '(string|int8u)',
|
156
|
-
0xc68d => 'int(16|32)u',
|
157
|
-
0xc68e => 'int(16|32)u',
|
158
|
-
0xc6d2 => '',
|
146
|
+
# DNG tags: (use '' for non-DNG tags in the range 0xc612-0xcd48)
|
147
|
+
0xc615 => '(string|int8u)', 0xc6f4 => '(string|int8u)',
|
148
|
+
0xc61a => '(int16u|int32u|rational64u)', 0xc6f6 => '(string|int8u)',
|
149
|
+
0xc61d => 'int(16|32)u', 0xc6f8 => '(string|int8u)',
|
150
|
+
0xc61f => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)',
|
151
|
+
0xc620 => '(int16u|int32u|rational64u)', 0xc716 => '(string|int8u)',
|
152
|
+
0xc628 => '(int16u|rational64u)', 0xc717 => '(string|int8u)',
|
153
|
+
0xc634 => 'int8u', 0xc718 => '(string|int8u)',
|
154
|
+
0xc640 => '', 0xc71e => 'int(16|32)u',
|
155
|
+
0xc660 => '', 0xc71f => 'int(16|32)u',
|
156
|
+
0xc68b => '(string|int8u)', 0xc791 => 'int(16|32)u',
|
157
|
+
0xc68d => 'int(16|32)u', 0xc792 => 'int(16|32)u',
|
158
|
+
0xc68e => 'int(16|32)u', 0xc793 => '(int16u|int32u|rational64u)',
|
159
|
+
0xc6d2 => '', 0xcd43 => 'int(16|32)u',
|
160
|
+
0xc6d3 => '', 0xcd48 => '(string|int8u)',
|
161
|
+
|
159
162
|
# Exif 3.0 spec
|
160
163
|
0x10e => 'string|utf8', 0xa430 => 'string|utf8', 0xa439 => 'string|utf8',
|
161
164
|
0x10f => 'string|utf8', 0xa433 => 'string|utf8', 0xa43a => 'string|utf8',
|
@@ -430,7 +433,7 @@ sub ValidateExif($$$$$$$$)
|
|
430
433
|
my $stdFmt = $stdFormat{$ifd} || $stdFormat{IFD};
|
431
434
|
if (defined $$stdFmt{All} or ($tagTablePtr eq \%Image::ExifTool::Exif::Main and
|
432
435
|
($exifSpec{$tag} or $$stdFmt{$tag} or
|
433
|
-
($tag >= 0xc612 and $tag <=
|
436
|
+
($tag >= 0xc612 and $tag <= 0xcd48 and not defined $$stdFmt{$tag}))) or # (DNG tags)
|
434
437
|
$$tagTablePtr{SHORT_NAME} eq 'GPS::Main')
|
435
438
|
{
|
436
439
|
my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP};
|
@@ -456,8 +459,8 @@ sub ValidateExif($$$$$$$$)
|
|
456
459
|
} elsif (not $otherSpec{$$et{FileType}} or
|
457
460
|
(not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
|
458
461
|
{
|
459
|
-
if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$
|
460
|
-
$et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1);
|
462
|
+
if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$ti{Unknown}) {
|
463
|
+
$et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1) unless $otherSpec{$ifd};
|
461
464
|
}
|
462
465
|
}
|
463
466
|
# change expected count from read Format to Writable size
|
@@ -478,7 +481,7 @@ sub ValidateExif($$$$$$$$)
|
|
478
481
|
} elsif (not $otherSpec{$$et{FileType}} or
|
479
482
|
(not $otherSpec{$$et{FileType}}{$tag} and not $otherSpec{$$et{FileType}}{All}))
|
480
483
|
{
|
481
|
-
$et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1);
|
484
|
+
$et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1) unless $otherSpec{$ifd};
|
482
485
|
}
|
483
486
|
}
|
484
487
|
|
@@ -142,7 +142,6 @@ sub SaveMakerNotes($)
|
|
142
142
|
}
|
143
143
|
# save position of maker notes for pointer fixups
|
144
144
|
$fixup->{Shift} += length($makerNotes);
|
145
|
-
$$et{MAKER_NOTE_FIXUP} = $fixup;
|
146
145
|
$$et{MAKER_NOTE_BYTE_ORDER} = GetByteOrder();
|
147
146
|
# add value data
|
148
147
|
$makerNotes .= $makerInfo->{ValBuff};
|
@@ -150,7 +149,8 @@ sub SaveMakerNotes($)
|
|
150
149
|
my $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::Exif::Main');
|
151
150
|
my $tagInfo = $et->GetTagInfo($tagTablePtr, 0x927c, \$makerNotes);
|
152
151
|
# save the MakerNotes
|
153
|
-
$et->FoundTag($tagInfo, $makerNotes);
|
152
|
+
my $key = $et->FoundTag($tagInfo, $makerNotes);
|
153
|
+
$$et{TAG_EXTRA}{$key}{Fixup} = $fixup;
|
154
154
|
# save the garbage collection some work later
|
155
155
|
delete $makerInfo->{Entries};
|
156
156
|
delete $makerInfo->{ValBuff};
|
@@ -930,8 +930,16 @@ Entry: for (;;) {
|
|
930
930
|
}
|
931
931
|
}
|
932
932
|
unless ($success) {
|
933
|
-
|
934
|
-
|
933
|
+
my $wrn = sprintf("Error reading value for $name entry $index, ID 0x%.4x", $oldID);
|
934
|
+
my $truncOK;
|
935
|
+
if ($oldInfo and not $$oldInfo{Unknown}) {
|
936
|
+
$wrn .= " $$oldInfo{Name}";
|
937
|
+
$truncOK = $$oldInfo{TruncateOK};
|
938
|
+
}
|
939
|
+
return undef if $et->Error($wrn, $inMakerNotes || $truncOK);
|
940
|
+
unless ($truncOK) {
|
941
|
+
++$index; $oldID = $newID; next; # drop this tag
|
942
|
+
}
|
935
943
|
}
|
936
944
|
} elsif (not $invalidPreview) {
|
937
945
|
return undef if $et->Error("Bad $name offset for $tagStr", $inMakerNotes);
|
@@ -1094,6 +1102,8 @@ Entry: for (;;) {
|
|
1094
1102
|
# add, edit or delete this tag
|
1095
1103
|
shift @newTags; # remove from list
|
1096
1104
|
my $curInfo = $set{$newID};
|
1105
|
+
# don't allow MakerNotes to be added to ExifIFD of CR3 file
|
1106
|
+
next if $newID == 0x927c and $isNew > 0 and $$et{FileType} eq 'CR3';
|
1097
1107
|
unless ($curInfo or $$addDirs{$newID}) {
|
1098
1108
|
# we can finally get the specific tagInfo reference for this tag
|
1099
1109
|
# (because we can now evaluate the Condition statement since all
|
@@ -1429,8 +1439,8 @@ NoOverwrite: next if $isNew > 0;
|
|
1429
1439
|
if ($$et{DEL_GROUP}{MakerNotes} and
|
1430
1440
|
($$et{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0))
|
1431
1441
|
{
|
1432
|
-
if ($et->IsRawType()) {
|
1433
|
-
$et->
|
1442
|
+
if ($et->IsRawType() and not ($et->IsRawType() == 2 and $dirName eq 'ExifIFD')) {
|
1443
|
+
$et->Warn("Can't delete MakerNotes from $$et{FileType}",1);
|
1434
1444
|
} else {
|
1435
1445
|
if ($isNew <= 0) {
|
1436
1446
|
++$$et{CHANGED};
|
@@ -96,6 +96,8 @@ my %ctboID = (
|
|
96
96
|
"\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac" => 1, # XMP
|
97
97
|
"\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16" => 2, # PreviewImage
|
98
98
|
# ID 3 is used for 'mdat' atom (not a uuid)
|
99
|
+
# (haven't seen ID 4 yet)
|
100
|
+
"\x57\x66\xb8\x29\xbb\x6a\x47\xc5\xbc\xfb\x8b\x9f\x22\x60\xd0\x6d" => 5, # something to do with burst-roll image
|
99
101
|
);
|
100
102
|
|
101
103
|
# mark UserData tags that don't have ItemList counterparts as Preferred
|
@@ -1054,6 +1056,7 @@ sub WriteQuickTime($$$)
|
|
1054
1056
|
Parent => $dirName,
|
1055
1057
|
DirName => $subName,
|
1056
1058
|
Name => $$tagInfo{Name},
|
1059
|
+
TagInfo => $tagInfo,
|
1057
1060
|
DirID => $tag,
|
1058
1061
|
DataPt => \$buff,
|
1059
1062
|
DataLen => $size,
|
@@ -19,6 +19,8 @@ my %webpMap = (
|
|
19
19
|
'XMP ' => 'RIFF', # (the RIFF chunk name is 'XMP ')
|
20
20
|
EXIF => 'RIFF',
|
21
21
|
ICCP => 'RIFF',
|
22
|
+
C2PA => 'RIFF',
|
23
|
+
JUMBF => 'C2PA',
|
22
24
|
XMP => 'XMP ',
|
23
25
|
IFD0 => 'EXIF',
|
24
26
|
IFD1 => 'IFD0',
|
@@ -66,6 +68,7 @@ sub WriteRIFF($$)
|
|
66
68
|
$et->InitWriteDirs(\%webpMap);
|
67
69
|
my $addDirs = $$et{ADD_DIRS};
|
68
70
|
my $editDirs = $$et{EDIT_DIRS};
|
71
|
+
$$addDirs{IFD0} = 'EXIF' if $$addDirs{EXIF}; # set flag to add IFD0 if adding EXIF (don't ask)
|
69
72
|
my ($createVP8X, $deleteVP8X);
|
70
73
|
|
71
74
|
# write header
|
@@ -142,6 +145,17 @@ sub WriteRIFF($$)
|
|
142
145
|
}
|
143
146
|
# RIFF chunks are padded to an even number of bytes
|
144
147
|
my $len2 = $len + ($len & 0x01);
|
148
|
+
# handle incorrect "XMP\0" chunk ID written by Google software
|
149
|
+
if ($tag eq "XMP\0") {
|
150
|
+
if ($$et{DEL_GROUP}{XMP}) {
|
151
|
+
# just ignore this chunk if deleting XMP
|
152
|
+
$raf->Seek($len2, 1) or $et->Error('Seek error'), last;
|
153
|
+
++$$et{CHANGED};
|
154
|
+
next;
|
155
|
+
} else {
|
156
|
+
$et->Warn('Incorrect XMP tag ID',1) if $pass;
|
157
|
+
}
|
158
|
+
}
|
145
159
|
# edit/add/delete necessary metadata chunks (EXIF must come before XMP)
|
146
160
|
if ($$editDirs{$tag} or $tag eq '' or ($tag eq 'XMP ' and $$addDirs{EXIF})) {
|
147
161
|
my $handledTag;
|
@@ -156,13 +170,12 @@ sub WriteRIFF($$)
|
|
156
170
|
#
|
157
171
|
# add/edit/delete EXIF/XMP/ICCP (note: EXIF must come before XMP, and ICCP is written elsewhere)
|
158
172
|
#
|
159
|
-
my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
|
160
|
-
my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile' );
|
173
|
+
my %dirName = ( EXIF => 'IFD0', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'JUMBF' );
|
174
|
+
my %tblName = ( EXIF => 'Exif', 'XMP ' => 'XMP', ICCP => 'ICC_Profile', C2PA => 'Jpeg2000' );
|
161
175
|
my $dir;
|
162
|
-
foreach $dir ('EXIF', 'XMP ', 'ICCP' ) {
|
176
|
+
foreach $dir ('EXIF', 'XMP ', 'ICCP', 'C2PA' ) {
|
163
177
|
next unless $tag eq $dir or ($$addDirs{$dir} and
|
164
178
|
($tag eq '' or ($tag eq 'XMP ' and $dir eq 'EXIF')));
|
165
|
-
delete $$addDirs{$dir}; # (don't try to add again)
|
166
179
|
my $start;
|
167
180
|
unless ($pass) {
|
168
181
|
# write the EXIF and save the result for the next pass
|
@@ -170,8 +183,15 @@ sub WriteRIFF($$)
|
|
170
183
|
if ($tag eq 'EXIF') {
|
171
184
|
# (only need to set directory $start for EXIF)
|
172
185
|
if ($buff =~ /^Exif\0\0/) {
|
173
|
-
|
174
|
-
|
186
|
+
if ($$et{DEL_GROUP}{EXIF}) {
|
187
|
+
# remove incorrect header if rewriting anyway
|
188
|
+
$buff = substr($buff, 6);
|
189
|
+
$len -= 6;
|
190
|
+
$len2 -= 6;
|
191
|
+
} else {
|
192
|
+
$et->Warn('Improper EXIF header',1) unless $pass;
|
193
|
+
$start = 6;
|
194
|
+
}
|
175
195
|
} else {
|
176
196
|
$start = 0;
|
177
197
|
}
|
@@ -189,11 +209,16 @@ sub WriteRIFF($$)
|
|
189
209
|
Parent => $dir,
|
190
210
|
DirName => $dirName{$dir},
|
191
211
|
);
|
212
|
+
# must pass the TagInfo to enable deletion of C2PA information
|
213
|
+
if (ref $Image::ExifTool::RIFF::Main{$dir} eq 'HASH') {
|
214
|
+
$dirInfo{TagInfo} = $Image::ExifTool::RIFF::Main{$dir};
|
215
|
+
}
|
192
216
|
my $tagTablePtr = GetTagTable("Image::ExifTool::$tblName{$dir}::Main");
|
193
217
|
# (override writeProc for EXIF because it has the TIFF header)
|
194
218
|
my $writeProc = $dir eq 'EXIF' ? \&Image::ExifTool::WriteTIFF : undef;
|
195
219
|
$dirDat{$dir} = $et->WriteDirectory(\%dirInfo, $tagTablePtr, $writeProc);
|
196
220
|
}
|
221
|
+
delete $$addDirs{$dir}; # (don't try to add again)
|
197
222
|
if (defined $dirDat{$dir}) {
|
198
223
|
if ($dir eq $tag) {
|
199
224
|
$handledTag = 1; # set flag indicating we edited this tag
|
@@ -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
|
@@ -1002,10 +1003,8 @@ TAG: foreach $tagInfo (@matchingTags) {
|
|
1002
1003
|
$$nvHash{NoReplace} = 1 if $$tagInfo{List} and not $options{Replace};
|
1003
1004
|
$$nvHash{WantGroup} = $wantGroup;
|
1004
1005
|
$$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
|
-
}
|
1006
|
+
# save maker note fixup information if writing maker notes
|
1007
|
+
$$nvHash{MAKER_NOTE_FIXUP} = $options{Fixup} if $$tagInfo{MakerNotes};
|
1009
1008
|
if ($createOnly) { # create only (never edit)
|
1010
1009
|
# empty item in DelValue list to never edit existing value
|
1011
1010
|
$$nvHash{DelValue} = [ '' ];
|
@@ -1272,6 +1271,7 @@ sub SetNewValuesFromFile($$;@)
|
|
1272
1271
|
# +------------------------------------------+
|
1273
1272
|
$srcExifTool->Options(
|
1274
1273
|
Binary => 1,
|
1274
|
+
ByteUnit => $$options{ByteUnit},
|
1275
1275
|
Charset => $$options{Charset},
|
1276
1276
|
CharsetEXIF => $$options{CharsetEXIF},
|
1277
1277
|
CharsetFileName => $$options{CharsetFileName},
|
@@ -1372,8 +1372,8 @@ sub SetNewValuesFromFile($$;@)
|
|
1372
1372
|
#
|
1373
1373
|
unless (@setTags) {
|
1374
1374
|
# transfer maker note information to this object
|
1375
|
-
$$self{MAKER_NOTE_FIXUP} = $$srcExifTool{MAKER_NOTE_FIXUP};
|
1376
1375
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
1376
|
+
my $tagExtra = $$srcExifTool{TAG_EXTRA};
|
1377
1377
|
foreach $tag (@tags) {
|
1378
1378
|
# don't try to set errors or warnings
|
1379
1379
|
next if $tag =~ /^(Error|Warning)\b/;
|
@@ -1381,10 +1381,13 @@ sub SetNewValuesFromFile($$;@)
|
|
1381
1381
|
if ($opts{SrcType} and $opts{SrcType} ne $srcType) {
|
1382
1382
|
$$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType});
|
1383
1383
|
}
|
1384
|
+
my $fixup = $$tagExtra{$tag}{Fixup};
|
1385
|
+
$opts{Fixup} = $fixup if $fixup;
|
1384
1386
|
# set value for this tag
|
1385
1387
|
my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts);
|
1386
1388
|
# delete this tag if we couldn't set it
|
1387
1389
|
$n or delete $$info{$tag};
|
1390
|
+
delete $opts{Fixup} if $fixup;
|
1388
1391
|
}
|
1389
1392
|
return $info;
|
1390
1393
|
}
|
@@ -1617,7 +1620,7 @@ SET: foreach $set (@setList) {
|
|
1617
1620
|
}
|
1618
1621
|
# transfer maker note information if setting this tag
|
1619
1622
|
if ($$srcExifTool{TAG_INFO}{$tag}{MakerNotes}) {
|
1620
|
-
$$
|
1623
|
+
$$opts{Fixup} = $$srcExifTool{TAG_EXTRA}{$tag}{Fixup};
|
1621
1624
|
$$self{MAKER_NOTE_BYTE_ORDER} = $$srcExifTool{MAKER_NOTE_BYTE_ORDER};
|
1622
1625
|
}
|
1623
1626
|
if ($dstTag eq '*') {
|
@@ -1649,6 +1652,7 @@ SET: foreach $set (@setList) {
|
|
1649
1652
|
$rtnInfo{NextFreeTagKey(\%rtnInfo, 'Warning')} = $wrn;
|
1650
1653
|
$noWarn = 1;
|
1651
1654
|
}
|
1655
|
+
delete $$opts{Fixup};
|
1652
1656
|
$rtnInfo{$tag} = $val if $rtn; # tag was set successfully
|
1653
1657
|
}
|
1654
1658
|
}
|
@@ -4176,6 +4180,7 @@ sub WriteDirectory($$$;$)
|
|
4176
4180
|
$out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose};
|
4177
4181
|
# set directory name from default group0 name if not done already
|
4178
4182
|
my $dirName = $$dirInfo{DirName};
|
4183
|
+
my $parent = $$dirInfo{Parent} || '';
|
4179
4184
|
my $dataPt = $$dirInfo{DataPt};
|
4180
4185
|
my $grp0 = $$tagTablePtr{GROUPS}{0};
|
4181
4186
|
$dirName or $dirName = $$dirInfo{DirName} = $grp0;
|
@@ -4183,14 +4188,19 @@ sub WriteDirectory($$$;$)
|
|
4183
4188
|
my $delGroup = $$self{DEL_GROUP};
|
4184
4189
|
# delete entire directory if specified
|
4185
4190
|
my $grp1 = $dirName;
|
4186
|
-
$delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1})
|
4191
|
+
$delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1});
|
4192
|
+
if ($permanentDir{$grp0} and not ($$dirInfo{TagInfo} and $$dirInfo{TagInfo}{Deletable})) {
|
4193
|
+
undef $delFlag;
|
4194
|
+
}
|
4187
4195
|
# (never delete an entire QuickTime group)
|
4188
4196
|
if ($delFlag) {
|
4189
4197
|
if (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and
|
4190
4198
|
$self->IsRawType() and
|
4191
4199
|
# allow non-permanent MakerNote directories to be deleted (ie. NikonCapture)
|
4192
4200
|
(not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or
|
4193
|
-
$$dirInfo{TagInfo}{Permanent})
|
4201
|
+
$$dirInfo{TagInfo}{Permanent}) and
|
4202
|
+
# allow MakerNotes to be deleted from ExifIFD of CR3 file
|
4203
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
4194
4204
|
{
|
4195
4205
|
$self->WarnOnce("Can't delete $1 from $$self{FileType}",1);
|
4196
4206
|
undef $grp1;
|
@@ -4226,7 +4236,6 @@ sub WriteDirectory($$$;$)
|
|
4226
4236
|
if ($delFlag == 2 and $right) {
|
4227
4237
|
# also check grandparent because some routines create 2 levels in 1
|
4228
4238
|
my $right2 = $$self{ADD_DIRS}{$right} || '';
|
4229
|
-
my $parent = $$dirInfo{Parent};
|
4230
4239
|
if (not $parent or $parent eq $right or $parent eq $right2) {
|
4231
4240
|
# prevent duplicate directories from being recreated at the same path
|
4232
4241
|
my $path = join '-', @{$$self{PATH}}, $dirName;
|
@@ -4284,10 +4293,27 @@ sub WriteDirectory($$$;$)
|
|
4284
4293
|
last unless $self->IsOverwriting($nvHash, $dataPt ? $$dataPt : '');
|
4285
4294
|
my $verb = 'Writing';
|
4286
4295
|
my $newVal = $self->GetNewValue($nvHash);
|
4287
|
-
|
4296
|
+
if (defined $newVal and length $newVal) {
|
4297
|
+
# hack to add back TIFF header when writing MakerNoteCanon to CMT3 in CR3 images
|
4298
|
+
if ($$tagInfo{Name} eq 'MakerNoteCanon') {
|
4299
|
+
require Image::ExifTool::Canon;
|
4300
|
+
if ($tagInfo eq $Image::ExifTool::Canon::uuid{CMT3}) {
|
4301
|
+
my $hdr;
|
4302
|
+
if (substr($newVal, 0, 1) eq "\0") {
|
4303
|
+
$hdr = "MM\0\x2a" . pack('N', 8);
|
4304
|
+
} else {
|
4305
|
+
$hdr = "II\x2a\0" . pack('V', 8);
|
4306
|
+
}
|
4307
|
+
$newVal = $hdr . $newVal;
|
4308
|
+
}
|
4309
|
+
}
|
4310
|
+
} else {
|
4288
4311
|
return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed
|
4289
4312
|
# don't allow MakerNotes to be removed from RAW files
|
4290
|
-
if ($blockName eq 'MakerNotes' and $
|
4313
|
+
if ($blockName eq 'MakerNotes' and $self->IsRawType() and
|
4314
|
+
# but allow MakerNotes to be deleted from ExifIFD of CR3 image (shouldn't be there)
|
4315
|
+
not ($self->IsRawType() == 2 and $parent eq 'ExifIFD'))
|
4316
|
+
{
|
4291
4317
|
$self->Warn("Can't delete MakerNotes from $$self{FileType}",1);
|
4292
4318
|
return undef;
|
4293
4319
|
}
|
@@ -7067,7 +7093,7 @@ sub WriteBinaryData($$$)
|
|
7067
7093
|
$newVal = length($data) if defined $data;
|
7068
7094
|
my $format = $$tagInfo{Format} || $$tagTablePtr{FORMAT} || 'int32u';
|
7069
7095
|
if ($format =~ /^int16/ and $newVal > 0xffff) {
|
7070
|
-
$self->Error("$$tagInfo{DataTag} is too large (64
|
7096
|
+
$self->Error("$$tagInfo{DataTag} is too large (64 KiB max. for this file)");
|
7071
7097
|
}
|
7072
7098
|
}
|
7073
7099
|
my $rtnVal = WriteValue($newVal, $format, $count, $dataPt, $entry);
|
@@ -0,0 +1,185 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: XISF.pm
|
3
|
+
#
|
4
|
+
# Description: Read Extensible Image Serialization Format metadata
|
5
|
+
#
|
6
|
+
# Revisions: 2023-10-10 - P. Harvey Created
|
7
|
+
#
|
8
|
+
# References: 1) https://pixinsight.com/doc/docs/XISF-1.0-spec/XISF-1.0-spec.html
|
9
|
+
#------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
package Image::ExifTool::XISF;
|
12
|
+
|
13
|
+
use strict;
|
14
|
+
use vars qw($VERSION);
|
15
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
16
|
+
use Image::ExifTool::XMP;
|
17
|
+
|
18
|
+
$VERSION = '1.00';
|
19
|
+
|
20
|
+
# XISF tags (ref 1)
|
21
|
+
%Image::ExifTool::XISF::Main = (
|
22
|
+
GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
|
23
|
+
VARS => { LONG_TAGS => 1 },
|
24
|
+
NOTES => q{
|
25
|
+
This table lists some standard Extensible Image Serialization Format (XISF)
|
26
|
+
tags, but ExifTool will extract any other tags found. See
|
27
|
+
L<https://pixinsight.com/xisf/> for the specification.
|
28
|
+
},
|
29
|
+
ImageGeometry => { },
|
30
|
+
ImageSampleFormat => { },
|
31
|
+
ImageBounds => { },
|
32
|
+
ImageImageType => { Name => 'ImageType' },
|
33
|
+
ImageColorSpace => { Name => 'ColorSpace' },
|
34
|
+
ImageLocation => { },
|
35
|
+
ImageResolutionHorizontal => 'XResolution',
|
36
|
+
ImageResolutionVertical => 'YResolution',
|
37
|
+
ImageResolutionUnit => 'ResolutionUnit',
|
38
|
+
ImageICCProfile => {
|
39
|
+
Name => 'ICC_Profile',
|
40
|
+
ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
41
|
+
Binary => 1,
|
42
|
+
},
|
43
|
+
ImageICCProfileLocation => { Name => 'ICCProfileLocation' },
|
44
|
+
ImagePixelStorage => { },
|
45
|
+
ImageOffset => { Name => 'ImagePixelOffset' },
|
46
|
+
ImageOrientation => { Name => 'Orientation' },
|
47
|
+
ImageId => { Name => 'ImageID' },
|
48
|
+
ImageUuid => { Name => 'UUID' },
|
49
|
+
ImageData => { Binary => 1 },
|
50
|
+
'CreationTime' => {
|
51
|
+
Name => 'CreateDate',
|
52
|
+
Shift => 'Time',
|
53
|
+
Groups => { 2 => 'Time' },
|
54
|
+
ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
|
55
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
56
|
+
},
|
57
|
+
CreatorApplication => { },
|
58
|
+
Abstract => { },
|
59
|
+
AccessRights => { },
|
60
|
+
Authors => { Groups => { 2 => 'Author' } },
|
61
|
+
BibliographicReferences => { },
|
62
|
+
BriefDescription => { },
|
63
|
+
CompressionLevel => { },
|
64
|
+
CompressionCodecs => { },
|
65
|
+
Contributors => { Groups => { 2 => 'Author' } },
|
66
|
+
Copyright => { Groups => { 2 => 'Author' } },
|
67
|
+
CreatorModule => { },
|
68
|
+
CreatorOS => { },
|
69
|
+
Description => { },
|
70
|
+
Keywords => { },
|
71
|
+
Languages => { },
|
72
|
+
License => { },
|
73
|
+
OriginalCreationTime => {
|
74
|
+
Name => 'DateTimeOriginal',
|
75
|
+
Description => 'Date/Time Original',
|
76
|
+
Shift => 'Time',
|
77
|
+
Groups => { 2 => 'Time' },
|
78
|
+
ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)',
|
79
|
+
PrintConv => '$self->ConvertDateTime($val)',
|
80
|
+
},
|
81
|
+
RelatedResources => { },
|
82
|
+
Title => { },
|
83
|
+
);
|
84
|
+
|
85
|
+
#------------------------------------------------------------------------------
|
86
|
+
# Handle properties in XISF metadata structures
|
87
|
+
# Inputs: 0) attribute list ref, 1) attr hash ref,
|
88
|
+
# 2) property name ref, 3) property value ref
|
89
|
+
# Returns: true if value was changed
|
90
|
+
sub HandleXISFAttrs($$$$)
|
91
|
+
{
|
92
|
+
my ($attrList, $attrs, $prop, $valPt) = @_;
|
93
|
+
return 0 unless defined $$attrs{id};
|
94
|
+
my ($changed, $a);
|
95
|
+
# use "id" as the tag name, "value" as the value, and ignore "type"
|
96
|
+
$$prop = $$attrs{id};
|
97
|
+
$$prop =~ s/^XISF://; # remove XISF namespace
|
98
|
+
if (defined $$attrs{value}) {
|
99
|
+
$$valPt = $$attrs{value};
|
100
|
+
$changed = 1;
|
101
|
+
}
|
102
|
+
my @attrs = @$attrList;
|
103
|
+
@$attrList = ( );
|
104
|
+
foreach $a (@attrs) {
|
105
|
+
if ($a eq 'id' or $a eq 'value' or $a eq 'type') {
|
106
|
+
delete $$attrs{$a};
|
107
|
+
} else {
|
108
|
+
push @$attrList, $a;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
return $changed;
|
112
|
+
}
|
113
|
+
|
114
|
+
#------------------------------------------------------------------------------
|
115
|
+
# Read information in a XISF document
|
116
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref
|
117
|
+
# Returns: 1 on success, 0 if this wasn't a valid XISF file
|
118
|
+
sub ProcessXISF($$)
|
119
|
+
{
|
120
|
+
my ($et, $dirInfo) = @_;
|
121
|
+
my $raf = $$dirInfo{RAF};
|
122
|
+
my $buff;
|
123
|
+
|
124
|
+
return 0 unless $raf->Read($buff, 16) == 16 and $buff =~ /^XISF0100/;
|
125
|
+
$et->SetFileType();
|
126
|
+
SetByteOrder('II');
|
127
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::XISF::Main');
|
128
|
+
my $hdrLen = Get32u(\$buff, 8);
|
129
|
+
$raf->Read($buff, $hdrLen) == $hdrLen or $et->Warn('Error reading XISF header'), return 1;
|
130
|
+
$et->FoundTag(XML => $buff);
|
131
|
+
my %dirInfo = (
|
132
|
+
DataPt => \$buff,
|
133
|
+
IgnoreProp => { xisf => 1, Metadata => 1, Property => 1 },
|
134
|
+
XMPParseOpts => { AttrProc => \&HandleXISFAttrs },
|
135
|
+
);
|
136
|
+
Image::ExifTool::XMP::ProcessXMP($et, \%dirInfo, $tagTablePtr);
|
137
|
+
my $geo = $$et{VALUE}{ImageGeometry};
|
138
|
+
if ($geo) {
|
139
|
+
my ($w, $h, $n) = split /:/, $geo;
|
140
|
+
$et->FoundTag(ImageWidth => $w);
|
141
|
+
$et->FoundTag(ImageHeight => $h);
|
142
|
+
$et->FoundTag(NumPlanes => $n);
|
143
|
+
}
|
144
|
+
return 1;
|
145
|
+
}
|
146
|
+
|
147
|
+
1; # end
|
148
|
+
|
149
|
+
__END__
|
150
|
+
|
151
|
+
=head1 NAME
|
152
|
+
|
153
|
+
Image::ExifTool::XISF - Read Extensible Image Serialization Format metadata
|
154
|
+
|
155
|
+
=head1 SYNOPSIS
|
156
|
+
|
157
|
+
This module is used by Image::ExifTool
|
158
|
+
|
159
|
+
=head1 DESCRIPTION
|
160
|
+
|
161
|
+
This module contains definitions required by Image::ExifTool to read meta
|
162
|
+
information from XISF (Extensible Image Serialization Format) images.
|
163
|
+
|
164
|
+
=head1 AUTHOR
|
165
|
+
|
166
|
+
Copyright 2003-2023, Phil Harvey (philharvey66 at gmail.com)
|
167
|
+
|
168
|
+
This library is free software; you can redistribute it and/or modify it
|
169
|
+
under the same terms as Perl itself.
|
170
|
+
|
171
|
+
=head1 REFERENCES
|
172
|
+
|
173
|
+
=over 4
|
174
|
+
|
175
|
+
=item L<https://pixinsight.com/doc/docs/XISF-1.0-spec/XISF-1.0-spec.html>
|
176
|
+
|
177
|
+
=back
|
178
|
+
|
179
|
+
=head1 SEE ALSO
|
180
|
+
|
181
|
+
L<Image::ExifTool::TagNames/XISF Tags>,
|
182
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
183
|
+
|
184
|
+
=cut
|
185
|
+
|