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