exiftool_vendored 12.25.0 → 12.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/Changes +174 -7
- data/bin/MANIFEST +11 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +44 -43
- data/bin/arg_files/xmp2exif.args +2 -1
- data/bin/config_files/convert_regions.config +25 -14
- data/bin/config_files/example.config +1 -1
- data/bin/exiftool +118 -92
- data/bin/fmt_files/gpx.fmt +1 -1
- data/bin/fmt_files/gpx_wpt.fmt +1 -1
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +16 -3
- data/bin/lib/Image/ExifTool/CBOR.pm +331 -0
- data/bin/lib/Image/ExifTool/Canon.pm +52 -20
- data/bin/lib/Image/ExifTool/Charset.pm +2 -0
- data/bin/lib/Image/ExifTool/DPX.pm +13 -2
- data/bin/lib/Image/ExifTool/Exif.pm +107 -8
- data/bin/lib/Image/ExifTool/FLIR.pm +33 -8
- data/bin/lib/Image/ExifTool/FlashPix.pm +35 -10
- data/bin/lib/Image/ExifTool/FujiFilm.pm +1 -0
- data/bin/lib/Image/ExifTool/Geotag.pm +13 -2
- data/bin/lib/Image/ExifTool/GoPro.pm +16 -1
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +96 -4
- data/bin/lib/Image/ExifTool/ID3.pm +15 -3
- data/bin/lib/Image/ExifTool/JPEG.pm +68 -2
- data/bin/lib/Image/ExifTool/JSON.pm +7 -3
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +164 -36
- data/bin/lib/Image/ExifTool/LIF.pm +153 -0
- data/bin/lib/Image/ExifTool/Lang/nl.pm +60 -59
- data/bin/lib/Image/ExifTool/M2TS.pm +103 -7
- data/bin/lib/Image/ExifTool/MIE.pm +2 -1
- data/bin/lib/Image/ExifTool/MRC.pm +1 -1
- data/bin/lib/Image/ExifTool/MacOS.pm +2 -2
- data/bin/lib/Image/ExifTool/Nikon.pm +50 -6
- data/bin/lib/Image/ExifTool/NikonSettings.pm +10 -2
- data/bin/lib/Image/ExifTool/Olympus.pm +9 -2
- data/bin/lib/Image/ExifTool/Other.pm +93 -0
- data/bin/lib/Image/ExifTool/PDF.pm +11 -12
- data/bin/lib/Image/ExifTool/PNG.pm +7 -6
- data/bin/lib/Image/ExifTool/Panasonic.pm +14 -2
- data/bin/lib/Image/ExifTool/Pentax.pm +28 -5
- data/bin/lib/Image/ExifTool/Photoshop.pm +6 -0
- data/bin/lib/Image/ExifTool/QuickTime.pm +123 -25
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +203 -121
- data/bin/lib/Image/ExifTool/README +9 -2
- data/bin/lib/Image/ExifTool/RIFF.pm +7 -2
- data/bin/lib/Image/ExifTool/Samsung.pm +47 -10
- data/bin/lib/Image/ExifTool/Sony.pm +113 -42
- data/bin/lib/Image/ExifTool/TagLookup.pm +4599 -4451
- data/bin/lib/Image/ExifTool/TagNames.pod +276 -41
- data/bin/lib/Image/ExifTool/Torrent.pm +18 -11
- data/bin/lib/Image/ExifTool/WriteIPTC.pl +1 -1
- data/bin/lib/Image/ExifTool/WritePDF.pl +1 -0
- data/bin/lib/Image/ExifTool/WritePNG.pl +2 -0
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +21 -4
- data/bin/lib/Image/ExifTool/WriteXMP.pl +1 -1
- data/bin/lib/Image/ExifTool/Writer.pl +47 -2
- data/bin/lib/Image/ExifTool/XMP.pm +32 -12
- data/bin/lib/Image/ExifTool/XMP2.pl +5 -2
- data/bin/lib/Image/ExifTool/XMPStruct.pl +3 -1
- data/bin/lib/Image/ExifTool/ZISRAW.pm +121 -2
- data/bin/lib/Image/ExifTool.pm +153 -52
- data/bin/lib/Image/ExifTool.pod +70 -60
- data/bin/perl-Image-ExifTool.spec +43 -42
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +6 -3
@@ -11,7 +11,7 @@ use strict;
|
|
11
11
|
use vars qw($VERSION);
|
12
12
|
use Image::ExifTool qw(:DataAccess :Utils);
|
13
13
|
|
14
|
-
$VERSION = '1.
|
14
|
+
$VERSION = '1.32';
|
15
15
|
|
16
16
|
sub ProcessOcad($$$);
|
17
17
|
sub ProcessJPEG_HDR($$$);
|
@@ -96,6 +96,10 @@ sub ProcessJPEG_HDR($$$);
|
|
96
96
|
Name => 'Stim',
|
97
97
|
Condition => '$$valPt =~ /^Stim\0/',
|
98
98
|
SubDirectory => { TagTable => 'Image::ExifTool::Stim::Main' },
|
99
|
+
}, {
|
100
|
+
Name => 'JPS',
|
101
|
+
Condition => '$$valPt =~ /^_JPSJPS_/',
|
102
|
+
SubDirectory => { TagTable => 'Image::ExifTool::JPEG::JPS' },
|
99
103
|
}, {
|
100
104
|
Name => 'ThermalData', # (written by DJI FLIR models)
|
101
105
|
Condition => '$$self{Make} eq "DJI"',
|
@@ -287,6 +291,68 @@ sub ProcessJPEG_HDR($$$);
|
|
287
291
|
}],
|
288
292
|
);
|
289
293
|
|
294
|
+
# JPS APP3 segment (ref http://paulbourke.net/stereographics/stereoimage/)
|
295
|
+
%Image::ExifTool::JPEG::JPS = (
|
296
|
+
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
297
|
+
GROUPS => { 0 => 'APP3', 1 => 'JPS', 2 => 'Image' },
|
298
|
+
NOTES => 'Tags found in JPEG Stereo (JPS) images.',
|
299
|
+
0x0a => {
|
300
|
+
Name => 'JPSSeparation',
|
301
|
+
Format => 'int32u', # (just so we can look ahead to MediaType);
|
302
|
+
Notes => 'stereo only',
|
303
|
+
RawConv => q{
|
304
|
+
$$self{MediaType} = $val & 0xff;
|
305
|
+
return undef unless $$self{MediaType} == 1;
|
306
|
+
return(($val >> 24) & 0xff);
|
307
|
+
},
|
308
|
+
},
|
309
|
+
0x08 => {
|
310
|
+
Name => 'HdrLength',
|
311
|
+
Format => 'int16u',
|
312
|
+
Hidden => 1,
|
313
|
+
RawConv => '$$self{HdrLength} = $val; undef',
|
314
|
+
},
|
315
|
+
0x0b => {
|
316
|
+
Name => 'JPSFlags',
|
317
|
+
PrintConv => { BITMASK => {
|
318
|
+
0 => 'Half height',
|
319
|
+
1 => 'Half width',
|
320
|
+
2 => 'Left field first',
|
321
|
+
}},
|
322
|
+
},
|
323
|
+
0x0c => [{
|
324
|
+
Name => 'JPSLayout',
|
325
|
+
Condition => '$$self{MediaType} == 0',
|
326
|
+
Notes => 'mono',
|
327
|
+
PrintConv => {
|
328
|
+
0 => 'Both Eyes',
|
329
|
+
1 => 'Left Eye',
|
330
|
+
2 => 'Right Eye',
|
331
|
+
},
|
332
|
+
},{
|
333
|
+
Name => 'JPSLayout',
|
334
|
+
Condition => '$$self{MediaType} == 1',
|
335
|
+
Notes => 'stereo',
|
336
|
+
PrintConv => {
|
337
|
+
1 => 'Interleaved',
|
338
|
+
2 => 'Side By Side',
|
339
|
+
3 => 'Over Under',
|
340
|
+
4 => 'Anaglyph',
|
341
|
+
},
|
342
|
+
}],
|
343
|
+
0x0d => {
|
344
|
+
Name => 'JPSType',
|
345
|
+
Hook => '$varSize += $$self{HdrLength} - 4', # comment starts after header block
|
346
|
+
PrintConv => { 0 => 'Mono', 1 => 'Stereo' },
|
347
|
+
},
|
348
|
+
# 0x0e - in16u comment length (ignored -- assume the remainder is all comment)
|
349
|
+
# (this is offset if we had a 4-byte JPS header block)
|
350
|
+
0x10 => {
|
351
|
+
Name => 'JPSComment',
|
352
|
+
Format => 'string',
|
353
|
+
},
|
354
|
+
);
|
355
|
+
|
290
356
|
# EPPIM APP6 (Toshiba PrintIM) segment (ref PH, from PDR-M700 samples)
|
291
357
|
%Image::ExifTool::JPEG::EPPIM = (
|
292
358
|
GROUPS => { 0 => 'APP6', 1 => 'EPPIM', 2 => 'Image' },
|
@@ -545,7 +611,7 @@ sub ProcessJPEG_HDR($$$);
|
|
545
611
|
},
|
546
612
|
2 => {
|
547
613
|
Name => 'ImageFormat',
|
548
|
-
ValueConv => 'chr($val)',
|
614
|
+
ValueConv => 'chr($val & 0xff)',
|
549
615
|
PrintConv => { B => 'IMode B' },
|
550
616
|
},
|
551
617
|
3 => {
|
@@ -14,7 +14,7 @@ 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.05';
|
18
18
|
|
19
19
|
sub ProcessJSON($$);
|
20
20
|
sub ProcessTag($$$$%);
|
@@ -83,8 +83,12 @@ sub ProcessTag($$$$%)
|
|
83
83
|
FoundTag($et, $tagTablePtr, $tag, $val, %flags, Struct => 1);
|
84
84
|
return unless $et->Options('Struct') > 1;
|
85
85
|
}
|
86
|
-
|
87
|
-
|
86
|
+
# support hashes with ordered keys
|
87
|
+
my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val;
|
88
|
+
foreach (@keys) {
|
89
|
+
my $tg = $tag . ((/^\d/ and $tag =~ /\d$/) ? '_' : '') . ucfirst;
|
90
|
+
$tg =~ s/([^a-zA-Z])([a-z])/$1\U$2/g;
|
91
|
+
ProcessTag($et, $tagTablePtr, $tg, $$val{$_}, %flags, Flat => 1);
|
88
92
|
}
|
89
93
|
} elsif (ref $val eq 'ARRAY') {
|
90
94
|
foreach (@$val) {
|
@@ -16,7 +16,7 @@ use strict;
|
|
16
16
|
use vars qw($VERSION);
|
17
17
|
use Image::ExifTool qw(:DataAccess :Utils);
|
18
18
|
|
19
|
-
$VERSION = '1.
|
19
|
+
$VERSION = '1.32';
|
20
20
|
|
21
21
|
sub ProcessJpeg2000Box($$$);
|
22
22
|
sub ProcessJUMD($$$);
|
@@ -42,8 +42,9 @@ my %jp2Map = (
|
|
42
42
|
'UUID-IPTC' => 'JP2',
|
43
43
|
'UUID-EXIF' => 'JP2',
|
44
44
|
'UUID-XMP' => 'JP2',
|
45
|
-
|
46
|
-
|
45
|
+
jp2h => 'JP2',
|
46
|
+
colr => 'jp2h',
|
47
|
+
ICC_Profile => 'colr',
|
47
48
|
IFD1 => 'IFD0',
|
48
49
|
EXIF => 'IFD0', # to write EXIF as a block
|
49
50
|
ExifIFD => 'IFD0',
|
@@ -116,9 +117,6 @@ my %j2cMarker = (
|
|
116
117
|
0x76 => 'NLT', # non-linearity point transformation
|
117
118
|
);
|
118
119
|
|
119
|
-
my %jumbfTypes = (
|
120
|
-
);
|
121
|
-
|
122
120
|
# JPEG 2000 "box" (ie. atom) names
|
123
121
|
# Note: only tags with a defined "Format" are extracted
|
124
122
|
%Image::ExifTool::Jpeg2000::Main = (
|
@@ -127,10 +125,13 @@ my %jumbfTypes = (
|
|
127
125
|
WRITE_PROC => \&ProcessJpeg2000Box,
|
128
126
|
PREFERRED => 1, # always add these tags when writing
|
129
127
|
NOTES => q{
|
130
|
-
The tags below are
|
131
|
-
|
132
|
-
tags in Jpeg2000 images.
|
128
|
+
The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG
|
129
|
+
images, but not all of these are extracted. Note that ExifTool currently
|
130
|
+
writes only EXIF, IPTC and XMP tags in Jpeg2000 images.
|
133
131
|
},
|
132
|
+
#
|
133
|
+
# NOTE: ONLY TAGS WITH "Format" DEFINED ARE EXTRACTED!
|
134
|
+
#
|
134
135
|
'jP ' => 'JP2Signature', # (ref 1)
|
135
136
|
"jP\x1a\x1a" => 'JP2Signature', # (ref 2)
|
136
137
|
prfl => 'Profile',
|
@@ -340,10 +341,20 @@ my %jumbfTypes = (
|
|
340
341
|
},
|
341
342
|
{
|
342
343
|
Name => 'UUID-Signature', # (seen in JUMB data of JPEG images)
|
344
|
+
# (may be able to remove this when JUMBF specification is finalized)
|
343
345
|
Condition => '$$valPt=~/^casg\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
|
344
346
|
Format => 'undef',
|
345
347
|
ValueConv => 'substr($val,16)',
|
346
348
|
},
|
349
|
+
{
|
350
|
+
Name => 'UUID-C2PAClaimSignature', # (seen in incorrectly-formatted JUMB data of JPEG images)
|
351
|
+
# (may be able to remove this when JUMBF specification is finalized)
|
352
|
+
Condition => '$$valPt=~/^c2cs\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/',
|
353
|
+
SubDirectory => {
|
354
|
+
TagTable => 'Image::ExifTool::CBOR::Main',
|
355
|
+
Start => '$valuePtr + 16',
|
356
|
+
},
|
357
|
+
},
|
347
358
|
{
|
348
359
|
Name => 'UUID-Unknown',
|
349
360
|
},
|
@@ -386,6 +397,27 @@ my %jumbfTypes = (
|
|
386
397
|
},
|
387
398
|
SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' },
|
388
399
|
},
|
400
|
+
cbor => {
|
401
|
+
Name => 'CBORData',
|
402
|
+
Flags => [ 'Binary', 'Protected' ],
|
403
|
+
SubDirectory => { TagTable => 'Image::ExifTool::CBOR::Main' },
|
404
|
+
},
|
405
|
+
bfdb => { # used in JUMBF (see # (used when tag is renamed according to JUMDLabel)
|
406
|
+
Name => 'BinaryDataType',
|
407
|
+
Notes => 'JUMBF, MIME type and optional file name',
|
408
|
+
Format => 'undef',
|
409
|
+
# (ignore "toggles" byte and just extract MIME type and file name)
|
410
|
+
ValueConv => '$_=substr($val,1); s/\0+$//; s/\0/, /; $_',
|
411
|
+
JUMBF_Suffix => 'Type', # (used when tag is renamed according to JUMDLabel)
|
412
|
+
},
|
413
|
+
bidb => { # used in JUMBF
|
414
|
+
Name => 'BinaryData',
|
415
|
+
Notes => 'JUMBF',
|
416
|
+
Groups => { 2 => 'Preview' },
|
417
|
+
Format => 'undef',
|
418
|
+
Binary => 1,
|
419
|
+
JUMBF_Suffix => 'Data', # (used when tag is renamed according to JUMDLabel)
|
420
|
+
},
|
389
421
|
#
|
390
422
|
# stuff seen in JPEG XL images:
|
391
423
|
#
|
@@ -529,11 +561,31 @@ my %jumbfTypes = (
|
|
529
561
|
|
530
562
|
%Image::ExifTool::Jpeg2000::ColorSpec = (
|
531
563
|
PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
|
564
|
+
WRITE_PROC => \&Image::ExifTool::WriteBinaryData, # (we don't actually call this)
|
532
565
|
GROUPS => { 2 => 'Image' },
|
533
566
|
FORMAT => 'int8s',
|
567
|
+
WRITABLE => 1,
|
568
|
+
WRITE_GROUP => 'colr',
|
569
|
+
DATAMEMBER => [ 0 ],
|
570
|
+
IS_SUBDIR => [ 3 ],
|
571
|
+
NOTES => q{
|
572
|
+
The table below contains tags in the color specification (colr) box. This
|
573
|
+
box may be rewritten by writing either ICC_Profile, ColorSpace or
|
574
|
+
ColorSpecData. When writing, any existing colr boxes are replaced with the
|
575
|
+
newly created colr box.
|
576
|
+
|
577
|
+
B<NOTE>: Care must be taken when writing this color specification because
|
578
|
+
writing a specification that is incompatible with the image data may make
|
579
|
+
the image undisplayable.
|
580
|
+
},
|
534
581
|
0 => {
|
535
582
|
Name => 'ColorSpecMethod',
|
536
583
|
RawConv => '$$self{ColorSpecMethod} = $val',
|
584
|
+
Protected => 1,
|
585
|
+
Notes => q{
|
586
|
+
default for writing is 2 when writing ICC_Profile, 1 when writing
|
587
|
+
ColorSpace, or 4 when writing ColorSpecData
|
588
|
+
},
|
537
589
|
PrintConv => {
|
538
590
|
1 => 'Enumerated',
|
539
591
|
2 => 'Restricted ICC',
|
@@ -541,9 +593,15 @@ my %jumbfTypes = (
|
|
541
593
|
4 => 'Vendor Color',
|
542
594
|
},
|
543
595
|
},
|
544
|
-
1 =>
|
596
|
+
1 => {
|
597
|
+
Name => 'ColorSpecPrecedence',
|
598
|
+
Notes => 'default for writing is 0',
|
599
|
+
Protected => 1,
|
600
|
+
},
|
545
601
|
2 => {
|
546
602
|
Name => 'ColorSpecApproximation',
|
603
|
+
Notes => 'default for writing is 0',
|
604
|
+
Protected => 1,
|
547
605
|
PrintConv => {
|
548
606
|
0 => 'Not Specified',
|
549
607
|
1 => 'Accurate',
|
@@ -568,6 +626,7 @@ my %jumbfTypes = (
|
|
568
626
|
Name => 'ColorSpace',
|
569
627
|
Condition => '$$self{ColorSpecMethod} == 1',
|
570
628
|
Format => 'int32u',
|
629
|
+
Protected => 1,
|
571
630
|
PrintConv => { # ref 15444-2 2002-05-15
|
572
631
|
0 => 'Bi-level',
|
573
632
|
1 => 'YCbCr(1)',
|
@@ -597,6 +656,8 @@ my %jumbfTypes = (
|
|
597
656
|
{
|
598
657
|
Name => 'ColorSpecData',
|
599
658
|
Format => 'undef[$size-3]',
|
659
|
+
Writable => 'undef',
|
660
|
+
Protected => 1,
|
600
661
|
Binary => 1,
|
601
662
|
},
|
602
663
|
],
|
@@ -607,23 +668,24 @@ my %jumbfTypes = (
|
|
607
668
|
PROCESS_PROC => \&ProcessJUMD,
|
608
669
|
GROUPS => { 0 => 'JUMBF', 1 => 'JUMBF', 2 => 'Image' },
|
609
670
|
NOTES => 'Information extracted from the JUMBF description box.',
|
610
|
-
'
|
671
|
+
'type' => {
|
611
672
|
Name => 'JUMDType',
|
612
673
|
ValueConv => 'unpack "H*", $val',
|
613
674
|
PrintConv => q{
|
614
675
|
my @a = $val =~ /^(\w{8})(\w{4})(\w{4})(\w{16})$/;
|
615
676
|
return $val unless @a;
|
616
677
|
my $ascii = pack 'H*', $a[0];
|
617
|
-
$a[0] = $ascii if $ascii =~ /^[a-zA-Z0-9]{4}$/;
|
678
|
+
$a[0] = "($ascii)" if $ascii =~ /^[a-zA-Z0-9]{4}$/;
|
618
679
|
return join '-', @a;
|
619
680
|
},
|
620
681
|
# seen:
|
621
682
|
# cacb/cast/caas/cacl/casg/json-00110010800000aa00389b71
|
622
683
|
# 6579d6fbdba2446bb2ac1b82feeb89d1 - JPEG image
|
623
684
|
},
|
624
|
-
'
|
625
|
-
'
|
626
|
-
Name => '
|
685
|
+
'label' => { Name => 'JUMDLabel' },
|
686
|
+
'toggles' => {
|
687
|
+
Name => 'JUMDToggles',
|
688
|
+
Unknown => 1,
|
627
689
|
PrintConv => { BITMASK => {
|
628
690
|
0 => 'Requestable',
|
629
691
|
1 => 'Label',
|
@@ -631,8 +693,8 @@ my %jumbfTypes = (
|
|
631
693
|
3 => 'Signature',
|
632
694
|
}},
|
633
695
|
},
|
634
|
-
'
|
635
|
-
'
|
696
|
+
'id' => { Name => 'JUMDID', Description => 'JUMD ID' },
|
697
|
+
'sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' },
|
636
698
|
);
|
637
699
|
|
638
700
|
#------------------------------------------------------------------------------
|
@@ -675,20 +737,21 @@ sub ProcessJUMD($$$)
|
|
675
737
|
delete $$et{JUMBFLabel};
|
676
738
|
$$dirInfo{DirLen} < 17 and $et->Warn('Truncated JUMD directory'), return 0;
|
677
739
|
my $type = substr($$dataPt, $pos, 4);
|
678
|
-
$et->HandleTag($tagTablePtr, '
|
740
|
+
$et->HandleTag($tagTablePtr, 'type', substr($$dataPt, $pos, 16));
|
679
741
|
$pos += 16;
|
680
742
|
my $flags = Get8u($dataPt, $pos++);
|
681
|
-
$et->HandleTag($tagTablePtr, '
|
743
|
+
$et->HandleTag($tagTablePtr, 'toggles', $flags);
|
682
744
|
if ($flags & 0x02) { # label exists?
|
683
745
|
pos($$dataPt) = $pos;
|
684
746
|
$$dataPt =~ /\0/g or $et->Warn('Missing JUMD label terminator'), return 0;
|
685
747
|
my $len = pos($$dataPt) - $pos;
|
686
748
|
my $name = substr($$dataPt, $pos, $len);
|
687
|
-
$et->HandleTag($tagTablePtr, '
|
749
|
+
$et->HandleTag($tagTablePtr, 'label', $name);
|
688
750
|
$pos += $len;
|
689
751
|
if ($len) {
|
690
752
|
$name =~ s/[^-_a-zA-Z0-9]([a-z])/\U$1/g; # capitalize characters after illegal characters
|
691
753
|
$name =~ tr/-_a-zA-Z0-9//dc; # remove other illegal characters
|
754
|
+
$name =~ s/__/_/; # collapse double underlines
|
692
755
|
$name = ucfirst $name; # capitalize first letter
|
693
756
|
$name = "Tag$name" if length($name) < 2; # must at least 2 characters long
|
694
757
|
$$et{JUMBFLabel} = $name;
|
@@ -696,12 +759,12 @@ sub ProcessJUMD($$$)
|
|
696
759
|
}
|
697
760
|
if ($flags & 0x04) { # ID exists?
|
698
761
|
$pos + 4 > $end and $et->Warn('Missing JUMD ID'), return 0;
|
699
|
-
$et->HandleTag($tagTablePtr, '
|
762
|
+
$et->HandleTag($tagTablePtr, 'id', Get32u($dataPt, $pos));
|
700
763
|
$pos += 4;
|
701
764
|
}
|
702
765
|
if ($flags & 0x08) { # signature exists?
|
703
766
|
$pos + 32 > $end and $et->Warn('Missing JUMD signature'), return 0;
|
704
|
-
$et->HandleTag($tagTablePtr, '
|
767
|
+
$et->HandleTag($tagTablePtr, 'sig', substr($$dataPt, $pos, 32));
|
705
768
|
$pos += 32;
|
706
769
|
}
|
707
770
|
$pos == $end or $et->Warn('Extra data in JUMD box'." $pos $end", 1);
|
@@ -784,6 +847,48 @@ sub CreateNewBoxes($$)
|
|
784
847
|
return 1;
|
785
848
|
}
|
786
849
|
|
850
|
+
#------------------------------------------------------------------------------
|
851
|
+
# Create Color Specification Box
|
852
|
+
# Inputs: 0) ExifTool object ref, 1) Output file or scalar ref
|
853
|
+
# Returns: 1 on success
|
854
|
+
sub CreateColorSpec($$)
|
855
|
+
{
|
856
|
+
my ($et, $outfile) = @_;
|
857
|
+
my $meth = $et->GetNewValue('Jpeg2000:ColorSpecMethod');
|
858
|
+
my $prec = $et->GetNewValue('Jpeg2000:ColorSpecPrecedence') || 0;
|
859
|
+
my $approx = $et->GetNewValue('Jpeg2000:ColorSpecApproximation') || 0;
|
860
|
+
my $icc = $et->GetNewValue('ICC_Profile');
|
861
|
+
my $space = $et->GetNewValue('Jpeg2000:ColorSpace');
|
862
|
+
my $cdata = $et->GetNewValue('Jpeg2000:ColorSpecData');
|
863
|
+
unless ($meth) {
|
864
|
+
if ($icc) {
|
865
|
+
$meth = 2;
|
866
|
+
} elsif (defined $space) {
|
867
|
+
$meth = 1;
|
868
|
+
} elsif (defined $cdata) {
|
869
|
+
$meth = 4;
|
870
|
+
} else {
|
871
|
+
$et->Warn('Color space not defined'), return 0;
|
872
|
+
}
|
873
|
+
}
|
874
|
+
if ($meth eq '1') {
|
875
|
+
defined $space or $et->Warn('Must specify ColorSpace'), return 0;
|
876
|
+
$cdata = pack('N', $space);
|
877
|
+
} elsif ($meth eq '2' or $meth eq '3') {
|
878
|
+
defined $icc or $et->Warn('Must specify ICC_Profile'), return 0;
|
879
|
+
$cdata = $icc;
|
880
|
+
} elsif ($meth eq '4') {
|
881
|
+
defined $cdata or $et->Warn('Must specify ColorSpecData'), return 0;
|
882
|
+
} else {
|
883
|
+
$et->Warn('Unknown ColorSpecMethod'), return 0;
|
884
|
+
}
|
885
|
+
my $boxhdr = pack('N', length($cdata) + 11) . 'colr';
|
886
|
+
Write($outfile, $boxhdr, pack('CCC',$meth,$prec,$approx), $cdata) or return 0;
|
887
|
+
++$$et{CHANGED};
|
888
|
+
$et->VPrint(1, " + Jpeg2000:ColorSpec\n");
|
889
|
+
return 1;
|
890
|
+
}
|
891
|
+
|
787
892
|
#------------------------------------------------------------------------------
|
788
893
|
# Process JPEG 2000 box
|
789
894
|
# Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) Pointer to tag table
|
@@ -801,7 +906,7 @@ sub ProcessJpeg2000Box($$$)
|
|
801
906
|
my $raf = $$dirInfo{RAF};
|
802
907
|
my $outfile = $$dirInfo{OutFile};
|
803
908
|
my $dirEnd = $dirStart + $dirLen;
|
804
|
-
my ($err, $outBuff, $verbose);
|
909
|
+
my ($err, $outBuff, $verbose, $doColour);
|
805
910
|
|
806
911
|
if ($outfile) {
|
807
912
|
unless ($raf) {
|
@@ -809,13 +914,19 @@ sub ProcessJpeg2000Box($$$)
|
|
809
914
|
$outBuff = '';
|
810
915
|
$outfile = \$outBuff;
|
811
916
|
}
|
917
|
+
# determine if we will be writing colr box
|
918
|
+
if ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'JP2Header') {
|
919
|
+
$doColour = 2 if defined $et->GetNewValue('ColorSpecMethod') or $et->GetNewValue('ICC_Profile') or
|
920
|
+
defined $et->GetNewValue('ColorSpecPrecedence') or defined $et->GetNewValue('ColorSpace') or
|
921
|
+
defined $et->GetNewValue('ColorSpecApproximation') or defined $et->GetNewValue('ColorSpecData');
|
922
|
+
}
|
812
923
|
} else {
|
813
924
|
# (must not set verbose flag when writing!)
|
814
925
|
$verbose = $$et{OPTIONS}{Verbose};
|
815
926
|
$et->VerboseDir($$dirInfo{DirName}) if $verbose;
|
816
927
|
}
|
817
928
|
# loop through all contained boxes
|
818
|
-
my ($pos, $boxLen);
|
929
|
+
my ($pos, $boxLen, $lastBox);
|
819
930
|
for ($pos=$dirStart; ; $pos+=$boxLen) {
|
820
931
|
my ($boxID, $buff, $valuePtr);
|
821
932
|
my $hdrLen = 8; # the box header length
|
@@ -824,9 +935,7 @@ sub ProcessJpeg2000Box($$$)
|
|
824
935
|
my $n = $raf->Read($buff,$hdrLen);
|
825
936
|
unless ($n == $hdrLen) {
|
826
937
|
$n and $err = '', last;
|
827
|
-
|
828
|
-
CreateNewBoxes($et, $outfile) or $err = 1;
|
829
|
-
}
|
938
|
+
CreateNewBoxes($et, $outfile) or $err = 1 if $outfile;
|
830
939
|
last;
|
831
940
|
}
|
832
941
|
$dataPt = \$buff;
|
@@ -838,6 +947,17 @@ sub ProcessJpeg2000Box($$$)
|
|
838
947
|
}
|
839
948
|
$boxLen = unpack("x$pos N",$$dataPt); # (length includes header and data)
|
840
949
|
$boxID = substr($$dataPt, $pos+4, 4);
|
950
|
+
# remove old colr boxes if necessary
|
951
|
+
if ($doColour and $boxID eq 'colr') {
|
952
|
+
if ($doColour == 1) { # did we successfully write the new colr box?
|
953
|
+
$et->VPrint(1," - Jpeg2000:ColorSpec\n");
|
954
|
+
++$$et{CHANGED};
|
955
|
+
next;
|
956
|
+
}
|
957
|
+
$et->Warn('Out-of-order colr box encountered');
|
958
|
+
undef $doColour;
|
959
|
+
}
|
960
|
+
$lastBox = $boxID;
|
841
961
|
$pos += $hdrLen; # move to end of box header
|
842
962
|
if ($boxLen == 1) {
|
843
963
|
# box header contains an additional 8-byte integer for length
|
@@ -931,6 +1051,14 @@ sub ProcessJpeg2000Box($$$)
|
|
931
1051
|
}
|
932
1052
|
}
|
933
1053
|
}
|
1054
|
+
# create new tag for JUMBF data values with name corresponding to JUMBFLabel
|
1055
|
+
if ($tagInfo and $$et{JUMBFLabel} and (not $$tagInfo{SubDirectory} or $$tagInfo{BlockExtract})) {
|
1056
|
+
$tagInfo = { %$tagInfo, Name => $$et{JUMBFLabel} . ($$tagInfo{JUMBF_Suffix} || '') };
|
1057
|
+
delete $$tagInfo{Description};
|
1058
|
+
AddTagToTable($tagTablePtr, '_JUMBF_' . $$et{JUMBFLabel}, $tagInfo);
|
1059
|
+
delete $$tagInfo{Protected}; # (must do this so -j -b returns JUMBF binary data)
|
1060
|
+
$$tagInfo{TagID} = $boxID;
|
1061
|
+
}
|
934
1062
|
if ($verbose) {
|
935
1063
|
$et->VerboseInfo($boxID, $tagInfo,
|
936
1064
|
Table => $tagTablePtr,
|
@@ -941,13 +1069,6 @@ sub ProcessJpeg2000Box($$$)
|
|
941
1069
|
);
|
942
1070
|
next unless $tagInfo;
|
943
1071
|
}
|
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
|
-
}
|
951
1072
|
if ($$tagInfo{SubDirectory}) {
|
952
1073
|
my $subdir = $$tagInfo{SubDirectory};
|
953
1074
|
my $subdirStart = $valuePtr;
|
@@ -975,8 +1096,10 @@ sub ProcessJpeg2000Box($$$)
|
|
975
1096
|
# remove this directory from our create list
|
976
1097
|
delete $$et{AddJp2Dirs}{$$tagInfo{Name}};
|
977
1098
|
my $newdir;
|
978
|
-
# only edit writable UUID and
|
979
|
-
if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL})
|
1099
|
+
# only edit writable UUID, Exif and jp2h boxes
|
1100
|
+
if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL}) or
|
1101
|
+
($boxID eq 'jp2h' and $$et{EDIT_DIRS}{jp2h}))
|
1102
|
+
{
|
980
1103
|
$newdir = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc});
|
981
1104
|
next if defined $newdir and not length $newdir; # next if deleting the box
|
982
1105
|
} elsif (defined $uuid) {
|
@@ -988,6 +1111,11 @@ sub ProcessJpeg2000Box($$$)
|
|
988
1111
|
my $boxhdr = pack('N', length($newdir) + 8 + $prefixLen) . $boxID;
|
989
1112
|
$boxhdr .= substr($$dataPt, $valuePtr, $prefixLen) if $prefixLen;
|
990
1113
|
Write($outfile, $boxhdr, $newdir) or $err = 1;
|
1114
|
+
# write new colr box immediately after ihdr
|
1115
|
+
if ($doColour and $boxID eq 'ihdr') {
|
1116
|
+
# (shouldn't be multiple ihdr boxes, but just in case, write only 1)
|
1117
|
+
$doColour = $doColour==2 ? CreateColorSpec($et, $outfile) : 0;
|
1118
|
+
}
|
991
1119
|
} else {
|
992
1120
|
# extract as a block if specified
|
993
1121
|
$subdirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract};
|
@@ -0,0 +1,153 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: LIF.pm
|
3
|
+
#
|
4
|
+
# Description: Read LIF (Leica Image File) files
|
5
|
+
#
|
6
|
+
# Revisions: 2021-06-21 - P. Harvey Created
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
package Image::ExifTool::LIF;
|
10
|
+
|
11
|
+
use strict;
|
12
|
+
use vars qw($VERSION);
|
13
|
+
use Image::ExifTool qw(:DataAccess :Utils);
|
14
|
+
use Image::ExifTool::XMP;
|
15
|
+
|
16
|
+
$VERSION = '1.00';
|
17
|
+
|
18
|
+
%Image::ExifTool::LIF::Main = (
|
19
|
+
GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' },
|
20
|
+
PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP,
|
21
|
+
VARS => { NO_ID => 1 },
|
22
|
+
NOTES => q{
|
23
|
+
Tags extracted from Leica Image Format (LIF) imaging files. As well as the
|
24
|
+
tags listed below, all available information is extracted from the
|
25
|
+
XML-format metadata in the LIF header.
|
26
|
+
},
|
27
|
+
TimeStampList => {
|
28
|
+
Groups => { 2 => 'Time' },
|
29
|
+
ValueConv => q{
|
30
|
+
my $unixTimeZero = 134774 * 24 * 3600;
|
31
|
+
my @vals = split ' ', $val;
|
32
|
+
foreach (@vals) {
|
33
|
+
$_ = 1e-7 * hex($_);
|
34
|
+
# shift from Jan 1, 1601 to Jan 1, 1970
|
35
|
+
$_ = Image::ExifTool::ConvertUnixTime($_ - $unixTimeZero);
|
36
|
+
}
|
37
|
+
return \@vals;
|
38
|
+
},
|
39
|
+
},
|
40
|
+
);
|
41
|
+
|
42
|
+
#------------------------------------------------------------------------------
|
43
|
+
# Shorten obscenely long LIF tag names
|
44
|
+
# Inputs: Tag name
|
45
|
+
# Returns: Shortened tag name
|
46
|
+
sub ShortenTagNames($)
|
47
|
+
{
|
48
|
+
local $_;
|
49
|
+
$_ = shift;
|
50
|
+
s/DescriptionDimensionsDimensionDescription/Dimensions/;
|
51
|
+
s/DescriptionChannelsChannelDescription/Channel/;
|
52
|
+
s/ShutterListShutter/Shutter/;
|
53
|
+
s/SettingDefinition/Setting/;
|
54
|
+
s/AdditionalZPositionListAdditionalZPosition/AdditionalZPosition/;
|
55
|
+
s/LMSDataContainerHeader//g;
|
56
|
+
s/FilterWheelWheel/FilterWheel/;
|
57
|
+
s/FilterWheelFilter/FilterWheel/;
|
58
|
+
s/DetectorListDetector/Detector/;
|
59
|
+
s/OnlineDyeSeparationOnlineDyeSeparation/OnlineDyeSeparation/;
|
60
|
+
s/AotfListAotf/Aotf/;
|
61
|
+
s/SettingAotfLaserLineSetting/SettingAotfLaser/;
|
62
|
+
s/DataROISetROISet/DataROISet/;
|
63
|
+
s/AdditionalZPosition/AddZPos/;
|
64
|
+
s/FRAPplusBlock_FRAPBlock_FRAP_PrePost_Info/FRAP_/;
|
65
|
+
s/FRAPplusBlock_FRAPBlock_FRAP_(Master)?/FRAP_/;
|
66
|
+
s/LDM_Block_SequentialLDM_Block_Sequential_/LDM_/;
|
67
|
+
s/ATLConfocalSetting/ATLConfocal/;
|
68
|
+
s/LaserArrayLaser/Laser/;
|
69
|
+
s/LDM_Master/LDM_/;
|
70
|
+
s/(List)?ATLConfocal/ATL_/;
|
71
|
+
s/Separation/Sep/;
|
72
|
+
s/BleachPointsElement/BleachPoint/;
|
73
|
+
s/BeamPositionBeamPosition/BeamPosition/;
|
74
|
+
s/DataROISetPossible(ROI)?/DataROISet/;
|
75
|
+
s/RoiElementChildrenElementDataROISingle(Roi)?/Roi/;
|
76
|
+
s/InfoLaserLineSettingArrayLaserLineSetting/LastLineSetting/;
|
77
|
+
s/FilterWheelWheelNameFilterName/FilterWheelFilterName/;
|
78
|
+
s/LUT_ListLut/Lut/;
|
79
|
+
s/ROI_ListRoiRoidata/ROI_/;
|
80
|
+
s/LaserLineSettingArrayLaserLineSetting/LaserLineSetting/;
|
81
|
+
return $_;
|
82
|
+
}
|
83
|
+
|
84
|
+
#------------------------------------------------------------------------------
|
85
|
+
# Extract metadata from a LIF image
|
86
|
+
# Inputs: 0) ExifTool object reference, 1) dirInfo reference
|
87
|
+
# Returns: 1 on success, 0 if this wasn't a valid LIF file
|
88
|
+
sub ProcessLIF($$)
|
89
|
+
{
|
90
|
+
my ($et, $dirInfo) = @_;
|
91
|
+
my $raf = $$dirInfo{RAF};
|
92
|
+
my $buff;
|
93
|
+
|
94
|
+
# verify this is a valid LIF file
|
95
|
+
return 0 unless $raf->Read($buff, 15) == 15 and $buff =~ /^\x70\0{3}.{4}\x2a.{4}<\0/s;
|
96
|
+
|
97
|
+
$et->SetFileType();
|
98
|
+
SetByteOrder('II');
|
99
|
+
|
100
|
+
my $size = Get32u(\$buff, 4); # XML chunk size
|
101
|
+
my $len = Get32u(\$buff, 9) * 2; # XML data length
|
102
|
+
|
103
|
+
$size < $len and $et->Error('Corrupted LIF XML block'), return 1;
|
104
|
+
$size > 100000000 and $et->Error('LIF XML block too large'), return 1;
|
105
|
+
|
106
|
+
$raf->Seek(-2, 1) and $raf->Read($buff, $len) == $len or $et->Error('Truncated LIF XML block'), return 1;
|
107
|
+
|
108
|
+
my $tagTablePtr = GetTagTable('Image::ExifTool::LIF::Main');
|
109
|
+
|
110
|
+
# convert from UCS2 to UTF8
|
111
|
+
my $xml = Image::ExifTool::Decode($et, $buff, 'UCS2', 'II', 'UTF8');
|
112
|
+
|
113
|
+
my %dirInfo = ( DataPt => \$xml );
|
114
|
+
|
115
|
+
$$et{XmpIgnoreProps} = [ 'LMSDataContainerHeader', 'Element', 'Children', 'Data', 'Image', 'Attachment' ];
|
116
|
+
$$et{ShortenXmpTags} = \&ShortenTagNames;
|
117
|
+
|
118
|
+
$et->ProcessDirectory(\%dirInfo, $tagTablePtr);
|
119
|
+
|
120
|
+
return 1;
|
121
|
+
}
|
122
|
+
|
123
|
+
1; # end
|
124
|
+
|
125
|
+
__END__
|
126
|
+
|
127
|
+
=head1 NAME
|
128
|
+
|
129
|
+
Image::ExifTool::LIF - Read LIF meta information
|
130
|
+
|
131
|
+
=head1 SYNOPSIS
|
132
|
+
|
133
|
+
This module is used by Image::ExifTool
|
134
|
+
|
135
|
+
=head1 DESCRIPTION
|
136
|
+
|
137
|
+
This module contains definitions required by Image::ExifTool to read
|
138
|
+
metadata from Leica Image File (LIF) images.
|
139
|
+
|
140
|
+
=head1 AUTHOR
|
141
|
+
|
142
|
+
Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
|
143
|
+
|
144
|
+
This library is free software; you can redistribute it and/or modify it
|
145
|
+
under the same terms as Perl itself.
|
146
|
+
|
147
|
+
=head1 SEE ALSO
|
148
|
+
|
149
|
+
L<Image::ExifTool::TagNames/LIF Tags>,
|
150
|
+
L<Image::ExifTool(3pm)|Image::ExifTool>
|
151
|
+
|
152
|
+
=cut
|
153
|
+
|