exiftool_vendored 12.22.0 → 12.25.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 +50 -0
- data/bin/MANIFEST +11 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +44 -43
- data/bin/config_files/acdsee.config +193 -6
- data/bin/config_files/cuepointlist.config +70 -0
- data/bin/exiftool +45 -44
- data/bin/lib/Image/ExifTool.pm +85 -26
- data/bin/lib/Image/ExifTool.pod +61 -50
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +1 -1
- data/bin/lib/Image/ExifTool/Canon.pm +3 -2
- data/bin/lib/Image/ExifTool/DjVu.pm +6 -5
- data/bin/lib/Image/ExifTool/Exif.pm +16 -7
- data/bin/lib/Image/ExifTool/FujiFilm.pm +18 -8
- data/bin/lib/Image/ExifTool/JPEG.pm +6 -2
- data/bin/lib/Image/ExifTool/JSON.pm +24 -3
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +361 -16
- data/bin/lib/Image/ExifTool/MRC.pm +341 -0
- data/bin/lib/Image/ExifTool/MWG.pm +3 -3
- data/bin/lib/Image/ExifTool/MXF.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +1 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +5 -3
- data/bin/lib/Image/ExifTool/Nikon.pm +3 -2
- data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -1
- data/bin/lib/Image/ExifTool/PNG.pm +2 -2
- data/bin/lib/Image/ExifTool/Panasonic.pm +14 -1
- data/bin/lib/Image/ExifTool/PhaseOne.pm +4 -3
- data/bin/lib/Image/ExifTool/QuickTime.pm +102 -44
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +88 -29
- data/bin/lib/Image/ExifTool/RIFF.pm +83 -11
- data/bin/lib/Image/ExifTool/Samsung.pm +2 -1
- data/bin/lib/Image/ExifTool/Sony.pm +98 -24
- data/bin/lib/Image/ExifTool/TagLookup.pm +56 -15
- data/bin/lib/Image/ExifTool/TagNames.pod +388 -173
- data/bin/lib/Image/ExifTool/WritePostScript.pl +1 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +37 -12
- data/bin/lib/Image/ExifTool/WriteXMP.pl +6 -2
- data/bin/lib/Image/ExifTool/Writer.pl +1 -0
- data/bin/lib/Image/ExifTool/XMP.pm +20 -7
- data/bin/perl-Image-ExifTool.spec +42 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +6 -8
data/bin/lib/Image/ExifTool.pod
CHANGED
@@ -65,47 +65,47 @@ supported by ExifTool (r = read, w = write, c = create):
|
|
65
65
|
|
66
66
|
File Types
|
67
67
|
------------+-------------+-------------+-------------+------------
|
68
|
-
360 r/w | DPX r | ITC r |
|
69
|
-
3FR r | DR4 r/w/c | J2C r |
|
70
|
-
3G2 r/w | DSS r | JNG r/w |
|
71
|
-
3GP r/w | DV r | JP2 r/w |
|
72
|
-
A r | DVB r/w | JPEG r/w |
|
73
|
-
AA r | DVR-MS r | JSON r |
|
74
|
-
AAE r | DYLIB r |
|
75
|
-
AAX r/w | EIP r |
|
76
|
-
ACR r | EPS r/w |
|
77
|
-
AFM r | EPUB r |
|
78
|
-
AI r/w | ERF r/w |
|
79
|
-
AIFF r | EXE r |
|
80
|
-
APE r | EXIF r/w/c |
|
81
|
-
ARQ r/w | EXR r |
|
82
|
-
ARW r/w | EXV r/w/c |
|
83
|
-
ASF r | F4A/V r/w |
|
84
|
-
AVI r | FFF r/w |
|
85
|
-
AVIF r/w | FITS r |
|
86
|
-
AZW r | FLA r |
|
87
|
-
BMP r | FLAC r |
|
88
|
-
BPG r | FLIF r/w |
|
89
|
-
BTF r | FLV r |
|
90
|
-
CHM r | FPF r |
|
91
|
-
COS r | FPX r |
|
92
|
-
CR2 r/w | GIF r/w |
|
93
|
-
CR3 r/w | GPR r/w |
|
94
|
-
CRM r/w | GZ r |
|
95
|
-
CRW r/w | HDP r/w |
|
96
|
-
CS1 r/w | HDR r |
|
97
|
-
CSV r | HEIC r/w |
|
98
|
-
CZI r | HEIF r/w |
|
99
|
-
DCM r | HTML r |
|
100
|
-
DCP r/w | ICC r/w/c |
|
101
|
-
DCR r | ICS r |
|
102
|
-
DFONT r | IDML r |
|
103
|
-
DIVX r | IIQ r/w |
|
104
|
-
DJVU r | IND r/w |
|
105
|
-
DLL r | INSP r/w |
|
106
|
-
DNG r/w | INSV r |
|
107
|
-
DOC r | INX r |
|
108
|
-
DOCX r | ISO r |
|
68
|
+
360 r/w | DPX r | ITC r | NUMBERS r | RAM r
|
69
|
+
3FR r | DR4 r/w/c | J2C r | O r | RAR r
|
70
|
+
3G2 r/w | DSS r | JNG r/w | ODP r | RAW r/w
|
71
|
+
3GP r/w | DV r | JP2 r/w | ODS r | RIFF r
|
72
|
+
A r | DVB r/w | JPEG r/w | ODT r | RSRC r
|
73
|
+
AA r | DVR-MS r | JSON r | OFR r | RTF r
|
74
|
+
AAE r | DYLIB r | JXL r | OGG r | RW2 r/w
|
75
|
+
AAX r/w | EIP r | K25 r | OGV r | RWL r/w
|
76
|
+
ACR r | EPS r/w | KDC r | ONP r | RWZ r
|
77
|
+
AFM r | EPUB r | KEY r | OPUS r | RM r
|
78
|
+
AI r/w | ERF r/w | LA r | ORF r/w | SEQ r
|
79
|
+
AIFF r | EXE r | LFP r | ORI r/w | SKETCH r
|
80
|
+
APE r | EXIF r/w/c | LNK r | OTF r | SO r
|
81
|
+
ARQ r/w | EXR r | LRV r/w | PAC r | SR2 r/w
|
82
|
+
ARW r/w | EXV r/w/c | M2TS r | PAGES r | SRF r
|
83
|
+
ASF r | F4A/V r/w | M4A/V r/w | PBM r/w | SRW r/w
|
84
|
+
AVI r | FFF r/w | MACOS r | PCD r | SVG r
|
85
|
+
AVIF r/w | FITS r | MAX r | PCX r | SWF r
|
86
|
+
AZW r | FLA r | MEF r/w | PDB r | THM r/w
|
87
|
+
BMP r | FLAC r | MIE r/w/c | PDF r/w | TIFF r/w
|
88
|
+
BPG r | FLIF r/w | MIFF r | PEF r/w | TORRENT r
|
89
|
+
BTF r | FLV r | MKA r | PFA r | TTC r
|
90
|
+
CHM r | FPF r | MKS r | PFB r | TTF r
|
91
|
+
COS r | FPX r | MKV r | PFM r | TXT r
|
92
|
+
CR2 r/w | GIF r/w | MNG r/w | PGF r | VCF r
|
93
|
+
CR3 r/w | GPR r/w | MOBI r | PGM r/w | VRD r/w/c
|
94
|
+
CRM r/w | GZ r | MODD r | PLIST r | VSD r
|
95
|
+
CRW r/w | HDP r/w | MOI r | PICT r | WAV r
|
96
|
+
CS1 r/w | HDR r | MOS r/w | PMP r | WDP r/w
|
97
|
+
CSV r | HEIC r/w | MOV r/w | PNG r/w | WEBP r
|
98
|
+
CZI r | HEIF r/w | MP3 r | PPM r/w | WEBM r
|
99
|
+
DCM r | HTML r | MP4 r/w | PPT r | WMA r
|
100
|
+
DCP r/w | ICC r/w/c | MPC r | PPTX r | WMV r
|
101
|
+
DCR r | ICS r | MPG r | PS r/w | WTV r
|
102
|
+
DFONT r | IDML r | MPO r/w | PSB r/w | WV r
|
103
|
+
DIVX r | IIQ r/w | MQV r/w | PSD r/w | X3F r/w
|
104
|
+
DJVU r | IND r/w | MRC r | PSP r | XCF r
|
105
|
+
DLL r | INSP r/w | MRW r/w | QTIF r/w | XLS r
|
106
|
+
DNG r/w | INSV r | MXF r | R3D r | XLSX r
|
107
|
+
DOC r | INX r | NEF r/w | RA r | XMP r/w/c
|
108
|
+
DOCX r | ISO r | NRW r/w | RAF r/w | ZIP r
|
109
109
|
|
110
110
|
Meta Information
|
111
111
|
----------------------+----------------------+---------------------
|
@@ -176,6 +176,9 @@ Creates a new ExifTool object.
|
|
176
176
|
|
177
177
|
$exifTool = new Image::ExifTool;
|
178
178
|
|
179
|
+
One ExifTool object may be used to process many files, so creating multiple
|
180
|
+
ExifTool objects usually is not necessary.
|
181
|
+
|
179
182
|
Note that ExifTool uses AUTOLOAD to load non-member methods, so any class
|
180
183
|
using Image::ExifTool as a base class must define an AUTOLOAD which calls
|
181
184
|
Image::ExifTool::DoAutoLoad(). eg)
|
@@ -386,7 +389,8 @@ to some functions. Option names are not case sensitive.
|
|
386
389
|
|
387
390
|
The default option values may be changed by defining a
|
388
391
|
%Image::ExifTool::UserDefined::Options hash. See the ExifTool_config file
|
389
|
-
in the full ExifTool distribution for examples.
|
392
|
+
in the full ExifTool distribution for examples. A default of undef has the
|
393
|
+
same behaviour as a value of 0 for numerical options.
|
390
394
|
|
391
395
|
# exclude the 'OwnerName' tag from returned information
|
392
396
|
$exifTool->Options(Exclude => 'OwnerName');
|
@@ -438,6 +442,13 @@ large binary data blocks (eg. ThumbnailImage) are not necessarily extracted
|
|
438
442
|
unless this option is set or the tag is specifically requested by name.
|
439
443
|
Default is undef.
|
440
444
|
|
445
|
+
=item BlockExtract
|
446
|
+
|
447
|
+
Flag to extract some directories (mentioned in the
|
448
|
+
L<ExifTool tag name documentation|Image::ExifTool::TagNames>) as a block.
|
449
|
+
Setting this to a value of 2 also prevents parsing the block to extract tags
|
450
|
+
contained within.
|
451
|
+
|
441
452
|
=item ByteOrder
|
442
453
|
|
443
454
|
The byte order for newly created EXIF segments when writing. Note that if
|
@@ -2277,12 +2288,12 @@ AFCP, AIFF, APE, APP0, APP1, APP11, APP12, APP13, APP14, APP15, APP4, APP5,
|
|
2277
2288
|
APP6, APP8, ASF, Audible, CanonVRD, Composite, DICOM, DNG, DV, DjVu, Ducky,
|
2278
2289
|
EXE, EXIF, ExifTool, FITS, FLAC, FLIR, File, Flash, FlashPix, Font,
|
2279
2290
|
FotoStation, GIF, GIMP, GeoTiff, GoPro, H264, HTML, ICC_Profile, ID3, IPTC,
|
2280
|
-
ISO, ITC, JFIF, JPEG, JSON, Jpeg2000, LNK, Leaf, Lytro, M2TS, MIE,
|
2281
|
-
MNG, MOI, MPC, MPEG, MPF, MXF, MakerNotes, Matroska, Meta, Ogg,
|
2282
|
-
Opus, PDF, PICT, PLIST, PNG, PSP, Palm, Parrot, PanasonicRaw,
|
2283
|
-
PhotoMechanic, Photoshop, PostScript, PrintIM, QuickTime, RAF,
|
2284
|
-
RTF, Radiance, Rawzor, Real, Red, SVG, SigmaRaw, Stim, Theora,
|
2285
|
-
Trailer, UserParam, VCard, Vorbis, WTV, XML, XMP, ZIP
|
2291
|
+
ISO, ITC, JFIF, JPEG, JSON, JUMBF, Jpeg2000, LNK, Leaf, Lytro, M2TS, MIE,
|
2292
|
+
MIFF, MNG, MOI, MPC, MPEG, MPF, MXF, MakerNotes, Matroska, Meta, Ogg,
|
2293
|
+
OpenEXR, Opus, PDF, PICT, PLIST, PNG, PSP, Palm, Parrot, PanasonicRaw,
|
2294
|
+
PhotoCD, PhotoMechanic, Photoshop, PostScript, PrintIM, QuickTime, RAF,
|
2295
|
+
RIFF, RSRC, RTF, Radiance, Rawzor, Real, Red, SVG, SigmaRaw, Stim, Theora,
|
2296
|
+
Torrent, Trailer, UserParam, VCard, Vorbis, WTV, XML, XMP, ZIP
|
2286
2297
|
|
2287
2298
|
=item Family 1 (Specific Location):
|
2288
2299
|
|
@@ -2295,8 +2306,8 @@ GoPro, GraphConv, H264, HP, HTC, HTML, HTML-dc, HTML-ncc, HTML-office,
|
|
2295
2306
|
HTML-prod, HTML-vw96, HTTP-equiv, ICC-chrm, ICC-clrt, ICC-header, ICC-meas,
|
2296
2307
|
ICC-meta, ICC-view, ICC_Profile, ICC_Profile#, ID3, ID3v1, ID3v1_Enh,
|
2297
2308
|
ID3v2_2, ID3v2_3, ID3v2_4, IFD0, IFD1, IPTC, IPTC#, ISO, ITC, Insta360,
|
2298
|
-
InteropIFD, ItemList, JFIF, JFXX, JPEG, JPEG-HDR, JSON,
|
2299
|
-
KDC_IFD, Keys, Kodak, KodakBordersIFD, KodakEffectsIFD, KodakIFD,
|
2309
|
+
InteropIFD, ItemList, JFIF, JFXX, JPEG, JPEG-HDR, JSON, JUMBF, JVC,
|
2310
|
+
Jpeg2000, KDC_IFD, Keys, Kodak, KodakBordersIFD, KodakEffectsIFD, KodakIFD,
|
2300
2311
|
KyoceraRaw, LNK, Leaf, LeafSubIFD, Leica, Lyrics3, Lytro, M2TS, MAC,
|
2301
2312
|
MIE-Audio, MIE-Camera, MIE-Canon, MIE-Doc, MIE-Extender, MIE-Flash, MIE-GPS,
|
2302
2313
|
MIE-Geo, MIE-Image, MIE-Lens, MIE-Main, MIE-MakerNotes, MIE-Meta,
|
@@ -639,7 +639,7 @@ overlapping EXIF, IPTC and XMP tags to be reconciled when reading, and
|
|
639
639
|
synchronized when writing. The MWG Composite tags below are designed to aid
|
640
640
|
in the implementation of these recommendations. As well, the MWG defines
|
641
641
|
new XMP tags which are listed in the subsequent tables below. See
|
642
|
-
L<https://web.archive.org/web/
|
642
|
+
L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf>
|
643
643
|
for the official MWG specification.
|
644
644
|
},
|
645
645
|
MacOS => q{
|
@@ -88,7 +88,7 @@ sub ProcessCTMD($$$);
|
|
88
88
|
sub ProcessExifInfo($$$);
|
89
89
|
sub SwapWords($);
|
90
90
|
|
91
|
-
$VERSION = '4.
|
91
|
+
$VERSION = '4.47';
|
92
92
|
|
93
93
|
# Note: Removed 'USM' from 'L' lenses since it is redundant - PH
|
94
94
|
# (or is it? Ref 32 shows 5 non-USM L-type lenses)
|
@@ -473,7 +473,8 @@ $VERSION = '4.46';
|
|
473
473
|
253 => 'Canon EF 70-200mm f/2.8L IS II USM + 2x', #PH (NC)
|
474
474
|
253.1 => 'Canon EF 70-200mm f/2.8L IS III USM + 2x', #PH (NC)
|
475
475
|
# 253.2 => 'Tamron SP 70-200mm f/2.8 Di VC USD G2 (A025) + 2x', #forum9367
|
476
|
-
254 => 'Canon EF 100mm f/2.8L Macro IS USM', #42
|
476
|
+
254 => 'Canon EF 100mm f/2.8L Macro IS USM or Tamron Lens', #42
|
477
|
+
254.1 => 'Tamron SP 90mm f/2.8 Di VC USD 1:1 Macro (F017)', #PH
|
477
478
|
255 => 'Sigma 24-105mm f/4 DG OS HSM | A or Other Lens', #50
|
478
479
|
255.1 => 'Sigma 180mm f/2.8 EX DG OS HSM APO Macro', #50
|
479
480
|
255.2 => 'Tamron SP 70-200mm f/2.8 Di VC USD', #exiv issue 1202 (A009)
|
@@ -18,7 +18,7 @@ use strict;
|
|
18
18
|
use vars qw($VERSION);
|
19
19
|
use Image::ExifTool qw(:DataAccess :Utils);
|
20
20
|
|
21
|
-
$VERSION = '1.
|
21
|
+
$VERSION = '1.07';
|
22
22
|
|
23
23
|
sub ParseAnt($);
|
24
24
|
sub ProcessAnt($$$);
|
@@ -227,10 +227,11 @@ Tok: for (;;) {
|
|
227
227
|
last unless $tok =~ /(\\+)$/ and length($1) & 0x01;
|
228
228
|
$tok .= '"'; # quote is part of the string
|
229
229
|
}
|
230
|
-
#
|
231
|
-
|
232
|
-
|
233
|
-
|
230
|
+
# convert C escape sequences, allowed in quoted text
|
231
|
+
# (note: this only converts a few of them!)
|
232
|
+
my %esc = ( a => "\a", b => "\b", f => "\f", n => "\n",
|
233
|
+
r => "\r", t => "\t", '"' => '"', '\\' => '\\' );
|
234
|
+
$tok =~ s/\\(.)/$esc{$1}||'\\'.$1/egs;
|
234
235
|
} else { # key name
|
235
236
|
pos($$dataPt) = pos($$dataPt) - 1;
|
236
237
|
# allow anything in key but whitespace, braces and double quotes
|
@@ -56,7 +56,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
|
|
56
56
|
use Image::ExifTool qw(:DataAccess :Utils);
|
57
57
|
use Image::ExifTool::MakerNotes;
|
58
58
|
|
59
|
-
$VERSION = '4.
|
59
|
+
$VERSION = '4.34';
|
60
60
|
|
61
61
|
sub ProcessExif($$$);
|
62
62
|
sub WriteExif($$$);
|
@@ -321,6 +321,7 @@ my %utf8StringConv = (
|
|
321
321
|
my %longBin = (
|
322
322
|
ValueConv => 'length($val) > 64 ? \$val : $val',
|
323
323
|
ValueConvInv => '$val',
|
324
|
+
LongBinary => 1, # flag to avoid decoding values of a large array
|
324
325
|
);
|
325
326
|
|
326
327
|
# PrintConv for SampleFormat (0x153)
|
@@ -3618,11 +3619,11 @@ my %opcodeInfo = (
|
|
3618
3619
|
},
|
3619
3620
|
0xc6fc => {
|
3620
3621
|
Name => 'ProfileToneCurve',
|
3622
|
+
%longBin,
|
3621
3623
|
Writable => 'float',
|
3622
3624
|
WriteGroup => 'IFD0',
|
3623
3625
|
Count => -1,
|
3624
3626
|
Protected => 1,
|
3625
|
-
Binary => 1,
|
3626
3627
|
},
|
3627
3628
|
0xc6fd => {
|
3628
3629
|
Name => 'ProfileEmbedPolicy',
|
@@ -3747,11 +3748,11 @@ my %opcodeInfo = (
|
|
3747
3748
|
},
|
3748
3749
|
0xc726 => {
|
3749
3750
|
Name => 'ProfileLookTableData',
|
3751
|
+
%longBin,
|
3750
3752
|
Writable => 'float',
|
3751
3753
|
WriteGroup => 'IFD0',
|
3752
3754
|
Count => -1,
|
3753
3755
|
Protected => 1,
|
3754
|
-
Binary => 1,
|
3755
3756
|
},
|
3756
3757
|
0xc740 => { Name => 'OpcodeList1', %opcodeInfo }, # DNG 1.3
|
3757
3758
|
0xc741 => { Name => 'OpcodeList2', %opcodeInfo }, # DNG 1.3
|
@@ -6172,15 +6173,23 @@ sub ProcessExif($$$)
|
|
6172
6173
|
# (avoids long delays when processing some corrupted files)
|
6173
6174
|
if ($count > 100000 and $formatStr !~ /^(undef|string|binary)$/) {
|
6174
6175
|
my $tagName = $tagInfo ? $$tagInfo{Name} : sprintf('tag 0x%.4x', $tagID);
|
6176
|
+
# (count of 196608 is typical for ColorMap)
|
6175
6177
|
if ($tagName ne 'TransferFunction' or $count != 196608) {
|
6176
6178
|
my $minor = $count > 2000000 ? 0 : 2;
|
6177
6179
|
next if $et->Warn("Ignoring $dirName $tagName with excessive count", $minor);
|
6178
6180
|
}
|
6179
6181
|
}
|
6180
|
-
|
6181
|
-
|
6182
|
-
|
6183
|
-
|
6182
|
+
if ($count > 500 and $formatStr !~ /^(undef|string|binary)$/ and
|
6183
|
+
(not $tagInfo or $$tagInfo{LongBinary}) and not $$et{OPTIONS}{IgnoreMinorErrors})
|
6184
|
+
{
|
6185
|
+
$et->WarnOnce('Not decoding some large array(s). Ignore minor errors to decode', 2);
|
6186
|
+
$val = "(large array of $count $formatStr values)";
|
6187
|
+
} else {
|
6188
|
+
# convert according to specified format
|
6189
|
+
$val = ReadValue($valueDataPt,$valuePtr,$formatStr,$count,$readSize,\$rational);
|
6190
|
+
# re-code if necessary
|
6191
|
+
$val = $et->Decode($val, $strEnc) if $strEnc and $formatStr eq 'string' and defined $val;
|
6192
|
+
}
|
6184
6193
|
}
|
6185
6194
|
|
6186
6195
|
if ($verbose) {
|
@@ -31,7 +31,7 @@ use vars qw($VERSION);
|
|
31
31
|
use Image::ExifTool qw(:DataAccess :Utils);
|
32
32
|
use Image::ExifTool::Exif;
|
33
33
|
|
34
|
-
$VERSION = '1.
|
34
|
+
$VERSION = '1.80';
|
35
35
|
|
36
36
|
sub ProcessFujiDir($$$);
|
37
37
|
sub ProcessFaceRec($$$);
|
@@ -507,6 +507,7 @@ my %faceCategories = (
|
|
507
507
|
0 => 'Off',
|
508
508
|
1 => 'On',
|
509
509
|
2 => 'No flash & flash', #3
|
510
|
+
6 => 'Pixel Shift', #IB (GFX100S)
|
510
511
|
},
|
511
512
|
}],
|
512
513
|
0x1101 => {
|
@@ -517,6 +518,8 @@ my %faceCategories = (
|
|
517
518
|
Name => 'DriveSettings',
|
518
519
|
SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::DriveSettings' },
|
519
520
|
},
|
521
|
+
0x1105 => { Name => 'PixelShiftShots', Writable => 'int16u' }, #IB
|
522
|
+
0x1106 => { Name => 'PixelShiftOffset', Writable => 'rational64s', Count => 2 }, #IB
|
520
523
|
# (0x1150-0x1152 exist only for Pro Low-light and Pro Focus PictureModes)
|
521
524
|
# 0x1150 - Pro Low-light - val=1; Pro Focus - val=2 (ref 7); HDR - val=128 (forum10799)
|
522
525
|
# 0x1151 - Pro Low-light - val=4 (number of pictures taken?); Pro Focus - val=2,3 (ref 7); HDR - val=3 (forum10799)
|
@@ -915,15 +918,22 @@ my %faceCategories = (
|
|
915
918
|
WRITABLE => 1,
|
916
919
|
0.1 => {
|
917
920
|
Name => 'FocusMode2',
|
918
|
-
Mask =>
|
921
|
+
Mask => 0x0000000f,
|
919
922
|
PrintConv => {
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
0x11 => 'AF-S (Auto)',
|
923
|
+
0x0 => 'AF-M',
|
924
|
+
0x1 => 'AF-S',
|
925
|
+
0x2 => 'AF-C',
|
924
926
|
},
|
925
927
|
},
|
926
928
|
0.2 => {
|
929
|
+
Name => 'PreAF',
|
930
|
+
Mask => 0x00f0,
|
931
|
+
PrintConv => {
|
932
|
+
0 => 'Off',
|
933
|
+
1 => 'On',
|
934
|
+
},
|
935
|
+
},
|
936
|
+
0.3 => {
|
927
937
|
Name => 'AFAreaMode',
|
928
938
|
Mask => 0x0f00,
|
929
939
|
PrintConv => {
|
@@ -932,7 +942,7 @@ my %faceCategories = (
|
|
932
942
|
2 => 'Wide/Tracking',
|
933
943
|
},
|
934
944
|
},
|
935
|
-
0.
|
945
|
+
0.4 => {
|
936
946
|
Name => 'AFAreaPointSize',
|
937
947
|
Mask => 0xf000,
|
938
948
|
PrintConv => {
|
@@ -940,7 +950,7 @@ my %faceCategories = (
|
|
940
950
|
OTHER => sub { return $_[0] },
|
941
951
|
},
|
942
952
|
},
|
943
|
-
0.
|
953
|
+
0.5 => {
|
944
954
|
Name => 'AFAreaZoneSize',
|
945
955
|
Mask => 0xf0000,
|
946
956
|
PrintConv => {
|
@@ -193,11 +193,15 @@ sub ProcessJPEG_HDR($$$);
|
|
193
193
|
Condition => '$$valPt =~ /^UNICODE\0/',
|
194
194
|
Notes => 'PhotoStudio Unicode comment',
|
195
195
|
},
|
196
|
-
APP11 => {
|
196
|
+
APP11 => [{
|
197
197
|
Name => 'JPEG-HDR',
|
198
198
|
Condition => '$$valPt =~ /^HDR_RI /',
|
199
199
|
SubDirectory => { TagTable => 'Image::ExifTool::JPEG::HDR' },
|
200
|
-
},
|
200
|
+
},{
|
201
|
+
Name => 'JUMBF',
|
202
|
+
Condition => '$$valPt =~ /^JP/',
|
203
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
|
204
|
+
}],
|
201
205
|
APP12 => [{
|
202
206
|
Name => 'PictureInfo',
|
203
207
|
Condition => '$$valPt =~ /(\[picture info\]|Type=)/',
|
@@ -14,13 +14,15 @@ use vars qw($VERSION);
|
|
14
14
|
use Image::ExifTool qw(:DataAccess :Utils);
|
15
15
|
use Image::ExifTool::Import;
|
16
16
|
|
17
|
-
$VERSION = '1.
|
17
|
+
$VERSION = '1.03';
|
18
18
|
|
19
|
+
sub ProcessJSON($$);
|
19
20
|
sub ProcessTag($$$$%);
|
20
21
|
|
21
22
|
%Image::ExifTool::JSON::Main = (
|
22
23
|
GROUPS => { 0 => 'JSON', 1 => 'JSON', 2 => 'Other' },
|
23
24
|
VARS => { NO_ID => 1 },
|
25
|
+
PROCESS_PROC => \&ProcessJSON,
|
24
26
|
NOTES => q{
|
25
27
|
Other than a few tags in the table below, JSON tags have not been
|
26
28
|
pre-defined. However, ExifTool will read any existing tags from basic
|
@@ -103,7 +105,26 @@ sub ProcessJSON($$)
|
|
103
105
|
my ($et, $dirInfo) = @_;
|
104
106
|
my $raf = $$dirInfo{RAF};
|
105
107
|
my $structOpt = $et->Options('Struct');
|
106
|
-
my (%database, $key, $tag);
|
108
|
+
my (%database, $key, $tag, $dataPt);
|
109
|
+
|
110
|
+
unless ($raf) {
|
111
|
+
$dataPt = $$dirInfo{DataPt};
|
112
|
+
if ($$dirInfo{DirStart} or ($$dirInfo{DirLen} and $$dirInfo{DirLen} ne length($$dataPt))) {
|
113
|
+
my $buff = substr(${$$dirInfo{DataPt}}, $$dirInfo{DirStart}, $$dirInfo{DirLen});
|
114
|
+
$dataPt = \$buff;
|
115
|
+
}
|
116
|
+
$raf = new File::RandomAccess($dataPt);
|
117
|
+
# extract as a block if requested
|
118
|
+
my $blockName = $$dirInfo{BlockInfo} ? $$dirInfo{BlockInfo}{Name} : '';
|
119
|
+
my $blockExtract = $et->Options('BlockExtract');
|
120
|
+
if ($blockName and ($blockExtract or $$et{REQ_TAG_LOOKUP}{lc $blockName} or
|
121
|
+
($$et{TAGS_FROM_FILE} and not $$et{EXCL_TAG_LOOKUP}{lc $blockName})))
|
122
|
+
{
|
123
|
+
$et->FoundTag($$dirInfo{BlockInfo}, $$dataPt);
|
124
|
+
return 1 if $blockExtract and $blockExtract > 1;
|
125
|
+
}
|
126
|
+
$et->VerboseDir('JSON');
|
127
|
+
}
|
107
128
|
|
108
129
|
# read information from JSON file into database structure
|
109
130
|
my $err = Image::ExifTool::Import::ReadJSON($raf, \%database,
|
@@ -111,7 +132,7 @@ sub ProcessJSON($$)
|
|
111
132
|
|
112
133
|
return 0 if $err or not %database;
|
113
134
|
|
114
|
-
$et->SetFileType();
|
135
|
+
$et->SetFileType() unless $dataPt;
|
115
136
|
|
116
137
|
my $tagTablePtr = GetTagTable('Image::ExifTool::JSON::Main');
|
117
138
|
|
@@ -16,9 +16,10 @@ use strict;
|
|
16
16
|
use vars qw($VERSION);
|
17
17
|
use Image::ExifTool qw(:DataAccess :Utils);
|
18
18
|
|
19
|
-
$VERSION = '1.
|
19
|
+
$VERSION = '1.29';
|
20
20
|
|
21
21
|
sub ProcessJpeg2000Box($$$);
|
22
|
+
sub ProcessJUMD($$$);
|
22
23
|
|
23
24
|
my %resolutionUnit = (
|
24
25
|
-3 => 'km',
|
@@ -54,6 +55,22 @@ my %jp2Map = (
|
|
54
55
|
MakerNotes => 'ExifIFD',
|
55
56
|
);
|
56
57
|
|
58
|
+
# map of where information is written in a JXL image
|
59
|
+
my %jxlMap = (
|
60
|
+
IFD0 => 'Exif',
|
61
|
+
XMP => 'XML',
|
62
|
+
'Exif' => 'JP2',
|
63
|
+
IFD1 => 'IFD0',
|
64
|
+
EXIF => 'IFD0', # to write EXIF as a block
|
65
|
+
ExifIFD => 'IFD0',
|
66
|
+
GPS => 'IFD0',
|
67
|
+
SubIFD => 'IFD0',
|
68
|
+
GlobParamIFD => 'IFD0',
|
69
|
+
PrintIM => 'IFD0',
|
70
|
+
InteropIFD => 'ExifIFD',
|
71
|
+
MakerNotes => 'ExifIFD',
|
72
|
+
);
|
73
|
+
|
57
74
|
# UUID's for writable UUID directories (by tag name)
|
58
75
|
my %uuid = (
|
59
76
|
'UUID-EXIF' => 'JpgTiffExif->JP2',
|
@@ -99,6 +116,9 @@ my %j2cMarker = (
|
|
99
116
|
0x76 => 'NLT', # non-linearity point transformation
|
100
117
|
);
|
101
118
|
|
119
|
+
my %jumbfTypes = (
|
120
|
+
);
|
121
|
+
|
102
122
|
# JPEG 2000 "box" (ie. atom) names
|
103
123
|
# Note: only tags with a defined "Format" are extracted
|
104
124
|
%Image::ExifTool::Jpeg2000::Main = (
|
@@ -107,8 +127,9 @@ my %j2cMarker = (
|
|
107
127
|
WRITE_PROC => \&ProcessJpeg2000Box,
|
108
128
|
PREFERRED => 1, # always add these tags when writing
|
109
129
|
NOTES => q{
|
110
|
-
The tags below are extracted from JPEG 2000 images
|
111
|
-
currently writes only EXIF, IPTC and XMP
|
130
|
+
The tags below are extracted from JPEG 2000 images and the JUMBF metadata in
|
131
|
+
JPEG images. Note that ExifTool currently writes only EXIF, IPTC and XMP
|
132
|
+
tags in Jpeg2000 images.
|
112
133
|
},
|
113
134
|
'jP ' => 'JP2Signature', # (ref 1)
|
114
135
|
"jP\x1a\x1a" => 'JP2Signature', # (ref 2)
|
@@ -199,13 +220,22 @@ my %j2cMarker = (
|
|
199
220
|
chck => 'DigitalSignature',
|
200
221
|
mp7b => 'MPEG7Binary',
|
201
222
|
free => 'Free',
|
202
|
-
jp2c =>
|
223
|
+
jp2c => [{
|
224
|
+
Name => 'ContiguousCodestream',
|
225
|
+
Condition => 'not $$self{jumd_level}',
|
226
|
+
},{
|
227
|
+
Name => 'PreviewImage',
|
228
|
+
Groups => { 2 => 'Preview' },
|
229
|
+
Format => 'undef',
|
230
|
+
Binary => 1,
|
231
|
+
}],
|
203
232
|
jp2i => {
|
204
233
|
Name => 'IntellectualProperty',
|
205
234
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
206
235
|
},
|
207
|
-
'xml '=> {
|
236
|
+
'xml '=> [{
|
208
237
|
Name => 'XML',
|
238
|
+
Condition => 'not $$self{IsJXL}',
|
209
239
|
Writable => 'undef',
|
210
240
|
Flags => [ 'Binary', 'Protected', 'BlockExtract' ],
|
211
241
|
List => 1,
|
@@ -213,12 +243,18 @@ my %j2cMarker = (
|
|
213
243
|
by default, the XML data in this tag is parsed using the ExifTool XMP module
|
214
244
|
to to allow individual tags to be accessed when reading, but it may also be
|
215
245
|
extracted as a block via the "XML" tag, which is also how this tag is
|
216
|
-
written and copied.
|
217
|
-
|
246
|
+
written and copied. It may also be extracted as a block by setting the API
|
247
|
+
BlockExtract option. This is a List-type tag because multiple XML blocks
|
248
|
+
may exist
|
218
249
|
},
|
219
250
|
# (note: extracting as a block was broken in 11.04, and finally fixed in 12.14)
|
220
251
|
SubDirectory => { TagTable => 'Image::ExifTool::XMP::XML' },
|
221
|
-
},
|
252
|
+
},{
|
253
|
+
Name => 'XMP',
|
254
|
+
Notes => 'used for XMP in JPEG XL files',
|
255
|
+
# NOTE: the hacked code relies on this being at index 1 of the tagInfo list!
|
256
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
257
|
+
}],
|
222
258
|
uuid => [
|
223
259
|
{
|
224
260
|
Name => 'UUID-EXIF',
|
@@ -302,6 +338,12 @@ my %j2cMarker = (
|
|
302
338
|
Start => '$valuePtr + 16',
|
303
339
|
},
|
304
340
|
},
|
341
|
+
{
|
342
|
+
Name => 'UUID-Signature', # (seen in JUMB data of JPEG images)
|
343
|
+
Condition => '$$valPt=~/^casg\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
|
344
|
+
Format => 'undef',
|
345
|
+
ValueConv => 'substr($val,16)',
|
346
|
+
},
|
305
347
|
{
|
306
348
|
Name => 'UUID-Unknown',
|
307
349
|
},
|
@@ -321,6 +363,52 @@ my %j2cMarker = (
|
|
321
363
|
Name => 'URL',
|
322
364
|
Format => 'string',
|
323
365
|
},
|
366
|
+
# JUMBF boxes (ref https://github.com/thorfdbg/codestream-parser)
|
367
|
+
jumd => {
|
368
|
+
Name => 'JUMBFDescr',
|
369
|
+
SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::JUMD' },
|
370
|
+
},
|
371
|
+
jumb => {
|
372
|
+
Name => 'JUMBFBox',
|
373
|
+
SubDirectory => {
|
374
|
+
TagTable => 'Image::ExifTool::Jpeg2000::Main',
|
375
|
+
ProcessProc => \&ProcessJUMB,
|
376
|
+
},
|
377
|
+
},
|
378
|
+
json => {
|
379
|
+
Name => 'JSONData',
|
380
|
+
Flags => [ 'Binary', 'Protected', 'BlockExtract' ],
|
381
|
+
Notes => q{
|
382
|
+
by default, data in this tag is parsed using the ExifTool JSON module to to
|
383
|
+
allow individual tags to be accessed when reading, but it may also be
|
384
|
+
extracted as a block via the "JSONData" tag or by setting the API
|
385
|
+
BlockExtract option
|
386
|
+
},
|
387
|
+
SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
|
388
|
+
},
|
389
|
+
#
|
390
|
+
# stuff seen in JPEG XL images:
|
391
|
+
#
|
392
|
+
# jbrd - JPEG Bitstream Reconstruction Data (allows lossless conversion back to original JPG)
|
393
|
+
jxlc => {
|
394
|
+
Name => 'JXLCodestream',
|
395
|
+
Format => 'undef',
|
396
|
+
Notes => q{
|
397
|
+
Codestream in JPEG XL image. Currently processed only to determine
|
398
|
+
ImageSize
|
399
|
+
},
|
400
|
+
RawConv => 'Image::ExifTool::Jpeg2000::ProcessJXLCodestream($self,\$val); undef',
|
401
|
+
},
|
402
|
+
Exif => {
|
403
|
+
Name => 'EXIF',
|
404
|
+
SubDirectory => {
|
405
|
+
TagTable => 'Image::ExifTool::Exif::Main',
|
406
|
+
ProcessProc => \&Image::ExifTool::ProcessTIFF,
|
407
|
+
WriteProc => \&Image::ExifTool::WriteTIFF,
|
408
|
+
DirName => 'EXIF',
|
409
|
+
Start => '$valuePtr + 4',
|
410
|
+
},
|
411
|
+
},
|
324
412
|
);
|
325
413
|
|
326
414
|
%Image::ExifTool::Jpeg2000::ImageHeader = (
|
@@ -375,6 +463,7 @@ my %j2cMarker = (
|
|
375
463
|
'jp2 ' => 'JPEG 2000 Image (.JP2)', # image/jp2
|
376
464
|
'jpm ' => 'JPEG 2000 Compound Image (.JPM)', # image/jpm
|
377
465
|
'jpx ' => 'JPEG 2000 with extensions (.JPX)', # image/jpx
|
466
|
+
'jxl ' => 'JPEG XL Image (.JXL)', # image/jxl
|
378
467
|
},
|
379
468
|
},
|
380
469
|
1 => {
|
@@ -513,6 +602,112 @@ my %j2cMarker = (
|
|
513
602
|
],
|
514
603
|
);
|
515
604
|
|
605
|
+
# JUMBF description box
|
606
|
+
%Image::ExifTool::Jpeg2000::JUMD = (
|
607
|
+
PROCESS_PROC => \&ProcessJUMD,
|
608
|
+
GROUPS => { 0 => 'JUMBF', 1 => 'JUMBF', 2 => 'Image' },
|
609
|
+
NOTES => 'Information extracted from the JUMBF description box.',
|
610
|
+
'jumd-type' => {
|
611
|
+
Name => 'JUMDType',
|
612
|
+
ValueConv => 'unpack "H*", $val',
|
613
|
+
PrintConv => q{
|
614
|
+
my @a = $val =~ /^(\w{8})(\w{4})(\w{4})(\w{16})$/;
|
615
|
+
return $val unless @a;
|
616
|
+
my $ascii = pack 'H*', $a[0];
|
617
|
+
$a[0] = $ascii if $ascii =~ /^[a-zA-Z0-9]{4}$/;
|
618
|
+
return join '-', @a;
|
619
|
+
},
|
620
|
+
# seen:
|
621
|
+
# cacb/cast/caas/cacl/casg/json-00110010800000aa00389b71
|
622
|
+
# 6579d6fbdba2446bb2ac1b82feeb89d1 - JPEG image
|
623
|
+
},
|
624
|
+
'jumd-label' => { Name => 'JUMDLabel' },
|
625
|
+
'jumd-flags' => {
|
626
|
+
Name => 'JUMDFlags',
|
627
|
+
PrintConv => { BITMASK => {
|
628
|
+
0 => 'Requestable',
|
629
|
+
1 => 'Label',
|
630
|
+
2 => 'ID',
|
631
|
+
3 => 'Signature',
|
632
|
+
}},
|
633
|
+
},
|
634
|
+
'jumd-id' => { Name => 'JUMDID', Description => 'JUMD ID' },
|
635
|
+
'jumd-sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' },
|
636
|
+
);
|
637
|
+
|
638
|
+
#------------------------------------------------------------------------------
|
639
|
+
# Read JUMBF box to keep track of sub-document numbers
|
640
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
641
|
+
# Returns: 1 on success
|
642
|
+
sub ProcessJUMB($$$)
|
643
|
+
{
|
644
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
645
|
+
if ($$et{jumd_level}) {
|
646
|
+
++$$et{jumd_level}[-1]; # increment current sub-document number
|
647
|
+
} else {
|
648
|
+
$$et{jumd_level} = [ ++$$et{DOC_COUNT} ]; # new top-level sub-document
|
649
|
+
$$et{SET_GROUP0} = 'JUMBF';
|
650
|
+
}
|
651
|
+
$$et{DOC_NUM} = join '-', @{$$et{jumd_level}};
|
652
|
+
push @{$$et{jumd_level}}, 0;
|
653
|
+
ProcessJpeg2000Box($et, $dirInfo, $tagTablePtr);
|
654
|
+
delete $$et{DOC_NUM};
|
655
|
+
delete $$et{JUMBFLabel};
|
656
|
+
pop @{$$et{jumd_level}};
|
657
|
+
if (@{$$et{jumd_level}} < 2) {
|
658
|
+
delete $$et{jumd_level};
|
659
|
+
delete $$et{SET_GROUP0};
|
660
|
+
}
|
661
|
+
return 1;
|
662
|
+
}
|
663
|
+
|
664
|
+
#------------------------------------------------------------------------------
|
665
|
+
# Read JUMBF description box (ref https://github.com/thorfdbg/codestream-parser)
|
666
|
+
# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref
|
667
|
+
# Returns: 1 on success
|
668
|
+
sub ProcessJUMD($$$)
|
669
|
+
{
|
670
|
+
my ($et, $dirInfo, $tagTablePtr) = @_;
|
671
|
+
my $dataPt = $$dirInfo{DataPt};
|
672
|
+
my $pos = $$dirInfo{DirStart};
|
673
|
+
my $end = $pos + $$dirInfo{DirLen};
|
674
|
+
$et->VerboseDir('JUMD', 0, $end-$pos);
|
675
|
+
delete $$et{JUMBFLabel};
|
676
|
+
$$dirInfo{DirLen} < 17 and $et->Warn('Truncated JUMD directory'), return 0;
|
677
|
+
my $type = substr($$dataPt, $pos, 4);
|
678
|
+
$et->HandleTag($tagTablePtr, 'jumd-type', substr($$dataPt, $pos, 16));
|
679
|
+
$pos += 16;
|
680
|
+
my $flags = Get8u($dataPt, $pos++);
|
681
|
+
$et->HandleTag($tagTablePtr, 'jumd-flags', $flags);
|
682
|
+
if ($flags & 0x02) { # label exists?
|
683
|
+
pos($$dataPt) = $pos;
|
684
|
+
$$dataPt =~ /\0/g or $et->Warn('Missing JUMD label terminator'), return 0;
|
685
|
+
my $len = pos($$dataPt) - $pos;
|
686
|
+
my $name = substr($$dataPt, $pos, $len);
|
687
|
+
$et->HandleTag($tagTablePtr, 'jumd-label', $name);
|
688
|
+
$pos += $len;
|
689
|
+
if ($len) {
|
690
|
+
$name =~ s/[^-_a-zA-Z0-9]([a-z])/\U$1/g; # capitalize characters after illegal characters
|
691
|
+
$name =~ tr/-_a-zA-Z0-9//dc; # remove other illegal characters
|
692
|
+
$name = ucfirst $name; # capitalize first letter
|
693
|
+
$name = "Tag$name" if length($name) < 2; # must at least 2 characters long
|
694
|
+
$$et{JUMBFLabel} = $name;
|
695
|
+
}
|
696
|
+
}
|
697
|
+
if ($flags & 0x04) { # ID exists?
|
698
|
+
$pos + 4 > $end and $et->Warn('Missing JUMD ID'), return 0;
|
699
|
+
$et->HandleTag($tagTablePtr, 'jumd-id', Get32u($dataPt, $pos));
|
700
|
+
$pos += 4;
|
701
|
+
}
|
702
|
+
if ($flags & 0x08) { # signature exists?
|
703
|
+
$pos + 32 > $end and $et->Warn('Missing JUMD signature'), return 0;
|
704
|
+
$et->HandleTag($tagTablePtr, 'jumd-sig', substr($$dataPt, $pos, 32));
|
705
|
+
$pos += 32;
|
706
|
+
}
|
707
|
+
$pos == $end or $et->Warn('Extra data in JUMD box'." $pos $end", 1);
|
708
|
+
return 1;
|
709
|
+
}
|
710
|
+
|
516
711
|
#------------------------------------------------------------------------------
|
517
712
|
# Create new JPEG 2000 boxes when writing
|
518
713
|
# (Currently only supports adding top-level Writable JPEG2000 tags and certain UUID boxes)
|
@@ -542,8 +737,29 @@ sub CreateNewBoxes($$)
|
|
542
737
|
$et->VerboseValue("+ Jpeg2000:$$tagInfo{Name}", $val);
|
543
738
|
}
|
544
739
|
}
|
545
|
-
# add UUID boxes
|
740
|
+
# add UUID boxes (and/or JXL Exif/XML boxes)
|
546
741
|
foreach $dirName (sort keys %$addDirs) {
|
742
|
+
# handle JPEG XL XMP and EXIF
|
743
|
+
if ($dirName eq 'XML' or $dirName eq 'Exif') {
|
744
|
+
my ($tag, $dir) = $dirName eq 'XML' ? ('xml ', 'XMP') : ('Exif', 'EXIF');
|
745
|
+
my $tagInfo = $Image::ExifTool::Jpeg2000::Main{$tag};
|
746
|
+
$tagInfo = $$tagInfo[1] if ref $tagInfo eq 'ARRAY'; # (hack for stupid JXL XMP)
|
747
|
+
my $subdir = $$tagInfo{SubDirectory};
|
748
|
+
my $tagTable = GetTagTable($$subdir{TagTable});
|
749
|
+
$tagTable = GetTagTable('Image::ExifTool::XMP::Main') if $dir eq 'XMP';
|
750
|
+
my %dirInfo = (
|
751
|
+
DirName => $dir,
|
752
|
+
Parent => 'JP2',
|
753
|
+
);
|
754
|
+
my $newdir = $et->WriteDirectory(\%dirInfo, $tagTable, $$subdir{WriteProc});
|
755
|
+
if (defined $newdir and length $newdir) {
|
756
|
+
# not sure why, but EXIF box is padded with leading 0's in my sample
|
757
|
+
my $pad = $dirName eq 'Exif' ? "\0\0\0\0" : '';
|
758
|
+
my $boxhdr = pack('N', length($newdir) + length($pad) + 8) . $tag;
|
759
|
+
Write($outfile, $boxhdr, $pad, $newdir) or return 0;
|
760
|
+
next;
|
761
|
+
}
|
762
|
+
}
|
547
763
|
next unless $uuid{$dirName};
|
548
764
|
my $tagInfo;
|
549
765
|
foreach $tagInfo (@{$Image::ExifTool::Jpeg2000::Main{uuid}}) {
|
@@ -725,6 +941,13 @@ sub ProcessJpeg2000Box($$$)
|
|
725
941
|
);
|
726
942
|
next unless $tagInfo;
|
727
943
|
}
|
944
|
+
# create new tag for JUMBF data values with name corresponding to JUMBFLabel
|
945
|
+
if ($$et{JUMBFLabel} and (not $$tagInfo{SubDirectory} or $$tagInfo{BlockExtract})) {
|
946
|
+
$tagInfo = { %$tagInfo, Name => $$et{JUMBFLabel} };
|
947
|
+
AddTagToTable($tagTablePtr, '_JUMBF_' . $$et{JUMBFLabel}, $tagInfo);
|
948
|
+
delete $$tagInfo{Protected}; # (must do this so -j -b returns JUMBF binary data)
|
949
|
+
$$tagInfo{TagID} = $boxID;
|
950
|
+
}
|
728
951
|
if ($$tagInfo{SubDirectory}) {
|
729
952
|
my $subdir = $$tagInfo{SubDirectory};
|
730
953
|
my $subdirStart = $valuePtr;
|
@@ -752,8 +975,8 @@ sub ProcessJpeg2000Box($$$)
|
|
752
975
|
# remove this directory from our create list
|
753
976
|
delete $$et{AddJp2Dirs}{$$tagInfo{Name}};
|
754
977
|
my $newdir;
|
755
|
-
# only edit writable UUID boxes
|
756
|
-
if ($uuid) {
|
978
|
+
# only edit writable UUID and Exif boxes
|
979
|
+
if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL})) {
|
757
980
|
$newdir = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
|
758
981
|
next if defined $newdir and not length $newdir; # next if deleting the box
|
759
982
|
} elsif (defined $uuid) {
|
@@ -803,6 +1026,68 @@ sub ProcessJpeg2000Box($$$)
|
|
803
1026
|
return 1;
|
804
1027
|
}
|
805
1028
|
|
1029
|
+
#------------------------------------------------------------------------------
|
1030
|
+
# Return bits from a bitstream object
|
1031
|
+
# Inputs: 0) array ref, 1) number of bits
|
1032
|
+
# Returns: specified number of bits as an integer, and shifts input bitstream
|
1033
|
+
sub GetBits($$)
|
1034
|
+
{
|
1035
|
+
my ($a, $n) = @_;
|
1036
|
+
my $v = 0;
|
1037
|
+
my $bit = 1;
|
1038
|
+
my $i;
|
1039
|
+
while ($n--) {
|
1040
|
+
for ($i=0; $i<@$a; ++$i) {
|
1041
|
+
# consume bits LSB first
|
1042
|
+
my $set = $$a[$i] & 1;
|
1043
|
+
$$a[$i] >>= 1;
|
1044
|
+
if ($i) {
|
1045
|
+
$$a[$i-1] |= 0x80 if $set;
|
1046
|
+
} else {
|
1047
|
+
$v |= $bit if $set;
|
1048
|
+
$bit <<= 1;
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
}
|
1052
|
+
return $v;
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
#------------------------------------------------------------------------------
|
1056
|
+
# Extract parameters from JPEG XL codestream [unverified!]
|
1057
|
+
# Inputs: 0) ExifTool ref, 1) codestream ref
|
1058
|
+
# Returns: 1
|
1059
|
+
sub ProcessJXLCodestream($$)
|
1060
|
+
{
|
1061
|
+
my ($et, $dataPt) = @_;
|
1062
|
+
# add padding if necessary to avoid unpacking past end of data
|
1063
|
+
if (length $$dataPt < 14) {
|
1064
|
+
my $tmp = $$dataPt . ("\0" x 14);
|
1065
|
+
$dataPt = \$tmp;
|
1066
|
+
}
|
1067
|
+
my @a = unpack 'x2C12', $$dataPt;
|
1068
|
+
my ($x, $y);
|
1069
|
+
my $small = GetBits(\@a, 1);
|
1070
|
+
if ($small) {
|
1071
|
+
$y = (GetBits(\@a, 5) + 1) * 8;
|
1072
|
+
} else {
|
1073
|
+
$y = GetBits(\@a, [9, 13, 18, 30]->[GetBits(\@a, 2)]) + 1;
|
1074
|
+
}
|
1075
|
+
my $ratio = GetBits(\@a, 3);
|
1076
|
+
if ($ratio == 0) {
|
1077
|
+
if ($small) {
|
1078
|
+
$x = (GetBits(\@a, 5) + 1) * 8;;
|
1079
|
+
} else {
|
1080
|
+
$x = GetBits(\@a, [9, 13, 18, 30]->[GetBits(\@a, 2)]) + 1;
|
1081
|
+
}
|
1082
|
+
} else {
|
1083
|
+
my $r = [[1,1],[12,10],[4,3],[3,2],[16,9],[5,4],[2,1]]->[$ratio-1];
|
1084
|
+
$x = int($y * $$r[0] / $$r[1]);
|
1085
|
+
}
|
1086
|
+
$et->FoundTag(ImageWidth => $x);
|
1087
|
+
$et->FoundTag(ImageHeight => $y);
|
1088
|
+
return 1;
|
1089
|
+
}
|
1090
|
+
|
806
1091
|
#------------------------------------------------------------------------------
|
807
1092
|
# Read/write meta information from a JPEG 2000 image
|
808
1093
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
@@ -817,8 +1102,9 @@ sub ProcessJP2($$)
|
|
817
1102
|
|
818
1103
|
# check to be sure this is a valid JPG2000 file
|
819
1104
|
return 0 unless $raf->Read($hdr,12) == 12;
|
820
|
-
unless ($hdr eq "\
|
821
|
-
$hdr eq "\
|
1105
|
+
unless ($hdr eq "\0\0\0\x0cjP \x0d\x0a\x87\x0a" or # (ref 1)
|
1106
|
+
$hdr eq "\0\0\0\x0cjP\x1a\x1a\x0d\x0a\x87\x0a" or # (ref 2)
|
1107
|
+
$$et{IsJXL})
|
822
1108
|
{
|
823
1109
|
return 0 unless $hdr =~ /^\xff\x4f\xff\x51\0/; # check for JP2 codestream format
|
824
1110
|
if ($outfile) {
|
@@ -835,17 +1121,23 @@ sub ProcessJP2($$)
|
|
835
1121
|
}
|
836
1122
|
if ($outfile) {
|
837
1123
|
Write($outfile, $hdr) or return -1;
|
838
|
-
|
1124
|
+
if ($$et{IsJXL}) {
|
1125
|
+
$et->InitWriteDirs(\%jxlMap);
|
1126
|
+
$$et{AddJp2Tags} = { }; # (don't add JP2 tags in JXL files)
|
1127
|
+
} else {
|
1128
|
+
$et->InitWriteDirs(\%jp2Map);
|
1129
|
+
$$et{AddJp2Tags} = $et->GetNewTagInfoHash(\%Image::ExifTool::Jpeg2000::Main);
|
1130
|
+
}
|
839
1131
|
# save list of directories to create
|
840
|
-
my %addDirs = %{$$et{ADD_DIRS}};
|
1132
|
+
my %addDirs = %{$$et{ADD_DIRS}}; # (make a copy)
|
841
1133
|
$$et{AddJp2Dirs} = \%addDirs;
|
842
|
-
$$et{AddJp2Tags} = $et->GetNewTagInfoHash(\%Image::ExifTool::Jpeg2000::Main);
|
843
1134
|
} else {
|
844
1135
|
my ($buff, $fileType);
|
845
1136
|
# recognize JPX and JPM as unique types of JP2
|
846
1137
|
if ($raf->Read($buff, 12) == 12 and $buff =~ /^.{4}ftyp(.{4})/s) {
|
847
1138
|
$fileType = 'JPX' if $1 eq 'jpx ';
|
848
1139
|
$fileType = 'JPM' if $1 eq 'jpm ';
|
1140
|
+
$fileType = 'JXL' if $1 eq 'jxl ';
|
849
1141
|
}
|
850
1142
|
$raf->Seek(-length($buff), 1) if defined $buff;
|
851
1143
|
$et->SetFileType($fileType);
|
@@ -860,6 +1152,59 @@ sub ProcessJP2($$)
|
|
860
1152
|
return $et->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
861
1153
|
}
|
862
1154
|
|
1155
|
+
#------------------------------------------------------------------------------
|
1156
|
+
# Read meta information from a JPEG XL image
|
1157
|
+
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
1158
|
+
# Returns: 1 on success, 0 if this wasn't a valid JPEG XL file, -1 on write error
|
1159
|
+
sub ProcessJXL($$)
|
1160
|
+
{
|
1161
|
+
my ($et, $dirInfo) = @_;
|
1162
|
+
my $raf = $$dirInfo{RAF};
|
1163
|
+
my $outfile = $$dirInfo{OutFile};
|
1164
|
+
my ($hdr, $buff);
|
1165
|
+
|
1166
|
+
return 0 unless $raf->Read($hdr,12) == 12;
|
1167
|
+
if ($hdr eq "\0\0\0\x0cJXL \x0d\x0a\x87\x0a") {
|
1168
|
+
# JPEG XL in ISO BMFF container
|
1169
|
+
$$et{IsJXL} = 1;
|
1170
|
+
} elsif ($hdr =~ /^\xff\x0a/) {
|
1171
|
+
# JPEG XL codestream
|
1172
|
+
if ($outfile) {
|
1173
|
+
if ($$et{OPTIONS}{IgnoreMinorErrors}) {
|
1174
|
+
$et->Warn('Wrapped JXL codestream in ISO BMFF container');
|
1175
|
+
} else {
|
1176
|
+
$et->Error('Will wrap JXL codestream in ISO BMFF container for writing',1);
|
1177
|
+
return 0;
|
1178
|
+
}
|
1179
|
+
$$et{IsJXL} = 2;
|
1180
|
+
my $buff = "\0\0\0\x0cJXL \x0d\x0a\x87\x0a\0\0\0\x14ftypjxl \0\0\0\0jxl ";
|
1181
|
+
# add metadata to empty ISO BMFF container
|
1182
|
+
$$dirInfo{RAF} = new File::RandomAccess(\$buff);
|
1183
|
+
} else {
|
1184
|
+
$et->SetFileType('JXL Codestream','image/jxl', 'jxl');
|
1185
|
+
return ProcessJXLCodestream($et, \$hdr);
|
1186
|
+
}
|
1187
|
+
} else {
|
1188
|
+
return 0;
|
1189
|
+
}
|
1190
|
+
$raf->Seek(0,0) or $et->Error('Seek error'), return 0;
|
1191
|
+
|
1192
|
+
my $success = ProcessJP2($et, $dirInfo);
|
1193
|
+
|
1194
|
+
if ($outfile and $success > 0 and $$et{IsJXL} == 2) {
|
1195
|
+
# attach the JXL codestream box to the ISO BMFF file
|
1196
|
+
$raf->Seek(0,2) or return -1;
|
1197
|
+
my $size = $raf->Tell();
|
1198
|
+
$raf->Seek(0,0) or return -1;
|
1199
|
+
SetByteOrder('MM');
|
1200
|
+
Write($outfile, Set32u($size + 8), 'jxlc') or return -1;
|
1201
|
+
while ($raf->Read($buff, 65536)) {
|
1202
|
+
Write($outfile, $buff) or return -1;
|
1203
|
+
}
|
1204
|
+
}
|
1205
|
+
return $success;
|
1206
|
+
}
|
1207
|
+
|
863
1208
|
1; # end
|
864
1209
|
|
865
1210
|
__END__
|