exiftool_vendored 12.25.0 → 12.35.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 +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
|
+
|