File Coverage

blib/lib/Image/ExifTool/JPEG.pm
Criterion Covered Total %
statement 21 32 65.6
branch 2 8 25.0
condition n/a
subroutine 4 5 80.0
pod 0 2 0.0
total 27 47 57.4


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: JPEG.pm
3             #
4             # Description: Definitions for uncommon JPEG segments
5             #
6             # Revisions: 10/06/2006 - P. Harvey Created
7             #------------------------------------------------------------------------------
8              
9             package Image::ExifTool::JPEG;
10 12     12   99 use strict;
  12         35  
  12         644  
11 12     12   109 use vars qw($VERSION);
  12         26  
  12         1020  
12 12     12   108 use Image::ExifTool qw(:DataAccess :Utils);
  12         30  
  12         36710  
13              
14             $VERSION = '1.40';
15              
16             sub ProcessOcad($$$);
17             sub ProcessJPEG_HDR($$$);
18              
19             # (most of the tags in this table are for documentation purposes only)
20             %Image::ExifTool::JPEG::Main = (
21             NOTES => q{
22             This table lists information extracted by ExifTool from JPEG images. See
23             L for the JPEG specification.
24             },
25             APP0 => [{
26             Name => 'JFIF',
27             Condition => '$$valPt =~ /^JFIF\0/',
28             SubDirectory => { TagTable => 'Image::ExifTool::JFIF::Main' },
29             }, {
30             Name => 'JFXX',
31             Condition => '$$valPt =~ /^JFXX\0\x10/',
32             SubDirectory => { TagTable => 'Image::ExifTool::JFIF::Extension' },
33             }, {
34             Name => 'CIFF',
35             Condition => '$$valPt =~ /^(II|MM).{4}HEAPJPGM/s',
36             SubDirectory => { TagTable => 'Image::ExifTool::CanonRaw::Main' },
37             }, {
38             Name => 'AVI1',
39             Condition => '$$valPt =~ /^AVI1/',
40             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::AVI1' },
41             }, {
42             Name => 'Ocad',
43             Condition => '$$valPt =~ /^Ocad/',
44             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::Ocad' },
45             }],
46             APP1 => [{
47             Name => 'EXIF',
48             Condition => '$$valPt =~ /^Exif\0/',
49             SubDirectory => { TagTable => 'Image::ExifTool::Exif::Main' },
50             }, {
51             Name => 'ExtendedXMP',
52             Condition => '$$valPt =~ m{^http://ns.adobe.com/xmp/extension/\0}',
53             SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
54             }, {
55             Name => 'XMP',
56             Condition => '$$valPt =~ /^http/ or $$valPt =~ /
57             SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
58             }, {
59             Name => 'QVCI',
60             Condition => '$$valPt =~ /^QVCI\0/',
61             SubDirectory => { TagTable => 'Image::ExifTool::Casio::QVCI' },
62             }, {
63             Name => 'FLIR',
64             Condition => '$$valPt =~ /^FLIR\0/',
65             SubDirectory => { TagTable => 'Image::ExifTool::FLIR::FFF' },
66             }, {
67             Name => 'RawThermalImage', # (from Parrot Bebop-Pro Thermal drone)
68             Condition => '$$valPt =~ /^PARROT\0(II\x2a\0|MM\0\x2a)/',
69             Groups => { 0 => 'APP1', 1 => 'Parrot', 2 => 'Preview' },
70             Notes => 'thermal image from Parrot Bebop-Pro Thermal drone',
71             RawConv => 'substr($val, 7)',
72             Binary => 1,
73             }],
74             APP2 => [{
75             Name => 'ICC_Profile',
76             Condition => '$$valPt =~ /^ICC_PROFILE\0/',
77             SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' },
78             }, {
79             Name => 'FPXR',
80             Condition => '$$valPt =~ /^FPXR\0/',
81             SubDirectory => { TagTable => 'Image::ExifTool::FlashPix::Main' },
82             }, {
83             Name => 'MPF',
84             Condition => '$$valPt =~ /^MPF\0/',
85             SubDirectory => { TagTable => 'Image::ExifTool::MPF::Main' },
86             }, {
87             Name => 'InfiRayVersion',
88             Condition => '$$valPt =~ /^....IJPEG\0/s',
89             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Version' },
90             }, {
91             Name => 'UniformResourceName',
92             Groups => { 1 => 'APP2' },
93             Condition => '$$valPt =~ /^urn:/',
94             Notes => 'used in Apple HDR images',
95             }, {
96             Name => 'PreviewImage',
97             Condition => '$$valPt =~ /^(|QVGA\0|BGTH)\xff\xd8\xff\xdb/',
98             Notes => 'Samsung APP2 preview image', # (Samsung/GoPro="", BenQ="QVGA\0", Digilife="BGTH")
99             }],
100             APP3 => [{
101             Name => 'Meta',
102             Condition => '$$valPt =~ /^(Meta|META|Exif)\0\0/',
103             SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Meta' },
104             }, {
105             Name => 'Stim',
106             Condition => '$$valPt =~ /^Stim\0/',
107             SubDirectory => { TagTable => 'Image::ExifTool::Stim::Main' },
108             }, {
109             Name => 'JPS',
110             Condition => '$$valPt =~ /^_JPSJPS_/',
111             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::JPS' },
112             }, {
113             Name => 'ThermalData', # (written by DJI FLIR models)
114             Condition => '$$self{Make} eq "DJI"',
115             Notes => 'DJI raw thermal data',
116             Groups => { 0 => 'APP3', 1 => 'DJI', 2 => 'Image' },
117             Binary => 1,
118             }, {
119             Name => 'ImagingData', # (written by InfiRay models)
120             Condition => '$$self{HasIJPEG}',
121             Notes => 'InfiRay IR+thermal+visible data',
122             Groups => { 0 => 'APP3', 1 => 'InfiRay', 2 => 'Image' },
123             Binary => 1,
124             }, {
125             Name => 'PreviewImage', # (written by HP R837 and Samsung S1060)
126             Condition => '$$valPt =~ /^\xff\xd8\xff\xdb/',
127             Notes => 'Samsung/HP preview image', # (Samsung, HP, BenQ)
128             }],
129             APP4 => [{
130             Name => 'Scalado',
131             Condition => '$$valPt =~ /^SCALADO\0/',
132             SubDirectory => { TagTable => 'Image::ExifTool::Scalado::Main' },
133             }, {
134             Name => 'FPXR', # (non-standard location written by some HP models)
135             Condition => '$$valPt =~ /^FPXR\0/',
136             SubDirectory => { TagTable => 'Image::ExifTool::FlashPix::Main' },
137             }, {
138             Name => 'QualcommDualCamera',
139             Condition => '$$valPt =~ /^Qualcomm Dual Camera Attributes/',
140             SubDirectory => { TagTable => 'Image::ExifTool::Qualcomm::DualCamera' },
141             }, {
142             Name => 'InfiRayFactory',
143             Condition => '$$self{HasIJPEG}"',
144             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Factory' },
145             }, {
146             Name => 'ThermalParams', # (written by some DJI FLIR models)
147             Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^\xaa\x55\x12\x06/',
148             SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams' },
149             }, {
150             Name => 'ThermalParams2', # (written by M3T)
151             Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^(.{32})?.{32}\x2c\x01\x20\0/s',
152             SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams2' },
153             }, {
154             Name => 'ThermalParams3', # (written by M30T)
155             Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^.{32}\xaa\x55\x38\0/s',
156             SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams3' },
157             }, {
158             Name => 'PreviewImage', # (eg. Samsung S1060)
159             Notes => 'continued from APP3',
160             }],
161             APP5 => [{
162             Name => 'RMETA',
163             Condition => '$$valPt =~ /^RMETA\0/',
164             SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RMETA' },
165             }, {
166             Name => 'SamsungUniqueID',
167             Condition => '$$valPt =~ /ssuniqueid\0/',
168             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::APP5' },
169             }, {
170             Name => 'InfiRayPicture',
171             Condition => '$$self{HasIJPEG}',
172             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Picture' },
173             }, {
174             Name => 'ThermalCalibration', # (written by DJI FLIR models)
175             Condition => '$$self{Make} eq "DJI"',
176             Notes => 'DJI thermal calibration data',
177             Groups => { 0 => 'APP5', 1 => 'DJI', 2 => 'Image' },
178             Binary => 1,
179             }, {
180             Name => 'PreviewImage', # (eg. BenQ DC E1050)
181             Notes => 'continued from APP4',
182             }],
183             APP6 => [{
184             Name => 'EPPIM',
185             Condition => '$$valPt =~ /^EPPIM\0/',
186             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::EPPIM' },
187             }, {
188             Name => 'NITF',
189             Condition => '$$valPt =~ /^NTIF\0/',
190             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::NITF' },
191             }, {
192             Name => 'HP_TDHD', # (written by R837)
193             Condition => '$$valPt =~ /^TDHD\x01\0\0\0/',
194             SubDirectory => { TagTable => 'Image::ExifTool::HP::TDHD' },
195             }, {
196             Name => 'GoPro',
197             Condition => '$$valPt =~ /^GoPro\0/',
198             SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' },
199             }, {
200             Name => 'InfiRayMixMode',
201             Condition => '$$self{HasIJPEG}',
202             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::MixMode' },
203             }, {
204             Name => 'DJI_DTAT', # (written by ZH20T)
205             Condition => '$$valPt =~ /^DTAT\0\0.\{/s',
206             Groups => { 0 => 'APP6', 1 => 'DJI' },
207             Notes => 'DJI Thermal Analysis Tool record',
208             ValueConv => 'substr($val,7)',
209             # also seen Motorola APP6 "MMIMETA\0", with sub-types: AL3A,ALED,MMI0,MOTD,QC3A,LMB1
210             }],
211             APP7 => [{
212             Name => 'Pentax',
213             Condition => '$$valPt =~ /^PENTAX \0/',
214             SubDirectory => { TagTable => 'Image::ExifTool::Pentax::Main' },
215             }, {
216             Name => 'Ricoh',
217             Condition => '$$valPt =~ /^RICOH\0/',
218             SubDirectory => { TagTable => 'Image::ExifTool::Pentax::Main' },
219             }, {
220             Name => 'Huawei',
221             Condition => '$$valPt =~ /^HUAWEI\0\0/',
222             SubDirectory => { TagTable => 'Image::ExifTool::Unknown::Main' },
223             }, {
224             Name => 'Qualcomm',
225             Condition => '$$valPt =~ /^\x1aQualcomm Camera Attributes/',
226             SubDirectory => { TagTable => 'Image::ExifTool::Qualcomm::Main' },
227             }, {
228             Name => 'InfiRayOpMode',
229             Condition => '$$self{HasIJPEG}',
230             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::OpMode' },
231             }, {
232             Name => 'DJI-DBG',
233             Condition => '$$valPt =~ /^DJI-DBG\0/',
234             SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' },
235             }],
236             APP8 => [{
237             Name => 'SPIFF',
238             Condition => '$$valPt =~ /^SPIFF\0/',
239             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::SPIFF' },
240             }, {
241             Name => 'InfiRayIsothermal',
242             Condition => '$$self{HasIJPEG}',
243             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Isothermal' },
244             }, {
245             Name => 'SEAL',
246             Condition => '$$valPt =~ /^SEAL\0/',
247             SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
248             }],
249             APP9 => [{
250             Name => 'MediaJukebox',
251             Condition => '$$valPt =~ /^Media Jukebox\0/',
252             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::MediaJukebox' },
253             }, {
254             Name => 'InfiRaySensor',
255             Condition => '$$self{HasIJPEG}',
256             SubDirectory => { TagTable => 'Image::ExifTool::InfiRay::Sensor' },
257             }, {
258             Name => 'SEAL',
259             Condition => '$$valPt =~ /^SEAL\0/',
260             SubDirectory => { TagTable => 'Image::ExifTool::XMP::SEAL' },
261             }],
262             APP10 => [{
263             Name => 'Comment',
264             Condition => '$$valPt =~ /^UNICODE\0/',
265             Notes => 'PhotoStudio Unicode comment',
266             }, {
267             Name => 'HDRGainInfo', #PH (NC)
268             Condition => '$$valPt =~ /^AROT\0\0.{4}/s',
269             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::HDRGainInfo' },
270             }],
271             APP11 => [{
272             Name => 'JPEG-HDR',
273             Condition => '$$valPt =~ /^HDR_RI /',
274             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::HDR' },
275             }, {
276             Name => 'JUMBF',
277             Condition => '$$valPt =~ /^JP/',
278             SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' },
279             # Note: The suggested options for reading C2PA CAI JUMBF metadata are "-G3 -b -j -u"
280             }],
281             APP12 => [{
282             Name => 'PictureInfo',
283             Condition => '$$valPt =~ /(\[picture info\]|Type=)/',
284             SubDirectory => { TagTable => 'Image::ExifTool::APP12::PictureInfo' },
285             }, {
286             Name => 'Ducky',
287             Condition => '$$valPt =~ /^Ducky/',
288             SubDirectory => { TagTable => 'Image::ExifTool::APP12::Ducky' },
289             }],
290             APP13 => [{
291             Name => 'Photoshop',
292             Condition => '$$valPt =~ /^(Photoshop 3.0\0|Adobe_Photoshop2.5)/',
293             SubDirectory => { TagTable => 'Image::ExifTool::Photoshop::Main' },
294             }, {
295             Name => 'Adobe_CM',
296             Condition => '$$valPt =~ /^Adobe_CM/',
297             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::AdobeCM' },
298             }],
299             APP14 => {
300             Name => 'Adobe',
301             Condition => '$$valPt =~ /^Adobe/',
302             Writable => 2, # (for docs only)
303             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::Adobe' },
304             },
305             APP15 => {
306             Name => 'GraphicConverter',
307             Condition => '$$valPt =~ /^Q\s*(\d+)/',
308             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::GraphConv' },
309             },
310             # APP15 - Also unknown "TEXT\0" segment stored by Casio/FujiFilm
311             COM => {
312             Name => 'Comment',
313             # note: flag as writable for documentation, but it won't show up
314             # in the TagLookup as writable because there is no WRITE_PROC
315             Writable => 2,
316             },
317             SOF => {
318             Name => 'StartOfFrame',
319             SubDirectory => { TagTable => 'Image::ExifTool::JPEG::SOF' },
320             },
321             DQT => {
322             Name => 'DefineQuantizationTable',
323             Notes => 'used to calculate the Extra JPEGDigest tag value',
324             },
325             Trailer => [{
326             Name => 'AFCP',
327             Condition => '$$valPt =~ /AXS(!|\*).{8}$/s',
328             SubDirectory => { TagTable => 'Image::ExifTool::AFCP::Main' },
329             }, {
330             Name => 'CanonVRD',
331             Condition => '$$valPt =~ /CANON OPTIONAL DATA\0.{44}$/s',
332             SubDirectory => { TagTable => 'Image::ExifTool::CanonVRD::Main' },
333             }, {
334             Name => 'FotoStation',
335             Condition => '$$valPt =~ /\xa1\xb2\xc3\xd4$/',
336             SubDirectory => { TagTable => 'Image::ExifTool::FotoStation::Main' },
337             }, {
338             Name => 'PhotoMechanic',
339             Condition => '$$valPt =~ /cbipcbbl$/',
340             SubDirectory => { TagTable => 'Image::ExifTool::PhotoMechanic::Main' },
341             }, {
342             Name => 'MIE',
343             Condition => q{
344             $$valPt =~ /~\0\x04\0zmie~\0\0\x06.{4}[\x10\x18]\x04$/s or
345             $$valPt =~ /~\0\x04\0zmie~\0\0\x0a.{8}[\x10\x18]\x08$/s
346             },
347             SubDirectory => { TagTable => 'Image::ExifTool::MIE::Main' },
348             }, {
349             Name => 'MPF',
350             SubDirectory => { TagTable => 'Image::ExifTool::MPF::Main' },
351             }, {
352             Name => 'Samsung',
353             Condition => '$$valPt =~ /QDIOBS$/',
354             SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' },
355             }, {
356             Name => 'Vivo',
357             Condition => '$$valPt =~ /^(streamdata|vivo\{")/',
358             SubDirectory => { TagTable => 'Image::ExifTool::Trailer::Vivo' },
359             }, {
360             Name => 'OnePlus',
361             SubDirectory => { TagTable => 'Image::ExifTool::Trailer::OnePlus' },
362             }, {
363             Name => 'Google',
364             SubDirectory => { TagTable => 'Image::ExifTool::Trailer::Google' },
365             }, {
366             Name => 'EmbeddedVideo',
367             Notes => 'extracted only when ExtractEmbedded option is used',
368             Condition => '$$valPt =~ /^.{4}ftyp/s',
369             }, {
370             Name => 'Insta360',
371             Condition => '$$valPt =~ /8db42d694ccc418790edff439fe026bf$/',
372             }, {
373             Name => 'NikonApp',
374             Condition => '$$valPt =~ m(\0{6}/NIKON APP$)',
375             Notes => 'contains editing information in XMP format',
376             }, {
377             Name => 'SonyHiddenData',
378             Condition => '$$valPt =~ /^\x55\x26\x11\x05\0/',
379             }, {
380             Name => 'PreviewImage',
381             Condition => '$$valPt =~ /^\xff\xd8\xff/',
382             Writable => 2, # (for docs only)
383             }],
384             );
385              
386             # HDR gain information (ref PH)
387             %Image::ExifTool::JPEG::HDRGainInfo = (
388             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
389             GROUPS => { 0 => 'APP10', 1 => 'AROT', 2 => 'Image' },
390             6 => {
391             Name => 'HDRGainCurveSize',
392             Format => 'int32u',
393             },
394             10 => {
395             Name => 'HDRGainCurve', # (NC)
396             Format => 'int32uRev[$val{6}]',
397             Binary => 1,
398             },
399             );
400              
401             # JPS APP3 segment (ref http://paulbourke.net/stereographics/stereoimage/)
402             %Image::ExifTool::JPEG::JPS = (
403             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
404             GROUPS => { 0 => 'APP3', 1 => 'JPS', 2 => 'Image' },
405             NOTES => 'Tags found in JPEG Stereo (JPS) images.',
406             0x0a => {
407             Name => 'JPSSeparation',
408             Format => 'int32u', # (just so we can look ahead to MediaType);
409             Notes => 'stereo only',
410             RawConv => q{
411             $$self{MediaType} = $val & 0xff;
412             return undef unless $$self{MediaType} == 1;
413             return(($val >> 24) & 0xff);
414             },
415             },
416             0x08 => {
417             Name => 'HdrLength',
418             Format => 'int16u',
419             Hidden => 1,
420             RawConv => '$$self{HdrLength} = $val; undef',
421             },
422             0x0b => {
423             Name => 'JPSFlags',
424             PrintConv => { BITMASK => {
425             0 => 'Half height',
426             1 => 'Half width',
427             2 => 'Left field first',
428             }},
429             },
430             0x0c => [{
431             Name => 'JPSLayout',
432             Condition => '$$self{MediaType} == 0',
433             Notes => 'mono',
434             PrintConv => {
435             0 => 'Both Eyes',
436             1 => 'Left Eye',
437             2 => 'Right Eye',
438             },
439             },{
440             Name => 'JPSLayout',
441             Condition => '$$self{MediaType} == 1',
442             Notes => 'stereo',
443             PrintConv => {
444             1 => 'Interleaved',
445             2 => 'Side By Side',
446             3 => 'Over Under',
447             4 => 'Anaglyph',
448             },
449             }],
450             0x0d => {
451             Name => 'JPSType',
452             Hook => '$varSize += $$self{HdrLength} - 4', # comment starts after header block
453             PrintConv => { 0 => 'Mono', 1 => 'Stereo' },
454             },
455             # 0x0e - in16u comment length (ignored -- assume the remainder is all comment)
456             # (this is offset if we had a 4-byte JPS header block)
457             0x10 => {
458             Name => 'JPSComment',
459             Format => 'string',
460             },
461             );
462              
463             # EPPIM APP6 (Toshiba PrintIM) segment (ref PH, from PDR-M700 samples)
464             %Image::ExifTool::JPEG::EPPIM = (
465             GROUPS => { 0 => 'APP6', 1 => 'EPPIM', 2 => 'Image' },
466             NOTES => q{
467             APP6 is used in by the Toshiba PDR-M700 to store a TIFF structure containing
468             PrintIM information.
469             },
470             0xc4a5 => {
471             Name => 'PrintIM',
472             # must set Writable here so this tag will be saved with MakerNotes option
473             # (but it isn't actually writable because there is no WRITE_PROC)
474             Writable => 'undef',
475             Description => 'Print Image Matching',
476             SubDirectory => {
477             TagTable => 'Image::ExifTool::PrintIM::Main',
478             },
479             },
480             );
481              
482             # APP8 SPIFF segment. Refs:
483             # 1) http://www.fileformat.info/format/spiff/
484             # 2) http://www.jpeg.org/public/spiff.pdf
485             %Image::ExifTool::JPEG::SPIFF = (
486             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
487             GROUPS => { 0 => 'APP8', 1 => 'SPIFF', 2 => 'Image' },
488             NOTES => q{
489             This information is found in APP8 of SPIFF-style JPEG images (the "official"
490             yet rarely used JPEG file format standard: Still Picture Interchange File
491             Format). See L for the official
492             specification.
493             },
494             0 => {
495             Name => 'SPIFFVersion',
496             Format => 'int8u[2]',
497             PrintConv => '$val =~ tr/ /./; $val',
498             },
499             2 => {
500             Name => 'ProfileID',
501             PrintConv => {
502             0 => 'Not Specified',
503             1 => 'Continuous-tone Base',
504             2 => 'Continuous-tone Progressive',
505             3 => 'Bi-level Facsimile',
506             4 => 'Continuous-tone Facsimile',
507             },
508             },
509             3 => 'ColorComponents',
510             6 => {
511             Name => 'ImageHeight',
512             Notes => q{
513             at index 4 in specification, but there are 2 extra bytes here in my only
514             SPIFF sample, version 1.2
515             },
516             Format => 'int32u',
517             },
518             10 => {
519             Name => 'ImageWidth',
520             Format => 'int32u',
521             },
522             14 => {
523             Name => 'ColorSpace',
524             PrintConv => {
525             0 => 'Bi-level',
526             1 => 'YCbCr, ITU-R BT 709, video',
527             2 => 'No color space specified',
528             3 => 'YCbCr, ITU-R BT 601-1, RGB',
529             4 => 'YCbCr, ITU-R BT 601-1, video',
530             8 => 'Gray-scale',
531             9 => 'PhotoYCC',
532             10 => 'RGB',
533             11 => 'CMY',
534             12 => 'CMYK',
535             13 => 'YCCK',
536             14 => 'CIELab',
537             },
538             },
539             15 => 'BitsPerSample',
540             16 => {
541             Name => 'Compression',
542             PrintConv => {
543             0 => 'Uncompressed, interleaved, 8 bits per sample',
544             1 => 'Modified Huffman',
545             2 => 'Modified READ',
546             3 => 'Modified Modified READ',
547             4 => 'JBIG',
548             5 => 'JPEG',
549             },
550             },
551             17 => {
552             Name => 'ResolutionUnit',
553             PrintConv => {
554             0 => 'None',
555             1 => 'inches',
556             2 => 'cm',
557             },
558             },
559             18 => {
560             Name => 'YResolution',
561             Format => 'int32u',
562             },
563             22 => {
564             Name => 'XResolution',
565             Format => 'int32u',
566             },
567             );
568              
569             # APP9 Media Jukebox segment (ref PH)
570             %Image::ExifTool::JPEG::MediaJukebox = (
571             GROUPS => { 0 => 'XML', 1 => 'MediaJukebox', 2 => 'Image' },
572             VARS => { ID_FMT => 'none' },
573             NOTES => 'Tags found in the XML metadata of the APP9 "Media Jukebox" segment.',
574             Date => {
575             Groups => { 2 => 'Time' },
576             # convert from days since Dec 30, 1899 to seconds since Jan 1, 1970
577             ValueConv => 'ConvertUnixTime(($val - (70 * 365 + 17 + 2)) * 24 * 3600)',
578             PrintConv => '$self->ConvertDateTime($val)',
579             },
580             Album => { },
581             Caption => { },
582             Keywords => { },
583             Name => { },
584             People => { },
585             Places => { },
586             Tool_Name => { },
587             Tool_Version => { },
588             );
589              
590             # JPEG-HDR APP11 information (ref PH, guessed from http://anyhere.com/gward/papers/cic05.pdf)
591             %Image::ExifTool::JPEG::HDR = (
592             GROUPS => { 0 => 'APP11', 1 => 'JPEG-HDR', 2 => 'Image' },
593             PROCESS_PROC => \&ProcessJPEG_HDR,
594             TAG_PREFIX => '', # (no prefix for unknown tags)
595             NOTES => 'Information extracted from APP11 of a JPEG-HDR image.',
596             ver => 'JPEG-HDRVersion',
597             # (need names for the next 3 tags)
598             ln0 => { Description => 'Ln0' },
599             ln1 => { Description => 'Ln1' },
600             s2n => { Description => 'S2n' },
601             alp => { Name => 'Alpha' }, # (Alpha/Beta are saturation parameters)
602             bet => { Name => 'Beta' },
603             cor => { Name => 'CorrectionMethod' },
604             RatioImage => {
605             Groups => { 2 => 'Preview' },
606             Notes => 'the embedded JPEG-compressed ratio image',
607             Binary => 1,
608             },
609             );
610              
611             # AdobeCM APP13 (no references)
612             %Image::ExifTool::JPEG::AdobeCM = (
613             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
614             GROUPS => { 0 => 'APP13', 1 => 'AdobeCM', 2 => 'Image' },
615             NOTES => q{
616             The APP13 "Adobe_CM" segment presumably contains color management
617             information, but the meaning of the data is currently unknown. If anyone
618             has an idea about what this means, please let me know.
619             },
620             FORMAT => 'int16u',
621             0 => 'AdobeCMType',
622             );
623              
624             # Adobe APP14 refs:
625             # http://partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf
626             # http://java.sun.com/j2se/1.5.0/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#color
627             %Image::ExifTool::JPEG::Adobe = (
628             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
629             GROUPS => { 0 => 'APP14', 1 => 'Adobe', 2 => 'Image' },
630             NOTES => q{
631             The APP14 "Adobe" segment stores image encoding information for DCT filters.
632             This segment may be copied or deleted as a block using the Extra "Adobe"
633             tag, but note that it is not deleted by default when deleting all metadata
634             because it may affect the appearance of the image.
635             },
636             FORMAT => 'int16u',
637             0 => 'DCTEncodeVersion',
638             1 => {
639             Name => 'APP14Flags0',
640             PrintConv => {
641             0 => '(none)',
642             BITMASK => {
643             15 => 'Encoded with Blend=1 downsampling'
644             },
645             },
646             },
647             2 => {
648             Name => 'APP14Flags1',
649             PrintConv => {
650             0 => '(none)',
651             BITMASK => { },
652             },
653             },
654             3 => {
655             Name => 'ColorTransform',
656             Format => 'int8u',
657             PrintConv => {
658             0 => 'Unknown (RGB or CMYK)',
659             1 => 'YCbCr',
660             2 => 'YCCK',
661             },
662             },
663             );
664              
665             # GraphicConverter APP15 (ref PH)
666             %Image::ExifTool::JPEG::GraphConv = (
667             GROUPS => { 0 => 'APP15', 1 => 'GraphConv', 2 => 'Image' },
668             NOTES => 'APP15 is used by GraphicConverter to store JPEG quality.',
669             'Q' => 'Quality',
670             );
671              
672             # APP0 AVI1 segment (ref http://www.schnarff.com/file-formats/bmp/BMPDIB.TXT)
673             %Image::ExifTool::JPEG::AVI1 = (
674             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
675             GROUPS => { 0 => 'APP0', 1 => 'AVI1', 2 => 'Image' },
676             NOTES => 'This information may be found in APP0 of JPEG image data from AVI videos.',
677             FIRST_ENTRY => 0,
678             0 => {
679             Name => 'InterleavedField',
680             PrintConv => {
681             0 => 'Not Interleaved',
682             1 => 'Odd',
683             2 => 'Even',
684             },
685             },
686             );
687              
688             # APP0 Ocad segment (ref PH)
689             %Image::ExifTool::JPEG::Ocad = (
690             PROCESS_PROC => \&ProcessOcad,
691             GROUPS => { 0 => 'APP0', 1 => 'Ocad', 2 => 'Image' },
692             TAG_PREFIX => 'Ocad',
693             FIRST_ENTRY => 0,
694             NOTES => q{
695             Tags extracted from the JPEG APP0 "Ocad" segment (found in Photobucket
696             images).
697             },
698             Rev => {
699             Name => 'OcadRevision',
700             Format => 'string[6]',
701             }
702             );
703              
704             # APP6 NITF segment (National Imagery Transmission Format)
705             # ref http://www.gwg.nga.mil/ntb/baseline/docs/n010697/bwcguide25aug98.pdf
706             %Image::ExifTool::JPEG::NITF = (
707             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
708             GROUPS => { 0 => 'APP6', 1 => 'NITF', 2 => 'Image' },
709             NOTES => q{
710             Information in APP6 used by the National Imagery Transmission Format. See
711             L for
712             the official specification.
713             },
714             0 => {
715             Name => 'NITFVersion',
716             Format => 'int8u[2]',
717             ValueConv => 'sprintf("%d.%.2d", split(" ",$val))',
718             },
719             2 => {
720             Name => 'ImageFormat',
721             ValueConv => 'chr($val & 0xff)',
722             PrintConv => { B => 'IMode B' },
723             },
724             3 => {
725             Name => 'BlocksPerRow',
726             Format => 'int16u',
727             },
728             5 => {
729             Name => 'BlocksPerColumn',
730             Format => 'int16u',
731             },
732             7 => {
733             Name => 'ImageColor',
734             PrintConv => { 0 => 'Monochrome' },
735             },
736             8 => 'BitDepth',
737             9 => {
738             Name => 'ImageClass',
739             PrintConv => {
740             0 => 'General Purpose',
741             4 => 'Tactical Imagery',
742             },
743             },
744             10 => {
745             Name => 'JPEGProcess',
746             PrintConv => {
747             1 => 'Baseline sequential DCT, Huffman coding, 8-bit samples',
748             4 => 'Extended sequential DCT, Huffman coding, 12-bit samples',
749             },
750             },
751             11 => 'Quality',
752             12 => {
753             Name => 'StreamColor',
754             PrintConv => { 0 => 'Monochrome' },
755             },
756             13 => 'StreamBitDepth',
757             14 => {
758             Name => 'Flags',
759             Format => 'int32u',
760             PrintConv => 'sprintf("0x%x", $val)',
761             },
762             );
763              
764             #------------------------------------------------------------------------------
765             # Extract information from the JPEG APP0 Ocad segment
766             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
767             # Returns: 1 on success
768             sub ProcessOcad($$$)
769             {
770 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
771 0         0 my $dataPt = $$dirInfo{DataPt};
772 0         0 $et->VerboseDir('APP0 Ocad', undef, length $$dataPt);
773 0         0 for (;;) {
774 0 0       0 last unless $$dataPt =~ /\$(\w+):([^\0\$]+)/g;
775 0         0 my ($tag, $val) = ($1, $2);
776 0         0 $val =~ s/^\s+//; $val =~ s/\s+$//; # remove leading/trailing spaces
  0         0  
777 0 0       0 AddTagToTable($tagTablePtr, $tag) unless $$tagTablePtr{$tag};
778 0         0 $et->HandleTag($tagTablePtr, $tag, $val);
779             }
780 0         0 return 1;
781             }
782              
783             #------------------------------------------------------------------------------
784             # Extract information from the JPEG APP0 Ocad segment
785             # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref
786             # Returns: 1 on success
787             sub ProcessJPEG_HDR($$$)
788             {
789 19     19 0 63 my ($et, $dirInfo, $tagTablePtr) = @_;
790 19         78 my $dataPt = $$dirInfo{DataPt};
791 19 50       142 $$dataPt =~ /~\0/g or $et->Warn('Unrecognized JPEG-HDR format'), return 0;
792 19         56 my $pos = pos $$dataPt;
793 19         77 my $meta = substr($$dataPt, 7, $pos-9);
794 19         129 $et->VerboseDir('APP11 JPEG-HDR', undef, length $$dataPt);
795 19         185 while ($meta =~ /(\w+)=([^,\s]*)/g) {
796 133         502 my ($tag, $val) = ($1, $2);
797 133 50       435 AddTagToTable($tagTablePtr, $tag) unless $$tagTablePtr{$tag};
798 133         413 $et->HandleTag($tagTablePtr, $tag, $val);
799             }
800 19         110 $et->HandleTag($tagTablePtr, 'RatioImage', substr($$dataPt, $pos));
801 19         86 return 1;
802             }
803              
804             1; # end
805              
806             __END__