File Coverage

blib/lib/Image/ExifTool/Exif.pm
Criterion Covered Total %
statement 618 977 63.2
branch 378 780 48.4
condition 252 541 46.5
subroutine 30 33 90.9
pod 0 28 0.0
total 1278 2359 54.1


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: Exif.pm
3             #
4             # Description: Read EXIF/TIFF meta information
5             #
6             # Revisions: 11/25/2003 - P. Harvey Created
7             # 02/06/2004 - P. Harvey Moved processing functions from ExifTool
8             # 03/19/2004 - P. Harvey Check PreviewImage for validity
9             # 11/11/2004 - P. Harvey Split off maker notes into MakerNotes.pm
10             # 12/13/2004 - P. Harvey Added AUTOLOAD to load write routines
11             #
12             # References: 0) http://www.exif.org/Exif2-2.PDF
13             # 1) http://partners.adobe.com/asn/developer/pdfs/tn/TIFF6.pdf
14             # 2) http://www.adobe.com/products/dng/pdfs/dng_spec_1_3_0_0.pdf
15             # 3) http://www.awaresystems.be/imaging/tiff/tifftags.html
16             # 4) http://www.remotesensing.org/libtiff/TIFFTechNote2.html
17             # 5) http://www.exif.org/dcf.PDF
18             # 6) http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
19             # 7) http://www.fine-view.com/jp/lab/doc/ps6ffspecsv2.pdf
20             # 8) http://www.ozhiker.com/electronics/pjmt/jpeg_info/meta.html
21             # 9) http://hul.harvard.edu/jhove/tiff-tags.html
22             # 10) http://partners.adobe.com/public/developer/en/tiff/TIFFPM6.pdf
23             # 11) Robert Mucke private communication
24             # 12) http://www.broomscloset.com/closet/photo/exif/TAG2000-22_DIS12234-2.PDF
25             # 13) http://www.microsoft.com/whdc/xps/wmphoto.mspx
26             # 14) http://www.asmail.be/msg0054681802.html
27             # 15) http://crousseau.free.fr/imgfmt_raw.htm
28             # 16) http://www.cybercom.net/~dcoffin/dcraw/
29             # 17) http://www.digitalpreservation.gov/formats/content/tiff_tags.shtml
30             # 18) http://www.asmail.be/msg0055568584.html
31             # 19) http://libpsd.graphest.com/files/Photoshop%20File%20Formats.pdf
32             # 20) http://tiki-lounge.com/~raf/tiff/fields.html
33             # 21) http://community.roxen.com/developers/idocs/rfc/rfc3949.html
34             # 22) http://tools.ietf.org/html/draft-ietf-fax-tiff-fx-extension1-01
35             # 23) MetaMorph Stack (STK) Image File Format:
36             # --> ftp://ftp.meta.moleculardevices.com/support/stack/STK.doc
37             # 24) http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf (Exif 2.3)
38             # 25) Vesa Kivisto private communication (7D)
39             # 26) Jeremy Brown private communication
40             # 27) Gregg Lee private communication
41             # 28) http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/cinemadng/pdfs/CinemaDNG_Format_Specification_v1_1.pdf
42             # 29) http://www.libtiff.org
43             # 30) http://geotiff.maptools.org/spec/geotiffhome.html
44             # 31) https://android.googlesource.com/platform/external/dng_sdk/+/refs/heads/master/source/dng_tag_codes.h
45             # 32) Jeffry Friedl private communication
46             # IB) Iliah Borg private communication (LibRaw)
47             # JD) Jens Duttke private communication
48             #------------------------------------------------------------------------------
49              
50             package Image::ExifTool::Exif;
51              
52 104     104   693 use strict;
  104         414  
  104         3740  
53 104         10364 use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat
54             %lightSource %flash %compression %photometricInterpretation %orientation
55 104     104   547 %subfileType %saveForValidate);
  104         210  
56 104     104   541 use Image::ExifTool qw(:DataAccess :Utils);
  104         179  
  104         20562  
57 104     104   57154 use Image::ExifTool::MakerNotes;
  104         481  
  104         1885091  
58              
59             $VERSION = '4.40';
60              
61             sub ProcessExif($$$);
62             sub WriteExif($$$);
63             sub CheckExif($$$);
64             sub RebuildMakerNotes($$$);
65             sub EncodeExifText($$);
66             sub ValidateIFD($;$);
67             sub ValidateImageData($$$;$);
68             sub ProcessTiffIFD($$$);
69             sub PrintParameter($$$);
70             sub GetOffList($$$$$);
71             sub PrintOpcode($$$);
72             sub PrintLensInfo($);
73             sub ConvertLensInfo($);
74              
75             # size limit for loading binary data block into memory
76 675     675 0 1975 sub BINARY_DATA_LIMIT { return 10 * 1024 * 1024; }
77              
78             # byte sizes for the various EXIF format types below
79             @formatSize = (undef,1,1,2,4,8,1,1,2,4,8,4,8,4,2,8,8,8,8);
80              
81             @formatName = (
82             undef, 'int8u', 'string', 'int16u',
83             'int32u', 'rational64u','int8s', 'undef',
84             'int16s', 'int32s', 'rational64s','float',
85             'double', 'ifd', 'unicode', 'complex',
86             'int64u', 'int64s', 'ifd64', # (new BigTIFF formats)
87             );
88              
89             # hash to look up EXIF format numbers by name
90             # (format types are all lower case)
91             %formatNumber = (
92             'int8u' => 1, # BYTE
93             'string' => 2, # ASCII
94             'int16u' => 3, # SHORT
95             'int32u' => 4, # LONG
96             'rational64u' => 5, # RATIONAL
97             'int8s' => 6, # SBYTE
98             'undef' => 7, # UNDEFINED
99             'binary' => 7, # (same as undef)
100             'int16s' => 8, # SSHORT
101             'int32s' => 9, # SLONG
102             'rational64s' => 10, # SRATIONAL
103             'float' => 11, # FLOAT
104             'double' => 12, # DOUBLE
105             'ifd' => 13, # IFD (with int32u format)
106             'unicode' => 14, # UNICODE [see Note below]
107             'complex' => 15, # COMPLEX [see Note below]
108             'int64u' => 16, # LONG8 [BigTIFF]
109             'int64s' => 17, # SLONG8 [BigTIFF]
110             'ifd64' => 18, # IFD8 (with int64u format) [BigTIFF]
111             # Note: unicode and complex types are not yet properly supported by ExifTool.
112             # These are types which have been observed in the Adobe DNG SDK code, but
113             # aren't fully supported there either. We know the sizes, but that's about it.
114             # We don't know if the unicode is null terminated, or the format for complex
115             # (although I suspect it would be two 4-byte floats, real and imaginary).
116             );
117              
118             # lookup for integer format strings
119             %intFormat = (
120             'int8u' => 1,
121             'int16u' => 3,
122             'int32u' => 4,
123             'int8s' => 6,
124             'int16s' => 8,
125             'int32s' => 9,
126             'ifd' => 13,
127             'int64u' => 16,
128             'int64s' => 17,
129             'ifd64' => 18,
130             );
131              
132             # EXIF LightSource PrintConv values
133             %lightSource = (
134             0 => 'Unknown',
135             1 => 'Daylight',
136             2 => 'Fluorescent',
137             3 => 'Tungsten (Incandescent)',
138             4 => 'Flash',
139             9 => 'Fine Weather',
140             10 => 'Cloudy',
141             11 => 'Shade',
142             12 => 'Daylight Fluorescent', # (D 5700 - 7100K)
143             13 => 'Day White Fluorescent', # (N 4600 - 5500K)
144             14 => 'Cool White Fluorescent', # (W 3800 - 4500K)
145             15 => 'White Fluorescent', # (WW 3250 - 3800K)
146             16 => 'Warm White Fluorescent', # (L 2600 - 3250K)
147             17 => 'Standard Light A',
148             18 => 'Standard Light B',
149             19 => 'Standard Light C',
150             20 => 'D55',
151             21 => 'D65',
152             22 => 'D75',
153             23 => 'D50',
154             24 => 'ISO Studio Tungsten',
155             255 => 'Other',
156             );
157              
158             # EXIF Flash values
159             %flash = (
160             OTHER => sub {
161             # translate "Off" and "On" when writing
162             my ($val, $inv) = @_;
163             return undef unless $inv and $val =~ /^(off|on)$/i;
164             return lc $val eq 'off' ? 0x00 : 0x01;
165             },
166             0x00 => 'No Flash',
167             0x01 => 'Fired',
168             0x05 => 'Fired, Return not detected',
169             0x07 => 'Fired, Return detected',
170             0x08 => 'On, Did not fire', # not charged up?
171             0x09 => 'On, Fired',
172             0x0d => 'On, Return not detected',
173             0x0f => 'On, Return detected',
174             0x10 => 'Off, Did not fire',
175             0x14 => 'Off, Did not fire, Return not detected',
176             0x18 => 'Auto, Did not fire',
177             0x19 => 'Auto, Fired',
178             0x1d => 'Auto, Fired, Return not detected',
179             0x1f => 'Auto, Fired, Return detected',
180             0x20 => 'No flash function',
181             0x30 => 'Off, No flash function',
182             0x41 => 'Fired, Red-eye reduction',
183             0x45 => 'Fired, Red-eye reduction, Return not detected',
184             0x47 => 'Fired, Red-eye reduction, Return detected',
185             0x49 => 'On, Red-eye reduction',
186             0x4d => 'On, Red-eye reduction, Return not detected',
187             0x4f => 'On, Red-eye reduction, Return detected',
188             0x50 => 'Off, Red-eye reduction',
189             0x58 => 'Auto, Did not fire, Red-eye reduction',
190             0x59 => 'Auto, Fired, Red-eye reduction',
191             0x5d => 'Auto, Fired, Red-eye reduction, Return not detected',
192             0x5f => 'Auto, Fired, Red-eye reduction, Return detected',
193             );
194              
195             # TIFF Compression values
196             # (values with format "Xxxxx XXX Compressed" are used to identify RAW file types)
197             %compression = (
198             1 => 'Uncompressed',
199             2 => 'CCITT 1D',
200             3 => 'T4/Group 3 Fax',
201             4 => 'T6/Group 4 Fax',
202             5 => 'LZW',
203             6 => 'JPEG (old-style)', #3
204             7 => 'JPEG', #4
205             8 => 'Adobe Deflate', #3
206             9 => 'JBIG B&W', #3
207             10 => 'JBIG Color', #3
208             99 => 'JPEG', #16
209             262 => 'Kodak 262', #16
210             32766 => 'Next', #3
211             32767 => 'Sony ARW Compressed', #16
212             32769 => 'Packed RAW', #PH (used by Epson, Nikon, Samsung)
213             32770 => 'Samsung SRW Compressed', #PH
214             32771 => 'CCIRLEW', #3
215             32772 => 'Samsung SRW Compressed 2', #PH (NX3000,NXmini)
216             32773 => 'PackBits',
217             32809 => 'Thunderscan', #3
218             32867 => 'Kodak KDC Compressed', #PH
219             32895 => 'IT8CTPAD', #3
220             32896 => 'IT8LW', #3
221             32897 => 'IT8MP', #3
222             32898 => 'IT8BL', #3
223             32908 => 'PixarFilm', #3
224             32909 => 'PixarLog', #3
225             # 32910,32911 - Pixar reserved
226             32946 => 'Deflate', #3
227             32947 => 'DCS', #3
228             33003 => 'Aperio JPEG 2000 YCbCr', #https://openslide.org/formats/aperio/
229             33005 => 'Aperio JPEG 2000 RGB', #https://openslide.org/formats/aperio/
230             34661 => 'JBIG', #3
231             34676 => 'SGILog', #3
232             34677 => 'SGILog24', #3
233             34712 => 'JPEG 2000', #3
234             34713 => 'Nikon NEF Compressed', #PH
235             34715 => 'JBIG2 TIFF FX', #20
236             34718 => 'Microsoft Document Imaging (MDI) Binary Level Codec', #18
237             34719 => 'Microsoft Document Imaging (MDI) Progressive Transform Codec', #18
238             34720 => 'Microsoft Document Imaging (MDI) Vector', #18
239             34887 => 'ESRI Lerc', #LibTiff
240             # 34888,34889 - ESRI reserved
241             34892 => 'Lossy JPEG', # (DNG 1.4)
242             34925 => 'LZMA2', #LibTiff
243             34926 => 'Zstd', #LibTiff
244             34927 => 'WebP', #LibTiff
245             34933 => 'PNG', # (TIFF mail list)
246             34934 => 'JPEG XR', # (TIFF mail list)
247             65000 => 'Kodak DCR Compressed', #PH
248             65535 => 'Pentax PEF Compressed', #Jens
249             );
250              
251             %photometricInterpretation = (
252             0 => 'WhiteIsZero',
253             1 => 'BlackIsZero',
254             2 => 'RGB',
255             3 => 'RGB Palette',
256             4 => 'Transparency Mask',
257             5 => 'CMYK',
258             6 => 'YCbCr',
259             8 => 'CIELab',
260             9 => 'ICCLab', #3
261             10 => 'ITULab', #3
262             32803 => 'Color Filter Array', #2
263             32844 => 'Pixar LogL', #3
264             32845 => 'Pixar LogLuv', #3
265             32892 => 'Sequential Color Filter', #JR (Sony ARQ)
266             34892 => 'Linear Raw', #2
267             51177 => 'Depth Map', # (DNG 1.5)
268             52527 => 'Semantic Mask', # (DNG 1.6)
269             );
270              
271             %orientation = (
272             1 => 'Horizontal (normal)',
273             2 => 'Mirror horizontal',
274             3 => 'Rotate 180',
275             4 => 'Mirror vertical',
276             5 => 'Mirror horizontal and rotate 270 CW',
277             6 => 'Rotate 90 CW',
278             7 => 'Mirror horizontal and rotate 90 CW',
279             8 => 'Rotate 270 CW',
280             );
281              
282             %subfileType = (
283             0 => 'Full-resolution image',
284             1 => 'Reduced-resolution image',
285             2 => 'Single page of multi-page image',
286             3 => 'Single page of multi-page reduced-resolution image',
287             4 => 'Transparency mask',
288             5 => 'Transparency mask of reduced-resolution image',
289             6 => 'Transparency mask of multi-page image',
290             7 => 'Transparency mask of reduced-resolution multi-page image',
291             8 => 'Depth map', # (DNG 1.5)
292             9 => 'Depth map of reduced-resolution image', # (DNG 1.5)
293             16 => 'Enhanced image data', # (DNG 1.5)
294             0x10001 => 'Alternate reduced-resolution image', # (DNG 1.2)
295             0x10004 => 'Semantic Mask', # (DNG 1.6)
296             0xffffffff => 'invalid', #(found in E5700 NEF's)
297             BITMASK => {
298             0 => 'Reduced resolution',
299             1 => 'Single page',
300             2 => 'Transparency mask',
301             3 => 'TIFF/IT final page', #20 (repurposed as DepthMap repurposes by DNG 1.5)
302             4 => 'TIFF-FX mixed raster content', #20 (repurposed as EnhancedImageData by DNG 1.5)
303             },
304             );
305              
306             # PrintConv for parameter tags
307             %Image::ExifTool::Exif::printParameter = (
308             PrintConv => {
309             0 => 'Normal',
310             OTHER => \&Image::ExifTool::Exif::PrintParameter,
311             },
312             );
313              
314             # convert DNG UTF-8 string values (may be string or int8u format)
315             my %utf8StringConv = (
316             Writable => 'string',
317             Format => 'string',
318             ValueConv => '$self->Decode($val, "UTF8")',
319             ValueConvInv => '$self->Encode($val,"UTF8")',
320             );
321              
322             # ValueConv that makes long values binary type
323             my %longBin = (
324             ValueConv => 'length($val) > 64 ? \$val : $val',
325             ValueConvInv => '$val',
326             LongBinary => 1, # flag to avoid decoding values of a large array
327             );
328              
329             # PrintConv for SampleFormat (0x153)
330             my %sampleFormat = (
331             1 => 'Unsigned', # unsigned integer
332             2 => 'Signed', # two's complement signed integer
333             3 => 'Float', # IEEE floating point
334             4 => 'Undefined',
335             5 => 'Complex int', # complex integer (ref 3)
336             6 => 'Complex float', # complex IEEE floating point (ref 3)
337             );
338              
339             # save the values of these tags for additional validation checks
340             %saveForValidate = (
341             0x100 => 1, # ImageWidth
342             0x101 => 1, # ImageHeight
343             0x102 => 1, # BitsPerSample
344             0x103 => 1, # Compression
345             0x115 => 1, # SamplesPerPixel
346             );
347              
348             # conversions for DNG OpcodeList tags
349             my %opcodeInfo = (
350             Writable => 'undef',
351             WriteGroup => 'SubIFD',
352             Protected => 1,
353             Binary => 1,
354             ConvertBinary => 1, # needed because the ValueConv value is binary
355             PrintConvColumns => 2,
356             PrintConv => {
357             OTHER => \&PrintOpcode,
358             1 => 'WarpRectilinear',
359             2 => 'WarpFisheye',
360             3 => 'FixVignetteRadial',
361             4 => 'FixBadPixelsConstant',
362             5 => 'FixBadPixelsList',
363             6 => 'TrimBounds',
364             7 => 'MapTable',
365             8 => 'MapPolynomial',
366             9 => 'GainMap',
367             10 => 'DeltaPerRow',
368             11 => 'DeltaPerColumn',
369             12 => 'ScalePerRow',
370             13 => 'ScalePerColumn',
371             14 => 'WarpRectilinear2', # (DNG 1.6)
372             },
373             PrintConvInv => undef, # (so the inverse conversion is not performed)
374             );
375              
376             # main EXIF tag table
377             %Image::ExifTool::Exif::Main = (
378             GROUPS => { 0 => 'EXIF', 1 => 'IFD0', 2 => 'Image'},
379             WRITE_PROC => \&WriteExif,
380             CHECK_PROC => \&CheckExif,
381             WRITE_GROUP => 'ExifIFD', # default write group
382             SET_GROUP1 => 1, # set group1 name to directory name for all tags in table
383             0x1 => {
384             Name => 'InteropIndex',
385             Description => 'Interoperability Index',
386             Protected => 1,
387             Writable => 'string',
388             WriteGroup => 'InteropIFD',
389             PrintConv => {
390             R98 => 'R98 - DCF basic file (sRGB)',
391             R03 => 'R03 - DCF option file (Adobe RGB)',
392             THM => 'THM - DCF thumbnail file',
393             },
394             },
395             0x2 => { #5
396             Name => 'InteropVersion',
397             Description => 'Interoperability Version',
398             Protected => 1,
399             Writable => 'undef',
400             Mandatory => 1,
401             WriteGroup => 'InteropIFD',
402             RawConv => '$val=~s/\0+$//; $val', # (some idiots add null terminators)
403             },
404             0x0b => { #PH
405             Name => 'ProcessingSoftware',
406             Writable => 'string',
407             WriteGroup => 'IFD0',
408             Notes => 'used by ACD Systems Digital Imaging',
409             },
410             0xfe => {
411             Name => 'SubfileType',
412             Notes => 'called NewSubfileType by the TIFF specification',
413             Protected => 1,
414             Writable => 'int32u',
415             WriteGroup => 'IFD0',
416             # set priority directory if this is the full resolution image
417             DataMember => 'SubfileType',
418             RawConv => q{
419             if ($val == ($val & 0x02)) {
420             $self->SetPriorityDir() if $val == 0;
421             $$self{PageCount} = ($$self{PageCount} || 0) + 1;
422             $$self{MultiPage} = 1 if $val == 2 or $$self{PageCount} > 1;
423             }
424             $$self{SubfileType} = $val;
425             },
426             PrintConv => \%subfileType,
427             },
428             0xff => {
429             Name => 'OldSubfileType',
430             Notes => 'called SubfileType by the TIFF specification',
431             Protected => 1,
432             Writable => 'int16u',
433             WriteGroup => 'IFD0',
434             # set priority directory if this is the full resolution image
435             RawConv => q{
436             if ($val == 1 or $val == 3) {
437             $self->SetPriorityDir() if $val == 1;
438             $$self{PageCount} = ($$self{PageCount} || 0) + 1;
439             $$self{MultiPage} = 1 if $val == 3 or $$self{PageCount} > 1;
440             }
441             $val;
442             },
443             PrintConv => {
444             1 => 'Full-resolution image',
445             2 => 'Reduced-resolution image',
446             3 => 'Single page of multi-page image',
447             },
448             },
449             0x100 => {
450             Name => 'ImageWidth',
451             # even though Group 1 is set dynamically we need to register IFD1 once
452             # so it will show up in the group lists
453             Groups => { 1 => 'IFD1' },
454             Protected => 1,
455             Writable => 'int32u',
456             WriteGroup => 'IFD0',
457             # Note: priority 0 tags automatically have their priority increased for the
458             # priority directory (the directory with a SubfileType of "Full-resolution image")
459             Priority => 0,
460             },
461             0x101 => {
462             Name => 'ImageHeight',
463             Notes => 'called ImageLength by the EXIF spec.',
464             Protected => 1,
465             Writable => 'int32u',
466             WriteGroup => 'IFD0',
467             Priority => 0,
468             },
469             0x102 => {
470             Name => 'BitsPerSample',
471             Protected => 1,
472             Writable => 'int16u',
473             WriteGroup => 'IFD0',
474             Count => -1, # can be 1 or 3: -1 means 'variable'
475             Priority => 0,
476             },
477             0x103 => {
478             Name => 'Compression',
479             Protected => 1,
480             Writable => 'int16u',
481             WriteGroup => 'IFD0',
482             Mandatory => 1,
483             DataMember => 'Compression',
484             SeparateTable => 'Compression',
485             RawConv => q{
486             Image::ExifTool::Exif::IdentifyRawFile($self, $val);
487             return $$self{Compression} = $val;
488             },
489             PrintConv => \%compression,
490             Priority => 0,
491             },
492             0x106 => {
493             Name => 'PhotometricInterpretation',
494             Protected => 1,
495             Writable => 'int16u',
496             WriteGroup => 'IFD0',
497             PrintConv => \%photometricInterpretation,
498             Priority => 0,
499             },
500             0x107 => {
501             Name => 'Thresholding',
502             Protected => 1,
503             Writable => 'int16u',
504             WriteGroup => 'IFD0',
505             PrintConv => {
506             1 => 'No dithering or halftoning',
507             2 => 'Ordered dither or halftone',
508             3 => 'Randomized dither',
509             },
510             },
511             0x108 => {
512             Name => 'CellWidth',
513             Protected => 1,
514             Writable => 'int16u',
515             WriteGroup => 'IFD0',
516             },
517             0x109 => {
518             Name => 'CellLength',
519             Protected => 1,
520             Writable => 'int16u',
521             WriteGroup => 'IFD0',
522             },
523             0x10a => {
524             Name => 'FillOrder',
525             Protected => 1,
526             Writable => 'int16u',
527             WriteGroup => 'IFD0',
528             PrintConv => {
529             1 => 'Normal',
530             2 => 'Reversed',
531             },
532             },
533             0x10d => {
534             Name => 'DocumentName',
535             Writable => 'string',
536             WriteGroup => 'IFD0',
537             },
538             0x10e => {
539             Name => 'ImageDescription',
540             Writable => 'string',
541             WriteGroup => 'IFD0',
542             Priority => 0,
543             },
544             0x10f => {
545             Name => 'Make',
546             Groups => { 2 => 'Camera' },
547             Writable => 'string',
548             WriteGroup => 'IFD0',
549             DataMember => 'Make',
550             # remove trailing blanks and save as an ExifTool member variable
551             RawConv => '$val =~ s/\s+$//; $$self{Make} = $val',
552             # NOTE: trailing "blanks" (spaces) are removed from all EXIF tags which
553             # may be "unknown" (filled with spaces) according to the EXIF spec.
554             # This allows conditional replacement with "exiftool -TAG-= -TAG=VALUE".
555             # - also removed are any other trailing whitespace characters
556             },
557             0x110 => {
558             Name => 'Model',
559             Description => 'Camera Model Name',
560             Groups => { 2 => 'Camera' },
561             Writable => 'string',
562             WriteGroup => 'IFD0',
563             DataMember => 'Model',
564             # remove trailing blanks and save as an ExifTool member variable
565             RawConv => '$val =~ s/\s+$//; $$self{Model} = $val',
566             },
567             0x111 => [
568             {
569             Condition => q[
570             $$self{TIFF_TYPE} eq 'MRW' and $$self{DIR_NAME} eq 'IFD0' and
571             $$self{Model} =~ /^DiMAGE A200/
572             ],
573             Name => 'StripOffsets',
574             IsOffset => 1,
575             OffsetPair => 0x117, # point to associated byte counts
576             # A200 stores this information in the wrong byte order!!
577             ValueConv => '$val=join(" ",unpack("N*",pack("V*",split(" ",$val))));\$val',
578             ByteOrder => 'LittleEndian',
579             },
580             {
581             # (APP1 IFD2 is for Leica JPEG preview)
582             Condition => q[
583             not ($$self{TIFF_TYPE} eq 'CR2' and $$self{DIR_NAME} eq 'IFD0') and
584             not ($$self{TIFF_TYPE} =~ /^(DNG|TIFF)$/ and $$self{Compression} eq '7' and $$self{SubfileType} ne '0') and
585             not ($$self{TIFF_TYPE} eq 'APP1' and $$self{DIR_NAME} eq 'IFD2')
586             ],
587             Name => 'StripOffsets',
588             IsOffset => 1,
589             OffsetPair => 0x117, # point to associated byte counts
590             ValueConv => 'length($val) > 32 ? \$val : $val',
591             },
592             {
593             # PreviewImageStart in IFD0 of CR2 images
594             Condition => '$$self{TIFF_TYPE} eq "CR2"',
595             Name => 'PreviewImageStart',
596             IsOffset => 1,
597             OffsetPair => 0x117,
598             Notes => q{
599             called StripOffsets in most locations, but it is PreviewImageStart in IFD0
600             of CR2 images and various IFD's of DNG images except for SubIFD2 where it is
601             JpgFromRawStart
602             },
603             DataTag => 'PreviewImage',
604             Writable => 'int32u',
605             WriteGroup => 'IFD0',
606             Protected => 2,
607             Permanent => 1,
608             },
609             {
610             # PreviewImageStart in various IFD's of DNG images except SubIFD2
611             Condition => '$$self{DIR_NAME} ne "SubIFD2"',
612             Name => 'PreviewImageStart',
613             IsOffset => 1,
614             OffsetPair => 0x117,
615             DataTag => 'PreviewImage',
616             Writable => 'int32u',
617             WriteGroup => 'All', # (writes to specific group of associated Composite tag)
618             Protected => 2,
619             Permanent => 1,
620             },
621             {
622             # JpgFromRawStart in various IFD's of DNG images except SubIFD2
623             Name => 'JpgFromRawStart',
624             IsOffset => 1,
625             OffsetPair => 0x117,
626             DataTag => 'JpgFromRaw',
627             Writable => 'int32u',
628             WriteGroup => 'SubIFD2',
629             Protected => 2,
630             Permanent => 1,
631             },
632             ],
633             0x112 => {
634             Name => 'Orientation',
635             Writable => 'int16u',
636             WriteGroup => 'IFD0',
637             PrintConv => \%orientation,
638             Priority => 0, # so PRIORITY_DIR takes precedence
639             },
640             0x115 => {
641             Name => 'SamplesPerPixel',
642             Protected => 1,
643             Writable => 'int16u',
644             WriteGroup => 'IFD0',
645             Priority => 0,
646             },
647             0x116 => {
648             Name => 'RowsPerStrip',
649             Protected => 1,
650             Writable => 'int32u',
651             WriteGroup => 'IFD0',
652             Priority => 0,
653             },
654             0x117 => [
655             {
656             Condition => q[
657             $$self{TIFF_TYPE} eq 'MRW' and $$self{DIR_NAME} eq 'IFD0' and
658             $$self{Model} =~ /^DiMAGE A200/
659             ],
660             Name => 'StripByteCounts',
661             OffsetPair => 0x111, # point to associated offset
662             # A200 stores this information in the wrong byte order!!
663             ValueConv => '$val=join(" ",unpack("N*",pack("V*",split(" ",$val))));\$val',
664             ByteOrder => 'LittleEndian',
665             },
666             {
667             # (APP1 IFD2 is for Leica JPEG preview)
668             Condition => q[
669             not ($$self{TIFF_TYPE} eq 'CR2' and $$self{DIR_NAME} eq 'IFD0') and
670             not ($$self{TIFF_TYPE} =~ /^(DNG|TIFF)$/ and $$self{Compression} eq '7' and $$self{SubfileType} ne '0') and
671             not ($$self{TIFF_TYPE} eq 'APP1' and $$self{DIR_NAME} eq 'IFD2')
672             ],
673             Name => 'StripByteCounts',
674             OffsetPair => 0x111, # point to associated offset
675             ValueConv => 'length($val) > 32 ? \$val : $val',
676             },
677             {
678             # PreviewImageLength in IFD0 of CR2 images
679             Condition => '$$self{TIFF_TYPE} eq "CR2"',
680             Name => 'PreviewImageLength',
681             OffsetPair => 0x111,
682             Notes => q{
683             called StripByteCounts in most locations, but it is PreviewImageLength in
684             IFD0 of CR2 images and various IFD's of DNG images except for SubIFD2 where
685             it is JpgFromRawLength
686             },
687             DataTag => 'PreviewImage',
688             Writable => 'int32u',
689             WriteGroup => 'IFD0',
690             Protected => 2,
691             Permanent => 1,
692             },
693             {
694             # PreviewImageLength in various IFD's of DNG images except SubIFD2
695             Condition => '$$self{DIR_NAME} ne "SubIFD2"',
696             Name => 'PreviewImageLength',
697             OffsetPair => 0x111,
698             DataTag => 'PreviewImage',
699             Writable => 'int32u',
700             WriteGroup => 'All', # (writes to specific group of associated Composite tag)
701             Protected => 2,
702             Permanent => 1,
703             },
704             {
705             # JpgFromRawLength in SubIFD2 of DNG images
706             Name => 'JpgFromRawLength',
707             OffsetPair => 0x111,
708             DataTag => 'JpgFromRaw',
709             Writable => 'int32u',
710             WriteGroup => 'SubIFD2',
711             Protected => 2,
712             Permanent => 1,
713             },
714             ],
715             0x118 => {
716             Name => 'MinSampleValue',
717             Writable => 'int16u',
718             WriteGroup => 'IFD0',
719             },
720             0x119 => {
721             Name => 'MaxSampleValue',
722             Writable => 'int16u',
723             WriteGroup => 'IFD0',
724             },
725             0x11a => {
726             Name => 'XResolution',
727             Writable => 'rational64u',
728             WriteGroup => 'IFD0',
729             Mandatory => 1,
730             Priority => 0, # so PRIORITY_DIR takes precedence
731             },
732             0x11b => {
733             Name => 'YResolution',
734             Writable => 'rational64u',
735             WriteGroup => 'IFD0',
736             Mandatory => 1,
737             Priority => 0,
738             },
739             0x11c => {
740             Name => 'PlanarConfiguration',
741             Protected => 1,
742             Writable => 'int16u',
743             WriteGroup => 'IFD0',
744             PrintConv => {
745             1 => 'Chunky',
746             2 => 'Planar',
747             },
748             Priority => 0,
749             },
750             0x11d => {
751             Name => 'PageName',
752             Writable => 'string',
753             WriteGroup => 'IFD0',
754             },
755             0x11e => {
756             Name => 'XPosition',
757             Writable => 'rational64u',
758             WriteGroup => 'IFD0',
759             },
760             0x11f => {
761             Name => 'YPosition',
762             Writable => 'rational64u',
763             WriteGroup => 'IFD0',
764             },
765             # FreeOffsets/FreeByteCounts are used by Ricoh for RMETA information
766             # in TIFF images (not yet supported)
767             0x120 => {
768             Name => 'FreeOffsets',
769             IsOffset => 1,
770             OffsetPair => 0x121,
771             ValueConv => 'length($val) > 32 ? \$val : $val',
772             },
773             0x121 => {
774             Name => 'FreeByteCounts',
775             OffsetPair => 0x120,
776             ValueConv => 'length($val) > 32 ? \$val : $val',
777             },
778             0x122 => {
779             Name => 'GrayResponseUnit',
780             Writable => 'int16u',
781             WriteGroup => 'IFD0',
782             PrintConv => { #3
783             1 => 0.1,
784             2 => 0.001,
785             3 => 0.0001,
786             4 => 0.00001,
787             5 => 0.000001,
788             },
789             },
790             0x123 => {
791             Name => 'GrayResponseCurve',
792             Binary => 1,
793             },
794             0x124 => {
795             Name => 'T4Options',
796             PrintConv => { BITMASK => {
797             0 => '2-Dimensional encoding',
798             1 => 'Uncompressed',
799             2 => 'Fill bits added',
800             } }, #3
801             },
802             0x125 => {
803             Name => 'T6Options',
804             PrintConv => { BITMASK => {
805             1 => 'Uncompressed',
806             } }, #3
807             },
808             0x128 => {
809             Name => 'ResolutionUnit',
810             Notes => 'the value 1 is not standard EXIF',
811             Writable => 'int16u',
812             WriteGroup => 'IFD0',
813             Mandatory => 1,
814             PrintConv => {
815             1 => 'None',
816             2 => 'inches',
817             3 => 'cm',
818             },
819             Priority => 0,
820             },
821             0x129 => {
822             Name => 'PageNumber',
823             Writable => 'int16u',
824             WriteGroup => 'IFD0',
825             Count => 2,
826             },
827             0x12c => 'ColorResponseUnit', #9
828             0x12d => {
829             Name => 'TransferFunction',
830             Protected => 1,
831             Writable => 'int16u',
832             WriteGroup => 'IFD0',
833             Count => 768,
834             Binary => 1,
835             },
836             0x131 => {
837             Name => 'Software',
838             Writable => 'string',
839             WriteGroup => 'IFD0',
840             DataMember => 'Software',
841             RawConv => '$val =~ s/\s+$//; $$self{Software} = $val', # trim trailing blanks
842             },
843             0x132 => {
844             Name => 'ModifyDate',
845             Groups => { 2 => 'Time' },
846             Notes => 'called DateTime by the EXIF spec.',
847             Writable => 'string',
848             Shift => 'Time',
849             WriteGroup => 'IFD0',
850             Validate => 'ValidateExifDate($val)',
851             PrintConv => '$self->ConvertDateTime($val)',
852             PrintConvInv => '$self->InverseDateTime($val,0)',
853             },
854             0x13b => {
855             Name => 'Artist',
856             Groups => { 2 => 'Author' },
857             Notes => 'becomes a list-type tag when the MWG module is loaded',
858             Writable => 'string',
859             WriteGroup => 'IFD0',
860             RawConv => '$val =~ s/\s+$//; $val', # trim trailing blanks
861             },
862             0x13c => {
863             Name => 'HostComputer',
864             Writable => 'string',
865             WriteGroup => 'IFD0',
866             },
867             0x13d => {
868             Name => 'Predictor',
869             Protected => 1,
870             Writable => 'int16u',
871             WriteGroup => 'IFD0',
872             PrintConv => {
873             1 => 'None',
874             2 => 'Horizontal differencing',
875             3 => 'Floating point', # (DNG 1.5)
876             34892 => 'Horizontal difference X2', # (DNG 1.5)
877             34893 => 'Horizontal difference X4', # (DNG 1.5)
878             34894 => 'Floating point X2', # (DNG 1.5)
879             34895 => 'Floating point X4', # (DNG 1.5)
880             },
881             },
882             0x13e => {
883             Name => 'WhitePoint',
884             Groups => { 2 => 'Camera' },
885             Writable => 'rational64u',
886             WriteGroup => 'IFD0',
887             Count => 2,
888             },
889             0x13f => {
890             Name => 'PrimaryChromaticities',
891             Writable => 'rational64u',
892             WriteGroup => 'IFD0',
893             Count => 6,
894             Priority => 0,
895             },
896             0x140 => {
897             Name => 'ColorMap',
898             Format => 'binary',
899             Binary => 1,
900             },
901             0x141 => {
902             Name => 'HalftoneHints',
903             Writable => 'int16u',
904             WriteGroup => 'IFD0',
905             Count => 2,
906             },
907             0x142 => {
908             Name => 'TileWidth',
909             Protected => 1,
910             Writable => 'int32u',
911             WriteGroup => 'IFD0',
912             },
913             0x143 => {
914             Name => 'TileLength',
915             Protected => 1,
916             Writable => 'int32u',
917             WriteGroup => 'IFD0',
918             },
919             0x144 => {
920             Name => 'TileOffsets',
921             IsOffset => 1,
922             OffsetPair => 0x145,
923             ValueConv => 'length($val) > 32 ? \$val : $val',
924             },
925             0x145 => {
926             Name => 'TileByteCounts',
927             OffsetPair => 0x144,
928             ValueConv => 'length($val) > 32 ? \$val : $val',
929             },
930             0x146 => 'BadFaxLines', #3
931             0x147 => { #3
932             Name => 'CleanFaxData',
933             PrintConv => {
934             0 => 'Clean',
935             1 => 'Regenerated',
936             2 => 'Unclean',
937             },
938             },
939             0x148 => 'ConsecutiveBadFaxLines', #3
940             0x14a => [
941             {
942             Name => 'SubIFD',
943             # use this opportunity to identify an ARW image, and if so we
944             # must decide if this is a SubIFD or the A100 raw data
945             # (use SubfileType, Compression and FILE_TYPE to identify ARW/SR2,
946             # then call SetARW to finish the job)
947             Condition => q{
948             $$self{DIR_NAME} ne 'IFD0' or $$self{FILE_TYPE} ne 'TIFF' or
949             $$self{Make} !~ /^SONY/ or
950             not $$self{SubfileType} or $$self{SubfileType} != 1 or
951             not $$self{Compression} or $$self{Compression} != 6 or
952             not require Image::ExifTool::Sony or
953             Image::ExifTool::Sony::SetARW($self, $valPt)
954             },
955             Groups => { 1 => 'SubIFD' },
956             Flags => 'SubIFD',
957             SubDirectory => {
958             Start => '$val',
959             MaxSubdirs => 10, # (have seen 5 in a DNG 1.4 image)
960             },
961             },
962             { #16
963             Name => 'A100DataOffset',
964             Notes => 'the data offset in original Sony DSLR-A100 ARW images',
965             DataMember => 'A100DataOffset',
966             RawConv => '$$self{A100DataOffset} = $val',
967             WriteGroup => 'IFD0', # (only for Validate)
968             IsOffset => 1,
969             Protected => 2,
970             },
971             ],
972             0x14c => {
973             Name => 'InkSet',
974             Writable => 'int16u',
975             WriteGroup => 'IFD0',
976             PrintConv => { #3
977             1 => 'CMYK',
978             2 => 'Not CMYK',
979             },
980             },
981             0x14d => 'InkNames', #3
982             0x14e => 'NumberofInks', #3
983             0x150 => 'DotRange',
984             0x151 => {
985             Name => 'TargetPrinter',
986             Writable => 'string',
987             WriteGroup => 'IFD0',
988             },
989             0x152 => {
990             Name => 'ExtraSamples',
991             PrintConv => { #20
992             0 => 'Unspecified',
993             1 => 'Associated Alpha',
994             2 => 'Unassociated Alpha',
995             },
996             },
997             0x153 => {
998             Name => 'SampleFormat',
999             Notes => 'SamplesPerPixel values',
1000             WriteGroup => 'SubIFD', # (only for Validate)
1001             PrintConvColumns => 2,
1002             PrintConv => [ \%sampleFormat, \%sampleFormat, \%sampleFormat, \%sampleFormat ],
1003             },
1004             0x154 => 'SMinSampleValue',
1005             0x155 => 'SMaxSampleValue',
1006             0x156 => 'TransferRange',
1007             0x157 => 'ClipPath', #3
1008             0x158 => 'XClipPathUnits', #3
1009             0x159 => 'YClipPathUnits', #3
1010             0x15a => { #3
1011             Name => 'Indexed',
1012             PrintConv => { 0 => 'Not indexed', 1 => 'Indexed' },
1013             },
1014             0x15b => {
1015             Name => 'JPEGTables',
1016             Binary => 1,
1017             },
1018             0x15f => { #10
1019             Name => 'OPIProxy',
1020             PrintConv => {
1021             0 => 'Higher resolution image does not exist',
1022             1 => 'Higher resolution image exists',
1023             },
1024             },
1025             # 0x181 => 'Decode', #20 (typo! - should be 0x1b1, ref 21)
1026             # 0x182 => 'DefaultImageColor', #20 (typo! - should be 0x1b2, ref 21)
1027             0x190 => { #3
1028             Name => 'GlobalParametersIFD',
1029             Groups => { 1 => 'GlobParamIFD' },
1030             Flags => 'SubIFD',
1031             SubDirectory => {
1032             DirName => 'GlobParamIFD',
1033             Start => '$val',
1034             MaxSubdirs => 1,
1035             },
1036             },
1037             0x191 => { #3
1038             Name => 'ProfileType',
1039             PrintConv => { 0 => 'Unspecified', 1 => 'Group 3 FAX' },
1040             },
1041             0x192 => { #3
1042             Name => 'FaxProfile',
1043             PrintConv => {
1044             0 => 'Unknown',
1045             1 => 'Minimal B&W lossless, S',
1046             2 => 'Extended B&W lossless, F',
1047             3 => 'Lossless JBIG B&W, J',
1048             4 => 'Lossy color and grayscale, C',
1049             5 => 'Lossless color and grayscale, L',
1050             6 => 'Mixed raster content, M',
1051             7 => 'Profile T', #20
1052             255 => 'Multi Profiles', #20
1053             },
1054             },
1055             0x193 => { #3
1056             Name => 'CodingMethods',
1057             PrintConv => { BITMASK => {
1058             0 => 'Unspecified compression',
1059             1 => 'Modified Huffman',
1060             2 => 'Modified Read',
1061             3 => 'Modified MR',
1062             4 => 'JBIG',
1063             5 => 'Baseline JPEG',
1064             6 => 'JBIG color',
1065             } },
1066             },
1067             0x194 => 'VersionYear', #3
1068             0x195 => 'ModeNumber', #3
1069             0x1b1 => 'Decode', #3
1070             0x1b2 => 'DefaultImageColor', #3 (changed to ImageBaseColor, ref 21)
1071             0x1b3 => 'T82Options', #20
1072             0x1b5 => { #19
1073             Name => 'JPEGTables',
1074             Binary => 1,
1075             },
1076             0x200 => {
1077             Name => 'JPEGProc',
1078             PrintConv => {
1079             1 => 'Baseline',
1080             14 => 'Lossless',
1081             },
1082             },
1083             0x201 => [
1084             {
1085             Name => 'ThumbnailOffset',
1086             Notes => q{
1087             ThumbnailOffset in IFD1 of JPEG and some TIFF-based images, IFD0 of MRW
1088             images and AVI and MOV videos, and the SubIFD in IFD1 of SRW images;
1089             PreviewImageStart in MakerNotes and IFD0 of ARW and SR2 images;
1090             JpgFromRawStart in SubIFD of NEF images and IFD2 of PEF images; and
1091             OtherImageStart in everything else
1092             },
1093             # thumbnail is found in IFD1 of JPEG and TIFF images, and
1094             # IFD0 of EXIF information in FujiFilm AVI (RIFF) and MOV videos
1095             Condition => q{
1096             # recognize NRW file from a JPEG-compressed thumbnail in IFD0
1097             if ($$self{TIFF_TYPE} eq 'NEF' and $$self{DIR_NAME} eq 'IFD0' and $$self{Compression} == 6) {
1098             $self->OverrideFileType($$self{TIFF_TYPE} = 'NRW');
1099             }
1100             $$self{DIR_NAME} eq 'IFD1' or
1101             ($$self{DIR_NAME} eq 'IFD0' and $$self{FILE_TYPE} =~ /^(RIFF|MOV)$/)
1102             },
1103             IsOffset => 1,
1104             OffsetPair => 0x202,
1105             DataTag => 'ThumbnailImage',
1106             Writable => 'int32u',
1107             WriteGroup => 'IFD1',
1108             # according to the EXIF spec. a JPEG-compressed thumbnail image may not
1109             # be stored in a TIFF file, but these TIFF-based RAW image formats
1110             # use IFD1 for a JPEG-compressed thumbnail: CR2, ARW, SR2 and PEF.
1111             # (SRF also stores a JPEG image in IFD1, but it is actually a preview
1112             # and we don't yet write SRF anyway)
1113             WriteCondition => q{
1114             $$self{FILE_TYPE} ne "TIFF" or
1115             $$self{TIFF_TYPE} =~ /^(CR2|ARW|SR2|PEF)$/
1116             },
1117             Protected => 2,
1118             },
1119             {
1120             Name => 'ThumbnailOffset',
1121             # thumbnail in IFD0 of MRW images (Minolta A200)
1122             # and IFD0 of NRW images (Nikon Coolpix P6000,P7000,P7100)
1123             Condition => '$$self{DIR_NAME} eq "IFD0" and $$self{TIFF_TYPE} =~ /^(MRW|NRW)$/',
1124             IsOffset => 1,
1125             OffsetPair => 0x202,
1126             # A200 uses the wrong base offset for this pointer!!
1127             WrongBase => '$$self{Model} =~ /^DiMAGE A200/ ? $$self{MRW_WrongBase} : undef',
1128             DataTag => 'ThumbnailImage',
1129             Writable => 'int32u',
1130             WriteGroup => 'IFD0',
1131             Protected => 2,
1132             Permanent => 1,
1133             },
1134             {
1135             Name => 'ThumbnailOffset',
1136             # in SubIFD of IFD1 in Samsung SRW images
1137             Condition => q{
1138             $$self{TIFF_TYPE} eq 'SRW' and $$self{DIR_NAME} eq 'SubIFD' and
1139             $$self{PATH}[-2] eq 'IFD1'
1140             },
1141             IsOffset => 1,
1142             OffsetPair => 0x202,
1143             DataTag => 'ThumbnailImage',
1144             Writable => 'int32u',
1145             WriteGroup => 'SubIFD',
1146             Protected => 2,
1147             Permanent => 1,
1148             },
1149             {
1150             Name => 'PreviewImageStart',
1151             Condition => '$$self{DIR_NAME} eq "MakerNotes"',
1152             IsOffset => 1,
1153             OffsetPair => 0x202,
1154             DataTag => 'PreviewImage',
1155             Writable => 'int32u',
1156             WriteGroup => 'MakerNotes',
1157             Protected => 2,
1158             Permanent => 1,
1159             },
1160             {
1161             Name => 'PreviewImageStart',
1162             # PreviewImage in IFD0 of ARW and SR2 files for all models
1163             Condition => '$$self{DIR_NAME} eq "IFD0" and $$self{TIFF_TYPE} =~ /^(ARW|SR2)$/',
1164             IsOffset => 1,
1165             OffsetPair => 0x202,
1166             DataTag => 'PreviewImage',
1167             Writable => 'int32u',
1168             WriteGroup => 'IFD0',
1169             Protected => 2,
1170             Permanent => 1,
1171             },
1172             {
1173             Name => 'JpgFromRawStart',
1174             Condition => '$$self{DIR_NAME} eq "SubIFD"',
1175             IsOffset => 1,
1176             OffsetPair => 0x202,
1177             DataTag => 'JpgFromRaw',
1178             Writable => 'int32u',
1179             WriteGroup => 'SubIFD',
1180             # JpgFromRaw is in SubIFD of NEF, NRW and SRW files
1181             Protected => 2,
1182             Permanent => 1,
1183             },
1184             {
1185             Name => 'JpgFromRawStart',
1186             Condition => '$$self{DIR_NAME} eq "IFD2"',
1187             IsOffset => 1,
1188             OffsetPair => 0x202,
1189             DataTag => 'JpgFromRaw',
1190             Writable => 'int32u',
1191             WriteGroup => 'IFD2',
1192             # JpgFromRaw is in IFD2 of PEF files
1193             Protected => 2,
1194             Permanent => 1,
1195             },
1196             {
1197             Name => 'OtherImageStart',
1198             Condition => '$$self{DIR_NAME} eq "SubIFD1"',
1199             IsOffset => 1,
1200             OffsetPair => 0x202,
1201             DataTag => 'OtherImage',
1202             Writable => 'int32u',
1203             WriteGroup => 'SubIFD1',
1204             Protected => 2,
1205             Permanent => 1,
1206             },
1207             {
1208             Name => 'OtherImageStart',
1209             Condition => '$$self{DIR_NAME} eq "SubIFD2"',
1210             IsOffset => 1,
1211             OffsetPair => 0x202,
1212             DataTag => 'OtherImage',
1213             Writable => 'int32u',
1214             WriteGroup => 'SubIFD2',
1215             Protected => 2,
1216             Permanent => 1,
1217             },
1218             {
1219             Name => 'OtherImageStart',
1220             IsOffset => 1,
1221             OffsetPair => 0x202,
1222             },
1223             ],
1224             0x202 => [
1225             {
1226             Name => 'ThumbnailLength',
1227             Notes => q{
1228             ThumbnailLength in IFD1 of JPEG and some TIFF-based images, IFD0 of MRW
1229             images and AVI and MOV videos, and the SubIFD in IFD1 of SRW images;
1230             PreviewImageLength in MakerNotes and IFD0 of ARW and SR2 images;
1231             JpgFromRawLength in SubIFD of NEF images, and IFD2 of PEF images; and
1232             OtherImageLength in everything else
1233             },
1234             Condition => q{
1235             $$self{DIR_NAME} eq 'IFD1' or
1236             ($$self{DIR_NAME} eq 'IFD0' and $$self{FILE_TYPE} =~ /^(RIFF|MOV)$/)
1237             },
1238             OffsetPair => 0x201,
1239             DataTag => 'ThumbnailImage',
1240             Writable => 'int32u',
1241             WriteGroup => 'IFD1',
1242             WriteCondition => q{
1243             $$self{FILE_TYPE} ne "TIFF" or
1244             $$self{TIFF_TYPE} =~ /^(CR2|ARW|SR2|PEF)$/
1245             },
1246             Protected => 2,
1247             },
1248             {
1249             Name => 'ThumbnailLength',
1250             # thumbnail in IFD0 of MRW images (Minolta A200)
1251             # and IFD0 of NRW images (Nikon Coolpix P6000,P7000,P7100)
1252             Condition => '$$self{DIR_NAME} eq "IFD0" and $$self{TIFF_TYPE} =~ /^(MRW|NRW)$/',
1253             OffsetPair => 0x201,
1254             DataTag => 'ThumbnailImage',
1255             Writable => 'int32u',
1256             WriteGroup => 'IFD0',
1257             Protected => 2,
1258             Permanent => 1,
1259             },
1260             {
1261             Name => 'ThumbnailLength',
1262             # in SubIFD of IFD1 in Samsung SRW images
1263             Condition => q{
1264             $$self{TIFF_TYPE} eq 'SRW' and $$self{DIR_NAME} eq 'SubIFD' and
1265             $$self{PATH}[-2] eq 'IFD1'
1266             },
1267             OffsetPair => 0x201,
1268             DataTag => 'ThumbnailImage',
1269             Writable => 'int32u',
1270             WriteGroup => 'SubIFD',
1271             Protected => 2,
1272             Permanent => 1,
1273             },
1274             {
1275             Name => 'PreviewImageLength',
1276             Condition => '$$self{DIR_NAME} eq "MakerNotes"',
1277             OffsetPair => 0x201,
1278             DataTag => 'PreviewImage',
1279             Writable => 'int32u',
1280             WriteGroup => 'MakerNotes',
1281             Protected => 2,
1282             Permanent => 1,
1283             },
1284             {
1285             Name => 'PreviewImageLength',
1286             # PreviewImage in IFD0 of ARW and SR2 files for all models
1287             Condition => '$$self{DIR_NAME} eq "IFD0" and $$self{TIFF_TYPE} =~ /^(ARW|SR2)$/',
1288             OffsetPair => 0x201,
1289             DataTag => 'PreviewImage',
1290             Writable => 'int32u',
1291             WriteGroup => 'IFD0',
1292             Protected => 2,
1293             Permanent => 1,
1294             },
1295             {
1296             Name => 'JpgFromRawLength',
1297             Condition => '$$self{DIR_NAME} eq "SubIFD"',
1298             OffsetPair => 0x201,
1299             DataTag => 'JpgFromRaw',
1300             Writable => 'int32u',
1301             WriteGroup => 'SubIFD',
1302             Protected => 2,
1303             Permanent => 1,
1304             },
1305             {
1306             Name => 'JpgFromRawLength',
1307             Condition => '$$self{DIR_NAME} eq "IFD2"',
1308             OffsetPair => 0x201,
1309             DataTag => 'JpgFromRaw',
1310             Writable => 'int32u',
1311             WriteGroup => 'IFD2',
1312             Protected => 2,
1313             Permanent => 1,
1314             },
1315             {
1316             Name => 'OtherImageLength',
1317             Condition => '$$self{DIR_NAME} eq "SubIFD1"',
1318             OffsetPair => 0x201,
1319             DataTag => 'OtherImage',
1320             Writable => 'int32u',
1321             WriteGroup => 'SubIFD1',
1322             Protected => 2,
1323             Permanent => 1,
1324             },
1325             {
1326             Name => 'OtherImageLength',
1327             Condition => '$$self{DIR_NAME} eq "SubIFD2"',
1328             OffsetPair => 0x201,
1329             DataTag => 'OtherImage',
1330             Writable => 'int32u',
1331             WriteGroup => 'SubIFD2',
1332             Protected => 2,
1333             Permanent => 1,
1334             },
1335             {
1336             Name => 'OtherImageLength',
1337             OffsetPair => 0x201,
1338             },
1339             ],
1340             0x203 => 'JPEGRestartInterval',
1341             0x205 => 'JPEGLosslessPredictors',
1342             0x206 => 'JPEGPointTransforms',
1343             0x207 => {
1344             Name => 'JPEGQTables',
1345             IsOffset => 1,
1346             # this tag is not supported for writing, so define an
1347             # invalid offset pair to cause a "No size tag" error to be
1348             # generated if we try to write a file containing this tag
1349             OffsetPair => -1,
1350             },
1351             0x208 => {
1352             Name => 'JPEGDCTables',
1353             IsOffset => 1,
1354             OffsetPair => -1, # (see comment for JPEGQTables)
1355             },
1356             0x209 => {
1357             Name => 'JPEGACTables',
1358             IsOffset => 1,
1359             OffsetPair => -1, # (see comment for JPEGQTables)
1360             },
1361             0x211 => {
1362             Name => 'YCbCrCoefficients',
1363             Protected => 1,
1364             Writable => 'rational64u',
1365             WriteGroup => 'IFD0',
1366             Count => 3,
1367             Priority => 0,
1368             },
1369             0x212 => {
1370             Name => 'YCbCrSubSampling',
1371             Protected => 1,
1372             Writable => 'int16u',
1373             WriteGroup => 'IFD0',
1374             Count => 2,
1375             PrintConvColumns => 2,
1376             PrintConv => \%Image::ExifTool::JPEG::yCbCrSubSampling,
1377             Priority => 0,
1378             },
1379             0x213 => {
1380             Name => 'YCbCrPositioning',
1381             Protected => 1,
1382             Writable => 'int16u',
1383             WriteGroup => 'IFD0',
1384             Mandatory => 1,
1385             PrintConv => {
1386             1 => 'Centered',
1387             2 => 'Co-sited',
1388             },
1389             Priority => 0,
1390             },
1391             0x214 => {
1392             Name => 'ReferenceBlackWhite',
1393             Writable => 'rational64u',
1394             WriteGroup => 'IFD0',
1395             Count => 6,
1396             Priority => 0,
1397             },
1398             # 0x220 - int32u: 0 (IFD0, Xaiomi Redmi models)
1399             # 0x221 - int32u: 0 (IFD0, Xaiomi Redmi models)
1400             # 0x222 - int32u: 0 (IFD0, Xaiomi Redmi models)
1401             # 0x223 - int32u: 0 (IFD0, Xaiomi Redmi models)
1402             # 0x224 - int32u: 0,1 (IFD0, Xaiomi Redmi models)
1403             # 0x225 - string: "" (IFD0, Xaiomi Redmi models)
1404             0x22f => 'StripRowCounts',
1405             0x2bc => {
1406             Name => 'ApplicationNotes', # (writable directory!)
1407             Format => 'undef',
1408             Writable => 'int8u',
1409             WriteGroup => 'IFD0', # (only for Validate)
1410             Flags => [ 'Binary', 'Protected' ],
1411             # this could be an XMP block
1412             SubDirectory => {
1413             DirName => 'XMP',
1414             TagTable => 'Image::ExifTool::XMP::Main',
1415             },
1416             },
1417             0x3e7 => 'USPTOMiscellaneous', #20
1418             0x1000 => { #5
1419             Name => 'RelatedImageFileFormat',
1420             Protected => 1,
1421             Writable => 'string',
1422             WriteGroup => 'InteropIFD',
1423             },
1424             0x1001 => { #5
1425             Name => 'RelatedImageWidth',
1426             Protected => 1,
1427             Writable => 'int16u',
1428             WriteGroup => 'InteropIFD',
1429             },
1430             0x1002 => { #5
1431             Name => 'RelatedImageHeight',
1432             Notes => 'called RelatedImageLength by the DCF spec.',
1433             Protected => 1,
1434             Writable => 'int16u',
1435             WriteGroup => 'InteropIFD',
1436             },
1437             # (0x474x tags written by MicrosoftPhoto)
1438             0x4746 => { #PH
1439             Name => 'Rating',
1440             Writable => 'int16u',
1441             WriteGroup => 'IFD0',
1442             Avoid => 1,
1443             },
1444             0x4747 => { # (written by Digital Image Pro)
1445             Name => 'XP_DIP_XML',
1446             Format => 'undef',
1447             # the following reference indicates this is Unicode:
1448             # http://social.msdn.microsoft.com/Forums/en-US/isvvba/thread/ce6edcbb-8fc2-40c6-ad98-85f5d835ddfb
1449             ValueConv => '$self->Decode($val,"UCS2","II")',
1450             },
1451             0x4748 => {
1452             Name => 'StitchInfo',
1453             SubDirectory => {
1454             TagTable => 'Image::ExifTool::Microsoft::Stitch',
1455             ByteOrder => 'LittleEndian', #PH (NC)
1456             },
1457             },
1458             0x4749 => { #PH
1459             Name => 'RatingPercent',
1460             Writable => 'int16u',
1461             WriteGroup => 'IFD0',
1462             Avoid => 1,
1463             },
1464             0x7000 => { #JR
1465             Name => 'SonyRawFileType',
1466             # (only valid if Sony:FileFormat >= ARW 2.0, ref IB)
1467             # Writable => 'int16u', (don't allow writes for now)
1468             PrintConv => {
1469             0 => 'Sony Uncompressed 14-bit RAW',
1470             1 => 'Sony Uncompressed 12-bit RAW', #IB
1471             2 => 'Sony Compressed RAW', # (lossy, ref IB)
1472             3 => 'Sony Lossless Compressed RAW', #IB
1473             4 => 'Sony Lossless Compressed RAW 2', #JR (ILCE-1)
1474             },
1475             },
1476             # 0x7001 - int16u[1] (in SubIFD of Sony ARW images) - values: 0,1
1477             0x7010 => { #IB
1478             Name => 'SonyToneCurve',
1479             # int16u[4] (in SubIFD of Sony ARW images -- don't allow writes for now)
1480             # - only the middle 4 points are stored (lower comes from black level,
1481             # and upper from data maximum)
1482             },
1483             # 0x7011 - int16u[4] (in SubIFD of Sony ARW images) - values: "0 4912 8212 12287","4000 7200 10050 12075"
1484             # 0x7020 - int32u[1] (in SubIFD of Sony ARW images) - values: 0,3
1485             0x7031 => {
1486             Name => 'VignettingCorrection',
1487             Notes => 'found in Sony ARW images',
1488             Protected => 1,
1489             Writable => 'int16s',
1490             WriteGroup => 'SubIFD',
1491             PrintConv => {
1492             256 => 'Off',
1493             257 => 'Auto',
1494             272 => 'Auto (ILCE-1)', #JR
1495             511 => 'No correction params available',
1496             },
1497             },
1498             0x7032 => {
1499             Name => 'VignettingCorrParams', #forum7640
1500             Notes => 'found in Sony ARW images',
1501             Protected => 1,
1502             Writable => 'int16s',
1503             WriteGroup => 'SubIFD',
1504             Count => 17,
1505             },
1506             0x7034 => {
1507             Name => 'ChromaticAberrationCorrection',
1508             Notes => 'found in Sony ARW images',
1509             Protected => 1,
1510             Writable => 'int16s',
1511             WriteGroup => 'SubIFD',
1512             PrintConv => {
1513             0 => 'Off',
1514             1 => 'Auto',
1515             255 => 'No correction params available',
1516             },
1517             },
1518             0x7035 => {
1519             Name => 'ChromaticAberrationCorrParams', #forum6509
1520             Notes => 'found in Sony ARW images',
1521             Protected => 1,
1522             Writable => 'int16s',
1523             WriteGroup => 'SubIFD',
1524             Count => 33,
1525             },
1526             0x7036 => {
1527             Name => 'DistortionCorrection',
1528             Notes => 'found in Sony ARW images',
1529             Protected => 1,
1530             Writable => 'int16s',
1531             WriteGroup => 'SubIFD',
1532             PrintConv => {
1533             0 => 'Off',
1534             1 => 'Auto',
1535             17 => 'Auto fixed by lens',
1536             255 => 'No correction params available',
1537             },
1538             },
1539             0x7037 => {
1540             Name => 'DistortionCorrParams', #forum6509
1541             Notes => 'found in Sony ARW images',
1542             Protected => 1,
1543             Writable => 'int16s',
1544             WriteGroup => 'SubIFD',
1545             Count => 17,
1546             },
1547             0x74c7 => { #IB (in ARW images from some Sony cameras)
1548             Name => 'SonyCropTopLeft',
1549             Writable => 'int32u',
1550             WriteGroup => 'SubIFD',
1551             Count => 2,
1552             Permanent => 1,
1553             Protected => 1,
1554             },
1555             0x74c8 => { #IB (in ARW images from some Sony cameras)
1556             Name => 'SonyCropSize',
1557             Writable => 'int32u',
1558             WriteGroup => 'SubIFD',
1559             Count => 2,
1560             Permanent => 1,
1561             Protected => 1,
1562             },
1563             0x800d => 'ImageID', #10
1564             0x80a3 => { Name => 'WangTag1', Binary => 1 }, #20
1565             0x80a4 => { Name => 'WangAnnotation', Binary => 1 },
1566             0x80a5 => { Name => 'WangTag3', Binary => 1 }, #20
1567             0x80a6 => { #20
1568             Name => 'WangTag4',
1569             PrintConv => 'length($val) <= 64 ? $val : \$val',
1570             },
1571             # tags 0x80b8-0x80bc are registered to Island Graphics
1572             0x80b9 => 'ImageReferencePoints', #29
1573             0x80ba => 'RegionXformTackPoint', #29
1574             0x80bb => 'WarpQuadrilateral', #29
1575             0x80bc => 'AffineTransformMat', #29
1576             0x80e3 => 'Matteing', #9
1577             0x80e4 => 'DataType', #9
1578             0x80e5 => 'ImageDepth', #9
1579             0x80e6 => 'TileDepth', #9
1580             # tags 0x8214-0x8219 are registered to Pixar
1581             0x8214 => 'ImageFullWidth', #29
1582             0x8215 => 'ImageFullHeight', #29
1583             0x8216 => 'TextureFormat', #29
1584             0x8217 => 'WrapModes', #29
1585             0x8218 => 'FovCot', #29
1586             0x8219 => 'MatrixWorldToScreen', #29
1587             0x821a => 'MatrixWorldToCamera', #29
1588             0x827d => 'Model2', #29 (Eastman Kodak)
1589             0x828d => { #12
1590             Name => 'CFARepeatPatternDim',
1591             Protected => 1,
1592             Writable => 'int16u',
1593             WriteGroup => 'SubIFD',
1594             Count => 2,
1595             },
1596             0x828e => {
1597             Name => 'CFAPattern2', #12
1598             Format => 'int8u', # (written incorrectly as 'undef' in Nikon NRW images)
1599             Protected => 1,
1600             Writable => 'int8u',
1601             WriteGroup => 'SubIFD',
1602             Count => -1,
1603             },
1604             0x828f => { #12
1605             Name => 'BatteryLevel',
1606             Groups => { 2 => 'Camera' },
1607             },
1608             0x8290 => {
1609             Name => 'KodakIFD',
1610             Groups => { 1 => 'KodakIFD' },
1611             Flags => 'SubIFD',
1612             Notes => 'used in various types of Kodak images',
1613             SubDirectory => {
1614             TagTable => 'Image::ExifTool::Kodak::IFD',
1615             DirName => 'KodakIFD',
1616             Start => '$val',
1617             MaxSubdirs => 1,
1618             },
1619             },
1620             0x8298 => {
1621             Name => 'Copyright',
1622             Groups => { 2 => 'Author' },
1623             Format => 'undef',
1624             Writable => 'string',
1625             WriteGroup => 'IFD0',
1626             Notes => q{
1627             may contain copyright notices for photographer and editor, separated by a
1628             newline. As per the EXIF specification, the newline is replaced by a null
1629             byte when writing to file, but this may be avoided by disabling the print
1630             conversion
1631             },
1632             # internally the strings are separated by a null character in this format:
1633             # Photographer only: photographer + NULL
1634             # Both: photographer + NULL + editor + NULL
1635             # Editor only: SPACE + NULL + editor + NULL
1636             # (this is done as a RawConv so conditional replaces will work properly)
1637             RawConv => sub {
1638             my ($val, $self) = @_;
1639             $val =~ s/ *\0/\n/; # translate first NULL to a newline, removing trailing blanks
1640             $val =~ s/ *\0.*//s; # truncate at second NULL and remove trailing blanks
1641             $val =~ s/\n$//; # remove trailing newline if it exists
1642             # decode if necessary (note: this is the only non-'string' EXIF value like this)
1643             my $enc = $self->Options('CharsetEXIF');
1644             $val = $self->Decode($val,$enc) if $enc;
1645             return $val;
1646             },
1647             RawConvInv => '$val . "\0"',
1648             PrintConvInv => sub {
1649             my ($val, $self) = @_;
1650             # encode if necessary (not automatic because Format is 'undef')
1651             my $enc = $self->Options('CharsetEXIF');
1652             $val = $self->Encode($val,$enc) if $enc and $val !~ /\0/;
1653             if ($val =~ /(.*?)\s*[\n\r]+\s*(.*)/s) {
1654             return $1 unless length $2;
1655             # photographer copyright set to ' ' if it doesn't exist, according to spec.
1656             return((length($1) ? $1 : ' ') . "\0" . $2);
1657             }
1658             return $val;
1659             },
1660             },
1661             0x829a => {
1662             Name => 'ExposureTime',
1663             Writable => 'rational64u',
1664             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
1665             PrintConvInv => '$val',
1666             },
1667             0x829d => {
1668             Name => 'FNumber',
1669             Writable => 'rational64u',
1670             PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)',
1671             PrintConvInv => '$val',
1672             },
1673             0x82a5 => { #3
1674             Name => 'MDFileTag',
1675             Notes => 'tags 0x82a5-0x82ac are used in Molecular Dynamics GEL files',
1676             },
1677             0x82a6 => 'MDScalePixel', #3
1678             0x82a7 => 'MDColorTable', #3
1679             0x82a8 => 'MDLabName', #3
1680             0x82a9 => 'MDSampleInfo', #3
1681             0x82aa => 'MDPrepDate', #3
1682             0x82ab => 'MDPrepTime', #3
1683             0x82ac => 'MDFileUnits', #3
1684             0x830e => { #30 (GeoTiff)
1685             Name => 'PixelScale',
1686             Writable => 'double',
1687             WriteGroup => 'IFD0',
1688             Count => 3,
1689             },
1690             0x8335 => 'AdventScale', #20
1691             0x8336 => 'AdventRevision', #20
1692             0x835c => 'UIC1Tag', #23
1693             0x835d => 'UIC2Tag', #23
1694             0x835e => 'UIC3Tag', #23
1695             0x835f => 'UIC4Tag', #23
1696             0x83bb => { #12
1697             Name => 'IPTC-NAA', # (writable directory! -- but see note below)
1698             # this should actually be written as 'undef' (see
1699             # http://www.awaresystems.be/imaging/tiff/tifftags/iptc.html),
1700             # but Photoshop writes it as int32u and Nikon Capture won't read
1701             # anything else, so we do the same thing here... Doh!
1702             Format => 'undef', # convert binary values as undef
1703             Writable => 'int32u', # but write int32u format code in IFD
1704             WriteGroup => 'IFD0',
1705             Flags => [ 'Binary', 'Protected' ],
1706             SubDirectory => {
1707             DirName => 'IPTC',
1708             TagTable => 'Image::ExifTool::IPTC::Main',
1709             },
1710             # Note: This directory may be written as a block via the IPTC-NAA tag,
1711             # but this technique is not recommended. Instead, it is better to
1712             # write the Extra IPTC tag and let ExifTool decide where it should go.
1713             },
1714             0x847e => 'IntergraphPacketData', #3
1715             0x847f => 'IntergraphFlagRegisters', #3
1716             0x8480 => { #30 (GeoTiff, obsolete)
1717             Name => 'IntergraphMatrix',
1718             Writable => 'double',
1719             WriteGroup => 'IFD0',
1720             Count => -1,
1721             },
1722             0x8481 => 'INGRReserved', #20
1723             0x8482 => { #30 (GeoTiff)
1724             Name => 'ModelTiePoint',
1725             Groups => { 2 => 'Location' },
1726             Writable => 'double',
1727             WriteGroup => 'IFD0',
1728             Count => -1,
1729             },
1730             0x84e0 => 'Site', #9
1731             0x84e1 => 'ColorSequence', #9
1732             0x84e2 => 'IT8Header', #9
1733             0x84e3 => { #9
1734             Name => 'RasterPadding',
1735             PrintConv => { #20
1736             0 => 'Byte',
1737             1 => 'Word',
1738             2 => 'Long Word',
1739             9 => 'Sector',
1740             10 => 'Long Sector',
1741             },
1742             },
1743             0x84e4 => 'BitsPerRunLength', #9
1744             0x84e5 => 'BitsPerExtendedRunLength', #9
1745             0x84e6 => 'ColorTable', #9
1746             0x84e7 => { #9
1747             Name => 'ImageColorIndicator',
1748             PrintConv => { #20
1749             0 => 'Unspecified Image Color',
1750             1 => 'Specified Image Color',
1751             },
1752             },
1753             0x84e8 => { #9
1754             Name => 'BackgroundColorIndicator',
1755             PrintConv => { #20
1756             0 => 'Unspecified Background Color',
1757             1 => 'Specified Background Color',
1758             },
1759             },
1760             0x84e9 => 'ImageColorValue', #9
1761             0x84ea => 'BackgroundColorValue', #9
1762             0x84eb => 'PixelIntensityRange', #9
1763             0x84ec => 'TransparencyIndicator', #9
1764             0x84ed => 'ColorCharacterization', #9
1765             0x84ee => { #9
1766             Name => 'HCUsage',
1767             PrintConv => { #20
1768             0 => 'CT',
1769             1 => 'Line Art',
1770             2 => 'Trap',
1771             },
1772             },
1773             0x84ef => 'TrapIndicator', #17
1774             0x84f0 => 'CMYKEquivalent', #17
1775             0x8546 => { #11
1776             Name => 'SEMInfo',
1777             Notes => 'found in some scanning electron microscope images',
1778             Writable => 'string',
1779             WriteGroup => 'IFD0',
1780             },
1781             0x8568 => {
1782             Name => 'AFCP_IPTC',
1783             SubDirectory => {
1784             # must change directory name so we don't create this directory
1785             DirName => 'AFCP_IPTC',
1786             TagTable => 'Image::ExifTool::IPTC::Main',
1787             },
1788             },
1789             0x85b8 => 'PixelMagicJBIGOptions', #20
1790             0x85d7 => 'JPLCartoIFD', #exifprobe (NC)
1791             0x85d8 => { #30 (GeoTiff)
1792             Name => 'ModelTransform',
1793             Groups => { 2 => 'Location' },
1794             Writable => 'double',
1795             WriteGroup => 'IFD0',
1796             Count => 16,
1797             },
1798             0x8602 => { #16
1799             Name => 'WB_GRGBLevels',
1800             Notes => 'found in IFD0 of Leaf MOS images',
1801             },
1802             # 0x8603 - Leaf CatchLight color matrix (ref 16)
1803             0x8606 => {
1804             Name => 'LeafData',
1805             Format => 'undef', # avoid converting huge block to string of int8u's!
1806             SubDirectory => {
1807             DirName => 'LeafIFD',
1808             TagTable => 'Image::ExifTool::Leaf::Main',
1809             },
1810             },
1811             0x8649 => { #19
1812             Name => 'PhotoshopSettings',
1813             Format => 'binary',
1814             WriteGroup => 'IFD0', # (only for Validate)
1815             SubDirectory => {
1816             DirName => 'Photoshop',
1817             TagTable => 'Image::ExifTool::Photoshop::Main',
1818             },
1819             },
1820             0x8769 => {
1821             Name => 'ExifOffset',
1822             Groups => { 1 => 'ExifIFD' },
1823             WriteGroup => 'IFD0', # (only for Validate)
1824             SubIFD => 2,
1825             SubDirectory => {
1826             DirName => 'ExifIFD',
1827             Start => '$val',
1828             },
1829             },
1830             0x8773 => {
1831             Name => 'ICC_Profile',
1832             WriteGroup => 'IFD0', # (only for Validate)
1833             SubDirectory => {
1834             TagTable => 'Image::ExifTool::ICC_Profile::Main',
1835             },
1836             },
1837             0x877f => { #20
1838             Name => 'TIFF_FXExtensions',
1839             PrintConv => { BITMASK => {
1840             0 => 'Resolution/Image Width',
1841             1 => 'N Layer Profile M',
1842             2 => 'Shared Data',
1843             3 => 'B&W JBIG2',
1844             4 => 'JBIG2 Profile M',
1845             }},
1846             },
1847             0x8780 => { #20
1848             Name => 'MultiProfiles',
1849             PrintConv => { BITMASK => {
1850             0 => 'Profile S',
1851             1 => 'Profile F',
1852             2 => 'Profile J',
1853             3 => 'Profile C',
1854             4 => 'Profile L',
1855             5 => 'Profile M',
1856             6 => 'Profile T',
1857             7 => 'Resolution/Image Width',
1858             8 => 'N Layer Profile M',
1859             9 => 'Shared Data',
1860             10 => 'JBIG2 Profile M',
1861             }},
1862             },
1863             0x8781 => { #22
1864             Name => 'SharedData',
1865             IsOffset => 1,
1866             # this tag is not supported for writing, so define an
1867             # invalid offset pair to cause a "No size tag" error to be
1868             # generated if we try to write a file containing this tag
1869             OffsetPair => -1,
1870             },
1871             0x8782 => 'T88Options', #20
1872             0x87ac => 'ImageLayer',
1873             0x87af => { #30
1874             Name => 'GeoTiffDirectory',
1875             Format => 'undef',
1876             Writable => 'int16u',
1877             Notes => q{
1878             these "GeoTiff" tags may read and written as a block, but they aren't
1879             extracted unless specifically requested. Byte order changes are handled
1880             automatically when copying between TIFF images with different byte order
1881             },
1882             WriteGroup => 'IFD0',
1883             Binary => 1,
1884             RawConv => '$val . GetByteOrder()', # save byte order
1885             # swap byte order if necessary
1886             RawConvInv => q{
1887             return $val if length $val < 2;
1888             my $order = substr($val, -2);
1889             return $val unless $order eq 'II' or $order eq 'MM';
1890             $val = substr($val, 0, -2);
1891             return $val if $order eq GetByteOrder();
1892             return pack('v*',unpack('n*',$val));
1893             },
1894             },
1895             0x87b0 => { #30
1896             Name => 'GeoTiffDoubleParams',
1897             Format => 'undef',
1898             Writable => 'double',
1899             WriteGroup => 'IFD0',
1900             Binary => 1,
1901             RawConv => '$val . GetByteOrder()', # save byte order
1902             # swap byte order if necessary
1903             RawConvInv => q{
1904             return $val if length $val < 2;
1905             my $order = substr($val, -2);
1906             return $val unless $order eq 'II' or $order eq 'MM';
1907             $val = substr($val, 0, -2);
1908             return $val if $order eq GetByteOrder();
1909             $val =~ s/(.{4})(.{4})/$2$1/sg; # swap words
1910             return pack('V*',unpack('N*',$val));
1911             },
1912             },
1913             0x87b1 => { #30
1914             Name => 'GeoTiffAsciiParams',
1915             Format => 'undef',
1916             Writable => 'string',
1917             WriteGroup => 'IFD0',
1918             Binary => 1,
1919             },
1920             0x87be => 'JBIGOptions', #29
1921             0x8822 => {
1922             Name => 'ExposureProgram',
1923             Groups => { 2 => 'Camera' },
1924             Notes => 'the value of 9 is not standard EXIF, but is used by the Canon EOS 7D',
1925             Writable => 'int16u',
1926             PrintConv => {
1927             0 => 'Not Defined',
1928             1 => 'Manual',
1929             2 => 'Program AE',
1930             3 => 'Aperture-priority AE',
1931             4 => 'Shutter speed priority AE',
1932             5 => 'Creative (Slow speed)',
1933             6 => 'Action (High speed)',
1934             7 => 'Portrait',
1935             8 => 'Landscape',
1936             9 => 'Bulb', #25
1937             },
1938             },
1939             0x8824 => {
1940             Name => 'SpectralSensitivity',
1941             Groups => { 2 => 'Camera' },
1942             Writable => 'string',
1943             },
1944             0x8825 => {
1945             Name => 'GPSInfo',
1946             Groups => { 1 => 'GPS' },
1947             WriteGroup => 'IFD0', # (only for Validate)
1948             Flags => 'SubIFD',
1949             SubDirectory => {
1950             DirName => 'GPS',
1951             TagTable => 'Image::ExifTool::GPS::Main',
1952             Start => '$val',
1953             MaxSubdirs => 1,
1954             },
1955             },
1956             0x8827 => {
1957             Name => 'ISO',
1958             Notes => q{
1959             called ISOSpeedRatings by EXIF 2.2, then PhotographicSensitivity by the EXIF
1960             2.3 spec.
1961             },
1962             Writable => 'int16u',
1963             Count => -1,
1964             PrintConv => '$val=~s/\s+/, /g; $val',
1965             PrintConvInv => '$val=~tr/,//d; $val',
1966             },
1967             0x8828 => {
1968             Name => 'Opto-ElectricConvFactor',
1969             Notes => 'called OECF by the EXIF spec.',
1970             Binary => 1,
1971             },
1972             0x8829 => 'Interlace', #12
1973             0x882a => { #12
1974             Name => 'TimeZoneOffset',
1975             Writable => 'int16s',
1976             Count => -1, # can be 1 or 2
1977             Notes => q{
1978             1 or 2 values: 1. The time zone offset of DateTimeOriginal from GMT in
1979             hours, 2. If present, the time zone offset of ModifyDate
1980             },
1981             },
1982             0x882b => { #12
1983             Name => 'SelfTimerMode',
1984             Writable => 'int16u',
1985             },
1986             0x8830 => { #24
1987             Name => 'SensitivityType',
1988             Notes => 'applies to EXIF:ISO tag',
1989             Writable => 'int16u',
1990             PrintConv => {
1991             0 => 'Unknown',
1992             1 => 'Standard Output Sensitivity',
1993             2 => 'Recommended Exposure Index',
1994             3 => 'ISO Speed',
1995             4 => 'Standard Output Sensitivity and Recommended Exposure Index',
1996             5 => 'Standard Output Sensitivity and ISO Speed',
1997             6 => 'Recommended Exposure Index and ISO Speed',
1998             7 => 'Standard Output Sensitivity, Recommended Exposure Index and ISO Speed',
1999             },
2000             },
2001             0x8831 => { #24
2002             Name => 'StandardOutputSensitivity',
2003             Writable => 'int32u',
2004             },
2005             0x8832 => { #24
2006             Name => 'RecommendedExposureIndex',
2007             Writable => 'int32u',
2008             },
2009             0x8833 => { #24
2010             Name => 'ISOSpeed',
2011             Writable => 'int32u',
2012             },
2013             0x8834 => { #24
2014             Name => 'ISOSpeedLatitudeyyy',
2015             Description => 'ISO Speed Latitude yyy',
2016             Writable => 'int32u',
2017             },
2018             0x8835 => { #24
2019             Name => 'ISOSpeedLatitudezzz',
2020             Description => 'ISO Speed Latitude zzz',
2021             Writable => 'int32u',
2022             },
2023             0x885c => 'FaxRecvParams', #9
2024             0x885d => 'FaxSubAddress', #9
2025             0x885e => 'FaxRecvTime', #9
2026             0x8871 => 'FedexEDR', #exifprobe (NC)
2027             # 0x8889 - string: "portrait" (ExifIFD, Xiaomi POCO F1)
2028             0x888a => { #PH
2029             Name => 'LeafSubIFD',
2030             Format => 'int32u', # Leaf incorrectly uses 'undef' format!
2031             Groups => { 1 => 'LeafSubIFD' },
2032             Flags => 'SubIFD',
2033             SubDirectory => {
2034             TagTable => 'Image::ExifTool::Leaf::SubIFD',
2035             Start => '$val',
2036             },
2037             },
2038             # 0x8891 - int16u: 35 (ExifIFD, Xiaomi POCO F1)
2039             # 0x8894 - int16u: 0 (ExifIFD, Xiaomi POCO F1)
2040             # 0x8895 - int16u: 0 (ExifIFD, Xiaomi POCO F1)
2041             # 0x889a - int16u: 0 (ExifIFD, Xiaomi POCO F1)
2042             # 0x89ab - seen "11 100 130 16 0 0 0 0" in IFD0 of TIFF image from IR scanner (forum8470)
2043             0x9000 => {
2044             Name => 'ExifVersion',
2045             Writable => 'undef',
2046             Mandatory => 1,
2047             RawConv => '$val=~s/\0+$//; $val', # (some idiots add null terminators)
2048             # (allow strings like "2.31" when writing)
2049             PrintConvInv => '$val=~tr/.//d; $val=~/^\d{4}$/ ? $val : $val =~ /^\d{3}$/ ? "0$val" : undef',
2050             },
2051             0x9003 => {
2052             Name => 'DateTimeOriginal',
2053             Description => 'Date/Time Original',
2054             Groups => { 2 => 'Time' },
2055             Notes => 'date/time when original image was taken',
2056             Writable => 'string',
2057             Shift => 'Time',
2058             Validate => 'ValidateExifDate($val)',
2059             PrintConv => '$self->ConvertDateTime($val)',
2060             PrintConvInv => '$self->InverseDateTime($val,0)',
2061             },
2062             0x9004 => {
2063             Name => 'CreateDate',
2064             Groups => { 2 => 'Time' },
2065             Notes => 'called DateTimeDigitized by the EXIF spec.',
2066             Writable => 'string',
2067             Shift => 'Time',
2068             Validate => 'ValidateExifDate($val)',
2069             PrintConv => '$self->ConvertDateTime($val)',
2070             PrintConvInv => '$self->InverseDateTime($val,0)',
2071             },
2072             0x9009 => { # undef[44] (or undef[11]) written by Google Plus uploader - PH
2073             Name => 'GooglePlusUploadCode',
2074             Format => 'int8u',
2075             Writable => 'undef',
2076             Count => -1,
2077             },
2078             0x9010 => {
2079             Name => 'OffsetTime',
2080             Groups => { 2 => 'Time' },
2081             Notes => 'time zone for ModifyDate',
2082             Writable => 'string',
2083             PrintConvInv => q{
2084             return "+00:00" if $val =~ /\d{2}Z$/;
2085             return sprintf("%s%.2d:%.2d",$1,$2,$3) if $val =~ /([-+])(\d{1,2}):(\d{2})/;
2086             return undef;
2087             },
2088             },
2089             0x9011 => {
2090             Name => 'OffsetTimeOriginal',
2091             Groups => { 2 => 'Time' },
2092             Notes => 'time zone for DateTimeOriginal',
2093             Writable => 'string',
2094             PrintConvInv => q{
2095             return "+00:00" if $val =~ /\d{2}Z$/;
2096             return sprintf("%s%.2d:%.2d",$1,$2,$3) if $val =~ /([-+])(\d{1,2}):(\d{2})/;
2097             return undef;
2098             },
2099             },
2100             0x9012 => {
2101             Name => 'OffsetTimeDigitized',
2102             Groups => { 2 => 'Time' },
2103             Notes => 'time zone for CreateDate',
2104             Writable => 'string',
2105             PrintConvInv => q{
2106             return "+00:00" if $val =~ /\d{2}Z$/;
2107             return sprintf("%s%.2d:%.2d",$1,$2,$3) if $val =~ /([-+])(\d{1,2}):(\d{2})/;
2108             return undef;
2109             },
2110             },
2111             0x9101 => {
2112             Name => 'ComponentsConfiguration',
2113             Format => 'int8u',
2114             Protected => 1,
2115             Writable => 'undef',
2116             Count => 4,
2117             Mandatory => 1,
2118             ValueConvInv => '$val=~tr/,//d; $val', # (so we can copy from XMP with -n)
2119             PrintConvColumns => 2,
2120             PrintConv => {
2121             0 => '-',
2122             1 => 'Y',
2123             2 => 'Cb',
2124             3 => 'Cr',
2125             4 => 'R',
2126             5 => 'G',
2127             6 => 'B',
2128             OTHER => sub {
2129             my ($val, $inv, $conv) = @_;
2130             my @a = split /,?\s+/, $val;
2131             if ($inv) {
2132             my %invConv;
2133             $invConv{lc $$conv{$_}} = $_ foreach keys %$conv;
2134             # strings like "YCbCr" and "RGB" still work for writing
2135             @a = $a[0] =~ /(Y|Cb|Cr|R|G|B)/g if @a == 1;
2136             foreach (@a) {
2137             $_ = $invConv{lc $_};
2138             return undef unless defined $_;
2139             }
2140             push @a, 0 while @a < 4;
2141             } else {
2142             foreach (@a) {
2143             $_ = $$conv{$_} || "Err ($_)";
2144             }
2145             }
2146             return join ', ', @a;
2147             },
2148             },
2149             },
2150             0x9102 => {
2151             Name => 'CompressedBitsPerPixel',
2152             Protected => 1,
2153             Writable => 'rational64u',
2154             },
2155             # 0x9103 - int16u: 1 (found in Pentax XG-1 samples)
2156             0x9201 => {
2157             Name => 'ShutterSpeedValue',
2158             Notes => 'displayed in seconds, but stored as an APEX value',
2159             Format => 'rational64s', # Leica M8 patch (incorrectly written as rational64u)
2160             Writable => 'rational64s',
2161             ValueConv => 'IsFloat($val) && abs($val)<100 ? 2**(-$val) : 0',
2162             ValueConvInv => '$val>0 ? -log($val)/log(2) : -100',
2163             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
2164             PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)',
2165             },
2166             0x9202 => {
2167             Name => 'ApertureValue',
2168             Notes => 'displayed as an F number, but stored as an APEX value',
2169             Writable => 'rational64u',
2170             ValueConv => '2 ** ($val / 2)',
2171             ValueConvInv => '$val>0 ? 2*log($val)/log(2) : 0',
2172             PrintConv => 'sprintf("%.1f",$val)',
2173             PrintConvInv => '$val',
2174             },
2175             # Wikipedia: BrightnessValue = Bv = Av + Tv - Sv
2176             # ExifTool: LightValue = LV = Av + Tv - Sv + 5 (5 is the Sv for ISO 100 in Exif usage)
2177             0x9203 => {
2178             Name => 'BrightnessValue',
2179             Writable => 'rational64s',
2180             },
2181             0x9204 => {
2182             Name => 'ExposureCompensation',
2183             Format => 'rational64s', # Leica M8 patch (incorrectly written as rational64u)
2184             Notes => 'called ExposureBiasValue by the EXIF spec.',
2185             Writable => 'rational64s',
2186             PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)',
2187             PrintConvInv => '$val',
2188             },
2189             0x9205 => {
2190             Name => 'MaxApertureValue',
2191             Notes => 'displayed as an F number, but stored as an APEX value',
2192             Groups => { 2 => 'Camera' },
2193             Writable => 'rational64u',
2194             ValueConv => '2 ** ($val / 2)',
2195             ValueConvInv => '$val>0 ? 2*log($val)/log(2) : 0',
2196             PrintConv => 'sprintf("%.1f",$val)',
2197             PrintConvInv => '$val',
2198             },
2199             0x9206 => {
2200             Name => 'SubjectDistance',
2201             Groups => { 2 => 'Camera' },
2202             Writable => 'rational64u',
2203             PrintConv => '$val =~ /^(inf|undef)$/ ? $val : "${val} m"',
2204             PrintConvInv => '$val=~s/\s*m$//;$val',
2205             },
2206             0x9207 => {
2207             Name => 'MeteringMode',
2208             Groups => { 2 => 'Camera' },
2209             Writable => 'int16u',
2210             PrintConv => {
2211             0 => 'Unknown',
2212             1 => 'Average',
2213             2 => 'Center-weighted average',
2214             3 => 'Spot',
2215             4 => 'Multi-spot',
2216             5 => 'Multi-segment',
2217             6 => 'Partial',
2218             255 => 'Other',
2219             },
2220             },
2221             0x9208 => {
2222             Name => 'LightSource',
2223             Groups => { 2 => 'Camera' },
2224             Writable => 'int16u',
2225             SeparateTable => 'LightSource',
2226             PrintConv => \%lightSource,
2227             },
2228             0x9209 => {
2229             Name => 'Flash',
2230             Groups => { 2 => 'Camera' },
2231             Writable => 'int16u',
2232             Flags => 'PrintHex',
2233             SeparateTable => 'Flash',
2234             PrintConv => \%flash,
2235             },
2236             0x920a => {
2237             Name => 'FocalLength',
2238             Groups => { 2 => 'Camera' },
2239             Writable => 'rational64u',
2240             PrintConv => 'sprintf("%.1f mm",$val)',
2241             PrintConvInv => '$val=~s/\s*mm$//;$val',
2242             },
2243             # Note: tags 0x920b-0x9217 are duplicates of 0xa20b-0xa217
2244             # (The EXIF standard uses 0xa2xx, but you'll find both in images)
2245             0x920b => { #12
2246             Name => 'FlashEnergy',
2247             Groups => { 2 => 'Camera' },
2248             },
2249             0x920c => 'SpatialFrequencyResponse', #12 (not in Fuji images - PH)
2250             0x920d => 'Noise', #12
2251             0x920e => 'FocalPlaneXResolution', #12
2252             0x920f => 'FocalPlaneYResolution', #12
2253             0x9210 => { #12
2254             Name => 'FocalPlaneResolutionUnit',
2255             Groups => { 2 => 'Camera' },
2256             PrintConv => {
2257             1 => 'None',
2258             2 => 'inches',
2259             3 => 'cm',
2260             4 => 'mm',
2261             5 => 'um',
2262             },
2263             },
2264             0x9211 => { #12
2265             Name => 'ImageNumber',
2266             Writable => 'int32u',
2267             },
2268             0x9212 => { #12
2269             Name => 'SecurityClassification',
2270             Writable => 'string',
2271             PrintConv => {
2272             T => 'Top Secret',
2273             S => 'Secret',
2274             C => 'Confidential',
2275             R => 'Restricted',
2276             U => 'Unclassified',
2277             },
2278             },
2279             0x9213 => { #12
2280             Name => 'ImageHistory',
2281             Writable => 'string',
2282             },
2283             0x9214 => {
2284             Name => 'SubjectArea',
2285             Groups => { 2 => 'Camera' },
2286             Writable => 'int16u',
2287             Count => -1, # 2, 3 or 4 values
2288             },
2289             0x9215 => 'ExposureIndex', #12
2290             0x9216 => 'TIFF-EPStandardID', #12
2291             0x9217 => { #12
2292             Name => 'SensingMethod',
2293             Groups => { 2 => 'Camera' },
2294             PrintConv => {
2295             # (values 1 and 6 are not used by corresponding EXIF tag 0xa217)
2296             1 => 'Monochrome area',
2297             2 => 'One-chip color area',
2298             3 => 'Two-chip color area',
2299             4 => 'Three-chip color area',
2300             5 => 'Color sequential area',
2301             6 => 'Monochrome linear',
2302             7 => 'Trilinear',
2303             8 => 'Color sequential linear',
2304             },
2305             },
2306             0x923a => 'CIP3DataFile', #20
2307             0x923b => 'CIP3Sheet', #20
2308             0x923c => 'CIP3Side', #20
2309             0x923f => 'StoNits', #9
2310             # handle maker notes as a conditional list
2311             0x927c => \@Image::ExifTool::MakerNotes::Main,
2312             0x9286 => {
2313             Name => 'UserComment',
2314             # I have seen other applications write it incorrectly as 'string' or 'int8u'
2315             Format => 'undef',
2316             Writable => 'undef',
2317             RawConv => 'Image::ExifTool::Exif::ConvertExifText($self,$val,1,$tag)',
2318             # (starts with "ASCII\0\0\0", "UNICODE\0", "JIS\0\0\0\0\0" or "\0\0\0\0\0\0\0\0")
2319             RawConvInv => 'Image::ExifTool::Exif::EncodeExifText($self,$val)',
2320             # SHOULD ADD SPECIAL LOGIC TO ALLOW CONDITIONAL OVERWRITE OF
2321             # "UNKNOWN" VALUES FILLED WITH SPACES
2322             },
2323             0x9290 => {
2324             Name => 'SubSecTime',
2325             Groups => { 2 => 'Time' },
2326             Notes => 'fractional seconds for ModifyDate',
2327             Writable => 'string',
2328             ValueConv => '$val=~s/ +$//; $val', # trim trailing blanks
2329             # extract fractional seconds from a full date/time value
2330             ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)',
2331             },
2332             0x9291 => {
2333             Name => 'SubSecTimeOriginal',
2334             Groups => { 2 => 'Time' },
2335             Notes => 'fractional seconds for DateTimeOriginal',
2336             Writable => 'string',
2337             ValueConv => '$val=~s/ +$//; $val', # trim trailing blanks
2338             ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)',
2339             },
2340             0x9292 => {
2341             Name => 'SubSecTimeDigitized',
2342             Groups => { 2 => 'Time' },
2343             Notes => 'fractional seconds for CreateDate',
2344             Writable => 'string',
2345             ValueConv => '$val=~s/ +$//; $val', # trim trailing blanks
2346             ValueConvInv => '$val=~/^(\d+)\s*$/ ? $1 : ($val=~/\.(\d+)/ ? $1 : undef)',
2347             },
2348             # The following 3 tags are found in MSOffice TIFF images
2349             # References:
2350             # http://social.msdn.microsoft.com/Forums/en-US/os_standocs/thread/03086d55-294a-49d5-967a-5303d34c40f8/
2351             # http://blogs.msdn.com/openspecification/archive/2009/12/08/details-of-three-tiff-tag-extensions-that-microsoft-office-document-imaging-modi-software-may-write-into-the-tiff-files-it-generates.aspx
2352             # http://www.microsoft.com/downloads/details.aspx?FamilyID=0dbc435d-3544-4f4b-9092-2f2643d64a39&displaylang=en#filelist
2353             0x932f => 'MSDocumentText',
2354             0x9330 => {
2355             Name => 'MSPropertySetStorage',
2356             Binary => 1,
2357             },
2358             0x9331 => {
2359             Name => 'MSDocumentTextPosition',
2360             Binary => 1, # (just in case -- don't know what format this is)
2361             },
2362             0x935c => { #3/19
2363             Name => 'ImageSourceData', # (writable directory!)
2364             Writable => 'undef',
2365             WriteGroup => 'IFD0',
2366             SubDirectory => { TagTable => 'Image::ExifTool::Photoshop::DocumentData' },
2367             Binary => 1,
2368             Protected => 1, # (because this can be hundreds of megabytes)
2369             ReadFromRAF => 1, # don't load into memory when reading
2370             },
2371             0x9400 => {
2372             Name => 'AmbientTemperature',
2373             Notes => 'ambient temperature in degrees C, called Temperature by the EXIF spec.',
2374             Writable => 'rational64s',
2375             PrintConv => '"$val C"',
2376             PrintConvInv => '$val=~s/ ?C//; $val',
2377             },
2378             0x9401 => {
2379             Name => 'Humidity',
2380             Notes => 'ambient relative humidity in percent',
2381             Writable => 'rational64u',
2382             },
2383             0x9402 => {
2384             Name => 'Pressure',
2385             Notes => 'air pressure in hPa or mbar',
2386             Writable => 'rational64u',
2387             },
2388             0x9403 => {
2389             Name => 'WaterDepth',
2390             Notes => 'depth under water in metres, negative for above water',
2391             Writable => 'rational64s',
2392             },
2393             0x9404 => {
2394             Name => 'Acceleration',
2395             Notes => 'directionless camera acceleration in units of mGal, or 10-5 m/s2',
2396             Writable => 'rational64u',
2397             },
2398             0x9405 => {
2399             Name => 'CameraElevationAngle',
2400             Writable => 'rational64s',
2401             },
2402             # 0x9999 - string: camera settings (ExifIFD, Xiaomi POCO F1)
2403             # 0x9aaa - int8u[2176]: ? (ExifIFD, Xiaomi POCO F1)
2404             0x9c9b => {
2405             Name => 'XPTitle',
2406             Format => 'undef',
2407             Writable => 'int8u',
2408             WriteGroup => 'IFD0',
2409             Notes => q{
2410             tags 0x9c9b-0x9c9f are used by Windows Explorer; special characters
2411             in these values are converted to UTF-8 by default, or Windows Latin1
2412             with the -L option. XPTitle is ignored by Windows Explorer if
2413             ImageDescription exists
2414             },
2415             ValueConv => '$self->Decode($val,"UCS2","II")',
2416             ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
2417             },
2418             0x9c9c => {
2419             Name => 'XPComment',
2420             Format => 'undef',
2421             Writable => 'int8u',
2422             WriteGroup => 'IFD0',
2423             ValueConv => '$self->Decode($val,"UCS2","II")',
2424             ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
2425             },
2426             0x9c9d => {
2427             Name => 'XPAuthor',
2428             Groups => { 2 => 'Author' },
2429             Format => 'undef',
2430             Writable => 'int8u',
2431             WriteGroup => 'IFD0',
2432             Notes => 'ignored by Windows Explorer if Artist exists',
2433             ValueConv => '$self->Decode($val,"UCS2","II")',
2434             ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
2435             },
2436             0x9c9e => {
2437             Name => 'XPKeywords',
2438             Format => 'undef',
2439             Writable => 'int8u',
2440             WriteGroup => 'IFD0',
2441             ValueConv => '$self->Decode($val,"UCS2","II")',
2442             ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
2443             },
2444             0x9c9f => {
2445             Name => 'XPSubject',
2446             Format => 'undef',
2447             Writable => 'int8u',
2448             WriteGroup => 'IFD0',
2449             ValueConv => '$self->Decode($val,"UCS2","II")',
2450             ValueConvInv => '$self->Encode($val,"UCS2","II") . "\0\0"',
2451             },
2452             0xa000 => {
2453             Name => 'FlashpixVersion',
2454             Writable => 'undef',
2455             Mandatory => 1,
2456             RawConv => '$val=~s/\0+$//; $val', # (some idiots add null terminators)
2457             PrintConvInv => '$val=~tr/.//d; $val=~/^\d{4}$/ ? $val : undef',
2458             },
2459             0xa001 => {
2460             Name => 'ColorSpace',
2461             Notes => q{
2462             the value of 0x2 is not standard EXIF. Instead, an Adobe RGB image is
2463             indicated by "Uncalibrated" with an InteropIndex of "R03". The values
2464             0xfffd and 0xfffe are also non-standard, and are used by some Sony cameras
2465             },
2466             Writable => 'int16u',
2467             Mandatory => 1,
2468             PrintHex => 1,
2469             PrintConv => {
2470             1 => 'sRGB',
2471             2 => 'Adobe RGB',
2472             0xffff => 'Uncalibrated',
2473             # Sony uses these definitions: (ref JD)
2474             # 0xffff => 'Adobe RGB', (conflicts with Uncalibrated)
2475             0xfffe => 'ICC Profile',
2476             0xfffd => 'Wide Gamut RGB',
2477             },
2478             },
2479             0xa002 => {
2480             Name => 'ExifImageWidth',
2481             Notes => 'called PixelXDimension by the EXIF spec.',
2482             Writable => 'int16u',
2483             Mandatory => 1,
2484             },
2485             0xa003 => {
2486             Name => 'ExifImageHeight',
2487             Notes => 'called PixelYDimension by the EXIF spec.',
2488             Writable => 'int16u',
2489             Mandatory => 1,
2490             },
2491             0xa004 => {
2492             Name => 'RelatedSoundFile',
2493             Writable => 'string',
2494             },
2495             0xa005 => {
2496             Name => 'InteropOffset',
2497             Groups => { 1 => 'InteropIFD' },
2498             Flags => 'SubIFD',
2499             Description => 'Interoperability Offset',
2500             SubDirectory => {
2501             DirName => 'InteropIFD',
2502             Start => '$val',
2503             MaxSubdirs => 1,
2504             },
2505             },
2506             # the following 4 tags found in SubIFD1 of some Samsung SRW images
2507             0xa010 => {
2508             Name => 'SamsungRawPointersOffset',
2509             IsOffset => 1,
2510             OffsetPair => 0xa011, # point to associated byte count
2511             },
2512             0xa011 => {
2513             Name => 'SamsungRawPointersLength',
2514             OffsetPair => 0xa010, # point to associated offset
2515             },
2516             0xa101 => {
2517             Name => 'SamsungRawByteOrder',
2518             Format => 'undef',
2519             # this is written incorrectly as string[1], but is "\0\0MM" or "II\0\0"
2520             FixedSize => 4,
2521             Count => 1,
2522             },
2523             0xa102 => {
2524             Name => 'SamsungRawUnknown',
2525             Unknown => 1,
2526             },
2527             0xa20b => {
2528             Name => 'FlashEnergy',
2529             Groups => { 2 => 'Camera' },
2530             Writable => 'rational64u',
2531             },
2532             0xa20c => {
2533             Name => 'SpatialFrequencyResponse',
2534             PrintConv => 'Image::ExifTool::Exif::PrintSFR($val)',
2535             },
2536             0xa20d => 'Noise',
2537             0xa20e => {
2538             Name => 'FocalPlaneXResolution',
2539             Groups => { 2 => 'Camera' },
2540             Writable => 'rational64u',
2541             },
2542             0xa20f => {
2543             Name => 'FocalPlaneYResolution',
2544             Groups => { 2 => 'Camera' },
2545             Writable => 'rational64u',
2546             },
2547             0xa210 => {
2548             Name => 'FocalPlaneResolutionUnit',
2549             Groups => { 2 => 'Camera' },
2550             Notes => 'values 1, 4 and 5 are not standard EXIF',
2551             Writable => 'int16u',
2552             PrintConv => {
2553             1 => 'None', # (not standard EXIF)
2554             2 => 'inches',
2555             3 => 'cm',
2556             4 => 'mm', # (not standard EXIF)
2557             5 => 'um', # (not standard EXIF)
2558             },
2559             },
2560             0xa211 => 'ImageNumber',
2561             0xa212 => 'SecurityClassification',
2562             0xa213 => 'ImageHistory',
2563             0xa214 => {
2564             Name => 'SubjectLocation',
2565             Groups => { 2 => 'Camera' },
2566             Writable => 'int16u',
2567             Count => 2,
2568             },
2569             0xa215 => { Name => 'ExposureIndex', Writable => 'rational64u' },
2570             0xa216 => 'TIFF-EPStandardID',
2571             0xa217 => {
2572             Name => 'SensingMethod',
2573             Groups => { 2 => 'Camera' },
2574             Writable => 'int16u',
2575             PrintConv => {
2576             1 => 'Not defined',
2577             2 => 'One-chip color area',
2578             3 => 'Two-chip color area',
2579             4 => 'Three-chip color area',
2580             5 => 'Color sequential area',
2581             7 => 'Trilinear',
2582             8 => 'Color sequential linear',
2583             # 15 - used by DJI XT2
2584             },
2585             },
2586             0xa300 => {
2587             Name => 'FileSource',
2588             Writable => 'undef',
2589             ValueConvInv => '($val=~/^\d+$/ and $val < 256) ? chr($val) : $val',
2590             PrintConv => {
2591             1 => 'Film Scanner',
2592             2 => 'Reflection Print Scanner',
2593             3 => 'Digital Camera',
2594             # handle the case where Sigma incorrectly gives this tag a count of 4
2595             "\3\0\0\0" => 'Sigma Digital Camera',
2596             },
2597             },
2598             0xa301 => {
2599             Name => 'SceneType',
2600             Writable => 'undef',
2601             ValueConvInv => 'chr($val & 0xff)',
2602             PrintConv => {
2603             1 => 'Directly photographed',
2604             },
2605             },
2606             0xa302 => {
2607             Name => 'CFAPattern',
2608             Writable => 'undef',
2609             RawConv => 'Image::ExifTool::Exif::DecodeCFAPattern($self, $val)',
2610             RawConvInv => q{
2611             my @a = split ' ', $val;
2612             return $val if @a <= 2; # also accept binary data for backward compatibility
2613             return pack(GetByteOrder() eq 'II' ? 'v2C*' : 'n2C*', @a);
2614             },
2615             PrintConv => 'Image::ExifTool::Exif::PrintCFAPattern($val)',
2616             PrintConvInv => 'Image::ExifTool::Exif::GetCFAPattern($val)',
2617             },
2618             0xa401 => {
2619             Name => 'CustomRendered',
2620             Writable => 'int16u',
2621             Notes => q{
2622             only 0 and 1 are standard EXIF, but other values are used by Apple iOS
2623             devices
2624             },
2625             PrintConv => {
2626             0 => 'Normal',
2627             1 => 'Custom',
2628             2 => 'HDR (no original saved)', #32 non-standard (Apple iOS)
2629             3 => 'HDR (original saved)', #32 non-standard (Apple iOS)
2630             4 => 'Original (for HDR)', #32 non-standard (Apple iOS)
2631             6 => 'Panorama', # non-standard (Apple iOS, horizontal or vertical)
2632             7 => 'Portrait HDR', #32 non-standard (Apple iOS)
2633             8 => 'Portrait', # non-standard (Apple iOS, blurred background)
2634             # 9 - also seen (Apple iOS) (HDR Portrait?)
2635             },
2636             },
2637             0xa402 => {
2638             Name => 'ExposureMode',
2639             Groups => { 2 => 'Camera' },
2640             Writable => 'int16u',
2641             PrintConv => {
2642             0 => 'Auto',
2643             1 => 'Manual',
2644             2 => 'Auto bracket',
2645             # have seen 3 from Samsung EX1, NX30, NX200 - PH
2646             },
2647             },
2648             0xa403 => {
2649             Name => 'WhiteBalance',
2650             Groups => { 2 => 'Camera' },
2651             Writable => 'int16u',
2652             # set Priority to zero to keep this WhiteBalance from overriding the
2653             # MakerNotes WhiteBalance, since the MakerNotes WhiteBalance and is more
2654             # accurate and contains more information (if it exists)
2655             Priority => 0,
2656             PrintConv => {
2657             0 => 'Auto',
2658             1 => 'Manual',
2659             },
2660             },
2661             0xa404 => {
2662             Name => 'DigitalZoomRatio',
2663             Groups => { 2 => 'Camera' },
2664             Writable => 'rational64u',
2665             },
2666             0xa405 => {
2667             Name => 'FocalLengthIn35mmFormat',
2668             Notes => 'called FocalLengthIn35mmFilm by the EXIF spec.',
2669             Groups => { 2 => 'Camera' },
2670             Writable => 'int16u',
2671             PrintConv => '"$val mm"',
2672             PrintConvInv => '$val=~s/\s*mm$//;$val',
2673             },
2674             0xa406 => {
2675             Name => 'SceneCaptureType',
2676             Groups => { 2 => 'Camera' },
2677             Writable => 'int16u',
2678             Notes => 'the value of 4 is non-standard, and used by some Samsung models',
2679             PrintConv => {
2680             0 => 'Standard',
2681             1 => 'Landscape',
2682             2 => 'Portrait',
2683             3 => 'Night',
2684             4 => 'Other', # (non-standard Samsung, ref forum 5724)
2685             },
2686             },
2687             0xa407 => {
2688             Name => 'GainControl',
2689             Groups => { 2 => 'Camera' },
2690             Writable => 'int16u',
2691             PrintConv => {
2692             0 => 'None',
2693             1 => 'Low gain up',
2694             2 => 'High gain up',
2695             3 => 'Low gain down',
2696             4 => 'High gain down',
2697             },
2698             },
2699             0xa408 => {
2700             Name => 'Contrast',
2701             Groups => { 2 => 'Camera' },
2702             Writable => 'int16u',
2703             PrintConv => {
2704             0 => 'Normal',
2705             1 => 'Low',
2706             2 => 'High',
2707             },
2708             PrintConvInv => 'Image::ExifTool::Exif::ConvertParameter($val)',
2709             },
2710             0xa409 => {
2711             Name => 'Saturation',
2712             Groups => { 2 => 'Camera' },
2713             Writable => 'int16u',
2714             PrintConv => {
2715             0 => 'Normal',
2716             1 => 'Low',
2717             2 => 'High',
2718             },
2719             PrintConvInv => 'Image::ExifTool::Exif::ConvertParameter($val)',
2720             },
2721             0xa40a => {
2722             Name => 'Sharpness',
2723             Groups => { 2 => 'Camera' },
2724             Writable => 'int16u',
2725             PrintConv => {
2726             0 => 'Normal',
2727             1 => 'Soft',
2728             2 => 'Hard',
2729             },
2730             PrintConvInv => 'Image::ExifTool::Exif::ConvertParameter($val)',
2731             },
2732             0xa40b => {
2733             Name => 'DeviceSettingDescription',
2734             Groups => { 2 => 'Camera' },
2735             Binary => 1,
2736             },
2737             0xa40c => {
2738             Name => 'SubjectDistanceRange',
2739             Groups => { 2 => 'Camera' },
2740             Writable => 'int16u',
2741             PrintConv => {
2742             0 => 'Unknown',
2743             1 => 'Macro',
2744             2 => 'Close',
2745             3 => 'Distant',
2746             },
2747             },
2748             # 0xa40d - int16u: 0 (GE E1486 TW)
2749             # 0xa40e - int16u: 1 (GE E1486 TW)
2750             0xa420 => { Name => 'ImageUniqueID', Writable => 'string' },
2751             0xa430 => { #24
2752             Name => 'OwnerName',
2753             Notes => 'called CameraOwnerName by the EXIF spec.',
2754             Writable => 'string',
2755             },
2756             0xa431 => { #24
2757             Name => 'SerialNumber',
2758             Notes => 'called BodySerialNumber by the EXIF spec.',
2759             Writable => 'string',
2760             },
2761             0xa432 => { #24
2762             Name => 'LensInfo',
2763             Notes => q{
2764             4 rational values giving focal and aperture ranges, called LensSpecification
2765             by the EXIF spec.
2766             },
2767             Writable => 'rational64u',
2768             Count => 4,
2769             # convert to the form "12-20mm f/3.8-4.5" or "50mm f/1.4"
2770             PrintConv => \&PrintLensInfo,
2771             PrintConvInv => \&ConvertLensInfo,
2772             },
2773             0xa433 => { Name => 'LensMake', Writable => 'string' }, #24
2774             0xa434 => { Name => 'LensModel', Writable => 'string' }, #24
2775             0xa435 => { Name => 'LensSerialNumber', Writable => 'string' }, #24
2776             0xa460 => { #Exif2.32
2777             Name => 'CompositeImage',
2778             Writable => 'int16u',
2779             PrintConv => {
2780             0 => 'Unknown',
2781             1 => 'Not a Composite Image',
2782             2 => 'General Composite Image',
2783             3 => 'Composite Image Captured While Shooting',
2784             },
2785             },
2786             0xa461 => { #Exif2.32
2787             Name => 'CompositeImageCount',
2788             Notes => q{
2789             2 values: 1. Number of source images, 2. Number of images used. Called
2790             SourceImageNumberOfCompositeImage by the EXIF spec.
2791             },
2792             Writable => 'int16u',
2793             Count => 2,
2794             },
2795             0xa462 => { #Exif2.32
2796             Name => 'CompositeImageExposureTimes',
2797             Notes => q{
2798             11 or more values: 1. Total exposure time period, 2. Total exposure of all
2799             source images, 3. Total exposure of all used images, 4. Max exposure time of
2800             source images, 5. Max exposure time of used images, 6. Min exposure time of
2801             source images, 7. Min exposure of used images, 8. Number of sequences, 9.
2802             Number of source images in sequence. 10-N. Exposure times of each source
2803             image. Called SourceExposureTimesOfCompositeImage by the EXIF spec.
2804             },
2805             Writable => 'undef',
2806             RawConv => sub {
2807             my $val = shift;
2808             my @v;
2809             my $i = 0;
2810             for (;;) {
2811             if ($i == 56 or $i == 58) {
2812             last if $i + 2 > length $val;
2813             push @v, Get16u(\$val, $i);
2814             $i += 2;
2815             } else {
2816             last if $i + 8 > length $val;
2817             push @v, Image::ExifTool::GetRational64u(\$val, $i);
2818             $i += 8;
2819             }
2820             }
2821             return join ' ', @v;
2822             },
2823             RawConvInv => sub {
2824             my $val = shift;
2825             my @v = split ' ', $val;
2826             my $i;
2827             for ($i=0; ; ++$i) {
2828             last unless defined $v[$i];
2829             $v[$i] = ($i == 7 or $i == 8) ? Set16u($v[$i]) : Image::ExifTool::SetRational64u($v[$i]);
2830             }
2831             return join '', @v;
2832             },
2833             PrintConv => sub {
2834             my $val = shift;
2835             my @v = split ' ', $val;
2836             my $i;
2837             for ($i=0; ; ++$i) {
2838             last unless defined $v[$i];
2839             $v[$i] = PrintExposureTime($v[$i]) unless $i == 7 or $i == 8;
2840             }
2841             return join ' ', @v;
2842             },
2843             PrintConvInv => '$val',
2844             },
2845             0xa480 => { Name => 'GDALMetadata', Writable => 'string', WriteGroup => 'IFD0' }, #3
2846             0xa481 => { Name => 'GDALNoData', Writable => 'string', WriteGroup => 'IFD0' }, #3
2847             0xa500 => { Name => 'Gamma', Writable => 'rational64u' },
2848             0xafc0 => 'ExpandSoftware', #JD (Opanda)
2849             0xafc1 => 'ExpandLens', #JD (Opanda)
2850             0xafc2 => 'ExpandFilm', #JD (Opanda)
2851             0xafc3 => 'ExpandFilterLens', #JD (Opanda)
2852             0xafc4 => 'ExpandScanner', #JD (Opanda)
2853             0xafc5 => 'ExpandFlashLamp', #JD (Opanda)
2854             0xb4c3 => { Name => 'HasselbladRawImage', Format => 'undef', Binary => 1 }, #IB
2855             #
2856             # Windows Media Photo / HD Photo (WDP/HDP) tags
2857             #
2858             0xbc01 => { #13
2859             Name => 'PixelFormat',
2860             PrintHex => 1,
2861             Format => 'undef',
2862             Notes => q{
2863             tags 0xbc** are used in Windows HD Photo (HDP and WDP) images. The actual
2864             PixelFormat values are 16-byte GUID's but the leading 15 bytes,
2865             '6fddc324-4e03-4bfe-b1853-d77768dc9', have been removed below to avoid
2866             unnecessary clutter
2867             },
2868             ValueConv => q{
2869             require Image::ExifTool::ASF;
2870             $val = Image::ExifTool::ASF::GetGUID($val);
2871             # GUID's are too long, so remove redundant information
2872             $val =~ s/^6fddc324-4e03-4bfe-b185-3d77768dc9//i and $val = hex($val);
2873             return $val;
2874             },
2875             PrintConv => {
2876             0x0d => '24-bit RGB',
2877             0x0c => '24-bit BGR',
2878             0x0e => '32-bit BGR',
2879             0x15 => '48-bit RGB',
2880             0x12 => '48-bit RGB Fixed Point',
2881             0x3b => '48-bit RGB Half',
2882             0x18 => '96-bit RGB Fixed Point',
2883             0x1b => '128-bit RGB Float',
2884             0x0f => '32-bit BGRA',
2885             0x16 => '64-bit RGBA',
2886             0x1d => '64-bit RGBA Fixed Point',
2887             0x3a => '64-bit RGBA Half',
2888             0x1e => '128-bit RGBA Fixed Point',
2889             0x19 => '128-bit RGBA Float',
2890             0x10 => '32-bit PBGRA',
2891             0x17 => '64-bit PRGBA',
2892             0x1a => '128-bit PRGBA Float',
2893             0x1c => '32-bit CMYK',
2894             0x2c => '40-bit CMYK Alpha',
2895             0x1f => '64-bit CMYK',
2896             0x2d => '80-bit CMYK Alpha',
2897             0x20 => '24-bit 3 Channels',
2898             0x21 => '32-bit 4 Channels',
2899             0x22 => '40-bit 5 Channels',
2900             0x23 => '48-bit 6 Channels',
2901             0x24 => '56-bit 7 Channels',
2902             0x25 => '64-bit 8 Channels',
2903             0x2e => '32-bit 3 Channels Alpha',
2904             0x2f => '40-bit 4 Channels Alpha',
2905             0x30 => '48-bit 5 Channels Alpha',
2906             0x31 => '56-bit 6 Channels Alpha',
2907             0x32 => '64-bit 7 Channels Alpha',
2908             0x33 => '72-bit 8 Channels Alpha',
2909             0x26 => '48-bit 3 Channels',
2910             0x27 => '64-bit 4 Channels',
2911             0x28 => '80-bit 5 Channels',
2912             0x29 => '96-bit 6 Channels',
2913             0x2a => '112-bit 7 Channels',
2914             0x2b => '128-bit 8 Channels',
2915             0x34 => '64-bit 3 Channels Alpha',
2916             0x35 => '80-bit 4 Channels Alpha',
2917             0x36 => '96-bit 5 Channels Alpha',
2918             0x37 => '112-bit 6 Channels Alpha',
2919             0x38 => '128-bit 7 Channels Alpha',
2920             0x39 => '144-bit 8 Channels Alpha',
2921             0x08 => '8-bit Gray',
2922             0x0b => '16-bit Gray',
2923             0x13 => '16-bit Gray Fixed Point',
2924             0x3e => '16-bit Gray Half',
2925             0x3f => '32-bit Gray Fixed Point',
2926             0x11 => '32-bit Gray Float',
2927             0x05 => 'Black & White',
2928             0x09 => '16-bit BGR555',
2929             0x0a => '16-bit BGR565',
2930             0x13 => '32-bit BGR101010',
2931             0x3d => '32-bit RGBE',
2932             },
2933             },
2934             0xbc02 => { #13
2935             Name => 'Transformation',
2936             PrintConv => {
2937             0 => 'Horizontal (normal)',
2938             1 => 'Mirror vertical',
2939             2 => 'Mirror horizontal',
2940             3 => 'Rotate 180',
2941             4 => 'Rotate 90 CW',
2942             5 => 'Mirror horizontal and rotate 90 CW',
2943             6 => 'Mirror horizontal and rotate 270 CW',
2944             7 => 'Rotate 270 CW',
2945             },
2946             },
2947             0xbc03 => { #13
2948             Name => 'Uncompressed',
2949             PrintConv => { 0 => 'No', 1 => 'Yes' },
2950             },
2951             0xbc04 => { #13
2952             Name => 'ImageType',
2953             PrintConv => { BITMASK => {
2954             0 => 'Preview',
2955             1 => 'Page',
2956             } },
2957             },
2958             0xbc80 => 'ImageWidth', #13
2959             0xbc81 => 'ImageHeight', #13
2960             0xbc82 => 'WidthResolution', #13
2961             0xbc83 => 'HeightResolution', #13
2962             0xbcc0 => { #13
2963             Name => 'ImageOffset',
2964             IsOffset => 1,
2965             OffsetPair => 0xbcc1, # point to associated byte count
2966             },
2967             0xbcc1 => { #13
2968             Name => 'ImageByteCount',
2969             OffsetPair => 0xbcc0, # point to associated offset
2970             },
2971             0xbcc2 => { #13
2972             Name => 'AlphaOffset',
2973             IsOffset => 1,
2974             OffsetPair => 0xbcc3, # point to associated byte count
2975             },
2976             0xbcc3 => { #13
2977             Name => 'AlphaByteCount',
2978             OffsetPair => 0xbcc2, # point to associated offset
2979             },
2980             0xbcc4 => { #13
2981             Name => 'ImageDataDiscard',
2982             PrintConv => {
2983             0 => 'Full Resolution',
2984             1 => 'Flexbits Discarded',
2985             2 => 'HighPass Frequency Data Discarded',
2986             3 => 'Highpass and LowPass Frequency Data Discarded',
2987             },
2988             },
2989             0xbcc5 => { #13
2990             Name => 'AlphaDataDiscard',
2991             PrintConv => {
2992             0 => 'Full Resolution',
2993             1 => 'Flexbits Discarded',
2994             2 => 'HighPass Frequency Data Discarded',
2995             3 => 'Highpass and LowPass Frequency Data Discarded',
2996             },
2997             },
2998             #
2999             0xc427 => 'OceScanjobDesc', #3
3000             0xc428 => 'OceApplicationSelector', #3
3001             0xc429 => 'OceIDNumber', #3
3002             0xc42a => 'OceImageLogic', #3
3003             0xc44f => { Name => 'Annotations', Binary => 1 }, #7/19
3004             0xc4a5 => {
3005             Name => 'PrintIM', # (writable directory!)
3006             # must set Writable here so this tag will be saved with MakerNotes option
3007             Writable => 'undef',
3008             WriteGroup => 'IFD0',
3009             Binary => 1,
3010             # (don't make Binary/Protected because we can't copy individual PrintIM tags anyway)
3011             Description => 'Print Image Matching',
3012             SubDirectory => {
3013             TagTable => 'Image::ExifTool::PrintIM::Main',
3014             },
3015             PrintConvInv => '$val =~ /^PrintIM/ ? $val : undef', # quick validation
3016             },
3017             0xc51b => { # (Hasselblad H3D)
3018             Name => 'HasselbladExif',
3019             Format => 'undef',
3020             RawConv => q{
3021             $$self{DOC_NUM} = ++$$self{DOC_COUNT};
3022             $self->ExtractInfo(\$val, { ReEntry => 1 });
3023             $$self{DOC_NUM} = 0;
3024             return undef;
3025             },
3026             },
3027             0xc573 => { #PH
3028             Name => 'OriginalFileName',
3029             Notes => 'used by some obscure software', # (possibly Swizzy Photosmacker?)
3030             # (it is a 'string', but obscure, so don't make it writable)
3031             },
3032             0xc580 => { #20
3033             Name => 'USPTOOriginalContentType',
3034             PrintConv => {
3035             0 => 'Text or Drawing',
3036             1 => 'Grayscale',
3037             2 => 'Color',
3038             },
3039             },
3040             # 0xc5d8 - found in CR2 images
3041             # 0xc5d9 - found in CR2 images
3042             0xc5e0 => { #forum8153 (CR2 images)
3043             Name => 'CR2CFAPattern',
3044             ValueConv => {
3045             1 => '0 1 1 2',
3046             2 => '2 1 1 0',
3047             3 => '1 2 0 1',
3048             4 => '1 0 2 1',
3049             },
3050             PrintConv => {
3051             '0 1 1 2' => '[Red,Green][Green,Blue]',
3052             '2 1 1 0' => '[Blue,Green][Green,Red]',
3053             '1 2 0 1' => '[Green,Blue][Red,Green]',
3054             '1 0 2 1' => '[Green,Red][Blue,Green]',
3055             },
3056             },
3057             #
3058             # DNG tags 0xc6XX, 0xc7XX and 0xcdXX (ref 2 unless otherwise stated)
3059             #
3060             0xc612 => {
3061             Name => 'DNGVersion',
3062             Notes => q{
3063             tags 0xc612-0xcd3b are defined by the DNG specification unless otherwise
3064             noted. See L for
3065             the specification
3066             },
3067             Writable => 'int8u',
3068             WriteGroup => 'IFD0',
3069             Count => 4,
3070             Protected => 1, # (confuses Apple Preview if written to a TIFF image)
3071             DataMember => 'DNGVersion',
3072             RawConv => '$$self{DNGVersion} = $val',
3073             PrintConv => '$val =~ tr/ /./; $val',
3074             PrintConvInv => '$val =~ tr/./ /; $val',
3075             },
3076             0xc613 => {
3077             Name => 'DNGBackwardVersion',
3078             Writable => 'int8u',
3079             WriteGroup => 'IFD0',
3080             Count => 4,
3081             Protected => 1,
3082             PrintConv => '$val =~ tr/ /./; $val',
3083             PrintConvInv => '$val =~ tr/./ /; $val',
3084             },
3085             0xc614 => {
3086             Name => 'UniqueCameraModel',
3087             Writable => 'string',
3088             WriteGroup => 'IFD0',
3089             },
3090             0xc615 => {
3091             Name => 'LocalizedCameraModel',
3092             WriteGroup => 'IFD0',
3093             %utf8StringConv,
3094             PrintConv => '$self->Printable($val, 0)',
3095             PrintConvInv => '$val',
3096             },
3097             0xc616 => {
3098             Name => 'CFAPlaneColor',
3099             WriteGroup => 'SubIFD', # (only for Validate)
3100             PrintConv => q{
3101             my @cols = qw(Red Green Blue Cyan Magenta Yellow White);
3102             my @vals = map { $cols[$_] || "Unknown($_)" } split(' ', $val);
3103             return join(',', @vals);
3104             },
3105             },
3106             0xc617 => {
3107             Name => 'CFALayout',
3108             WriteGroup => 'SubIFD', # (only for Validate)
3109             PrintConv => {
3110             1 => 'Rectangular',
3111             2 => 'Even columns offset down 1/2 row',
3112             3 => 'Even columns offset up 1/2 row',
3113             4 => 'Even rows offset right 1/2 column',
3114             5 => 'Even rows offset left 1/2 column',
3115             # the following are new for DNG 1.3:
3116             6 => 'Even rows offset up by 1/2 row, even columns offset left by 1/2 column',
3117             7 => 'Even rows offset up by 1/2 row, even columns offset right by 1/2 column',
3118             8 => 'Even rows offset down by 1/2 row, even columns offset left by 1/2 column',
3119             9 => 'Even rows offset down by 1/2 row, even columns offset right by 1/2 column',
3120             },
3121             },
3122             0xc618 => {
3123             Name => 'LinearizationTable',
3124             Writable => 'int16u',
3125             WriteGroup => 'SubIFD',
3126             Count => -1,
3127             Protected => 1,
3128             Binary => 1,
3129             },
3130             0xc619 => {
3131             Name => 'BlackLevelRepeatDim',
3132             Writable => 'int16u',
3133             WriteGroup => 'SubIFD',
3134             Count => 2,
3135             Protected => 1,
3136             },
3137             0xc61a => {
3138             Name => 'BlackLevel',
3139             Writable => 'rational64u',
3140             WriteGroup => 'SubIFD',
3141             Count => -1,
3142             Protected => 1,
3143             },
3144             0xc61b => {
3145             Name => 'BlackLevelDeltaH',
3146             %longBin,
3147             Writable => 'rational64s',
3148             WriteGroup => 'SubIFD',
3149             Count => -1,
3150             Protected => 1,
3151             },
3152             0xc61c => {
3153             Name => 'BlackLevelDeltaV',
3154             %longBin,
3155             Writable => 'rational64s',
3156             WriteGroup => 'SubIFD',
3157             Count => -1,
3158             Protected => 1,
3159             },
3160             0xc61d => {
3161             Name => 'WhiteLevel',
3162             Writable => 'int32u',
3163             WriteGroup => 'SubIFD',
3164             Count => -1,
3165             Protected => 1,
3166             },
3167             0xc61e => {
3168             Name => 'DefaultScale',
3169             Writable => 'rational64u',
3170             WriteGroup => 'SubIFD',
3171             Count => 2,
3172             Protected => 1,
3173             },
3174             0xc61f => {
3175             Name => 'DefaultCropOrigin',
3176             Writable => 'int32u',
3177             WriteGroup => 'SubIFD',
3178             Count => 2,
3179             Protected => 1,
3180             },
3181             0xc620 => {
3182             Name => 'DefaultCropSize',
3183             Writable => 'int32u',
3184             WriteGroup => 'SubIFD',
3185             Count => 2,
3186             Protected => 1,
3187             },
3188             0xc621 => {
3189             Name => 'ColorMatrix1',
3190             Writable => 'rational64s',
3191             WriteGroup => 'IFD0',
3192             Count => -1,
3193             Protected => 1,
3194             },
3195             0xc622 => {
3196             Name => 'ColorMatrix2',
3197             Writable => 'rational64s',
3198             WriteGroup => 'IFD0',
3199             Count => -1,
3200             Protected => 1,
3201             },
3202             0xc623 => {
3203             Name => 'CameraCalibration1',
3204             Writable => 'rational64s',
3205             WriteGroup => 'IFD0',
3206             Count => -1,
3207             Protected => 1,
3208             },
3209             0xc624 => {
3210             Name => 'CameraCalibration2',
3211             Writable => 'rational64s',
3212             WriteGroup => 'IFD0',
3213             Count => -1,
3214             Protected => 1,
3215             },
3216             0xc625 => {
3217             Name => 'ReductionMatrix1',
3218             Writable => 'rational64s',
3219             WriteGroup => 'IFD0',
3220             Count => -1,
3221             Protected => 1,
3222             },
3223             0xc626 => {
3224             Name => 'ReductionMatrix2',
3225             Writable => 'rational64s',
3226             WriteGroup => 'IFD0',
3227             Count => -1,
3228             Protected => 1,
3229             },
3230             0xc627 => {
3231             Name => 'AnalogBalance',
3232             Writable => 'rational64u',
3233             WriteGroup => 'IFD0',
3234             Count => -1,
3235             Protected => 1,
3236             },
3237             0xc628 => {
3238             Name => 'AsShotNeutral',
3239             Writable => 'rational64u',
3240             WriteGroup => 'IFD0',
3241             Count => -1,
3242             Protected => 1,
3243             },
3244             0xc629 => {
3245             Name => 'AsShotWhiteXY',
3246             Writable => 'rational64u',
3247             WriteGroup => 'IFD0',
3248             Count => 2,
3249             Protected => 1,
3250             },
3251             0xc62a => {
3252             Name => 'BaselineExposure',
3253             Writable => 'rational64s',
3254             WriteGroup => 'IFD0',
3255             Protected => 1,
3256             },
3257             0xc62b => {
3258             Name => 'BaselineNoise',
3259             Writable => 'rational64u',
3260             WriteGroup => 'IFD0',
3261             Protected => 1,
3262             },
3263             0xc62c => {
3264             Name => 'BaselineSharpness',
3265             Writable => 'rational64u',
3266             WriteGroup => 'IFD0',
3267             Protected => 1,
3268             },
3269             0xc62d => {
3270             Name => 'BayerGreenSplit',
3271             Writable => 'int32u',
3272             WriteGroup => 'SubIFD',
3273             Protected => 1,
3274             },
3275             0xc62e => {
3276             Name => 'LinearResponseLimit',
3277             Writable => 'rational64u',
3278             WriteGroup => 'IFD0',
3279             Protected => 1,
3280             },
3281             0xc62f => {
3282             Name => 'CameraSerialNumber',
3283             Groups => { 2 => 'Camera' },
3284             Writable => 'string',
3285             WriteGroup => 'IFD0',
3286             },
3287             0xc630 => {
3288             Name => 'DNGLensInfo',
3289             Groups => { 2 => 'Camera' },
3290             Writable => 'rational64u',
3291             WriteGroup => 'IFD0',
3292             Count => 4,
3293             PrintConv =>\&PrintLensInfo,
3294             PrintConvInv => \&ConvertLensInfo,
3295             },
3296             0xc631 => {
3297             Name => 'ChromaBlurRadius',
3298             Writable => 'rational64u',
3299             WriteGroup => 'SubIFD',
3300             Protected => 1,
3301             },
3302             0xc632 => {
3303             Name => 'AntiAliasStrength',
3304             Writable => 'rational64u',
3305             WriteGroup => 'SubIFD',
3306             Protected => 1,
3307             },
3308             0xc633 => {
3309             Name => 'ShadowScale',
3310             Writable => 'rational64u',
3311             WriteGroup => 'IFD0',
3312             Protected => 1,
3313             },
3314             0xc634 => [
3315             {
3316             Condition => '$$self{TIFF_TYPE} =~ /^(ARW|SR2)$/',
3317             Name => 'SR2Private',
3318             Groups => { 1 => 'SR2' },
3319             Flags => 'SubIFD',
3320             Format => 'int32u',
3321             # some utilities have problems unless this is int8u format:
3322             # - Adobe Camera Raw 5.3 gives an error
3323             # - Apple Preview 10.5.8 gets the wrong white balance
3324             FixFormat => 'int8u', # (stupid Sony)
3325             WriteGroup => 'IFD0', # (for Validate)
3326             SubDirectory => {
3327             DirName => 'SR2Private',
3328             TagTable => 'Image::ExifTool::Sony::SR2Private',
3329             Start => '$val',
3330             },
3331             },
3332             {
3333             Condition => '$$valPt =~ /^Adobe\0/',
3334             Name => 'DNGAdobeData',
3335             Flags => [ 'Binary', 'Protected' ],
3336             Writable => 'undef', # (writable directory!) (to make it possible to delete this mess)
3337             WriteGroup => 'IFD0',
3338             NestedHtmlDump => 1,
3339             SubDirectory => { TagTable => 'Image::ExifTool::DNG::AdobeData' },
3340             Format => 'undef', # but written as int8u (change to undef for speed)
3341             },
3342             {
3343             # Pentax/Samsung models that write AOC maker notes in JPG images:
3344             # K-5,K-7,K-m,K-x,K-r,K10D,K20D,K100D,K110D,K200D,K2000,GX10,GX20
3345             # (Note: the following expression also appears in WriteExif.pl)
3346             Condition => q{
3347             $$valPt =~ /^(PENTAX |SAMSUNG)\0/ and
3348             $$self{Model} =~ /\b(K(-[57mrx]|(10|20|100|110|200)D|2000)|GX(10|20))\b/
3349             },
3350             Name => 'MakerNotePentax',
3351             MakerNotes => 1, # (causes "MakerNotes header" to be identified in HtmlDump output)
3352             Binary => 1,
3353             WriteGroup => 'IFD0', # (for Validate)
3354             # Note: Don't make this block-writable for a few reasons:
3355             # 1) It would be dangerous (possibly confusing Pentax software)
3356             # 2) It is a different format from the JPEG version of MakerNotePentax
3357             # 3) It is converted to JPEG format by RebuildMakerNotes() when copying
3358             SubDirectory => {
3359             TagTable => 'Image::ExifTool::Pentax::Main',
3360             Start => '$valuePtr + 10',
3361             Base => '$start - 10',
3362             ByteOrder => 'Unknown', # easier to do this than read byteorder word
3363             },
3364             Format => 'undef', # but written as int8u (change to undef for speed)
3365             },
3366             {
3367             # must duplicate the above tag with a different name for more recent
3368             # Pentax models which use the "PENTAX" instead of the "AOC" maker notes
3369             # in JPG images (needed when copying maker notes from DNG to JPG)
3370             Condition => '$$valPt =~ /^(PENTAX |SAMSUNG)\0/',
3371             Name => 'MakerNotePentax5',
3372             MakerNotes => 1,
3373             Binary => 1,
3374             WriteGroup => 'IFD0', # (for Validate)
3375             SubDirectory => {
3376             TagTable => 'Image::ExifTool::Pentax::Main',
3377             Start => '$valuePtr + 10',
3378             Base => '$start - 10',
3379             ByteOrder => 'Unknown',
3380             },
3381             Format => 'undef',
3382             },
3383             {
3384             # Ricoh models such as the GR III
3385             Condition => '$$valPt =~ /^RICOH\0(II|MM)/',
3386             Name => 'MakerNoteRicohPentax',
3387             MakerNotes => 1,
3388             Binary => 1,
3389             WriteGroup => 'IFD0', # (for Validate)
3390             SubDirectory => {
3391             TagTable => 'Image::ExifTool::Pentax::Main',
3392             Start => '$valuePtr + 8',
3393             Base => '$start - 8',
3394             ByteOrder => 'Unknown',
3395             },
3396             Format => 'undef',
3397             },
3398             # the DJI FC2103 writes some interesting stuff here (with sections labelled
3399             # awb_dbg_info, ae_dbg_info, ae_histogram_info, af_dbg_info, hiso, xidiri) - PH
3400             {
3401             Name => 'MakerNoteDJIInfo',
3402             Condition => '$$valPt =~ /^\[ae_dbg_info:/',
3403             MakerNotes => 1,
3404             Binary => 1,
3405             WriteGroup => 'IFD0', # (for Validate)
3406             SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' },
3407             Format => 'undef',
3408             },
3409             {
3410             Name => 'DNGPrivateData',
3411             Flags => [ 'Binary', 'Protected' ],
3412             Format => 'undef',
3413             Writable => 'int8u',
3414             WriteGroup => 'IFD0',
3415             },
3416             ],
3417             0xc635 => {
3418             Name => 'MakerNoteSafety',
3419             Writable => 'int16u',
3420             WriteGroup => 'IFD0',
3421             PrintConv => {
3422             0 => 'Unsafe',
3423             1 => 'Safe',
3424             },
3425             },
3426             0xc640 => { #15
3427             Name => 'RawImageSegmentation',
3428             # (int16u[3], not writable)
3429             Notes => q{
3430             used in segmented Canon CR2 images. 3 numbers: 1. Number of segments minus
3431             one; 2. Pixel width of segments except last; 3. Pixel width of last segment
3432             },
3433             },
3434             0xc65a => {
3435             Name => 'CalibrationIlluminant1',
3436             Writable => 'int16u',
3437             WriteGroup => 'IFD0',
3438             Protected => 1,
3439             SeparateTable => 'LightSource',
3440             PrintConv => \%lightSource,
3441             },
3442             0xc65b => {
3443             Name => 'CalibrationIlluminant2',
3444             Writable => 'int16u',
3445             WriteGroup => 'IFD0',
3446             Protected => 1,
3447             SeparateTable => 'LightSource',
3448             PrintConv => \%lightSource,
3449             },
3450             0xc65c => {
3451             Name => 'BestQualityScale',
3452             Writable => 'rational64u',
3453             WriteGroup => 'SubIFD',
3454             Protected => 1,
3455             },
3456             0xc65d => {
3457             Name => 'RawDataUniqueID',
3458             Format => 'undef',
3459             Writable => 'int8u',
3460             WriteGroup => 'IFD0',
3461             Count => 16,
3462             Protected => 1,
3463             ValueConv => 'uc(unpack("H*",$val))',
3464             ValueConvInv => 'pack("H*", $val)',
3465             },
3466             0xc660 => { #3
3467             Name => 'AliasLayerMetadata',
3468             Notes => 'used by Alias Sketchbook Pro',
3469             },
3470             0xc68b => {
3471             Name => 'OriginalRawFileName',
3472             WriteGroup => 'IFD0',
3473             Protected => 1,
3474             %utf8StringConv,
3475             },
3476             0xc68c => {
3477             Name => 'OriginalRawFileData', # (writable directory!)
3478             Writable => 'undef', # must be defined here so tag will be extracted if specified
3479             WriteGroup => 'IFD0',
3480             Flags => [ 'Binary', 'Protected' ],
3481             SubDirectory => {
3482             TagTable => 'Image::ExifTool::DNG::OriginalRaw',
3483             },
3484             },
3485             0xc68d => {
3486             Name => 'ActiveArea',
3487             Writable => 'int32u',
3488             WriteGroup => 'SubIFD',
3489             Count => 4,
3490             Protected => 1,
3491             },
3492             0xc68e => {
3493             Name => 'MaskedAreas',
3494             Writable => 'int32u',
3495             WriteGroup => 'SubIFD',
3496             Count => -1,
3497             Protected => 1,
3498             },
3499             0xc68f => {
3500             Name => 'AsShotICCProfile', # (writable directory)
3501             Binary => 1,
3502             Writable => 'undef', # must be defined here so tag will be extracted if specified
3503             WriteGroup => 'IFD0',
3504             Protected => 1,
3505             WriteCheck => q{
3506             require Image::ExifTool::ICC_Profile;
3507             return Image::ExifTool::ICC_Profile::ValidateICC(\$val);
3508             },
3509             SubDirectory => {
3510             DirName => 'AsShotICCProfile',
3511             TagTable => 'Image::ExifTool::ICC_Profile::Main',
3512             },
3513             },
3514             0xc690 => {
3515             Name => 'AsShotPreProfileMatrix',
3516             Writable => 'rational64s',
3517             WriteGroup => 'IFD0',
3518             Count => -1,
3519             Protected => 1,
3520             },
3521             0xc691 => {
3522             Name => 'CurrentICCProfile', # (writable directory)
3523             Binary => 1,
3524             Writable => 'undef', # must be defined here so tag will be extracted if specified
3525             SubDirectory => {
3526             DirName => 'CurrentICCProfile',
3527             TagTable => 'Image::ExifTool::ICC_Profile::Main',
3528             },
3529             Writable => 'undef',
3530             WriteGroup => 'IFD0',
3531             Protected => 1,
3532             WriteCheck => q{
3533             require Image::ExifTool::ICC_Profile;
3534             return Image::ExifTool::ICC_Profile::ValidateICC(\$val);
3535             },
3536             },
3537             0xc692 => {
3538             Name => 'CurrentPreProfileMatrix',
3539             Writable => 'rational64s',
3540             WriteGroup => 'IFD0',
3541             Count => -1,
3542             Protected => 1,
3543             },
3544             0xc6bf => {
3545             Name => 'ColorimetricReference',
3546             Writable => 'int16u',
3547             WriteGroup => 'IFD0',
3548             Protected => 1,
3549             },
3550             0xc6c5 => { Name => 'SRawType', Description => 'SRaw Type', WriteGroup => 'IFD0' }, #exifprobe (CR2 proprietary)
3551             0xc6d2 => { #JD (Panasonic DMC-TZ5)
3552             # this text is UTF-8 encoded (hooray!) - PH (TZ5)
3553             Name => 'PanasonicTitle',
3554             Format => 'string', # written incorrectly as 'undef'
3555             Notes => 'proprietary Panasonic tag used for baby/pet name, etc',
3556             Writable => 'undef',
3557             WriteGroup => 'IFD0',
3558             # panasonic always records this tag (64 zero bytes),
3559             # so ignore it unless it contains valid information
3560             RawConv => 'length($val) ? $val : undef',
3561             ValueConv => '$self->Decode($val, "UTF8")',
3562             ValueConvInv => '$self->Encode($val,"UTF8")',
3563             },
3564             0xc6d3 => { #PH (Panasonic DMC-FS7)
3565             Name => 'PanasonicTitle2',
3566             Format => 'string', # written incorrectly as 'undef'
3567             Notes => 'proprietary Panasonic tag used for baby/pet name with age',
3568             Writable => 'undef',
3569             WriteGroup => 'IFD0',
3570             # panasonic always records this tag (128 zero bytes),
3571             # so ignore it unless it contains valid information
3572             RawConv => 'length($val) ? $val : undef',
3573             ValueConv => '$self->Decode($val, "UTF8")',
3574             ValueConvInv => '$self->Encode($val,"UTF8")',
3575             },
3576             # 0xc6dc - int32u[4]: found in CR2 images (PH, 7DmkIII)
3577             # 0xc6dd - int16u[256]: found in CR2 images (PH, 5DmkIV)
3578             0xc6f3 => {
3579             Name => 'CameraCalibrationSig',
3580             WriteGroup => 'IFD0',
3581             Protected => 1,
3582             %utf8StringConv,
3583             },
3584             0xc6f4 => {
3585             Name => 'ProfileCalibrationSig',
3586             WriteGroup => 'IFD0',
3587             Protected => 1,
3588             %utf8StringConv,
3589             },
3590             0xc6f5 => {
3591             Name => 'ProfileIFD', # (ExtraCameraProfiles)
3592             Groups => { 1 => 'ProfileIFD' },
3593             Flags => 'SubIFD',
3594             WriteGroup => 'IFD0', # (only for Validate)
3595             SubDirectory => {
3596             ProcessProc => \&ProcessTiffIFD,
3597             WriteProc => \&ProcessTiffIFD,
3598             DirName => 'ProfileIFD',
3599             Start => '$val',
3600             Base => '$start', # offsets relative to start of TIFF-like header
3601             MaxSubdirs => 10,
3602             Magic => 0x4352, # magic number for TIFF-like header
3603             },
3604             },
3605             0xc6f6 => {
3606             Name => 'AsShotProfileName',
3607             WriteGroup => 'IFD0',
3608             Protected => 1,
3609             %utf8StringConv,
3610             },
3611             0xc6f7 => {
3612             Name => 'NoiseReductionApplied',
3613             Writable => 'rational64u',
3614             WriteGroup => 'SubIFD',
3615             Protected => 1,
3616             },
3617             0xc6f8 => {
3618             Name => 'ProfileName',
3619             WriteGroup => 'IFD0',
3620             Protected => 1,
3621             %utf8StringConv,
3622             },
3623             0xc6f9 => {
3624             Name => 'ProfileHueSatMapDims',
3625             Writable => 'int32u',
3626             WriteGroup => 'IFD0',
3627             Count => 3,
3628             Protected => 1,
3629             },
3630             0xc6fa => {
3631             Name => 'ProfileHueSatMapData1',
3632             %longBin,
3633             Writable => 'float',
3634             WriteGroup => 'IFD0',
3635             Count => -1,
3636             Protected => 1,
3637             },
3638             0xc6fb => {
3639             Name => 'ProfileHueSatMapData2',
3640             %longBin,
3641             Writable => 'float',
3642             WriteGroup => 'IFD0',
3643             Count => -1,
3644             Protected => 1,
3645             },
3646             0xc6fc => {
3647             Name => 'ProfileToneCurve',
3648             %longBin,
3649             Writable => 'float',
3650             WriteGroup => 'IFD0',
3651             Count => -1,
3652             Protected => 1,
3653             },
3654             0xc6fd => {
3655             Name => 'ProfileEmbedPolicy',
3656             Writable => 'int32u',
3657             WriteGroup => 'IFD0',
3658             Protected => 1,
3659             PrintConv => {
3660             0 => 'Allow Copying',
3661             1 => 'Embed if Used',
3662             2 => 'Never Embed',
3663             3 => 'No Restrictions',
3664             },
3665             },
3666             0xc6fe => {
3667             Name => 'ProfileCopyright',
3668             WriteGroup => 'IFD0',
3669             Protected => 1,
3670             %utf8StringConv,
3671             },
3672             0xc714 => {
3673             Name => 'ForwardMatrix1',
3674             Writable => 'rational64s',
3675             WriteGroup => 'IFD0',
3676             Count => -1,
3677             Protected => 1,
3678             },
3679             0xc715 => {
3680             Name => 'ForwardMatrix2',
3681             Writable => 'rational64s',
3682             WriteGroup => 'IFD0',
3683             Count => -1,
3684             Protected => 1,
3685             },
3686             0xc716 => {
3687             Name => 'PreviewApplicationName',
3688             WriteGroup => 'IFD0',
3689             Protected => 1,
3690             %utf8StringConv,
3691             },
3692             0xc717 => {
3693             Name => 'PreviewApplicationVersion',
3694             Writable => 'string',
3695             WriteGroup => 'IFD0',
3696             Protected => 1,
3697             %utf8StringConv,
3698             },
3699             0xc718 => {
3700             Name => 'PreviewSettingsName',
3701             Writable => 'string',
3702             WriteGroup => 'IFD0',
3703             Protected => 1,
3704             %utf8StringConv,
3705             },
3706             0xc719 => {
3707             Name => 'PreviewSettingsDigest',
3708             Format => 'undef',
3709             Writable => 'int8u',
3710             WriteGroup => 'IFD0',
3711             Protected => 1,
3712             ValueConv => 'unpack("H*", $val)',
3713             ValueConvInv => 'pack("H*", $val)',
3714             },
3715             0xc71a => {
3716             Name => 'PreviewColorSpace',
3717             Writable => 'int32u',
3718             WriteGroup => 'IFD0',
3719             Protected => 1,
3720             PrintConv => {
3721             0 => 'Unknown',
3722             1 => 'Gray Gamma 2.2',
3723             2 => 'sRGB',
3724             3 => 'Adobe RGB',
3725             4 => 'ProPhoto RGB',
3726             },
3727             },
3728             0xc71b => {
3729             Name => 'PreviewDateTime',
3730             Groups => { 2 => 'Time' },
3731             Writable => 'string',
3732             Shift => 'Time',
3733             WriteGroup => 'IFD0',
3734             Protected => 1,
3735             ValueConv => q{
3736             require Image::ExifTool::XMP;
3737             return Image::ExifTool::XMP::ConvertXMPDate($val);
3738             },
3739             ValueConvInv => q{
3740             require Image::ExifTool::XMP;
3741             return Image::ExifTool::XMP::FormatXMPDate($val);
3742             },
3743             PrintConv => '$self->ConvertDateTime($val)',
3744             PrintConvInv => '$self->InverseDateTime($val,1,1)',
3745             },
3746             0xc71c => {
3747             Name => 'RawImageDigest',
3748             Format => 'undef',
3749             Writable => 'int8u',
3750             WriteGroup => 'IFD0',
3751             Count => 16,
3752             Protected => 1,
3753             ValueConv => 'unpack("H*", $val)',
3754             ValueConvInv => 'pack("H*", $val)',
3755             },
3756             0xc71d => {
3757             Name => 'OriginalRawFileDigest',
3758             Format => 'undef',
3759             Writable => 'int8u',
3760             WriteGroup => 'IFD0',
3761             Count => 16,
3762             Protected => 1,
3763             ValueConv => 'unpack("H*", $val)',
3764             ValueConvInv => 'pack("H*", $val)',
3765             },
3766             0xc71e => 'SubTileBlockSize',
3767             0xc71f => 'RowInterleaveFactor',
3768             0xc725 => {
3769             Name => 'ProfileLookTableDims',
3770             Writable => 'int32u',
3771             WriteGroup => 'IFD0',
3772             Count => 3,
3773             Protected => 1,
3774             },
3775             0xc726 => {
3776             Name => 'ProfileLookTableData',
3777             %longBin,
3778             Writable => 'float',
3779             WriteGroup => 'IFD0',
3780             Count => -1,
3781             Protected => 1,
3782             },
3783             0xc740 => { Name => 'OpcodeList1', %opcodeInfo }, # DNG 1.3
3784             0xc741 => { Name => 'OpcodeList2', %opcodeInfo }, # DNG 1.3
3785             0xc74e => { Name => 'OpcodeList3', %opcodeInfo }, # DNG 1.3
3786             0xc761 => { # DNG 1.3
3787             Name => 'NoiseProfile',
3788             Writable => 'double',
3789             WriteGroup => 'SubIFD',
3790             Count => -1,
3791             Protected => 1,
3792             },
3793             0xc763 => { #28
3794             Name => 'TimeCodes',
3795             Writable => 'int8u',
3796             WriteGroup => 'IFD0',
3797             Count => -1, # (8 * number of time codes, max 10)
3798             ValueConv => q{
3799             my @a = split ' ', $val;
3800             my @v;
3801             push @v, join('.', map { sprintf('%.2x',$_) } splice(@a,0,8)) while @a >= 8;
3802             join ' ', @v;
3803             },
3804             ValueConvInv => q{
3805             my @a = map hex, split /[. ]+/, $val;
3806             join ' ', @a;
3807             },
3808             # Note: Currently ignore the flags:
3809             # byte 0 0x80 - color frame
3810             # byte 0 0x40 - drop frame
3811             # byte 1 0x80 - field phase
3812             PrintConv => q{
3813             my @a = map hex, split /[. ]+/, $val;
3814             my @v;
3815             while (@a >= 8) {
3816             my $str = sprintf("%.2x:%.2x:%.2x.%.2x", $a[3]&0x3f,
3817             $a[2]&0x7f, $a[1]&0x7f, $a[0]&0x3f);
3818             if ($a[3] & 0x80) { # date+timezone exist if BGF2 is set
3819             my $tz = $a[7] & 0x3f;
3820             my $bz = sprintf('%.2x', $tz);
3821             $bz = 100 if $bz =~ /[a-f]/i; # not BCD
3822             if ($bz < 26) {
3823             $tz = ($bz < 13 ? 0 : 26) - $bz;
3824             } elsif ($bz == 32) {
3825             $tz = 12.75;
3826             } elsif ($bz >= 28 and $bz <= 31) {
3827             $tz = 0; # UTC
3828             } elsif ($bz < 100) {
3829             undef $tz; # undefined or user-defined
3830             } elsif ($tz < 0x20) {
3831             $tz = (($tz < 0x10 ? 10 : 20) - $tz) - 0.5;
3832             } else {
3833             $tz = (($tz < 0x30 ? 53 : 63) - $tz) + 0.5;
3834             }
3835             if ($a[7] & 0x80) { # MJD format (/w UTC time)
3836             my ($h,$m,$s,$f) = split /[:.]/, $str;
3837             my $jday = sprintf('%x%.2x%.2x', reverse @a[4..6]);
3838             $str = ConvertUnixTime(($jday - 40587) * 24 * 3600
3839             + ((($h+$tz) * 60) + $m) * 60 + $s) . ".$f";
3840             $str =~ s/^(\d+):(\d+):(\d+) /$1-$2-${3}T/;
3841             } else { # YYMMDD (Note: CinemaDNG 1.1 example seems wrong)
3842             my $yr = sprintf('%.2x',$a[6]) + 1900;
3843             $yr += 100 if $yr < 1970;
3844             $str = sprintf('%d-%.2x-%.2xT%s',$yr,$a[5],$a[4],$str);
3845             }
3846             $str .= TimeZoneString($tz*60) if defined $tz;
3847             }
3848             push @v, $str;
3849             splice @a, 0, 8;
3850             }
3851             join ' ', @v;
3852             },
3853             PrintConvInv => q{
3854             my @a = split ' ', $val;
3855             my @v;
3856             foreach (@a) {
3857             my @td = reverse split /T/;
3858             my $tz = 0x39; # default to unknown timezone
3859             if ($td[0] =~ s/([-+])(\d+):(\d+)$//) {
3860             if ($3 == 0) {
3861             $tz = hex(($1 eq '-') ? $2 : 0x26 - $2);
3862             } elsif ($3 == 30) {
3863             if ($1 eq '-') {
3864             $tz = $2 + 0x0a;
3865             $tz += 0x0a if $tz > 0x0f;
3866             } else {
3867             $tz = 0x3f - $2;
3868             $tz -= 0x0a if $tz < 0x3a;
3869             }
3870             } elsif ($3 == 45) {
3871             $tz = 0x32 if $1 eq '+' and $2 == 12;
3872             }
3873             }
3874             my @t = split /[:.]/, $td[0];
3875             push @t, '00' while @t < 4;
3876             my $bg;
3877             if ($td[1]) {
3878             # date was specified: fill in date & timezone
3879             my @d = split /[-]/, $td[1];
3880             next if @d < 3;
3881             $bg = sprintf('.%.2d.%.2d.%.2d.%.2x', $d[2], $d[1], $d[0]%100, $tz);
3882             $t[0] = sprintf('%.2x', hex($t[0]) + 0xc0); # set BGF1+BGF2
3883             } else { # time only
3884             $bg = '.00.00.00.00';
3885             }
3886             push @v, join('.', reverse(@t[0..3])) . $bg;
3887             }
3888             join ' ', @v;
3889             },
3890             },
3891             0xc764 => { #28
3892             Name => 'FrameRate',
3893             Writable => 'rational64s',
3894             WriteGroup => 'IFD0',
3895             PrintConv => 'int($val * 1000 + 0.5) / 1000',
3896             PrintConvInv => '$val',
3897             },
3898             0xc772 => { #28
3899             Name => 'TStop',
3900             Writable => 'rational64u',
3901             WriteGroup => 'IFD0',
3902             Count => -1, # (1 or 2)
3903             PrintConv => 'join("-", map { sprintf("%.2f",$_) } split " ", $val)',
3904             PrintConvInv => '$val=~tr/-/ /; $val',
3905             },
3906             0xc789 => { #28
3907             Name => 'ReelName',
3908             Writable => 'string',
3909             WriteGroup => 'IFD0',
3910             },
3911             0xc791 => { # DNG 1.4
3912             Name => 'OriginalDefaultFinalSize',
3913             Writable => 'int32u',
3914             WriteGroup => 'IFD0',
3915             Count => 2,
3916             Protected => 1,
3917             },
3918             0xc792 => { # DNG 1.4
3919             Name => 'OriginalBestQualitySize',
3920             Notes => 'called OriginalBestQualityFinalSize by the DNG spec',
3921             Writable => 'int32u',
3922             WriteGroup => 'IFD0',
3923             Count => 2,
3924             Protected => 1,
3925             },
3926             0xc793 => { # DNG 1.4
3927             Name => 'OriginalDefaultCropSize',
3928             Writable => 'rational64u',
3929             WriteGroup => 'IFD0',
3930             Count => 2,
3931             Protected => 1,
3932             },
3933             0xc7a1 => { #28
3934             Name => 'CameraLabel',
3935             Writable => 'string',
3936             WriteGroup => 'IFD0',
3937             },
3938             0xc7a3 => { # DNG 1.4
3939             Name => 'ProfileHueSatMapEncoding',
3940             Writable => 'int32u',
3941             WriteGroup => 'IFD0',
3942             Protected => 1,
3943             PrintConv => {
3944             0 => 'Linear',
3945             1 => 'sRGB',
3946             },
3947             },
3948             0xc7a4 => { # DNG 1.4
3949             Name => 'ProfileLookTableEncoding',
3950             Writable => 'int32u',
3951             WriteGroup => 'IFD0',
3952             Protected => 1,
3953             PrintConv => {
3954             0 => 'Linear',
3955             1 => 'sRGB',
3956             },
3957             },
3958             0xc7a5 => { # DNG 1.4
3959             Name => 'BaselineExposureOffset',
3960             Writable => 'rational64s', # (incorrectly "RATIONAL" in DNG 1.4 spec)
3961             WriteGroup => 'IFD0',
3962             Protected => 1,
3963             },
3964             0xc7a6 => { # DNG 1.4
3965             Name => 'DefaultBlackRender',
3966             Writable => 'int32u',
3967             WriteGroup => 'IFD0',
3968             Protected => 1,
3969             PrintConv => {
3970             0 => 'Auto',
3971             1 => 'None',
3972             },
3973             },
3974             0xc7a7 => { # DNG 1.4
3975             Name => 'NewRawImageDigest',
3976             Format => 'undef',
3977             Writable => 'int8u',
3978             WriteGroup => 'IFD0',
3979             Count => 16,
3980             Protected => 1,
3981             ValueConv => 'unpack("H*", $val)',
3982             ValueConvInv => 'pack("H*", $val)',
3983             },
3984             0xc7a8 => { # DNG 1.4
3985             Name => 'RawToPreviewGain',
3986             Writable => 'double',
3987             WriteGroup => 'IFD0',
3988             Protected => 1,
3989             },
3990             # 0xc7a9 - CacheBlob (ref 31)
3991             0xc7aa => { #31 undocumented DNG tag written by LR4 (val=256, related to fast load data?)
3992             Name => 'CacheVersion',
3993             Writable => 'int32u',
3994             WriteGroup => 'SubIFD2',
3995             Format => 'int8u',
3996             Count => 4,
3997             Protected => 1,
3998             PrintConv => '$val =~ tr/ /./; $val',
3999             PrintConvInv => '$val =~ tr/./ /; $val',
4000             },
4001             0xc7b5 => { # DNG 1.4
4002             Name => 'DefaultUserCrop',
4003             Writable => 'rational64u',
4004             WriteGroup => 'SubIFD',
4005             Count => 4,
4006             Protected => 1,
4007             },
4008             0xc7d5 => { #PH (in SubIFD1 of Nikon Z6/Z7 NEF images)
4009             Name => 'NikonNEFInfo',
4010             Condition => '$$valPt =~ /^Nikon\0/',
4011             SubDirectory => {
4012             TagTable => 'Image::ExifTool::Nikon::NEFInfo',
4013             Start => '$valuePtr + 18',
4014             Base => '$start - 8',
4015             ByteOrder => 'Unknown',
4016             },
4017             },
4018             # 0xc7d6 - int8u: 1 (SubIFD1 of Nikon Z6/Z7 NEF)
4019             0xc7e9 => { # DNG 1.5
4020             Name => 'DepthFormat',
4021             Writable => 'int16u',
4022             Notes => 'tags 0xc7e9-0xc7ee added by DNG 1.5.0.0',
4023             Protected => 1,
4024             WriteGroup => 'IFD0',
4025             PrintConv => {
4026             0 => 'Unknown',
4027             1 => 'Linear',
4028             2 => 'Inverse',
4029             },
4030             },
4031             0xc7ea => { # DNG 1.5
4032             Name => 'DepthNear',
4033             Writable => 'rational64u',
4034             Protected => 1,
4035             WriteGroup => 'IFD0',
4036             },
4037             0xc7eb => { # DNG 1.5
4038             Name => 'DepthFar',
4039             Writable => 'rational64u',
4040             Protected => 1,
4041             WriteGroup => 'IFD0',
4042             },
4043             0xc7ec => { # DNG 1.5
4044             Name => 'DepthUnits',
4045             Writable => 'int16u',
4046             Protected => 1,
4047             WriteGroup => 'IFD0',
4048             PrintConv => {
4049             0 => 'Unknown',
4050             1 => 'Meters',
4051             },
4052             },
4053             0xc7ed => { # DNG 1.5
4054             Name => 'DepthMeasureType',
4055             Writable => 'int16u',
4056             Protected => 1,
4057             WriteGroup => 'IFD0',
4058             PrintConv => {
4059             0 => 'Unknown',
4060             1 => 'Optical Axis',
4061             2 => 'Optical Ray',
4062             },
4063             },
4064             0xc7ee => { # DNG 1.5
4065             Name => 'EnhanceParams',
4066             Writable => 'string',
4067             Protected => 1,
4068             WriteGroup => 'IFD0',
4069             },
4070             0xcd2d => { # DNG 1.6
4071             Name => 'ProfileGainTableMap',
4072             Writable => 'undef',
4073             WriteGroup => 'SubIFD',
4074             Protected => 1,
4075             Binary => 1,
4076             },
4077             0xcd2e => { # DNG 1.6
4078             Name => 'SemanticName',
4079             # Writable => 'string',
4080             WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate)
4081             },
4082             0xcd30 => { # DNG 1.6
4083             Name => 'SemanticInstanceIFD',
4084             # Writable => 'string',
4085             WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate)
4086             },
4087             0xcd31 => { # DNG 1.6
4088             Name => 'CalibrationIlluminant3',
4089             Writable => 'int16u',
4090             WriteGroup => 'IFD0',
4091             Protected => 1,
4092             SeparateTable => 'LightSource',
4093             PrintConv => \%lightSource,
4094             },
4095             0xcd32 => { # DNG 1.6
4096             Name => 'CameraCalibration3',
4097             Writable => 'rational64s',
4098             WriteGroup => 'IFD0',
4099             Count => -1,
4100             Protected => 1,
4101             },
4102             0xcd33 => { # DNG 1.6
4103             Name => 'ColorMatrix3',
4104             Writable => 'rational64s',
4105             WriteGroup => 'IFD0',
4106             Count => -1,
4107             Protected => 1,
4108             },
4109             0xcd34 => { # DNG 1.6
4110             Name => 'ForwardMatrix3',
4111             Writable => 'rational64s',
4112             WriteGroup => 'IFD0',
4113             Count => -1,
4114             Protected => 1,
4115             },
4116             0xcd35 => { # DNG 1.6
4117             Name => 'IlluminantData1',
4118             Writable => 'undef',
4119             WriteGroup => 'IFD0',
4120             Protected => 1,
4121             },
4122             0xcd36 => { # DNG 1.6
4123             Name => 'IlluminantData2',
4124             Writable => 'undef',
4125             WriteGroup => 'IFD0',
4126             Protected => 1,
4127             },
4128             0xcd37 => { # DNG 1.6
4129             Name => 'IlluminantData3',
4130             Writable => 'undef',
4131             WriteGroup => 'IFD0',
4132             Protected => 1,
4133             },
4134             0xcd38 => { # DNG 1.6
4135             Name => 'MaskSubArea',
4136             # Writable => 'int32u',
4137             WriteGroup => 'SubIFD', #? (NC) Semantic Mask IFD (only for Validate)
4138             Count => 4,
4139             },
4140             0xcd39 => { # DNG 1.6
4141             Name => 'ProfileHueSatMapData3',
4142             %longBin,
4143             Writable => 'float',
4144             WriteGroup => 'IFD0',
4145             Count => -1,
4146             Protected => 1,
4147             },
4148             0xcd3a => { # DNG 1.6
4149             Name => 'ReductionMatrix3',
4150             Writable => 'rational64s',
4151             WriteGroup => 'IFD0',
4152             Count => -1,
4153             Protected => 1,
4154             },
4155             0xcd3b => { # DNG 1.6
4156             Name => 'RGBTables',
4157             Writable => 'undef',
4158             WriteGroup => 'IFD0',
4159             Protected => 1,
4160             },
4161             0xea1c => { #13
4162             Name => 'Padding',
4163             Binary => 1,
4164             Protected => 1,
4165             Writable => 'undef',
4166             # must start with 0x1c 0xea by the WM Photo specification
4167             # (not sure what should happen if padding is only 1 byte)
4168             # (why does MicrosoftPhoto write "1c ea 00 00 00 08"?)
4169             RawConvInv => '$val=~s/^../\x1c\xea/s; $val',
4170             },
4171             0xea1d => {
4172             Name => 'OffsetSchema',
4173             Notes => "Microsoft's ill-conceived maker note offset difference",
4174             Protected => 1,
4175             Writable => 'int32s',
4176             # From the Microsoft documentation:
4177             #
4178             # Any time the "Maker Note" is relocated by Windows, the Exif MakerNote
4179             # tag (37500) is updated automatically to reference the new location. In
4180             # addition, Windows records the offset (or difference) between the old and
4181             # new locations in the Exif OffsetSchema tag (59933). If the "Maker Note"
4182             # contains relative references, the developer can add the value in
4183             # OffsetSchema to the original references to find the correct information.
4184             #
4185             # My recommendation is for other developers to ignore this tag because the
4186             # information it contains is unreliable. It will be wrong if the image has
4187             # been subsequently edited by another application that doesn't recognize the
4188             # new Microsoft tag.
4189             #
4190             # The new tag unfortunately only gives the difference between the new maker
4191             # note offset and the original offset. Instead, it should have been designed
4192             # to store the original offset. The new offset may change if the image is
4193             # edited, which will invalidate the tag as currently written. If instead the
4194             # original offset had been stored, the new difference could be easily
4195             # calculated because the new maker note offset is known.
4196             #
4197             # I exchanged emails with a Microsoft technical representative, pointing out
4198             # this problem shortly after they released the update (Feb 2007), but so far
4199             # they have taken no steps to address this.
4200             },
4201             # 0xefee - int16u: 0 - seen this from a WIC-scanned image
4202              
4203             # tags in the range 0xfde8-0xfe58 have been observed in PS7 files
4204             # generated from RAW images. They are all strings with the
4205             # tag name at the start of the string. To accommodate these types
4206             # of tags, all tags with values above 0xf000 are handled specially
4207             # by ProcessExif().
4208             0xfde8 => {
4209             Name => 'OwnerName',
4210             Condition => '$$self{TIFF_TYPE} ne "DCR"', # (used for another purpose in Kodak DCR images)
4211             Avoid => 1,
4212             PSRaw => 1,
4213             Writable => 'string',
4214             ValueConv => '$val=~s/^.*: //;$val',
4215             ValueConvInv => q{"Owner's Name: $val"},
4216             Notes => q{
4217             tags 0xfde8-0xfdea and 0xfe4c-0xfe58 are generated by Photoshop Camera RAW.
4218             Some names are the same as other EXIF tags, but ExifTool will avoid writing
4219             these unless they already exist in the file
4220             },
4221             },
4222             0xfde9 => {
4223             Name => 'SerialNumber',
4224             Condition => '$$self{TIFF_TYPE} ne "DCR"', # (used for another purpose in Kodak DCR SubIFD)
4225             Avoid => 1,
4226             PSRaw => 1,
4227             Writable => 'string',
4228             ValueConv => '$val=~s/^.*: //;$val',
4229             ValueConvInv => q{"Serial Number: $val"},
4230             },
4231             0xfdea => {
4232             Name => 'Lens',
4233             Condition => '$$self{TIFF_TYPE} ne "DCR"', # (used for another purpose in Kodak DCR SubIFD)
4234             Avoid => 1,
4235             PSRaw => 1,
4236             Writable => 'string',
4237             ValueConv => '$val=~s/^.*: //;$val',
4238             ValueConvInv => q{"Lens: $val"},
4239             },
4240             0xfe4c => {
4241             Name => 'RawFile',
4242             Avoid => 1,
4243             PSRaw => 1,
4244             Writable => 'string',
4245             ValueConv => '$val=~s/^.*: //;$val',
4246             ValueConvInv => q{"Raw File: $val"},
4247             },
4248             0xfe4d => {
4249             Name => 'Converter',
4250             Avoid => 1,
4251             PSRaw => 1,
4252             Writable => 'string',
4253             ValueConv => '$val=~s/^.*: //;$val',
4254             ValueConvInv => q{"Converter: $val"},
4255             },
4256             0xfe4e => {
4257             Name => 'WhiteBalance',
4258             Avoid => 1,
4259             PSRaw => 1,
4260             Writable => 'string',
4261             ValueConv => '$val=~s/^.*: //;$val',
4262             ValueConvInv => q{"White Balance: $val"},
4263             },
4264             0xfe51 => {
4265             Name => 'Exposure',
4266             Avoid => 1,
4267             PSRaw => 1,
4268             Writable => 'string',
4269             ValueConv => '$val=~s/^.*: //;$val',
4270             ValueConvInv => q{"Exposure: $val"},
4271             },
4272             0xfe52 => {
4273             Name => 'Shadows',
4274             Avoid => 1,
4275             PSRaw => 1,
4276             Writable => 'string',
4277             ValueConv => '$val=~s/^.*: //;$val',
4278             ValueConvInv => q{"Shadows: $val"},
4279             },
4280             0xfe53 => {
4281             Name => 'Brightness',
4282             Avoid => 1,
4283             PSRaw => 1,
4284             Writable => 'string',
4285             ValueConv => '$val=~s/^.*: //;$val',
4286             ValueConvInv => q{"Brightness: $val"},
4287             },
4288             0xfe54 => {
4289             Name => 'Contrast',
4290             Avoid => 1,
4291             PSRaw => 1,
4292             Writable => 'string',
4293             ValueConv => '$val=~s/^.*: //;$val',
4294             ValueConvInv => q{"Contrast: $val"},
4295             },
4296             0xfe55 => {
4297             Name => 'Saturation',
4298             Avoid => 1,
4299             PSRaw => 1,
4300             Writable => 'string',
4301             ValueConv => '$val=~s/^.*: //;$val',
4302             ValueConvInv => q{"Saturation: $val"},
4303             },
4304             0xfe56 => {
4305             Name => 'Sharpness',
4306             Avoid => 1,
4307             PSRaw => 1,
4308             Writable => 'string',
4309             ValueConv => '$val=~s/^.*: //;$val',
4310             ValueConvInv => q{"Sharpness: $val"},
4311             },
4312             0xfe57 => {
4313             Name => 'Smoothness',
4314             Avoid => 1,
4315             PSRaw => 1,
4316             Writable => 'string',
4317             ValueConv => '$val=~s/^.*: //;$val',
4318             ValueConvInv => q{"Smoothness: $val"},
4319             },
4320             0xfe58 => {
4321             Name => 'MoireFilter',
4322             Avoid => 1,
4323             PSRaw => 1,
4324             Writable => 'string',
4325             ValueConv => '$val=~s/^.*: //;$val',
4326             ValueConvInv => q{"Moire Filter: $val"},
4327             },
4328              
4329             #-------------
4330             0xfe00 => {
4331             Name => 'KDC_IFD',
4332             Groups => { 1 => 'KDC_IFD' },
4333             Flags => 'SubIFD',
4334             Notes => 'used in some Kodak KDC images',
4335             SubDirectory => {
4336             TagTable => 'Image::ExifTool::Kodak::KDC_IFD',
4337             DirName => 'KDC_IFD',
4338             Start => '$val',
4339             },
4340             },
4341             );
4342              
4343             # conversions for Composite SubSec date/time tags
4344             my %subSecConv = (
4345             # @val array: 0) date/time, 1) sub-seconds, 2) time zone offset
4346             RawConv => q{
4347             my $v;
4348             if (defined $val[1] and $val[1]=~/^(\d+)/) {
4349             my $subSec = $1;
4350             # be careful here just in case the time already contains sub-seconds or a timezone (contrary to spec)
4351             undef $v unless ($v = $val[0]) =~ s/( \d{2}:\d{2}:\d{2})(?!\.\d+)/$1\.$subSec/;
4352             }
4353             if (defined $val[2] and $val[0]!~/[-+]/ and $val[2]=~/^([-+])(\d{1,2}):(\d{2})/) {
4354             $v = ($v || $val[0]) . sprintf('%s%.2d:%.2d', $1, $2, $3);
4355             }
4356             return $v;
4357             },
4358             PrintConv => '$self->ConvertDateTime($val)',
4359             PrintConvInv => '$self->InverseDateTime($val)',
4360             );
4361              
4362             # EXIF Composite tags (plus other more general Composite tags)
4363             %Image::ExifTool::Exif::Composite = (
4364             GROUPS => { 2 => 'Image' },
4365             ImageSize => {
4366             Require => {
4367             0 => 'ImageWidth',
4368             1 => 'ImageHeight',
4369             },
4370             Desire => {
4371             2 => 'ExifImageWidth',
4372             3 => 'ExifImageHeight',
4373             4 => 'RawImageCroppedSize', # (FujiFilm RAF images)
4374             },
4375             # use ExifImageWidth/Height only for Canon and Phase One TIFF-base RAW images
4376             ValueConv => q{
4377             return $val[4] if $val[4];
4378             return "$val[2] $val[3]" if $val[2] and $val[3] and
4379             $$self{TIFF_TYPE} =~ /^(CR2|Canon 1D RAW|IIQ|EIP)$/;
4380             return "$val[0] $val[1]" if IsFloat($val[0]) and IsFloat($val[1]);
4381             return undef;
4382             },
4383             PrintConv => '$val =~ tr/ /x/; $val',
4384             },
4385             Megapixels => {
4386             Require => 'ImageSize',
4387             ValueConv => 'my @d = ($val =~ /\d+/g); $d[0] * $d[1] / 1000000',
4388             PrintConv => 'sprintf("%.*f", ($val >= 1 ? 1 : ($val >= 0.001 ? 3 : 6)), $val)',
4389             },
4390             # pick the best shutter speed value
4391             ShutterSpeed => {
4392             Desire => {
4393             0 => 'ExposureTime',
4394             1 => 'ShutterSpeedValue',
4395             2 => 'BulbDuration',
4396             },
4397             ValueConv => '($val[2] and $val[2]>0) ? $val[2] : (defined($val[0]) ? $val[0] : $val[1])',
4398             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
4399             },
4400             Aperture => {
4401             Desire => {
4402             0 => 'FNumber',
4403             1 => 'ApertureValue',
4404             },
4405             RawConv => '($val[0] || $val[1]) ? $val : undef',
4406             ValueConv => '$val[0] || $val[1]',
4407             PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)',
4408             },
4409             LightValue => {
4410             Notes => q{
4411             calculated LV = 2 * log2(Aperture) - log2(ShutterSpeed) - log2(ISO/100);
4412             similar to exposure value but normalized to ISO 100
4413             },
4414             Require => {
4415             0 => 'Aperture',
4416             1 => 'ShutterSpeed',
4417             2 => 'ISO',
4418             },
4419             ValueConv => 'Image::ExifTool::Exif::CalculateLV($val[0],$val[1],$prt[2])',
4420             PrintConv => 'sprintf("%.1f",$val)',
4421             },
4422             FocalLength35efl => { #26/PH
4423             Description => 'Focal Length',
4424             Notes => 'this value may be incorrect if the image has been resized',
4425             Groups => { 2 => 'Camera' },
4426             Require => {
4427             0 => 'FocalLength',
4428             },
4429             Desire => {
4430             1 => 'ScaleFactor35efl',
4431             },
4432             ValueConv => 'ToFloat(@val); ($val[0] || 0) * ($val[1] || 1)',
4433             PrintConv => '$val[1] ? sprintf("%.1f mm (35 mm equivalent: %.1f mm)", $val[0], $val) : sprintf("%.1f mm", $val)',
4434             },
4435             ScaleFactor35efl => { #26/PH
4436             Description => 'Scale Factor To 35 mm Equivalent',
4437             Notes => q{
4438             this value and any derived values may be incorrect if the image has been
4439             resized
4440             },
4441             Groups => { 2 => 'Camera' },
4442             Desire => {
4443             0 => 'FocalLength',
4444             1 => 'FocalLengthIn35mmFormat',
4445             2 => 'Composite:DigitalZoom',
4446             3 => 'FocalPlaneDiagonal',
4447             4 => 'SensorSize',
4448             5 => 'FocalPlaneXSize',
4449             6 => 'FocalPlaneYSize',
4450             7 => 'FocalPlaneResolutionUnit',
4451             8 => 'FocalPlaneXResolution',
4452             9 => 'FocalPlaneYResolution',
4453             10 => 'ExifImageWidth',
4454             11 => 'ExifImageHeight',
4455             12 => 'CanonImageWidth',
4456             13 => 'CanonImageHeight',
4457             14 => 'ImageWidth',
4458             15 => 'ImageHeight',
4459             },
4460             ValueConv => 'Image::ExifTool::Exif::CalcScaleFactor35efl($self, @val)',
4461             PrintConv => 'sprintf("%.1f", $val)',
4462             },
4463             CircleOfConfusion => {
4464             Notes => q{
4465             calculated as D/1440, where D is the focal plane diagonal in mm. This value
4466             may be incorrect if the image has been resized
4467             },
4468             Groups => { 2 => 'Camera' },
4469             Require => 'ScaleFactor35efl',
4470             ValueConv => 'sqrt(24*24+36*36) / ($val * 1440)',
4471             PrintConv => 'sprintf("%.3f mm",$val)',
4472             },
4473             HyperfocalDistance => {
4474             Notes => 'this value may be incorrect if the image has been resized',
4475             Groups => { 2 => 'Camera' },
4476             Require => {
4477             0 => 'FocalLength',
4478             1 => 'Aperture',
4479             2 => 'CircleOfConfusion',
4480             },
4481             ValueConv => q{
4482             ToFloat(@val);
4483             return 'inf' unless $val[1] and $val[2];
4484             return $val[0] * $val[0] / ($val[1] * $val[2] * 1000);
4485             },
4486             PrintConv => 'sprintf("%.2f m", $val)',
4487             },
4488             DOF => {
4489             Description => 'Depth Of Field',
4490             Notes => 'this value may be incorrect if the image has been resized',
4491             Require => {
4492             0 => 'FocalLength',
4493             1 => 'Aperture',
4494             2 => 'CircleOfConfusion',
4495             },
4496             Desire => {
4497             3 => 'FocusDistance', # focus distance in metres (0 is infinity)
4498             4 => 'SubjectDistance',
4499             5 => 'ObjectDistance',
4500             6 => 'ApproximateFocusDistance',
4501             7 => 'FocusDistanceLower',
4502             8 => 'FocusDistanceUpper',
4503             },
4504             ValueConv => q{
4505             ToFloat(@val);
4506             my ($d, $f) = ($val[3], $val[0]);
4507             if (defined $d) {
4508             $d or $d = 1e10; # (use large number for infinity)
4509             } else {
4510             $d = $val[4] || $val[5] || $val[6];
4511             unless (defined $d) {
4512             return undef unless defined $val[7] and defined $val[8];
4513             $d = ($val[7] + $val[8]) / 2;
4514             }
4515             }
4516             return 0 unless $f and $val[2];
4517             my $t = $val[1] * $val[2] * ($d * 1000 - $f) / ($f * $f);
4518             my @v = ($d / (1 + $t), $d / (1 - $t));
4519             $v[1] < 0 and $v[1] = 0; # 0 means 'inf'
4520             return join(' ',@v);
4521             },
4522             PrintConv => q{
4523             $val =~ tr/,/./; # in case locale is whacky
4524             my @v = split ' ', $val;
4525             $v[1] or return sprintf("inf (%.2f m - inf)", $v[0]);
4526             my $dof = $v[1] - $v[0];
4527             my $fmt = ($dof>0 and $dof<0.02) ? "%.3f" : "%.2f";
4528             return sprintf("$fmt m ($fmt - $fmt m)",$dof,$v[0],$v[1]);
4529             },
4530             },
4531             FOV => {
4532             Description => 'Field Of View',
4533             Notes => q{
4534             calculated for the long image dimension. This value may be incorrect for
4535             fisheye lenses, or if the image has been resized
4536             },
4537             Require => {
4538             0 => 'FocalLength',
4539             1 => 'ScaleFactor35efl',
4540             },
4541             Desire => {
4542             2 => 'FocusDistance', # (multiply by 1000 to convert to mm)
4543             },
4544             # ref http://www.bobatkins.com/photography/technical/field_of_view.html
4545             # (calculations below apply to rectilinear lenses only, not fisheye)
4546             ValueConv => q{
4547             ToFloat(@val);
4548             return undef unless $val[0] and $val[1];
4549             my $corr = 1;
4550             if ($val[2]) {
4551             my $d = 1000 * $val[2] - $val[0];
4552             $corr += $val[0]/$d if $d > 0;
4553             }
4554             my $fd2 = atan2(36, 2*$val[0]*$val[1]*$corr);
4555             my @fov = ( $fd2 * 360 / 3.14159 );
4556             if ($val[2] and $val[2] > 0 and $val[2] < 10000) {
4557             push @fov, 2 * $val[2] * sin($fd2) / cos($fd2);
4558             }
4559             return join(' ', @fov);
4560             },
4561             PrintConv => q{
4562             my @v = split(' ',$val);
4563             my $str = sprintf("%.1f deg", $v[0]);
4564             $str .= sprintf(" (%.2f m)", $v[1]) if $v[1];
4565             return $str;
4566             },
4567             },
4568             # generate DateTimeOriginal from Date and Time Created if not extracted already
4569             DateTimeOriginal => {
4570             Condition => 'not defined $$self{VALUE}{DateTimeOriginal}',
4571             Description => 'Date/Time Original',
4572             Groups => { 2 => 'Time' },
4573             Desire => {
4574             0 => 'DateTimeCreated',
4575             1 => 'DateCreated',
4576             2 => 'TimeCreated',
4577             },
4578             RawConv => '($val[1] and $val[2]) ? $val : undef',
4579             ValueConv => q{
4580             return $val[0] if $val[0] and $val[0]=~/ /;
4581             return "$val[1] $val[2]";
4582             },
4583             PrintConv => '$self->ConvertDateTime($val)',
4584             },
4585             ThumbnailImage => {
4586             Groups => { 0 => 'EXIF', 1 => 'IFD1', 2 => 'Preview' },
4587             Writable => 1,
4588             WriteGroup => 'All',
4589             WriteCheck => '$self->CheckImage(\$val)',
4590             WriteAlso => {
4591             # (the 0xfeedfeed values are translated in the Exif write routine)
4592             ThumbnailOffset => 'defined $val ? 0xfeedfeed : undef',
4593             ThumbnailLength => 'defined $val ? 0xfeedfeed : undef',
4594             },
4595             Require => {
4596             0 => 'ThumbnailOffset',
4597             1 => 'ThumbnailLength',
4598             },
4599             Notes => q{
4600             this tag is writable, and may be used to update existing thumbnails, but may
4601             only create a thumbnail in IFD1 of certain types of files. Note that for
4602             this and other Composite embedded-image tags the family 0 and 1 groups match
4603             those of the originating tags
4604             },
4605             # retrieve the thumbnail from our EXIF data
4606             RawConv => q{
4607             @grps = $self->GetGroup($$val{0}); # set groups from ThumbnailOffsets
4608             Image::ExifTool::Exif::ExtractImage($self,$val[0],$val[1],"ThumbnailImage");
4609             },
4610             },
4611             ThumbnailTIFF => {
4612             Groups => { 2 => 'Preview' },
4613             Require => {
4614             0 => 'SubfileType',
4615             1 => 'Compression',
4616             2 => 'ImageWidth',
4617             3 => 'ImageHeight',
4618             4 => 'BitsPerSample',
4619             5 => 'PhotometricInterpretation',
4620             6 => 'StripOffsets',
4621             7 => 'SamplesPerPixel',
4622             8 => 'RowsPerStrip',
4623             9 => 'StripByteCounts',
4624             },
4625             Desire => {
4626             10 => 'PlanarConfiguration',
4627             11 => 'Orientation',
4628             },
4629             # rebuild the TIFF thumbnail from our EXIF data
4630             RawConv => q{
4631             my $tiff;
4632             ($tiff, @grps) = Image::ExifTool::Exif::RebuildTIFF($self, @val);
4633             return $tiff;
4634             },
4635             },
4636             PreviewImage => {
4637             Groups => { 0 => 'EXIF', 1 => 'SubIFD', 2 => 'Preview' },
4638             Writable => 1,
4639             WriteGroup => 'All',
4640             WriteCheck => '$self->CheckImage(\$val)',
4641             DelCheck => '$val = ""; return undef', # can't delete, so set to empty string
4642             WriteAlso => {
4643             PreviewImageStart => 'defined $val ? 0xfeedfeed : undef',
4644             PreviewImageLength => 'defined $val ? 0xfeedfeed : undef',
4645             PreviewImageValid => 'defined $val and length $val ? 1 : 0', # (for Olympus)
4646             },
4647             Require => {
4648             0 => 'PreviewImageStart',
4649             1 => 'PreviewImageLength',
4650             },
4651             Desire => {
4652             2 => 'PreviewImageValid',
4653             # (DNG and A100 ARW may be have 2 preview images)
4654             3 => 'PreviewImageStart (1)',
4655             4 => 'PreviewImageLength (1)',
4656             },
4657             Notes => q{
4658             this tag is writable, and may be used to update existing embedded images,
4659             but not create or delete them
4660             },
4661             # note: extract 2nd preview, but ignore double-referenced preview
4662             # (in A100 ARW images, the 2nd PreviewImageLength from IFD0 may be wrong anyway)
4663             RawConv => q{
4664             if ($val[3] and $val[4] and $val[0] ne $val[3]) {
4665             my %val = (
4666             0 => 'PreviewImageStart (1)',
4667             1 => 'PreviewImageLength (1)',
4668             2 => 'PreviewImageValid',
4669             );
4670             $self->FoundTag($tagInfo, \%val);
4671             }
4672             return undef if defined $val[2] and not $val[2];
4673             @grps = $self->GetGroup($$val{0});
4674             return Image::ExifTool::Exif::ExtractImage($self,$val[0],$val[1],'PreviewImage');
4675             },
4676             },
4677             JpgFromRaw => {
4678             Groups => { 0 => 'EXIF', 1 => 'SubIFD', 2 => 'Preview' },
4679             Writable => 1,
4680             WriteGroup => 'All',
4681             WriteCheck => '$self->CheckImage(\$val)',
4682             # Note: ExifTool 10.38 had disabled the ability to delete this -- why?
4683             # --> added the DelCheck in 10.61 to re-enable this
4684             DelCheck => '$val = ""; return undef', # can't delete, so set to empty string
4685             WriteAlso => {
4686             JpgFromRawStart => 'defined $val ? 0xfeedfeed : undef',
4687             JpgFromRawLength => 'defined $val ? 0xfeedfeed : undef',
4688             },
4689             Require => {
4690             0 => 'JpgFromRawStart',
4691             1 => 'JpgFromRawLength',
4692             },
4693             Notes => q{
4694             this tag is writable, and may be used to update existing embedded images,
4695             but not create or delete them
4696             },
4697             RawConv => q{
4698             @grps = $self->GetGroup($$val{0});
4699             return Image::ExifTool::Exif::ExtractImage($self,$val[0],$val[1],"JpgFromRaw");
4700             },
4701             },
4702             OtherImage => {
4703             Groups => { 0 => 'EXIF', 1 => 'SubIFD', 2 => 'Preview' },
4704             Writable => 1,
4705             WriteGroup => 'All',
4706             WriteCheck => '$self->CheckImage(\$val)',
4707             DelCheck => '$val = ""; return undef', # can't delete, so set to empty string
4708             WriteAlso => {
4709             OtherImageStart => 'defined $val ? 0xfeedfeed : undef',
4710             OtherImageLength => 'defined $val ? 0xfeedfeed : undef',
4711             },
4712             Require => {
4713             0 => 'OtherImageStart',
4714             1 => 'OtherImageLength',
4715             },
4716             Notes => q{
4717             this tag is writable, and may be used to update existing embedded images,
4718             but not create or delete them
4719             },
4720             # retrieve the thumbnail from our EXIF data
4721             RawConv => q{
4722             @grps = $self->GetGroup($$val{0});
4723             Image::ExifTool::Exif::ExtractImage($self,$val[0],$val[1],"OtherImage");
4724             },
4725             },
4726             PreviewImageSize => {
4727             Require => {
4728             0 => 'PreviewImageWidth',
4729             1 => 'PreviewImageHeight',
4730             },
4731             ValueConv => '"$val[0]x$val[1]"',
4732             },
4733             SubSecDateTimeOriginal => {
4734             Description => 'Date/Time Original',
4735             Groups => { 2 => 'Time' },
4736             Writable => 1,
4737             Shift => 0, # don't shift this tag
4738             Require => {
4739             0 => 'EXIF:DateTimeOriginal',
4740             },
4741             Desire => {
4742             1 => 'SubSecTimeOriginal',
4743             2 => 'OffsetTimeOriginal',
4744             },
4745             WriteAlso => {
4746             'EXIF:DateTimeOriginal' => '($val and $val=~/^(\d{4}:\d{2}:\d{2} \d{2}:\d{2}:\d{2})/) ? $1 : undef',
4747             'EXIF:SubSecTimeOriginal' => '($val and $val=~/\.(\d+)/) ? $1 : undef',
4748             'EXIF:OffsetTimeOriginal' => '($val and $val=~/([-+]\d{2}:\d{2}|Z)$/) ? ($1 eq "Z" ? "+00:00" : $1) : undef',
4749             },
4750             %subSecConv,
4751             },
4752             SubSecCreateDate => {
4753             Description => 'Create Date',
4754             Groups => { 2 => 'Time' },
4755             Writable => 1,
4756             Shift => 0, # don't shift this tag
4757             Require => {
4758             0 => 'EXIF:CreateDate',
4759             },
4760             Desire => {
4761             1 => 'SubSecTimeDigitized',
4762             2 => 'OffsetTimeDigitized',
4763             },
4764             WriteAlso => {
4765             'EXIF:CreateDate' => '($val and $val=~/^(\d{4}:\d{2}:\d{2} \d{2}:\d{2}:\d{2})/) ? $1 : undef',
4766             'EXIF:SubSecTimeDigitized' => '($val and $val=~/\.(\d+)/) ? $1 : undef',
4767             'EXIF:OffsetTimeDigitized' => '($val and $val=~/([-+]\d{2}:\d{2}|Z)$/) ? ($1 eq "Z" ? "+00:00" : $1) : undef',
4768             },
4769             %subSecConv,
4770             },
4771             SubSecModifyDate => {
4772             Description => 'Modify Date',
4773             Groups => { 2 => 'Time' },
4774             Writable => 1,
4775             Shift => 0, # don't shift this tag
4776             Require => {
4777             0 => 'EXIF:ModifyDate',
4778             },
4779             Desire => {
4780             1 => 'SubSecTime',
4781             2 => 'OffsetTime',
4782             },
4783             WriteAlso => {
4784             'EXIF:ModifyDate' => '($val and $val=~/^(\d{4}:\d{2}:\d{2} \d{2}:\d{2}:\d{2})/) ? $1 : undef',
4785             'EXIF:SubSecTime' => '($val and $val=~/\.(\d+)/) ? $1 : undef',
4786             'EXIF:OffsetTime' => '($val and $val=~/([-+]\d{2}:\d{2}|Z)$/) ? ($1 eq "Z" ? "+00:00" : $1) : undef',
4787             },
4788             %subSecConv,
4789             },
4790             CFAPattern => {
4791             Require => {
4792             0 => 'CFARepeatPatternDim',
4793             1 => 'CFAPattern2',
4794             },
4795             # generate CFAPattern
4796             ValueConv => q{
4797             my @a = split / /, $val[0];
4798             my @b = split / /, $val[1];
4799             return '?' unless @a==2 and @b==$a[0]*$a[1];
4800             return "$a[0] $a[1] @b";
4801             },
4802             PrintConv => 'Image::ExifTool::Exif::PrintCFAPattern($val)',
4803             },
4804             RedBalance => {
4805             Groups => { 2 => 'Camera' },
4806             Desire => {
4807             0 => 'WB_RGGBLevels',
4808             1 => 'WB_RGBGLevels',
4809             2 => 'WB_RBGGLevels',
4810             3 => 'WB_GRBGLevels',
4811             4 => 'WB_GRGBLevels',
4812             5 => 'WB_GBRGLevels',
4813             6 => 'WB_RGBLevels',
4814             7 => 'WB_GRBLevels',
4815             8 => 'WB_RBLevels',
4816             9 => 'WBRedLevel', # red
4817             10 => 'WBGreenLevel',
4818             },
4819             ValueConv => 'Image::ExifTool::Exif::RedBlueBalance(0,@val)',
4820             PrintConv => 'int($val * 1e6 + 0.5) * 1e-6',
4821             },
4822             BlueBalance => {
4823             Groups => { 2 => 'Camera' },
4824             Desire => {
4825             0 => 'WB_RGGBLevels',
4826             1 => 'WB_RGBGLevels',
4827             2 => 'WB_RBGGLevels',
4828             3 => 'WB_GRBGLevels',
4829             4 => 'WB_GRGBLevels',
4830             5 => 'WB_GBRGLevels',
4831             6 => 'WB_RGBLevels',
4832             7 => 'WB_GRBLevels',
4833             8 => 'WB_RBLevels',
4834             9 => 'WBBlueLevel', # blue
4835             10 => 'WBGreenLevel',
4836             },
4837             ValueConv => 'Image::ExifTool::Exif::RedBlueBalance(1,@val)',
4838             PrintConv => 'int($val * 1e6 + 0.5) * 1e-6',
4839             },
4840             GPSPosition => {
4841             Groups => { 2 => 'Location' },
4842             Writable => 1,
4843             Protected => 1,
4844             WriteAlso => {
4845             GPSLatitude => '$val =~ /(.*?)( ?[NS])?,/ ? $1 : undef',
4846             GPSLatitudeRef => '$val =~ /(-?)(.*?) ?([NS]?),/ ? ($3 || ($1 ? "S" : "N")) : undef',
4847             GPSLongitude => '$val =~ /, ?(.*?)( ?[EW]?)$/ ? $1 : undef',
4848             GPSLongitudeRef => '$val =~ /, ?(-?)(.*?) ?([EW]?)$/ ? ($3 || ($1 ? "W" : "E")) : undef',
4849             },
4850             PrintConvInv => q{
4851             return undef unless $val =~ /(.*? ?[NS]?), ?(.*? ?[EW]?)$/;
4852             my ($lat, $lon) = ($1, $2);
4853             require Image::ExifTool::GPS;
4854             $lat = Image::ExifTool::GPS::ToDegrees($lat, 1, "lat");
4855             $lon = Image::ExifTool::GPS::ToDegrees($lon, 1, "lon");
4856             return "$lat, $lon";
4857             },
4858             Require => {
4859             0 => 'GPSLatitude',
4860             1 => 'GPSLongitude',
4861             },
4862             Priority => 0,
4863             Notes => q{
4864             when written, writes GPSLatitude, GPSLatitudeRef, GPSLongitude and
4865             GPSLongitudeRef. This tag may be written using the same coordinate
4866             format as provided by Google Maps when right-clicking on a location
4867             },
4868             ValueConv => '(length($val[0]) or length($val[1])) ? "$val[0] $val[1]" : undef',
4869             PrintConv => '"$prt[0], $prt[1]"',
4870             },
4871             LensID => {
4872             Groups => { 2 => 'Camera' },
4873             Require => 'LensType',
4874             Desire => {
4875             1 => 'FocalLength',
4876             2 => 'MaxAperture',
4877             3 => 'MaxApertureValue',
4878             4 => 'MinFocalLength',
4879             5 => 'MaxFocalLength',
4880             6 => 'LensModel',
4881             7 => 'LensFocalRange',
4882             8 => 'LensSpec',
4883             9 => 'LensType2',
4884             10 => 'LensType3',
4885             11 => 'LensFocalLength', # (for Pentax to check for converter)
4886             12 => 'RFLensType',
4887             },
4888             Notes => q{
4889             attempt to identify the actual lens from all lenses with a given LensType.
4890             Applies only to LensType values with a lookup table. May be configured
4891             by adding user-defined lenses
4892             },
4893             # this LensID is only valid if the LensType has a PrintConv or is a model name
4894             RawConv => q{
4895             my $printConv = $$self{TAG_INFO}{LensType}{PrintConv};
4896             return $val if ref $printConv eq 'HASH' or (ref $printConv eq 'ARRAY' and
4897             ref $$printConv[0] eq 'HASH') or $val[0] =~ /(mm|\d\/F)/;
4898             return undef;
4899             },
4900             ValueConv => '$val',
4901             PrintConv => q{
4902             my $pcv;
4903             # use LensType2 instead of LensType if available and valid (Sony E-mount lenses)
4904             # (0x8000 or greater; 0 for several older/3rd-party E-mount lenses)
4905             if (defined $val[9] and ($val[9] & 0x8000 or $val[9] == 0)) {
4906             $val[0] = $val[9];
4907             $prt[0] = $prt[9];
4908             # Particularly GM lenses: often LensType2=0 but LensType3 is available and valid: use LensType3.
4909             if ($val[9] == 0 and $val[10] & 0x8000) {
4910             $val[0] = $val[10];
4911             $prt[0] = $prt[10];
4912             }
4913             $pcv = $$self{TAG_INFO}{LensType2}{PrintConv};
4914             }
4915             # use Canon RFLensType if available
4916             if ($val[12]) {
4917             $val[0] = $val[12];
4918             $prt[0] = $prt[12];
4919             $pcv = $$self{TAG_INFO}{RFLensType}{PrintConv};
4920             }
4921             my $lens = Image::ExifTool::Exif::PrintLensID($self, $prt[0], $pcv, $prt[8], @val);
4922             # check for use of lens converter (Pentax K-3)
4923             if ($val[11] and $val[1] and $lens) {
4924             my $conv = $val[1] / $val[11];
4925             $lens .= sprintf(' + %.1fx converter', $conv) if $conv > 1.1;
4926             }
4927             return $lens;
4928             },
4929             },
4930             'LensID-2' => {
4931             Name => 'LensID',
4932             Groups => { 2 => 'Camera' },
4933             Desire => {
4934             0 => 'LensModel',
4935             1 => 'Lens',
4936             2 => 'XMP-aux:LensID',
4937             3 => 'Make',
4938             },
4939             Inhibit => {
4940             4 => 'Composite:LensID',
4941             },
4942             RawConv => q{
4943             return undef if defined $val[2] and defined $val[3];
4944             return $val if defined $val[0] and $val[0] =~ /(mm|\d\/F)/;
4945             return $val if defined $val[1] and $val[1] =~ /(mm|\d\/F)/;
4946             return undef;
4947             },
4948             ValueConv => q{
4949             return $val[0] if defined $val[0] and $val[0] =~ /(mm|\d\/F)/;
4950             return $val[1];
4951             },
4952             PrintConv => '$_=$val; s/(\d)\/F/$1mm F/; s/mmF/mm F/; s/(\d) mm/${1}mm/; s/ - /-/; $_',
4953             },
4954             );
4955              
4956             # table for unknown IFD entries
4957             %Image::ExifTool::Exif::Unknown = (
4958             GROUPS => { 0 => 'EXIF', 1 => 'UnknownIFD', 2 => 'Image'},
4959             WRITE_PROC => \&WriteExif,
4960             );
4961              
4962             # add our composite tags
4963             Image::ExifTool::AddCompositeTags('Image::ExifTool::Exif');
4964              
4965              
4966             #------------------------------------------------------------------------------
4967             # AutoLoad our writer routines when necessary
4968             #
4969             sub AUTOLOAD
4970             {
4971 40     40   255 return Image::ExifTool::DoAutoLoad($AUTOLOAD, @_);
4972             }
4973              
4974             #------------------------------------------------------------------------------
4975             # Identify RAW file type for some TIFF-based formats using Compression value
4976             # Inputs: 0) ExifTool object reference, 1) Compression value
4977             # - sets TIFF_TYPE and FileType if identified
4978             sub IdentifyRawFile($$)
4979             {
4980 270     270 0 919 my ($et, $comp) = @_;
4981 270 100 66     4481 if ($$et{FILE_TYPE} eq 'TIFF' and not $$et{IdentifiedRawFile}) {
4982 71 100 66     1604 if ($compression{$comp} and $compression{$comp} =~ /^\w+ ([A-Z]{3}) Compressed$/) {
4983 3         23 $et->OverrideFileType($$et{TIFF_TYPE} = $1);
4984 3         56 $$et{IdentifiedRawFile} = 1;
4985             }
4986             }
4987             }
4988              
4989             #------------------------------------------------------------------------------
4990             # Calculate LV (Light Value)
4991             # Inputs: 0) Aperture, 1) ShutterSpeed, 2) ISO
4992             # Returns: LV value (and converts input values to floating point if necessary)
4993             sub CalculateLV($$$)
4994             {
4995 126     126 0 341 local $_;
4996             # do validity checks on arguments
4997 126 50       487 return undef unless @_ >= 3;
4998 126         395 foreach (@_) {
4999 378 50 66     3112 return undef unless $_ and /([+-]?(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?)/ and $1 > 0;
      66        
5000 373         874 $_ = $1; # extract float from any other garbage
5001             }
5002             # (A light value of 0 is defined as f/1.0 at 1 second with ISO 100)
5003 121         1497 return log($_[0] * $_[0] * 100 / ($_[1] * $_[2])) / log(2);
5004             }
5005              
5006             #------------------------------------------------------------------------------
5007             # Calculate scale factor for 35mm effective focal length (ref 26/PH)
5008             # Inputs: 0) ExifTool object ref
5009             # 1) Focal length
5010             # 2) Focal length in 35mm format
5011             # 3) Canon digital zoom factor
5012             # 4) Focal plane diagonal size (in mm)
5013             # 5) Sensor size (X and Y in mm)
5014             # 6/7) Focal plane X/Y size (in mm)
5015             # 8) focal plane resolution units (1=None,2=inches,3=cm,4=mm,5=um)
5016             # 9/10) Focal plane X/Y resolution
5017             # 11/12,13/14...) Image width/height in order of precedence (first valid pair is used)
5018             # Returns: 35mm conversion factor (or undefined if it can't be calculated)
5019             sub CalcScaleFactor35efl
5020             {
5021 548     548 0 1163 my $et = shift;
5022 548         899 my $res = $_[7]; # save resolution units (in case they have been converted to string)
5023 548         772 my $sensXY = $_[4];
5024 548         1915 Image::ExifTool::ToFloat(@_);
5025 548         857 my $focal = shift;
5026 548         810 my $foc35 = shift;
5027              
5028 548 100 100     2180 return $foc35 / $focal if $focal and $foc35;
5029              
5030 517   50     1712 my $digz = shift || 1;
5031 517         751 my $diag = shift;
5032 517         831 my $sens = shift;
5033             # calculate Canon sensor size using a dedicated algorithm
5034 517 100       1455 if ($$et{Make} eq 'Canon') {
5035 51         3341 require Image::ExifTool::Canon;
5036             my $canonDiag = Image::ExifTool::Canon::CalcSensorDiag(
5037             $$et{RATIONAL}{FocalPlaneXResolution},
5038             $$et{RATIONAL}{FocalPlaneYResolution},
5039 51         454 );
5040 51 100       175 $diag = $canonDiag if $canonDiag;
5041             }
5042 517 100 66     1671 unless ($diag and Image::ExifTool::IsFloat($diag)) {
5043 483 50 33     1329 if ($sens and $sensXY =~ / (\d+(\.?\d*)?)$/) {
5044 0         0 $diag = sqrt($sens * $sens + $1 * $1);
5045             } else {
5046 483         736 undef $diag;
5047 483         2026 my $xsize = shift;
5048 483         642 my $ysize = shift;
5049 483 100 66     1306 if ($xsize and $ysize) {
5050             # validate by checking aspect ratio because FocalPlaneX/YSize is not reliable
5051 16         43 my $a = $xsize / $ysize;
5052 16 50 66     95 if (abs($a-1.3333) < .1 or abs($a-1.5) < .1) {
5053 16         100 $diag = sqrt($xsize * $xsize + $ysize * $ysize);
5054             }
5055             }
5056             }
5057 483 100       1018 unless ($diag) {
5058             # get number of mm in units (assume inches unless otherwise specified)
5059 467         2421 my %lkup = ( 3=>10, 4=>1, 5=>0.001 , cm=>10, mm=>1, um=>0.001 );
5060 467   100     2801 my $units = $lkup{ shift() || $res || '' } || 25.4;
5061 467   100     3825 my $x_res = shift || return undef;
5062 123   66     270 my $y_res = shift || $x_res;
5063 123 50 33     336 Image::ExifTool::IsFloat($x_res) and $x_res != 0 or return undef;
5064 123 50 33     293 Image::ExifTool::IsFloat($y_res) and $y_res != 0 or return undef;
5065 123         245 my ($w, $h);
5066 123         180 for (;;) {
5067 125 50       294 @_ < 2 and return undef;
5068 125         211 $w = shift;
5069 125         190 $h = shift;
5070 125 100 66     439 next unless $w and $h;
5071 123         244 my $a = $w / $h;
5072 123 50 33     454 last if $a > 0.5 and $a < 2; # stop if we get a reasonable value
5073             }
5074             # calculate focal plane size in mm
5075 123         223 $w *= $units / $x_res;
5076 123         191 $h *= $units / $y_res;
5077 123         242 $diag = sqrt($w*$w+$h*$h);
5078             # make sure size is reasonable
5079 123 100 100     1231 return undef unless $diag > 1 and $diag < 100;
5080             }
5081             }
5082 57         512 return sqrt(36*36+24*24) * $digz / $diag;
5083             }
5084              
5085             #------------------------------------------------------------------------------
5086             # Print exposure compensation fraction
5087             sub PrintFraction($)
5088             {
5089 286     286 0 753 my $val = shift;
5090 286         573 my $str;
5091 286 50       802 if (defined $val) {
5092 286         734 $val *= 1.00001; # avoid round-off errors
5093 286 100       925 if (not $val) {
    100          
    50          
    100          
5094 258         522 $str = '0';
5095             } elsif (int($val)/$val > 0.999) {
5096 5         22 $str = sprintf("%+d", int($val));
5097             } elsif ((int($val*2))/($val*2) > 0.999) {
5098 0         0 $str = sprintf("%+d/2", int($val * 2));
5099             } elsif ((int($val*3))/($val*3) > 0.999) {
5100 10         41 $str = sprintf("%+d/3", int($val * 3));
5101             } else {
5102 13         92 $str = sprintf("%+.3g", $val);
5103             }
5104             }
5105 286         1738 return $str;
5106             }
5107              
5108             #------------------------------------------------------------------------------
5109             # Convert fraction or number to floating point value (or 'undef' or 'inf')
5110             sub ConvertFraction($)
5111             {
5112 1167     1167 0 2366 my $val = shift;
5113 1167 100       3440 if ($val =~ m{([-+]?\d+)/(\d+)}) {
5114 436 0       1742 $val = $2 ? $1 / $2 : ($1 ? 'inf' : 'undef');
    50          
5115             }
5116 1167         7077 return $val;
5117             }
5118              
5119             #------------------------------------------------------------------------------
5120             # Convert EXIF text to something readable
5121             # Inputs: 0) ExifTool object reference, 1) EXIF text,
5122             # 2) [optional] 1 to apply CharsetEXIF to ASCII text,
5123             # 3) tag name for warning message (may be argument 2)
5124             # Returns: text encoded according to Charset option (with trailing spaces removed)
5125             sub ConvertExifText($$;$$)
5126             {
5127 85     85 0 382 my ($et, $val, $asciiFlex, $tag) = @_;
5128 85 50       329 return $val if length($val) < 8;
5129 85         250 my $id = substr($val, 0, 8);
5130 85         237 my $str = substr($val, 8);
5131 85         147 my $type;
5132              
5133 85         202 delete $$et{WrongByteOrder};
5134 85 50 66     436 if ($$et{OPTIONS}{Validate} and $id =~ /^(ASCII|UNICODE|JIS)?\0* \0*$/) {
5135 0 0 0     0 $et->Warn(($1 || 'Undefined') . ' text header' . ($tag ? " for $tag" : '') . ' has spaces instead of nulls');
5136             }
5137             # Note: allow spaces instead of nulls in the ID codes because
5138             # it is fairly common for camera manufacturers to get this wrong
5139             # (also handle Canon ZoomBrowser EX 4.5 null followed by 7 bytes of garbage)
5140 85 50       491 if ($id =~ /^(ASCII)?(\0|[\0 ]+$)/) {
    0          
    0          
5141             # truncate at null terminator (shouldn't have a null based on the
5142             # EXIF spec, but it seems that few people actually read the spec)
5143 85         367 $str =~ s/\0.*//s;
5144             # allow ASCII text to contain any other specified encoding
5145 85 100 66     529 if ($asciiFlex and $asciiFlex eq '1') {
5146 84         329 my $enc = $et->Options('CharsetEXIF');
5147 84 50       306 $str = $et->Decode($str, $enc) if $enc;
5148             }
5149             # by the EXIF spec, the following string should be "UNICODE\0", but
5150             # apparently Kodak sometimes uses "Unicode\0" in the APP3 "Meta" information.
5151             # However, unfortunately Ricoh uses "Unicode\0" in the RR30 EXIF UserComment
5152             # when the text is actually ASCII, so only recognize uppercase "UNICODE\0".
5153             } elsif ($id =~ /^(UNICODE)[\0 ]$/) {
5154 0         0 $type = $1;
5155             # MicrosoftPhoto writes as little-endian even in big-endian EXIF,
5156             # so we must guess at the true byte ordering
5157 0         0 $str = $et->Decode($str, 'UTF16', 'Unknown');
5158             } elsif ($id =~ /^(JIS)[\0 ]{5}$/) {
5159 0         0 $type = $1;
5160 0         0 $str = $et->Decode($str, 'JIS', 'Unknown');
5161             } else {
5162 0 0 0     0 $tag = $asciiFlex if $asciiFlex and $asciiFlex ne '1';
5163 0 0       0 $et->Warn('Invalid EXIF text encoding' . ($tag ? " for $tag" : ''));
5164 0         0 $str = $id . $str;
5165             }
5166 85 0 33     295 if ($$et{WrongByteOrder} and $$et{OPTIONS}{Validate}) {
5167 0 0       0 $et->Warn('Wrong byte order for EXIF' . ($tag ? " $tag" : '') .
    0          
5168             ($type ? " $type" : '') . ' text');
5169             }
5170 85         220 $str =~ s/ +$//; # trim trailing blanks
5171 85         688 return $str;
5172             }
5173              
5174             #------------------------------------------------------------------------------
5175             # Print conversion for SpatialFrequencyResponse
5176             sub PrintSFR($)
5177             {
5178 0     0 0 0 my $val = shift;
5179 0 0       0 return $val unless length $val > 4;
5180 0         0 my ($n, $m) = (Get16u(\$val, 0), Get16u(\$val, 2));
5181 0         0 my @cols = split /\0/, substr($val, 4), $n+1;
5182 0         0 my $pos = length($val) - 8 * $n * $m;
5183 0 0 0     0 return $val unless @cols == $n+1 and $pos >= 4;
5184 0         0 pop @cols;
5185 0         0 my ($i, $j);
5186 0         0 for ($i=0; $i<$n; ++$i) {
5187 0         0 my @rows;
5188 0         0 for ($j=0; $j<$m; ++$j) {
5189 0         0 push @rows, Image::ExifTool::GetRational64u(\$val, $pos + 8*($i+$j*$n));
5190             }
5191 0         0 $cols[$i] .= '=' . join(',',@rows) . '';
5192             }
5193 0         0 return join '; ', @cols;
5194             }
5195              
5196             #------------------------------------------------------------------------------
5197             # Print numerical parameter value (with sign, or 'Normal' for zero)
5198             # Inputs: 0) value, 1) flag for inverse conversion, 2) conversion hash reference
5199             sub PrintParameter($$$)
5200             {
5201 195     195 0 469 my ($val, $inv, $conv) = @_;
5202 195 100       710 return $val if $inv;
5203 48 50       116 if ($val > 0) {
5204 48 50       109 if ($val > 0xfff0) { # a negative value in disguise?
5205 0         0 $val = $val - 0x10000;
5206             } else {
5207 48         109 $val = "+$val";
5208             }
5209             }
5210 48         135 return $val;
5211             }
5212              
5213             #------------------------------------------------------------------------------
5214             # Convert parameter back to standard EXIF value
5215             # 0,0.00,etc or "Normal" => 0
5216             # -1,-2,etc or "Soft" or "Low" => 1
5217             # +1,+2,1,2,etc or "Hard" or "High" => 2
5218             sub ConvertParameter($)
5219             {
5220 67     67 0 156 my $val = shift;
5221 67         185 my $isFloat = Image::ExifTool::IsFloat($val);
5222             # normal is a value of zero
5223 67 100 100     608 return 0 if $val =~ /\bn/i or ($isFloat and $val == 0);
      100        
5224             # "soft", "low" or any negative number is a value of 1
5225 39 50 66     256 return 1 if $val =~ /\b(s|l)/i or ($isFloat and $val < 0);
      33        
5226             # "hard", "high" or any positive number is a value of 2
5227 39 100 100     384 return 2 if $val =~ /\bh/i or $isFloat;
5228 2         14 return undef;
5229             }
5230              
5231             #------------------------------------------------------------------------------
5232             # Calculate Red/BlueBalance
5233             # Inputs: 0) 0=red, 1=blue, 1-8) WB_RGGB/RGBG/RBGG/GRBG/GRGB/RGB/GRB/RBLevels,
5234             # 8) red or blue level, 9) green level
5235             my @rggbLookup = (
5236             # indices for R, G, G and B components in input value
5237             [ 0, 1, 2, 3 ], # 0 RGGB
5238             [ 0, 1, 3, 2 ], # 1 RGBG
5239             [ 0, 2, 3, 1 ], # 2 RBGG
5240             [ 1, 0, 3, 2 ], # 3 GRBG
5241             [ 1, 0, 2, 3 ], # 4 GRGB
5242             [ 2, 3, 0, 1 ], # 5 GBRG
5243             [ 0, 1, 1, 2 ], # 6 RGB
5244             [ 1, 0, 0, 2 ], # 7 GRB
5245             [ 0, 256, 256, 1 ], # 8 RB (green level is 256)
5246             );
5247             sub RedBlueBalance($@)
5248             {
5249 86     86 0 218 my $blue = shift;
5250 86         168 my ($i, $val, $levels);
5251 86         362 for ($i=0; $i<@rggbLookup; ++$i) {
5252 228 100       498 $levels = shift or next;
5253 82         307 my @levels = split ' ', $levels;
5254 82 50       221 next if @levels < 2;
5255 82         167 my $lookup = $rggbLookup[$i];
5256 82         156 my $g = $$lookup[1]; # get green level or index
5257 82 100       296 if ($g < 4) {
    50          
5258 74 50       187 next if @levels < 3;
5259 74 50       325 $g = ($levels[$g] + $levels[$$lookup[2]]) / 2 or next;
5260             } elsif ($levels[$$lookup[$blue * 3]] < 4) {
5261 0         0 $g = 1; # Some Nikon cameras use a scaling factor of 1 (E5700)
5262             }
5263 82         279 $val = $levels[$$lookup[$blue * 3]] / $g;
5264 82         212 last;
5265             }
5266 86 50 33     258 $val = $_[0] / $_[1] if not defined $val and ($_[0] and $_[1]);
      66        
5267 86         572 return $val;
5268             }
5269              
5270             #------------------------------------------------------------------------------
5271             # Print exposure time as a fraction
5272             sub PrintExposureTime($)
5273             {
5274 559     559 0 1247 my $secs = shift;
5275 559 50       1433 return $secs unless Image::ExifTool::IsFloat($secs);
5276 559 100 100     3011 if ($secs < 0.25001 and $secs > 0) {
5277 432         4049 return sprintf("1/%d",int(0.5 + 1/$secs));
5278             }
5279 127         728 $_ = sprintf("%.1f",$secs);
5280 127         483 s/\.0$//;
5281 127         808 return $_;
5282             }
5283              
5284             #------------------------------------------------------------------------------
5285             # Print FNumber
5286             sub PrintFNumber($)
5287             {
5288 342     342 0 870 my $val = shift;
5289 342 50 33     966 if (Image::ExifTool::IsFloat($val) and $val > 0) {
5290             # round to 1 decimal place, or 2 for values < 1.0
5291 342 100       2686 $val = sprintf(($val<1 ? "%.2f" : "%.1f"), $val);
5292             }
5293 342         2266 return $val;
5294             }
5295              
5296             #------------------------------------------------------------------------------
5297             # Decode raw CFAPattern value
5298             # Inputs: 0) ExifTool ref, 1) binary value
5299             # Returns: string of numbers
5300             sub DecodeCFAPattern($$)
5301             {
5302 5     5 0 21 my ($self, $val) = @_;
5303             # some panasonic cameras (SV-AS3, SV-AS30) write this in ascii (very odd)
5304 5 50       28 if ($val =~ /^[0-6]+$/) {
5305 0         0 $self->Warn('Incorrectly formatted CFAPattern', 1);
5306 0         0 $val =~ tr/0-6/\x00-\x06/;
5307             }
5308 5 50       23 return $val unless length($val) >= 4;
5309 5 100       20 my @a = unpack(GetByteOrder() eq 'II' ? 'v2C*' : 'n2C*', $val);
5310 5         18 my $end = 2 + $a[0] * $a[1];
5311 5 100       19 if ($end > @a) {
5312             # try swapping byte order (I have seen this order different than in EXIF)
5313 2         13 my ($x, $y) = unpack('n2',pack('v2',$a[0],$a[1]));
5314 2 50       8 if (@a < 2 + $x * $y) {
5315 0         0 $self->Warn('Invalid CFAPattern', 1);
5316             } else {
5317 2         8 ($a[0], $a[1]) = ($x, $y);
5318             # (can't technically be wrong because the order isn't well defined by the EXIF spec)
5319             # $self->Warn('Wrong byte order for CFAPattern');
5320             }
5321             }
5322 5         57 return "@a";
5323             }
5324              
5325             #------------------------------------------------------------------------------
5326             # Print CFA Pattern
5327             sub PrintCFAPattern($)
5328             {
5329 6     6 0 18 my $val = shift;
5330 6         30 my @a = split ' ', $val;
5331 6 50       23 return '' unless @a >= 2;
5332 6 50 33     37 return '' unless $a[0] and $a[1];
5333 6         16 my $end = 2 + $a[0] * $a[1];
5334 6 50       22 return '' if $end > @a;
5335 6         26 my @cfaColor = qw(Red Green Blue Cyan Magenta Yellow White);
5336 6         19 my ($pos, $rtnVal) = (2, '[');
5337 6         10 for (;;) {
5338 24   50     58 $rtnVal .= $cfaColor[$a[$pos]] || 'Unknown';
5339 24 100       47 last if ++$pos >= $end;
5340 18 100       43 ($pos - 2) % $a[1] and $rtnVal .= ',', next;
5341 6         14 $rtnVal .= '][';
5342             }
5343 6         70 return $rtnVal . ']';
5344             }
5345              
5346             #------------------------------------------------------------------------------
5347             # Print Opcode List
5348             # Inputs: 0) value, 1) flag for inverse conversion, 2) conversion hash reference
5349             # Returns: converted value
5350             sub PrintOpcode($$$)
5351             {
5352 0     0 0 0 my ($val, $inv, $conv) = @_;
5353 0 0       0 return undef if $inv; # (can't do inverse conversion)
5354 0 0       0 return '' unless length $$val > 4;
5355 0         0 my $num = unpack('N', $$val);
5356 0         0 my $pos = 4;
5357 0         0 my ($i, @ops);
5358 0         0 for ($i=0; $i<$num; ++$i) {
5359 0 0       0 $pos + 16 <= length $$val or push(@ops, ''), last;
5360 0         0 my ($op, $ver, $flags, $len) = unpack("x${pos}N4", $$val);
5361 0   0     0 push @ops, $$conv{$op} || "[opcode $op]";
5362 0         0 $pos += 16 + $len;
5363             }
5364 0         0 return join ', ', @ops;
5365             }
5366              
5367             #------------------------------------------------------------------------------
5368             # Print conversion for lens info
5369             # Inputs: 0) string of values (min focal, max focal, min F, max F)
5370             # Returns: string in the form "12-20mm f/3.8-4.5" or "50mm f/1.4"
5371             sub PrintLensInfo($)
5372             {
5373 13     13 0 29 my $val = shift;
5374 13         51 my @vals = split ' ', $val;
5375 13 50       47 return $val unless @vals == 4;
5376 13         28 my $c = 0;
5377 13         34 foreach (@vals) {
5378 52 100       107 Image::ExifTool::IsFloat($_) and ++$c, next;
5379 4 50       12 $_ eq 'inf' and $_ = '?', ++$c, next;
5380 4 50       14 $_ eq 'undef' and $_ = '?', ++$c, next;
5381             }
5382 13 50       44 return $val unless $c == 4;
5383 13         24 $val = $vals[0];
5384             # (the Pentax Q writes zero for upper value of fixed-focal-length lenses)
5385 13 100 66     78 $val .= "-$vals[1]" if $vals[1] and $vals[1] ne $vals[0];
5386 13         33 $val .= "mm f/$vals[2]";
5387 13 100 100     87 $val .= "-$vals[3]" if $vals[3] and $vals[3] ne $vals[2];
5388 13         43 return $val;
5389             }
5390              
5391             #------------------------------------------------------------------------------
5392             # Get lens info from lens model string
5393             # Inputs: 0) lens string, 1) flag to allow unknown "?" values
5394             # Returns: 0) min focal, 1) max focal, 2) min aperture, 3) max aperture
5395             # Notes: returns empty list if lens string could not be parsed
5396             sub GetLensInfo($;$)
5397             {
5398 53     53 0 107 my ($lens, $unk) = @_;
5399             # extract focal length and aperture ranges for this lens
5400 53         74 my $pat = '\\d+(?:\\.\\d+)?';
5401 53 100       299 $pat .= '|\\?' if $unk;
5402 53 100       819 return () unless $lens =~ /($pat)(?:-($pat))?\s*mm.*?(?:[fF]\/?\s*)($pat)(?:-($pat))?/;
5403             # ($1=short focal, $2=long focal, $3=max aperture wide, $4=max aperture tele)
5404 33         110 my @a = ($1, $2, $3, $4);
5405 33 50       64 $a[1] or $a[1] = $a[0];
5406 33 50       52 $a[3] or $a[3] = $a[2];
5407 33 100       65 if ($unk) {
5408 1         2 local $_;
5409 1   50     7 $_ eq '?' and $_ = 'undef' foreach @a;
5410             }
5411 33         109 return @a;
5412             }
5413              
5414             #------------------------------------------------------------------------------
5415             # Match lens in list of possbilities based on value of LensModel
5416             # Inputs: 0) reference to list of possible models, 1) LensModel string
5417             # - updates list on return; guaranteed not to remove all list entries
5418             sub MatchLensModel($$)
5419             {
5420 4     4 0 11 my ($try, $lensModel) = @_;
5421 4 50 33     24 if (@$try > 1 and $lensModel) {
5422 0         0 my (@filt, $pat);
5423             # filter by focal length
5424 0 0       0 if ($lensModel =~ /((\d+-)?\d+mm)/) {
5425 0         0 my $focal = $1;
5426 0         0 @filt = grep /$focal/, @$try;
5427 0 0 0     0 @$try = @filt if @filt and @filt < @$try;
5428             }
5429             # filter by aperture
5430 0 0 0     0 if (@$try > 1 and $lensModel =~ m{(?:F/?|1:)(\d+(\.\d+)?)}i) {
5431 0         0 my $fnum = $1;
5432 0         0 @filt = grep m{(F/?|1:)$fnum(\b|[A-Z])}i, @$try;
5433 0 0 0     0 @$try = @filt if @filt and @filt < @$try;
5434             }
5435             # filter by model version, and other lens parameters
5436 0         0 foreach $pat ('I+', 'USM') {
5437 0 0 0     0 next unless @$try > 1 and $lensModel =~ /\b($pat)\b/;
5438 0         0 my $val = $1;
5439 0         0 @filt = grep /\b$val\b/, @$try;
5440 0 0 0     0 @$try = @filt if @filt and @filt < @$try;
5441             }
5442             }
5443             }
5444              
5445             #------------------------------------------------------------------------------
5446             # Attempt to identify the specific lens if multiple lenses have the same LensType
5447             # Inputs: 0) ExifTool object ref, 1) LensType print value, 2) PrintConv hash ref,
5448             # 3) LensSpec print value, 4) LensType numerical value, 5) FocalLength,
5449             # 6) MaxAperture, 7) MaxApertureValue, 8) MinFocalLength, 9) MaxFocalLength,
5450             # 10) LensModel, 11) LensFocalRange, 12) LensSpec
5451             my %sonyEtype;
5452             sub PrintLensID($$@)
5453             {
5454 34     34 0 177 my ($et, $lensTypePrt, $printConv, $lensSpecPrt, $lensType, $focalLength,
5455             $maxAperture, $maxApertureValue, $shortFocal, $longFocal, $lensModel,
5456             $lensFocalRange, $lensSpec) = @_;
5457             # this logic relies on the LensType lookup:
5458 34 50       116 return undef unless defined $lensType;
5459             # get print conversion hash if necessary
5460 34 50       153 $printConv or $printConv = $$et{TAG_INFO}{LensType}{PrintConv};
5461             # just copy LensType PrintConv value if it was a lens name
5462             # (Olympus or Panasonic -- just exclude things like Nikon and Leaf LensType)
5463 34 50       118 unless (ref $printConv eq 'HASH') {
5464 0 0 0     0 if (ref $printConv eq 'ARRAY' and ref $$printConv[0] eq 'HASH') {
5465 0         0 $printConv = $$printConv[0];
5466 0         0 $lensTypePrt =~ s/;.*//;
5467 0         0 $lensType =~ s/ .*//;
5468             } else {
5469 0 0       0 return $lensTypePrt if $lensTypePrt =~ /mm/;
5470 0 0       0 return $lensTypePrt if $lensTypePrt =~ s/(\d)\/F/$1mm F/;
5471 0         0 return undef;
5472             }
5473             }
5474             # get LensSpec information if available (Sony)
5475 34         86 my ($sf0, $lf0, $sa0, $la0);
5476 34 50       115 if ($lensSpecPrt) {
5477 0         0 ($sf0, $lf0, $sa0, $la0) = GetLensInfo($lensSpecPrt);
5478 0 0       0 undef $sf0 unless $sa0; # (make sure aperture isn't zero)
5479             }
5480             # use MaxApertureValue if MaxAperture is not available
5481 34 100       106 $maxAperture = $maxApertureValue unless $maxAperture;
5482 34 100 100     137 if ($lensFocalRange and $lensFocalRange =~ /^(\d+)(?: (?:to )?(\d+))?$/) {
5483 1   33     6 ($shortFocal, $longFocal) = ($1, $2 || $1);
5484             }
5485 34 50 66     327 if ($$et{Make} eq 'SONY') {
    100 66        
      66        
5486 0 0       0 if ($lensType eq 65535) {
    0          
5487             # handle Sony E-type lenses when LensType2 isn't valid (NEX/ILCE models only)
5488 0 0       0 if ($$et{Model} =~ /NEX|ILCE/) {
5489 0 0       0 unless (%sonyEtype) {
5490 0         0 my ($index, $i, %did, $lens);
5491 0         0 require Image::ExifTool::Sony;
5492 0         0 foreach (sort keys %Image::ExifTool::Sony::sonyLensTypes2) {
5493 0         0 ($lens = $Image::ExifTool::Sony::sonyLensTypes2{$_}) =~ s/ or .*//;
5494 0 0       0 next if $did{$lens};
5495 0 0       0 ($i, $index) = $index ? ("65535.$index", $index + 1) : (65535, 1);
5496 0         0 $did{$sonyEtype{$i} = $lens} = 1;
5497             }
5498             }
5499 0         0 $printConv = \%sonyEtype;
5500             }
5501             } elsif ($lensType != 0xff00) {
5502             # Patch for Metabones or other adapters on Sony E-mount cameras (ref Jos Roost)
5503             # Metabones Canon EF to E-mount adapters add 0xef00, 0xbc00 or 0x7700 to the
5504             # high byte for 2-byte Canon LensType values, so we need to adjust for these.
5505             # Offset 0xef00 is also used by Sigma MC-11, Fotodiox and Viltrox EF-E adapters.
5506             # Have to exclude A-mount Sigma Filtermatic with 'odd' LensType=0xff00.
5507 0         0 require Image::ExifTool::Minolta;
5508 0 0 0     0 if ($Image::ExifTool::Minolta::metabonesID{$lensType & 0xff00}) {
    0          
5509 0 0       0 $lensType -= ($lensType >= 0xef00 ? 0xef00 : $lensType >= 0xbc00 ? 0xbc00 : 0x7700);
    0          
5510 0         0 require Image::ExifTool::Canon;
5511 0         0 $printConv = \%Image::ExifTool::Canon::canonLensTypes;
5512 0 0       0 $lensTypePrt = $$printConv{$lensType} if $$printConv{$lensType};
5513             # Test for Sigma MC-11 SA-E adapter with Sigma SA lens using 0x4900 offset.
5514             # (upper limit of test cuts off two highest Sigma lenses, but prevents
5515             # conflict with old Minolta 25xxx and higher ID's)
5516             } elsif ($lensType >= 0x4900 and $lensType <= 0x590a) {
5517 0         0 require Image::ExifTool::Sigma;
5518 0         0 $lensType -= 0x4900;
5519 0         0 $printConv = \%Image::ExifTool::Sigma::sigmaLensTypes;
5520 0 0       0 $lensTypePrt = $$printConv{$lensType} if $$printConv{$lensType};
5521             }
5522             }
5523             # (Min/MaxFocalLength may report the current focal length for Tamron zoom lenses)
5524             } elsif ($shortFocal and $longFocal and (not $lensModel or $lensModel !~ /^TAMRON.*-\d+mm/)) {
5525             # Canon (and some other makes) include makernote information
5526             # which allows better lens identification
5527 28         1765 require Image::ExifTool::Canon;
5528 28         231 return Image::ExifTool::Canon::PrintLensID($printConv, $lensType,
5529             $shortFocal, $longFocal, $maxAperture, $lensModel);
5530             }
5531 6         16 my $lens = $$printConv{$lensType};
5532 6 100 33     35 return ($lensModel || $lensTypePrt) unless $lens;
5533 5 100       41 return $lens unless $$printConv{"$lensType.1"};
5534 4         21 $lens =~ s/ or .*//s; # remove everything after "or"
5535             # make list of all possible matching lenses
5536 4         15 my @lenses = ( $lens );
5537 4         38 my $i;
5538 4         26 for ($i=1; $$printConv{"$lensType.$i"}; ++$i) {
5539 28         94 push @lenses, $$printConv{"$lensType.$i"};
5540             }
5541             # attempt to determine actual lens
5542 4         12 my (@matches, @best, @user, $diff);
5543 4         11 foreach $lens (@lenses) {
5544 32 50       66 push @user, $lens if $Image::ExifTool::userLens{$lens};
5545             # sf = short focal
5546             # lf = long focal
5547             # sa = max aperture at short focal
5548             # la = max aperture at long focal
5549 32         53 my ($sf, $lf, $sa, $la) = GetLensInfo($lens);
5550 32 100       63 next unless $sf;
5551             # check against LensSpec parameters if available
5552 28 50       52 if ($sf0) {
5553 0 0 0     0 next if abs($sf - $sf0) > 0.5 or abs($sa - $sa0) > 0.15 or
      0        
      0        
5554             abs($lf - $lf0) > 0.5 or abs($la - $la0) > 0.15;
5555             # the basic parameters match, but also check against additional lens features:
5556             # for Sony A and E lenses, the full LensSpec string should match with end of LensType,
5557             # excluding any part between () at the end, and preceded by a space (the space
5558             # ensures that e.g. Zeiss Loxia 21mm having LensSpec "E 21mm F2.8" will not be
5559             # identified as "Sony FE 21mm F2.8 (SEL28F20 + SEL075UWC)")
5560 0 0 0     0 $lensSpecPrt and $lens =~ / \Q$lensSpecPrt\E( \(| GM$|$)/ and @best = ( $lens ), last;
5561             # exactly-matching Sony lens should have been found above, so only add non-Sony lenses
5562 0 0       0 push @best, $lens unless $lens =~ /^Sony /;
5563 0         0 next;
5564             }
5565             # adjust focal length and aperture if teleconverter is attached (Minolta)
5566 28 50       58 if ($lens =~ / \+ .*? (\d+(\.\d+)?)x( |$)/) {
5567 0         0 $sf *= $1; $lf *= $1;
  0         0  
5568 0         0 $sa *= $1; $la *= $1;
  0         0  
5569             }
5570             # see if we can rule out this lens using FocalLength and MaxAperture
5571 28 50       46 if ($focalLength) {
5572 28 100       79 next if $focalLength < $sf - 0.5;
5573 9 100       29 next if $focalLength > $lf + 0.5;
5574             }
5575 8 50       15 if ($maxAperture) {
5576             # it seems that most manufacturers set MaxAperture and MaxApertureValue
5577             # to the maximum aperture (smallest F number) for the current focal length
5578             # of the lens, so assume that MaxAperture varies with focal length and find
5579             # the closest match (this is somewhat contrary to the EXIF specification which
5580             # states "The smallest F number of the lens", without mention of focal length)
5581 8 100       25 next if $maxAperture < $sa - 0.15; # (0.15 is arbitrary)
5582 3 50       13 next if $maxAperture > $la + 0.15;
5583             # now determine the best match for this aperture
5584 3         6 my $aa; # approximate maximum aperture at this focal length
5585 3 50 33     39 if ($sf == $lf or $sa == $la or $focalLength <= $sf) {
    0 33        
5586             # either 1) prime lens, 2) fixed-aperture zoom, or 3) zoom at min focal
5587 3         9 $aa = $sa;
5588             } elsif ($focalLength >= $lf) {
5589 0         0 $aa = $la;
5590             } else {
5591             # assume a log-log variation of max aperture with focal length
5592             # (see http://regex.info/blog/2006-10-05/263)
5593 0         0 $aa = exp(log($sa) + (log($la)-log($sa)) / (log($lf)-log($sf)) *
5594             (log($focalLength)-log($sf)));
5595             # a linear relationship between 1/FocalLength and 1/MaxAperture fits Sony better (ref 27)
5596             #$aa = 1 / (1/$sa + (1/$focalLength - 1/$sf) * (1/$la - 1/$sa) / (1/$lf - 1/$sf));
5597             }
5598 3         8 my $d = abs($maxAperture - $aa);
5599 3 50       15 if (defined $diff) {
5600 0 0       0 $d > $diff + 0.15 and next; # (0.15 is arbitrary)
5601 0 0       0 $d < $diff - 0.15 and undef @best;
5602             }
5603 3         6 $diff = $d;
5604 3         7 push @best, $lens;
5605             }
5606 3         9 push @matches, $lens;
5607             }
5608             # return the user-defined lens if it exists
5609 4 50       17 if (@user) {
5610             # choose the best match if we have more than one
5611 0 0       0 if (@user > 1) {
5612 0         0 my ($try, @good);
5613 0         0 foreach $try (\@best, \@matches) {
5614 0   0     0 $Image::ExifTool::userLens{$_} and push @good, $_ foreach @$try;
5615 0 0       0 return join(' or ', @good) if @good;
5616             }
5617             }
5618 0         0 return join(' or ', @user);
5619             }
5620             # return the best match(es) from the possible lenses, after checking against LensModel
5621 4 100       16 @best = @matches unless @best;
5622 4 100       14 if (@best) {
5623 3         13 MatchLensModel(\@best, $lensModel);
5624 3         79 return join(' or ', @best);
5625             }
5626 1         3 $lens = $$printConv{$lensType};
5627 1 50 33     5 return $lensModel if $lensModel and $lens =~ / or /; # (eg. Sony NEX-5N)
5628 1         20 return $lens;
5629             }
5630              
5631             #------------------------------------------------------------------------------
5632             # Translate date into standard EXIF format
5633             # Inputs: 0) date
5634             # Returns: date in format '2003:10:22'
5635             # - bad formats recognized: '2003-10-22','2003/10/22','2003 10 22','20031022'
5636             # - removes null terminator if it exists
5637             sub ExifDate($)
5638             {
5639 67     67 0 197 my $date = shift;
5640 67         175 $date =~ s/\0$//; # remove any null terminator
5641             # separate year:month:day with colons
5642             # (have seen many other characters, including nulls, used erroneously)
5643 67         684 $date =~ s/(\d{4})[^\d]*(\d{2})[^\d]*(\d{2})$/$1:$2:$3/;
5644 67         525 return $date;
5645             }
5646              
5647             #------------------------------------------------------------------------------
5648             # Translate time into standard EXIF format
5649             # Inputs: 0) time
5650             # Returns: time in format '10:30:55'
5651             # - bad formats recognized: '10 30 55', '103055', '103055+0500'
5652             # - removes null terminator if it exists
5653             # - leaves time zone intact if specified (eg. '10:30:55+05:00')
5654             sub ExifTime($)
5655             {
5656 8     8 0 23 my $time = shift;
5657 8         24 $time =~ tr/ /:/; # use ':' (not ' ') as a separator
5658 8         20 $time =~ s/\0$//; # remove any null terminator
5659             # add separators if they don't exist
5660 8         60 $time =~ s/^(\d{2})(\d{2})(\d{2})/$1:$2:$3/;
5661 8         53 $time =~ s/([+-]\d{2})(\d{2})\s*$/$1:$2/; # to timezone too
5662 8         60 return $time;
5663             }
5664              
5665             #------------------------------------------------------------------------------
5666             # Generate TIFF file from scratch (in current byte order)
5667             # Inputs: 0) hash of IFD entries (TagID => Value; multiple values space-delimited)
5668             # 1) raw image data reference
5669             # Returns: TIFF image data, or undef on error
5670             sub GenerateTIFF($$)
5671             {
5672 4     4 0 11 my ($entries, $dataPt) = @_;
5673 4         8 my ($rtnVal, $tag, $offsetPos);
5674              
5675 4         15 my $num = scalar keys %$entries;
5676 4         21 my $ifdBuff = GetByteOrder() . Set16u(42) . Set32u(8) . Set16u($num);
5677 4         13 my $valBuff = '';
5678 4         14 my $tagTablePtr = GetTagTable('Image::ExifTool::Exif::Main');
5679 4         36 foreach $tag (sort { $a <=> $b } keys %$entries) {
  165         207  
5680 60         110 my $tagInfo = $$tagTablePtr{$tag};
5681 60 100       150 my $fmt = ref $tagInfo eq 'HASH' ? $$tagInfo{Writable} : 'int32u';
5682 60 50       89 return undef unless defined $fmt;
5683 60         141 my $val = Image::ExifTool::WriteValue($$entries{$tag}, $fmt, -1);
5684 60 50       219 return undef unless defined $val;
5685 60         83 my $format = $formatNumber{$fmt};
5686 60         106 $ifdBuff .= Set16u($tag) . Set16u($format) . Set32u(length($val)/$formatSize[$format]);
5687 60 100       122 $offsetPos = length($ifdBuff) if $tag == 0x111; # (remember StripOffsets position)
5688 60 100       90 if (length $val > 4) {
5689 12         33 $ifdBuff .= Set32u(10 + 12 * $num + 4 + length($valBuff));
5690 12         28 $valBuff .= $val;
5691             } else {
5692 48 100       97 $val .= "\0" x (4 - length($val)) if length $val < 4;
5693 48         85 $ifdBuff .= $val;
5694             }
5695             }
5696 4         24 $ifdBuff .= "\0\0\0\0"; # (no IFD1)
5697 4 50       16 return undef unless $offsetPos;
5698 4         20 Set32u(length($ifdBuff) + length($valBuff), \$ifdBuff, $offsetPos);
5699 4         21 return $ifdBuff . $valBuff . $$dataPt;
5700             }
5701              
5702             #------------------------------------------------------------------------------
5703             # Rebuild TIFF thumbnail(s)/preview(s) into stand-alone files with current byte order
5704             # Inputs: 0) ExifTool ref, 1) SubfileType, 2) Compression, 3) ImageWidth, 4) ImageHeight,
5705             # 5) BitsPerSample, 6) PhotometricInterpretation, 7) StripOffsets, 8) SamplesPerPixel,
5706             # 9) RowsPerStrip, 10) StripByteCounts, 10) PlanarConfiguration, 11) Orientation
5707             # Returns: 0) TIFF image or undef, 1/2) Family 0/1 groups for TIFF preview IFD
5708             sub RebuildTIFF($;@)
5709             {
5710 14     14 0 33 local $_;
5711 14         31 my $et = $_[0];
5712 14         41 my $value = $$et{VALUE};
5713 14         34 my ($i, $j, $rtn, $grp0, $grp1);
5714 14 50       61 return undef if $$et{FILE_TYPE} eq 'RWZ';
5715             SubFile:
5716 14         39 for ($i=0; ; ++$i) {
5717 40 100       144 my $key = 'SubfileType' . ($i ? " ($i)" : '');
5718 40 100       124 last unless defined $$value{$key};
5719 26 100       85 next unless $$value{$key} == 1; # (reduced-resolution image)
5720 12         39 my $grp = $et->GetGroup($key, 1);
5721 12         52 my $cmp = $et->FindValue('Compression', $grp);
5722 12 100       38 next unless $cmp == 1; # (no compression)
5723 6         31 my %vals = (Compression=>$cmp, PlanarConfiguration=>1, Orientation=>1);
5724 6         25 foreach (qw(ImageWidth ImageHeight BitsPerSample PhotometricInterpretation
5725             StripOffsets SamplesPerPixel RowsPerStrip StripByteCounts
5726             PlanarConfiguration Orientation))
5727             {
5728 60         119 my $val = $et->FindValue($_, $grp);
5729 60 100       167 defined $val and $vals{$_} = $val, next;
5730 2 50       7 next SubFile unless defined $vals{$_};
5731             }
5732 6         26 my ($w, $h) = @vals{'ImageWidth', 'ImageHeight'};
5733 6         37 my @bits = split ' ', $vals{BitsPerSample};
5734 6         21 my $rowBytes = 0;
5735 6         49 $rowBytes += $w * int(($_+7)/8) foreach @bits;
5736 6         15 my $dat = '';
5737 6         18 my @off = split ' ', $vals{StripOffsets};
5738 6         20 my @len = split ' ', $vals{StripByteCounts};
5739             # read the image data
5740 6         29 for ($j=0; $j<@off; ++$j) {
5741 6 100       38 next SubFile unless $len[$j] == $rowBytes * $vals{RowsPerStrip};
5742 4         23 my $tmp = $et->ExtractBinary($off[$j], $len[$j]);
5743 4 50       13 next SubFile unless defined $tmp;
5744 4         24 $dat .= $tmp;
5745             }
5746             # generate the TIFF image
5747             my %entries = (
5748             0x0fe => 0, # SubfileType = 0
5749             0x100 => $w, # ImageWidth
5750             0x101 => $h, # ImageHeight
5751             0x102 => $vals{BitsPerSample},# BitsPerSample
5752             0x103 => $vals{Compression},# Compression
5753             0x106 => $vals{PhotometricInterpretation}, # PhotometricInterpretation
5754             0x111 => 0, # StripOffsets (will be adjusted later)
5755             0x112 => $vals{Orientation},# Orientation
5756             0x115 => $vals{SamplesPerPixel}, # SamplesPerPixel
5757             0x116 => $h, # RowsPerStrip
5758             0x117 => $h * $rowBytes, # StripByteCounts
5759             0x11a => 72, # XResolution = 72
5760             0x11b => 72, # YResolution = 72
5761             0x11c => $vals{PlanarConfiguration}, # PlanarConfiguration
5762 4         77 0x128 => 2, # ResolutionUnit = 2
5763             );
5764 4         20 my $img = GenerateTIFF(\%entries, \$dat);
5765              
5766 4 50 33     33 if (not defined $img) {
    50          
5767 0 0       0 $et->Warn('Invalid ' . ($w > 256 ? 'Preview' : 'Thumbnail') . 'TIFF data');
5768             } elsif ($rtn or $w > 256) { # (call it a preview if larger than 256 pixels)
5769 0         0 $et->FoundTag('PreviewTIFF', \$img, $et->GetGroup($key));
5770             } else {
5771 4         10 $rtn = \$img;
5772 4         24 ($grp0, $grp1) = $et->GetGroup($key);
5773             }
5774             }
5775 14 50       49 return $rtn unless wantarray;
5776 14         411 return ($rtn, $grp0, $grp1);
5777             }
5778              
5779             #------------------------------------------------------------------------------
5780             # Extract image from file
5781             # Inputs: 0) ExifTool object reference, 1) data offset (in file), 2) data length
5782             # 3) [optional] tag name
5783             # Returns: Reference to Image if specifically requested or "Binary data" message
5784             # Returns undef if there was an error loading the image
5785             sub ExtractImage($$$$)
5786             {
5787 200     200 0 814 my ($et, $offset, $len, $tag) = @_;
5788 200         563 my $dataPt = \$$et{EXIF_DATA};
5789 200         452 my $dataPos = $$et{EXIF_POS};
5790 200         347 my $image;
5791              
5792             # no image if length is zero, and don't try to extract binary from XMP file
5793 200 100 100     1624 return undef if not $len or $$et{FILE_TYPE} eq 'XMP';
5794              
5795             # take data from EXIF block if possible
5796 139 100 66     1203 if (defined $dataPos and $offset>=$dataPos and $offset+$len<=$dataPos+length($$dataPt)) {
      100        
5797 97         522 $image = substr($$dataPt, $offset-$dataPos, $len);
5798             } else {
5799 42         217 $image = $et->ExtractBinary($offset, $len, $tag);
5800 42 100       143 return undef unless defined $image;
5801             # patch for incorrect ThumbnailOffset in some Sony DSLR-A100 ARW images
5802 37 0 66     250 if ($tag and $tag eq 'ThumbnailImage' and $$et{TIFF_TYPE} eq 'ARW' and
      66        
      33        
      33        
      0        
5803             $$et{Model} eq 'DSLR-A100' and $offset < 0x10000 and
5804             $image !~ /^(Binary data|\xff\xd8\xff)/)
5805             {
5806 0         0 my $try = $et->ExtractBinary($offset + 0x10000, $len, $tag);
5807 0 0 0     0 if (defined $try and $try =~ /^\xff\xd8\xff/) {
5808 0         0 $image = $try;
5809 0         0 $$et{VALUE}{ThumbnailOffset} += 0x10000;
5810 0         0 $et->Warn('Adjusted incorrect A100 ThumbnailOffset', 1);
5811             }
5812             }
5813             }
5814 134         767 return $et->ValidateImage(\$image, $tag);
5815             }
5816              
5817             #------------------------------------------------------------------------------
5818             # Utility routine to return tag ID string for warnings
5819             # Inputs: 0) Tag ID, 1) [optional] TagInfo ref
5820             # Returns: "tag 0xXXXX NAME"
5821             sub TagName($;$)
5822             {
5823 20     20 0 42 my ($tagID, $tagInfo) = @_;
5824 20 100       59 my $tagName = $tagInfo ? ' '.$$tagInfo{Name} : '';
5825 20         98 return sprintf('tag 0x%.4x%s', $tagID, $tagName);
5826             }
5827              
5828             #------------------------------------------------------------------------------
5829             # Get class name of next IFD offset for HtmlDump output
5830             # Inputs: 0) ExifTool ref, 1) current class ID
5831             # Returns: 0) new IFD offset name, 1) new class ID including "Offset_" for new offset
5832             # 2) new "Offset_" ID
5833             sub NextOffsetName($;$)
5834             {
5835 0     0 0 0 my ($et, $id) = @_;
5836 0 0       0 $$et{OffsetNum} = defined $$et{OffsetNum} ? $$et{OffsetNum} + 1 : 0;
5837 0         0 my $offName = 'o' . $$et{OffsetNum};
5838 0         0 my $sid = "Offset_$offName";
5839 0 0       0 $id = (defined $id ? "$id " : '') . $sid;
5840 0         0 return ($offName, $id, $sid);
5841             }
5842              
5843             #------------------------------------------------------------------------------
5844             # Process EXIF directory
5845             # Inputs: 0) ExifTool object reference
5846             # 1) Reference to directory information hash
5847             # 2) Pointer to tag table for this directory
5848             # Returns: 1 on success, otherwise returns 0 and sets a Warning
5849             sub ProcessExif($$$)
5850             {
5851 1051     1051 0 2502 my ($et, $dirInfo, $tagTablePtr) = @_;
5852 1051         2088 my $dataPt = $$dirInfo{DataPt};
5853 1051   100     3747 my $dataPos = $$dirInfo{DataPos} || 0;
5854 1051         2010 my $dataLen = $$dirInfo{DataLen};
5855 1051   100     2836 my $dirStart = $$dirInfo{DirStart} || 0;
5856 1051   100     2868 my $dirLen = $$dirInfo{DirLen} || $dataLen - $dirStart;
5857 1051         2019 my $dirName = $$dirInfo{DirName};
5858 1051   100     2695 my $base = $$dirInfo{Base} || 0;
5859 1051         1650 my $firstBase = $base;
5860 1051         1740 my $raf = $$dirInfo{RAF};
5861 1051         3567 my $verbose = $et->Options('Verbose');
5862 1051         2447 my $validate = $et->Options('Validate');
5863 1051         3124 my $saveFormat = $et->Options('SaveFormat');
5864 1051         2249 my $htmlDump = $$et{HTML_DUMP};
5865 1051         1716 my $success = 1;
5866 1051         2016 my ($tagKey, $dirSize, $makerAddr, $strEnc, %offsetInfo, $offName, $nextOffName);
5867 1051         2833 my $inMakerNotes = $$tagTablePtr{GROUPS}{0} eq 'MakerNotes';
5868 1051         2964 my $isExif = ($tagTablePtr eq \%Image::ExifTool::Exif::Main);
5869              
5870             # set encoding to assume for strings
5871 1051 100       3941 $strEnc = $et->Options('CharsetEXIF') if $$tagTablePtr{GROUPS}{0} eq 'EXIF';
5872              
5873             # ignore non-standard EXIF while in strict MWG compatibility mode
5874 1051 50 100     5167 if (($validate or $Image::ExifTool::MWG::strict) and $dirName eq 'IFD0' and
      100        
      66        
      66        
5875             $isExif and $$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/)
5876             {
5877 7         33 my $path = $et->MetadataPath();
5878 7 50       47 unless ($path =~ /^(JPEG-APP1-IFD0|TIFF-IFD0|PSD-EXIFInfo-IFD0)$/) {
5879 0 0       0 if ($Image::ExifTool::MWG::strict) {
5880 0         0 $et->Warn("Ignored non-standard EXIF at $path");
5881 0         0 return 0;
5882             } else {
5883 0         0 $et->Warn("Non-standard EXIF at $path", 1);
5884             }
5885             }
5886             }
5887             # mix htmlDump and Validate into verbose so we can test for all at once
5888 1051 50       2622 $verbose = -1 if $htmlDump;
5889 1051 100 66     2659 $verbose = -2 if $validate and not $verbose;
5890 1051 100       3184 $dirName eq 'EXIF' and $dirName = $$dirInfo{DirName} = 'IFD0';
5891 1051 100 100     6488 $$dirInfo{Multi} = 1 if $dirName =~ /^(IFD0|SubIFD)$/ and not defined $$dirInfo{Multi};
5892             # get a more descriptive name for MakerNote sub-directories
5893 1051         2255 my $dir = $$dirInfo{Name};
5894 1051 100 100     4611 $dir = $dirName unless $dir and $inMakerNotes and $dir !~ /^MakerNote/;
      100        
5895              
5896 1051         1848 my ($numEntries, $dirEnd);
5897 1051 100 100     4351 if ($dirStart >= 0 and $dirStart <= $dataLen-2) {
5898             # make sure data is large enough (patches bug in Olympus subdirectory lengths)
5899 975         2803 $numEntries = Get16u($dataPt, $dirStart);
5900 975         1996 $dirSize = 2 + 12 * $numEntries;
5901 975         1500 $dirEnd = $dirStart + $dirSize;
5902 975 100       2321 if ($dirSize > $dirLen) {
5903 361 50 66     1924 if (($verbose > 0 or $validate) and not $$dirInfo{SubIFD}) {
      66        
5904 0         0 my $short = $dirSize - $dirLen;
5905 0         0 $$et{INDENT} =~ s/..$//; # keep indent the same
5906 0         0 $et->Warn("Short directory size for $dir (missing $short bytes)");
5907 0         0 $$et{INDENT} .= '| ';
5908             }
5909 361 50       994 undef $dirSize if $dirEnd > $dataLen; # read from file if necessary
5910             }
5911             }
5912             # read IFD from file if necessary
5913 1051 100       2582 unless ($dirSize) {
5914 76         141 $success = 0;
5915 76 50       228 if ($raf) {
5916             # read the count of entries in this IFD
5917 76         162 my $offset = $dirStart + $dataPos;
5918 76         130 my ($buff, $buf2);
5919 76 50 33     280 if ($raf->Seek($offset + $base, 0) and $raf->Read($buff,2) == 2) {
5920 76         278 my $len = 12 * Get16u(\$buff,0);
5921             # also read next IFD pointer if available
5922 76 50       269 if ($raf->Read($buf2, $len+4) >= $len) {
5923 76         209 $buff .= $buf2;
5924 76         226 $dataPt = $$dirInfo{DataPt} = \$buff;
5925 76         174 $dataPos = $$dirInfo{DataPos} = $offset;
5926 76         180 $dataLen = $$dirInfo{DataLen} = length $buff;
5927 76         153 $dirStart = $$dirInfo{DirStart} = 0;
5928 76         151 $dirLen = $$dirInfo{DirLen} = length $buff;
5929 76         159 $success = 1;
5930             }
5931             }
5932             }
5933 76 50       194 if ($success) {
5934 76         208 $numEntries = Get16u($dataPt, $dirStart);
5935             } else {
5936 0         0 $et->Warn("Bad $dir directory", $inMakerNotes);
5937 0 0 0     0 return 0 unless $inMakerNotes and $dirLen >= 14 and $dirStart >= 0 and
      0        
      0        
5938             $dirStart + $dirLen <= length($$dataPt);
5939 0         0 $dirSize = $dirLen;
5940 0         0 $numEntries = int(($dirSize - 2) / 12); # read what we can
5941 0         0 Set16u($numEntries, $dataPt, $dirStart);
5942             }
5943 76         178 $dirSize = 2 + 12 * $numEntries;
5944 76         143 $dirEnd = $dirStart + $dirSize;
5945             }
5946 1051 100       2622 $verbose > 0 and $et->VerboseDir($dirName, $numEntries);
5947 1051         1960 my $bytesFromEnd = $dataLen - $dirEnd;
5948 1051 100       2383 if ($bytesFromEnd < 4) {
5949 4 50 33     22 unless ($bytesFromEnd==2 or $bytesFromEnd==0) {
5950 0         0 $et->Warn("Illegal $dir directory size ($numEntries entries)");
5951 0         0 return 0;
5952             }
5953             }
5954             # fix base offset for maker notes if necessary
5955 1051 100       2782 if (defined $$dirInfo{MakerNoteAddr}) {
5956 123         315 $makerAddr = $$dirInfo{MakerNoteAddr};
5957 123         366 delete $$dirInfo{MakerNoteAddr};
5958 123 100       614 if (Image::ExifTool::MakerNotes::FixBase($et, $dirInfo)) {
5959 3         8 $base = $$dirInfo{Base};
5960 3         6 $dataPos = $$dirInfo{DataPos};
5961             }
5962             }
5963 1051 50       2437 if ($htmlDump) {
5964 0         0 $offName = $$dirInfo{OffsetName};
5965 0 0 0     0 my $longName = $dir eq 'MakerNotes' ? ($$dirInfo{Name} || $dir) : $dir;
5966 0 0       0 if (defined $makerAddr) {
5967 0         0 my $hdrLen = $dirStart + $dataPos + $base - $makerAddr;
5968 0 0       0 $et->HDump($makerAddr, $hdrLen, "MakerNotes header", $longName) if $hdrLen > 0;
5969             }
5970 0 0       0 unless ($$dirInfo{NoDumpEntryCount}) {
5971 0         0 $et->HDump($dirStart + $dataPos + $base, 2, "$longName entries",
5972             "Entry count: $numEntries", undef, $offName);
5973             }
5974 0         0 my $tip;
5975 0         0 my $id = $offName;
5976 0 0       0 if ($bytesFromEnd >= 4) {
5977 0 0       0 my $nxt = ($dir =~ /^(.*?)(\d+)$/) ? $1 . ($2 + 1) : 'Next IFD';
5978 0         0 my $off = Get32u($dataPt, $dirEnd);
5979 0         0 $tip = sprintf("$nxt offset: 0x%.4x", $off);
5980 0 0       0 ($nextOffName, $id) = NextOffsetName($et, $offName) if $off;
5981             }
5982 0         0 $et->HDump($dirEnd + $dataPos + $base, 4, "Next IFD", $tip, 0, $id);
5983             }
5984              
5985             # patch for Canon EOS 40D firmware 1.0.4 bug (incorrect directory counts)
5986             # (must do this before parsing directory or CameraSettings offset will be suspicious)
5987 1051 50 66     3580 if ($inMakerNotes and $$et{Model} eq 'Canon EOS 40D' and $numEntries) {
      33        
5988 0         0 my $entry = $dirStart + 2 + 12 * ($numEntries - 1);
5989 0         0 my $fmt = Get16u($dataPt, $entry + 2);
5990 0 0 0     0 if ($fmt < 1 or $fmt > 13) {
5991 0         0 $et->HDump($entry+$dataPos+$base,12,"[invalid IFD entry]",
5992             "Bad format type: $fmt", 1, $offName);
5993             # adjust the number of directory entries
5994 0         0 --$numEntries;
5995 0         0 $dirEnd -= 12;
5996             }
5997             }
5998              
5999             # make sure that Compression and SubfileType are defined for this IFD (for Condition's)
6000 1051         2762 $$et{Compression} = $$et{SubfileType} = '';
6001              
6002             # loop through all entries in an EXIF directory (IFD)
6003 1051         2123 my ($index, $valEnd, $offList, $offHash, $mapFmt, @valPos);
6004 1051 100       2744 $mapFmt = $$tagTablePtr{VARS}{MAP_FORMAT} if $$tagTablePtr{VARS};
6005              
6006 1051         2299 my ($warnCount, $lastID) = (0, -1);
6007 1051         2830 for ($index=0; $index<$numEntries; ++$index) {
6008 14986 50       25182 if ($warnCount > 10) {
6009 0 0       0 $et->Warn("Too many warnings -- $dir parsing aborted", 2) and return 0;
6010             }
6011 14986         22095 my $entry = $dirStart + 2 + 12 * $index;
6012 14986         27915 my $tagID = Get16u($dataPt, $entry);
6013 14986         28465 my $format = Get16u($dataPt, $entry+2);
6014 14986         31412 my $count = Get32u($dataPt, $entry+4);
6015 14986 50 33     46966 if ($format < 1 or $format > 13) {
6016 0 0 0     0 if ($mapFmt and $$mapFmt{$format}) {
6017 0         0 $format = $$mapFmt{$format};
6018             } else {
6019 0         0 $et->HDump($entry+$dataPos+$base,12,"[invalid IFD entry]",
6020             "Bad format type: $format", 1, $offName);
6021             # warn unless the IFD was just padded with zeros
6022 0 0 0     0 if ($format or $validate) {
6023 0         0 $et->Warn("Bad format ($format) for $dir entry $index", $inMakerNotes);
6024 0         0 ++$warnCount;
6025             }
6026             # assume corrupted IFD if this is our first entry (except Sony ILCE-7M2 firmware 1.21)
6027 0 0 0     0 return 0 unless $index or $$et{Model} eq 'ILCE-7M2';
6028 0         0 next;
6029             }
6030             }
6031 14986         24724 my $formatStr = $formatName[$format]; # get name of this format
6032 14986         17985 my $valueDataPt = $dataPt;
6033 14986         16609 my $valueDataPos = $dataPos;
6034 14986         17286 my $valueDataLen = $dataLen;
6035 14986         18223 my $valuePtr = $entry + 8; # pointer to value within $$dataPt
6036 14986         31173 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID);
6037 14986         21418 my ($origFormStr, $bad, $rational, $subOffName);
6038             # save the EXIF format codes if requested
6039 14986 50       23232 $$et{SaveFormat}{$saveFormat = $formatStr} = 1 if $saveFormat;
6040             # hack to patch incorrect count in Kodak SubIFD3 tags
6041 14986 50 100     53205 if ($count < 2 and ref $$tagTablePtr{$tagID} eq 'HASH' and $$tagTablePtr{$tagID}{FixCount}) {
      66        
6042 0 0       0 $offList or ($offList, $offHash) = GetOffList($dataPt, $dirStart, $dataPos,
6043             $numEntries, $tagTablePtr);
6044 0         0 my $i = $$offHash{Get32u($dataPt, $valuePtr)};
6045 0 0 0     0 if (defined $i and $i < $#$offList) {
6046 0         0 my $oldCount = $count;
6047 0         0 $count = int(($$offList[$i+1] - $$offList[$i]) / $formatSize[$format]);
6048 0 0       0 $origFormStr = $formatName[$format] . '[' . $oldCount . ']' if $oldCount != $count;
6049             }
6050             }
6051 14986 100 100     26908 $validate and not $inMakerNotes and Image::ExifTool::Validate::ValidateExif(
6052             $et, $tagTablePtr, $tagID, $tagInfo, $lastID, $dir, $count, $formatStr);
6053 14986         22790 my $size = $count * $formatSize[$format];
6054 14986         18606 my $readSize = $size;
6055 14986 100       25104 if ($size > 4) {
6056 6739 50 0     13132 if ($size > 0x7fffffff and (not $tagInfo or not $$tagInfo{ReadFromRAF})) {
      33        
6057 0         0 $et->Warn(sprintf("Invalid size (%u) for %s %s",$size,$dir,TagName($tagID,$tagInfo)), $inMakerNotes);
6058 0         0 ++$warnCount;
6059 0         0 next;
6060             }
6061 6739         12239 $valuePtr = Get32u($dataPt, $valuePtr);
6062 6739 100 100     14007 if ($validate and not $inMakerNotes) {
6063 20         52 my $tagName = TagName($tagID, $tagInfo);
6064 20 50       57 $et->Warn("Odd offset for $dir $tagName", 1) if $valuePtr & 0x01;
6065 20 50 33     120 if ($valuePtr < 8 || ($valuePtr + $size > length($$dataPt) and
      33        
6066             $valuePtr + $size > $$et{VALUE}{FileSize}))
6067             {
6068 0         0 $et->Warn("Invalid offset for $dir $tagName");
6069 0         0 ++$warnCount;
6070 0         0 next;
6071             }
6072 20 50 33     84 if ($valuePtr + $size > $dirStart + $dataPos and $valuePtr < $dirEnd + $dataPos + 4) {
6073 0         0 $et->Warn("Value for $dir $tagName overlaps IFD");
6074             }
6075 20         43 foreach (@valPos) {
6076 81 50 33     249 next if $$_[0] >= $valuePtr + $size or $$_[0] + $$_[1] <= $valuePtr;
6077 0         0 $et->Warn("Value for $dir $tagName overlaps $$_[2]");
6078             }
6079 20         54 push @valPos, [ $valuePtr, $size, $tagName ];
6080             }
6081             # fix valuePtr if necessary
6082 6739 50       13107 if ($$dirInfo{FixOffsets}) {
6083 0         0 my $wFlag;
6084 0 0       0 $valEnd or $valEnd = $dataPos + $dirEnd + 4;
6085             #### eval FixOffsets ($valuePtr, $valEnd, $size, $tagID, $wFlag)
6086 0         0 eval $$dirInfo{FixOffsets};
6087             }
6088 6739         8517 my $suspect;
6089             # offset shouldn't point into TIFF header
6090 6739 100 66     13169 $valuePtr < 8 and not $$dirInfo{ZeroOffsetOK} and $suspect = $warnCount;
6091             # convert offset to pointer in $$dataPt
6092 6739 100 66     30264 if ($$dirInfo{EntryBased} or (ref $$tagTablePtr{$tagID} eq 'HASH' and
      66        
6093             $$tagTablePtr{$tagID}{EntryBased}))
6094             {
6095 10         14 $valuePtr += $entry;
6096             } else {
6097 6729         10086 $valuePtr -= $dataPos;
6098             }
6099             # value shouldn't overlap our directory
6100 6739 50 66     13024 $suspect = $warnCount if $valuePtr < $dirEnd and $valuePtr+$size > $dirStart;
6101             # load value from file if necessary
6102 6739 100 100     19286 if ($valuePtr < 0 or $valuePtr+$size > $dataLen) {
6103             # get value by seeking in file if we are allowed
6104 449         625 my $buff;
6105 449 50       877 if ($raf) {
6106             # avoid loading large binary data unless necessary
6107 449         1031 while ($size > BINARY_DATA_LIMIT) {
6108 0 0       0 if ($tagInfo) {
6109             # make large unknown blocks binary data
6110 0 0       0 $$tagInfo{Binary} = 1 if $$tagInfo{Unknown};
6111 0 0       0 last unless $$tagInfo{Binary}; # must read non-binary data
6112 0 0       0 last if $$tagInfo{SubDirectory};
6113 0         0 my $lcTag = lc($$tagInfo{Name});
6114 0 0 0     0 if ($$et{OPTIONS}{Binary} and
6115             not $$et{EXCL_TAG_LOOKUP}{$lcTag})
6116             {
6117             # read binary data if specified unless tagsFromFile won't use it
6118 0 0 0     0 last unless $$et{TAGS_FROM_FILE} and $$tagInfo{Protected};
6119             }
6120             # must read if tag is specified by name
6121 0 0       0 last if $$et{REQ_TAG_LOOKUP}{$lcTag};
6122             } else {
6123             # must read value if needed for a condition
6124 0 0       0 last if defined $tagInfo;
6125             }
6126             # (note: changing the value without changing $size will cause
6127             # a warning in the verbose output, but we need to maintain the
6128             # proper size for the htmlDump, so we can't change this)
6129 0         0 $buff = "Binary data $size bytes";
6130 0         0 $readSize = length $buff;
6131 0         0 last;
6132             }
6133             # read from file if necessary
6134 449 50       905 unless (defined $buff) {
6135 449         585 my $wrn;
6136 449   66     1372 my $readFromRAF = ($tagInfo and $$tagInfo{ReadFromRAF});
6137 449 50 33     1368 if (not $raf->Seek($base + $valuePtr + $dataPos, 0)) {
    50 33        
    50          
    50          
6138 0         0 $wrn = "Invalid offset for $dir entry $index";
6139             } elsif ($readFromRAF and $size > BINARY_DATA_LIMIT and
6140             not $$et{REQ_TAG_LOOKUP}{lc $$tagInfo{Name}})
6141             {
6142 0         0 $buff = "$$tagInfo{Name} data $size bytes";
6143 0         0 $readSize = length $buff;
6144             } elsif ($raf->Read($buff,$size) != $size) {
6145 0         0 $wrn = "Error reading value for $dir entry $index";
6146             } elsif ($readFromRAF) {
6147             # seek back to the start of the value
6148 0         0 $raf->Seek($base + $valuePtr + $dataPos, 0);
6149             }
6150 449 50       1175 if ($wrn) {
6151 0         0 $et->Warn($wrn, $inMakerNotes);
6152 0 0 0     0 return 0 unless $inMakerNotes or $htmlDump;
6153 0         0 ++$warnCount;
6154 0 0       0 $buff = '' unless defined $buff;
6155 0         0 $readSize = length $buff;
6156 0         0 $bad = 1;
6157             }
6158             }
6159 449         649 $valueDataLen = length $buff;
6160 449         674 $valueDataPt = \$buff;
6161 449         615 $valueDataPos = $valuePtr + $dataPos;
6162 449         792 $valuePtr = 0;
6163             } else {
6164 0         0 my ($tagStr, $tmpInfo, $leicaTrailer);
6165 0 0       0 if ($tagInfo) {
    0          
6166 0         0 $tagStr = $$tagInfo{Name};
6167 0         0 $leicaTrailer = $$tagInfo{LeicaTrailer};
6168             } elsif (defined $tagInfo) {
6169 0         0 $tmpInfo = $et->GetTagInfo($tagTablePtr, $tagID, \ '', $formatStr, $count);
6170 0 0       0 if ($tmpInfo) {
6171 0         0 $tagStr = $$tmpInfo{Name};
6172 0         0 $leicaTrailer = $$tmpInfo{LeicaTrailer};
6173             }
6174             }
6175 0 0 0     0 if ($tagInfo and $$tagInfo{ChangeBase}) {
6176             # adjust base offset for this tag only
6177             #### eval ChangeBase ($dirStart,$dataPos)
6178 0         0 my $newBase = eval $$tagInfo{ChangeBase};
6179 0         0 $valuePtr += $newBase;
6180             }
6181 0 0       0 $tagStr or $tagStr = sprintf("tag 0x%.4x",$tagID);
6182             # allow PreviewImage to run outside EXIF data
6183 0 0 0     0 if ($tagStr eq 'PreviewImage' and $$et{RAF}) {
    0 0        
6184 0         0 my $pos = $$et{RAF}->Tell();
6185 0         0 $buff = $et->ExtractBinary($base + $valuePtr + $dataPos, $size, 'PreviewImage');
6186 0         0 $$et{RAF}->Seek($pos, 0);
6187 0         0 $valueDataPt = \$buff;
6188 0         0 $valueDataPos = $valuePtr + $dataPos;
6189 0         0 $valueDataLen = $size;
6190 0         0 $valuePtr = 0;
6191             } elsif ($leicaTrailer and $$et{RAF}) {
6192 0 0       0 if ($verbose > 0) {
6193 0         0 $et->VPrint(0, "$$et{INDENT}$index) $tagStr --> (outside APP1 segment)\n");
6194             }
6195 0 0       0 if ($et->Options('FastScan')) {
6196 0         0 $et->Warn('Ignored Leica MakerNote trailer');
6197             } else {
6198 0         0 require Image::ExifTool::Fixup;
6199             $$et{LeicaTrailer} = {
6200 0   0     0 TagInfo => $tagInfo || $tmpInfo,
6201             Offset => $base + $valuePtr + $dataPos,
6202             Size => $size,
6203             Fixup => new Image::ExifTool::Fixup,
6204             };
6205             }
6206             } else {
6207 0         0 $et->Warn("Bad offset for $dir $tagStr", $inMakerNotes);
6208 0         0 ++$warnCount;
6209             }
6210 0 0       0 unless (defined $buff) {
6211 0         0 $valueDataPt = '';
6212 0         0 $valueDataPos = $valuePtr + $dataPos;
6213 0         0 $valueDataLen = 0;
6214 0         0 $valuePtr = 0;
6215 0         0 $bad = 1;
6216             }
6217             }
6218             }
6219             # warn about suspect offsets if they didn't already cause another warning
6220 6739 100 66     14034 if (defined $suspect and $suspect == $warnCount) {
6221 2 50       5 my $tagStr = $tagInfo ? $$tagInfo{Name} : sprintf('tag 0x%.4x', $tagID);
6222 2 50       8 if ($et->Warn("Suspicious $dir offset for $tagStr", $inMakerNotes)) {
6223 2         3 ++$warnCount;
6224 2 50       7 next unless $verbose;
6225             }
6226             }
6227             }
6228             # treat single unknown byte as int8u
6229 14984 100 100     29610 $formatStr = 'int8u' if $format == 7 and $count == 1;
6230              
6231 14984         19919 my ($val, $subdir, $wrongFormat);
6232 14984 50 33     26187 if ($tagID > 0xf000 and $isExif) {
6233 0         0 my $oldInfo = $$tagTablePtr{$tagID};
6234 0 0 0     0 if ((not $oldInfo or (ref $oldInfo eq 'HASH' and $$oldInfo{Condition} and
      0        
6235             not $$oldInfo{PSRaw})) and not $bad)
6236             {
6237             # handle special case of Photoshop RAW tags (0xfde8-0xfe58)
6238             # --> generate tags from the value if possible
6239 0         0 $val = ReadValue($valueDataPt,$valuePtr,$formatStr,$count,$readSize);
6240 0 0 0     0 if (defined $val and $val =~ /(.*): (.*)/) {
6241 0         0 my $tag = $1;
6242 0         0 $val = $2;
6243 0         0 $tag =~ s/'s//; # remove 's (so "Owner's Name" becomes "OwnerName")
6244 0         0 $tag =~ tr/a-zA-Z0-9_//cd; # remove unknown characters
6245 0 0       0 if ($tag) {
6246 0         0 $tagInfo = {
6247             Name => $tag,
6248             Condition => '$$self{TIFF_TYPE} ne "DCR"',
6249             ValueConv => '$_=$val;s/^.*: //;$_', # remove descr
6250             PSRaw => 1, # (just as flag to avoid adding this again)
6251             };
6252 0         0 AddTagToTable($tagTablePtr, $tagID, $tagInfo);
6253             # generate conditional list if a conditional tag already existed
6254 0 0       0 $$tagTablePtr{$tagID} = [ $oldInfo, $tagInfo ] if $oldInfo;
6255             }
6256             }
6257             }
6258             }
6259 14984 100 100     39812 if (defined $tagInfo and not $tagInfo) {
6260 387 50       981 if ($bad) {
6261 0         0 undef $tagInfo;
6262             } else {
6263             # GetTagInfo() required the value for a Condition
6264 387 100       1432 my $tmpVal = substr($$valueDataPt, $valuePtr, $readSize < 128 ? $readSize : 128);
6265             # (use original format name in this call -- $formatStr may have been changed to int8u)
6266 387         1316 $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID, \$tmpVal,
6267             $formatName[$format], $count);
6268             }
6269             }
6270             # make sure we are handling the 'ifd' format properly
6271 14984 50 66     42249 if (($format == 13 or $format == 18) and (not $tagInfo or not $$tagInfo{SubIFD})) {
      33        
      66        
6272 0         0 my $str = sprintf('%s tag 0x%.4x IFD format not handled', $dirName, $tagID);
6273 0         0 $et->Warn($str, $inMakerNotes);
6274             }
6275 14984 100       23291 if (defined $tagInfo) {
6276 14436         21798 my $readFormat = $$tagInfo{Format};
6277 14436         18885 $subdir = $$tagInfo{SubDirectory};
6278             # unless otherwise specified, all SubDirectory data except
6279             # EXIF SubIFD offsets should be unformatted
6280 14436 100 100     29030 $readFormat = 'undef' if $subdir and not $$tagInfo{SubIFD} and not $readFormat;
      100        
6281             # override EXIF format if specified
6282 14436 100       22430 if ($readFormat) {
6283 1737         2703 $formatStr = $readFormat;
6284 1737         3650 my $newNum = $formatNumber{$formatStr};
6285 1737 100 66     6310 if ($newNum and $newNum != $format) {
6286 946         2616 $origFormStr = $formatName[$format] . '[' . $count . ']';
6287 946         1491 $format = $newNum;
6288 946 50       2268 $size = $readSize = $$tagInfo{FixedSize} if $$tagInfo{FixedSize};
6289             # adjust number of items for new format size
6290 946         2627 $count = int($size / $formatSize[$format]);
6291             }
6292             }
6293             # verify that offset-type values are integral
6294 14436 50 100     46892 if (($$tagInfo{IsOffset} or $$tagInfo{SubIFD}) and not $intFormat{$formatStr}) {
      66        
6295 0         0 $et->Warn(sprintf('Wrong format (%s) for %s 0x%.4x %s',$formatStr,$dir,$tagID,$$tagInfo{Name}));
6296 0 0       0 if ($validate) {
6297 0         0 $$et{WrongFormat}{"$dir:$$tagInfo{Name}"} = 1;
6298 0         0 $offsetInfo{$tagID} = [ $tagInfo, '' ];
6299             }
6300 0 0       0 next unless $verbose;
6301 0         0 $wrongFormat = 1;
6302             }
6303             } else {
6304 548 100       1731 next unless $verbose;
6305             }
6306 14439 50       23371 unless ($bad) {
6307             # limit maximum length of data to reformat
6308             # (avoids long delays when processing some corrupted files)
6309 14439         17282 my $warned;
6310 14439 50 33     25910 if ($count > 100000 and $formatStr !~ /^(undef|string|binary)$/) {
6311 0 0       0 my $tagName = $tagInfo ? $$tagInfo{Name} : sprintf('tag 0x%.4x', $tagID);
6312             # (count of 196608 is typical for ColorMap)
6313 0 0 0     0 if ($tagName ne 'TransferFunction' or $count != 196608) {
6314 0 0       0 my $minor = $count > 2000000 ? 0 : 2;
6315 0 0       0 if ($et->Warn("Ignoring $dirName $tagName with excessive count", $minor)) {
6316 0 0       0 next unless $$et{OPTIONS}{HtmlDump};
6317 0         0 $warned = 1;
6318             }
6319             }
6320             }
6321 14439 50 100     31956 if ($count > 500 and $formatStr !~ /^(undef|string|binary)$/ and
      33        
      66        
      33        
6322             (not $tagInfo or $$tagInfo{LongBinary} or $warned) and not $$et{OPTIONS}{IgnoreMinorErrors})
6323             {
6324 0 0       0 $et->WarnOnce('Not decoding some large array(s). Ignore minor errors to decode', 2) unless $warned;
6325 0 0       0 next if $$et{TAGS_FROM_FILE}; # don't generate bogus value when copying tags
6326 0         0 $val = "(large array of $count $formatStr values)";
6327             } else {
6328             # convert according to specified format
6329 14439         33289 $val = ReadValue($valueDataPt,$valuePtr,$formatStr,$count,$readSize,\$rational);
6330             # re-code if necessary
6331 14439 0 33     30195 $val = $et->Decode($val, $strEnc) if $strEnc and $formatStr eq 'string' and defined $val;
      33        
6332             }
6333             }
6334              
6335 14439 100       23529 if ($verbose) {
6336 345         479 my $tval = $val;
6337             # also show as a rational
6338 345 100       631 $tval .= " ($rational)" if defined $rational;
6339 345 50       554 if ($htmlDump) {
6340 0         0 my ($tagName, $colName);
6341 0 0 0     0 if ($tagID == 0x927c and $dirName eq 'ExifIFD') {
    0          
6342 0         0 $tagName = 'MakerNotes';
6343             } elsif ($tagInfo) {
6344 0         0 $tagName = $$tagInfo{Name};
6345             } else {
6346 0         0 $tagName = sprintf("Tag 0x%.4x",$tagID);
6347             }
6348 0         0 my $dname = sprintf("${dir}-%.2d", $index);
6349             # build our tool tip
6350 0 0       0 $size < 0 and $size = $count * $formatSize[$format];
6351 0         0 my $fstr = "$formatName[$format]\[$count]";
6352 0 0 0     0 $fstr = "$origFormStr read as $fstr" if $origFormStr and $origFormStr ne $fstr;
6353 0 0       0 $fstr .= ' <-- WRONG' if $wrongFormat;
6354 0         0 my $tip = sprintf("Tag ID: 0x%.4x\n", $tagID) .
6355             "Format: $fstr\nSize: $size bytes\n";
6356 0 0       0 if ($size > 4) {
6357 0         0 my $offPt = Get32u($dataPt,$entry+8);
6358             # (test this with ../pics/{CanonEOS-1D_XMarkIII.hif,PanasonicDC-G9.rw2})
6359 0   0     0 my $actPt = $valuePtr + $valueDataPos + $base - ($$et{EXIF_POS} || 0) + ($$et{BASE_FUDGE} || 0);
      0        
6360 0         0 $tip .= sprintf("Value offset: 0x%.4x\n", $offPt);
6361             # highlight tag name (red for bad size)
6362 0 0 0     0 my $style = ($bad or not defined $tval) ? 'V' : 'H';
6363 0 0       0 if ($actPt != $offPt) {
6364 0         0 $tip .= sprintf("Actual offset: 0x%.4x\n", $actPt);
6365 0 0       0 my $sign = $actPt < $offPt ? '-' : '';
6366 0         0 $tip .= sprintf("Offset base: ${sign}0x%.4x\n", abs($actPt - $offPt));
6367 0 0       0 $style = 'F' if $style eq 'H'; # purple for different offsets
6368             }
6369 0 0 0     0 if ($$et{EXIF_POS} and not $$et{BASE_FUDGE}) {
6370             $tip .= sprintf("File offset: 0x%.4x\n", $actPt + $$et{EXIF_POS})
6371 0         0 }
6372 0         0 $colName = "$tagName";
6373 0 0       0 $colName .= ' (odd)' if $offPt & 0x01;
6374             } else {
6375 0         0 $colName = $tagName;
6376             }
6377 0 0       0 $colName .= ' (err)' if $wrongFormat;
6378 0 0 0     0 $colName .= ' (seq)' if $tagID <= $lastID and not $inMakerNotes;
6379 0         0 $lastID = $tagID;
6380 0 0       0 if (not defined $tval) {
6381 0         0 $tval = '';
6382             } else {
6383 0 0       0 $tval = substr($tval,0,28) . '[...]' if length($tval) > 32;
6384 0 0 0     0 if ($formatStr =~ /^(string|undef|binary)/) {
    0          
6385             # translate non-printable characters
6386 0         0 $tval =~ tr/\x00-\x1f\x7f-\xff/./;
6387             } elsif ($tagInfo and Image::ExifTool::IsInt($tval)) {
6388 0 0 0     0 if ($$tagInfo{IsOffset} or $$tagInfo{SubIFD}) {
    0          
6389 0         0 $tval = sprintf('0x%.4x', $tval);
6390 0   0     0 my $actPt = $val + $base - ($$et{EXIF_POS} || 0) + ($$et{BASE_FUDGE} || 0);
      0        
6391 0 0       0 if ($actPt != $val) {
6392 0         0 $tval .= sprintf("\nActual offset: 0x%.4x", $actPt);
6393 0 0       0 my $sign = $actPt < $val ? '-' : '';
6394 0         0 $tval .= sprintf("\nOffset base: ${sign}0x%.4x", abs($actPt - $val));
6395             }
6396             } elsif ($$tagInfo{PrintHex}) {
6397 0         0 $tval = sprintf('0x%x', $tval);
6398             }
6399             }
6400             }
6401 0         0 $tip .= "Value: $tval";
6402 0         0 my $id = $offName;
6403 0         0 my $sid;
6404 0 0 0     0 ($subOffName, $id, $sid) = NextOffsetName($et, $offName) if $tagInfo and $$tagInfo{SubIFD};
6405 0         0 $et->HDump($entry+$dataPos+$base, 12, "$dname $colName", $tip, 1, $id);
6406 0 0       0 next if $valueDataLen < 0; # don't process bad pointer entry
6407 0 0       0 if ($size > 4) {
6408 0         0 my $exifDumpPos = $valuePtr + $valueDataPos + $base;
6409 0         0 my $flag = 0;
6410 0 0       0 if ($subdir) {
6411 0 0       0 if ($$tagInfo{MakerNotes}) {
    0          
6412 0         0 $flag = 0x04;
6413             } elsif ($$tagInfo{NestedHtmlDump}) {
6414 0 0       0 $flag = $$tagInfo{NestedHtmlDump} == 2 ? 0x10 : 0x04;
6415             }
6416             }
6417             # add value data block (underlining maker notes data)
6418 0         0 $et->HDump($exifDumpPos,$size,"$tagName value",'SAME', $flag, $sid);
6419             }
6420             } else {
6421 345 50 66     754 if ($tagID <= $lastID and not $inMakerNotes) {
6422 0 0       0 my $str = $tagInfo ? ' '.$$tagInfo{Name} : '';
6423 0 0       0 if ($tagID == $lastID) {
6424 0         0 $et->Warn(sprintf('Duplicate tag 0x%.4x%s in %s', $tagID, $str, $dirName));
6425             } else {
6426 0         0 $et->Warn(sprintf('Tag ID 0x%.4x%s out of sequence in %s', $tagID, $str, $dirName));
6427             }
6428             }
6429 345         442 $lastID = $tagID;
6430 345 100       606 if ($verbose > 0) {
6431 257         381 my $fstr = $formatName[$format];
6432 257 100       403 $fstr = "$origFormStr read as $fstr" if $origFormStr;
6433 257         760 $et->VerboseInfo($tagID, $tagInfo,
6434             Table => $tagTablePtr,
6435             Index => $index,
6436             Value => $tval,
6437             DataPt => $valueDataPt,
6438             DataPos => $valueDataPos + $base,
6439             Size => $size,
6440             Start => $valuePtr,
6441             Format => $fstr,
6442             Count => $count,
6443             );
6444             }
6445             }
6446 345 100 66     1156 next if not $tagInfo or $wrongFormat;
6447             }
6448 14436 50       23088 next unless defined $val;
6449             #..............................................................................
6450             # Handle SubDirectory tag types
6451             #
6452 14436 100       22927 if ($subdir) {
6453             # don't process empty subdirectories
6454 1245 50       3156 unless ($size) {
6455 0 0 0     0 unless ($$tagInfo{MakerNotes} or $inMakerNotes) {
6456 0         0 $et->Warn("Empty $$tagInfo{Name} data", 1);
6457             }
6458 0         0 next;
6459             }
6460 1245         2322 my (@values, $newTagTable, $dirNum, $newByteOrder, $invalid);
6461 1245         2563 my $tagStr = $$tagInfo{Name};
6462 1245 100       3143 if ($$subdir{MaxSubdirs}) {
6463 144         606 @values = split ' ', $val;
6464             # limit the number of subdirectories we parse
6465 144         426 my $over = @values - $$subdir{MaxSubdirs};
6466 144 50       467 if ($over > 0) {
6467 0         0 $et->Warn("Ignoring $over $tagStr directories");
6468 0         0 splice @values, $$subdir{MaxSubdirs};
6469             }
6470 144         359 $val = shift @values;
6471             }
6472 1245 100       2929 if ($$subdir{TagTable}) {
6473 902         2685 $newTagTable = GetTagTable($$subdir{TagTable});
6474 902 50       2408 $newTagTable or warn("Unknown tag table $$subdir{TagTable}"), next;
6475             } else {
6476 343         617 $newTagTable = $tagTablePtr; # use existing table
6477             }
6478             # loop through all sub-directories specified by this tag
6479 1245         2412 for ($dirNum=0; ; ++$dirNum) {
6480 1251         1891 my $subdirBase = $base;
6481 1251         1797 my $subdirDataPt = $valueDataPt;
6482 1251         1782 my $subdirDataPos = $valueDataPos;
6483 1251         1667 my $subdirDataLen = $valueDataLen;
6484 1251         1834 my $subdirStart = $valuePtr;
6485 1251 100       3156 if (defined $$subdir{Start}) {
6486             # set local $valuePtr relative to file $base for eval
6487 443         840 my $valuePtr = $subdirStart + $subdirDataPos;
6488             #### eval Start ($valuePtr, $val)
6489 443         23112 my $newStart = eval($$subdir{Start});
6490 443 50       2467 unless (Image::ExifTool::IsInt($newStart)) {
6491 0         0 $et->Warn("Bad value for $tagStr");
6492 0         0 last;
6493             }
6494             # convert back to relative to $subdirDataPt
6495 443         1216 $newStart -= $subdirDataPos;
6496             # adjust directory size if necessary
6497 443 50 66     1533 unless ($$tagInfo{SubIFD} or $$subdir{BadOffset}) {
6498 51         110 $size -= $newStart - $subdirStart;
6499             }
6500 443         916 $subdirStart = $newStart;
6501             }
6502             # this is a pain, but some maker notes are always a specific
6503             # byte order, regardless of the byte order of the file
6504 1251         3099 my $oldByteOrder = GetByteOrder();
6505 1251         2434 $newByteOrder = $$subdir{ByteOrder};
6506 1251 100       2502 if ($newByteOrder) {
6507 171 100       1338 if ($newByteOrder =~ /^Little/i) {
    100          
    50          
    50          
6508 31         70 $newByteOrder = 'II';
6509             } elsif ($newByteOrder =~ /^Big/i) {
6510 29         62 $newByteOrder = 'MM';
6511             } elsif ($$subdir{OffsetPt}) {
6512 0         0 undef $newByteOrder;
6513 0         0 warn "Can't have variable byte ordering for SubDirectories using OffsetPt";
6514 0         0 last;
6515             } elsif ($subdirStart + 2 <= $subdirDataLen) {
6516             # attempt to determine the byte ordering by checking
6517             # the number of directory entries. This is an int16u
6518             # that should be a reasonable value.
6519 111         343 my $num = Get16u($subdirDataPt, $subdirStart);
6520 111 100 100     545 if ($num & 0xff00 and ($num>>8) > ($num&0xff)) {
6521             # This looks wrong, we shouldn't have this many entries
6522 4         72 my %otherOrder = ( II=>'MM', MM=>'II' );
6523 4         15 $newByteOrder = $otherOrder{$oldByteOrder};
6524             } else {
6525 107         229 $newByteOrder = $oldByteOrder;
6526             }
6527             }
6528             } else {
6529 1080         1832 $newByteOrder = $oldByteOrder;
6530             }
6531             # set base offset if necessary
6532 1251 100       3235 if ($$subdir{Base}) {
6533             # calculate subdirectory start relative to $base for eval
6534 35         86 my $start = $subdirStart + $subdirDataPos;
6535             #### eval Base ($start,$base)
6536 35         1600 $subdirBase = eval($$subdir{Base}) + $base;
6537             }
6538             # add offset to the start of the directory if necessary
6539 1251 100       3117 if ($$subdir{OffsetPt}) {
6540             #### eval OffsetPt ($valuePtr)
6541 24         1057 my $pos = eval $$subdir{OffsetPt};
6542 24 50       133 if ($pos + 4 > $subdirDataLen) {
6543 0         0 $et->Warn("Bad $tagStr OffsetPt");
6544 0         0 last;
6545             }
6546 24         125 SetByteOrder($newByteOrder);
6547 24         94 $subdirStart += Get32u($subdirDataPt, $pos);
6548 24         79 SetByteOrder($oldByteOrder);
6549             }
6550 1251 100 100     5315 if ($subdirStart < 0 or $subdirStart + 2 > $subdirDataLen) {
6551             # convert $subdirStart back to a file offset
6552 31 50       107 if ($raf) {
6553             # reset SubDirectory buffer (we will load it later)
6554 31         72 my $buff = '';
6555 31         73 $subdirDataPt = \$buff;
6556 31         74 $subdirDataLen = $size = length $buff;
6557             } else {
6558 0         0 my $msg = "Bad $tagStr SubDirectory start";
6559 0 0       0 if ($verbose > 0) {
6560 0 0       0 if ($subdirStart < 0) {
6561 0         0 $msg .= " (directory start $subdirStart is before EXIF start)";
6562             } else {
6563 0         0 my $end = $subdirStart + $size;
6564 0         0 $msg .= " (directory end is $end but EXIF size is only $subdirDataLen)";
6565             }
6566             }
6567 0         0 $et->Warn($msg, $inMakerNotes);
6568 0         0 last;
6569             }
6570             }
6571              
6572             # must update subdirDataPos if $base changes for this subdirectory
6573 1251         2281 $subdirDataPos += $base - $subdirBase;
6574              
6575             # build information hash for new directory
6576             my %subdirInfo = (
6577             Name => $tagStr,
6578             Base => $subdirBase,
6579             DataPt => $subdirDataPt,
6580             DataPos => $subdirDataPos,
6581             DataLen => $subdirDataLen,
6582             DirStart => $subdirStart,
6583             DirLen => $size,
6584             RAF => $raf,
6585             Parent => $dirName,
6586             DirName => $$subdir{DirName},
6587             FixBase => $$subdir{FixBase},
6588             FixOffsets => $$subdir{FixOffsets},
6589             EntryBased => $$subdir{EntryBased},
6590             TagInfo => $tagInfo,
6591             SubIFD => $$tagInfo{SubIFD},
6592 1251         13455 Subdir => $subdir,
6593             OffsetName => $subOffName,
6594             );
6595             # (remember: some cameras incorrectly write maker notes in IFD0)
6596 1251 100       3199 if ($$tagInfo{MakerNotes}) {
6597             # don't parse makernotes if FastScan > 1
6598 130         655 my $fast = $et->Options('FastScan');
6599 130 100 66     563 last if $fast and $fast > 1;
6600 129         392 $subdirInfo{MakerNoteAddr} = $valuePtr + $valueDataPos + $base;
6601 129 100       500 $subdirInfo{NoFixBase} = 1 if defined $$subdir{Base};
6602             }
6603             # set directory IFD name from group name of family 1 if it exists,
6604             # unless the tag is writable as a block in which case group 1 may
6605             # have been set automatically
6606 1250 100 100     6724 if ($$tagInfo{Groups} and not $$tagInfo{Writable}) {
6607 392         1023 $subdirInfo{DirName} = $$tagInfo{Groups}{1};
6608             # number multiple subdirectories
6609 392 100       998 $subdirInfo{DirName} =~ s/\d*$/$dirNum/ if $dirNum;
6610             }
6611 1250         3623 SetByteOrder($newByteOrder); # set byte order for this subdir
6612             # validate the subdirectory if necessary
6613 1250         2006 my $dirData = $subdirDataPt; # set data pointer to be used in eval
6614             #### eval Validate ($val, $dirData, $subdirStart, $size)
6615 1250         1929 my $ok = 0;
6616 1250 50 66     26639 if (defined $$subdir{Validate} and not eval $$subdir{Validate}) {
6617 0         0 $et->Warn("Invalid $tagStr data", $inMakerNotes);
6618 0         0 $invalid = 1;
6619             } else {
6620 1250 100 100     4771 if (not $subdirInfo{DirName} and $inMakerNotes) {
6621 622         1391 $subdirInfo{DirName} = $$tagInfo{Name};
6622             }
6623             # process the subdirectory
6624 1250         6239 $ok = $et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc});
6625             }
6626             # print debugging information if there were errors
6627 1250 50 66     5390 if (not $ok and $verbose > 1 and $subdirStart != $valuePtr) {
      33        
6628 0         0 my $out = $et->Options('TextOut');
6629 0         0 printf $out "%s (SubDirectory start = 0x%x)\n", $$et{INDENT}, $subdirStart;
6630             }
6631 1250         3625 SetByteOrder($oldByteOrder); # restore original byte swapping
6632              
6633 1250 100       7178 @values or last;
6634 6         49 $val = shift @values; # continue with next subdir
6635             }
6636 1245         4342 my $doMaker = $et->Options('MakerNotes');
6637 1245 100 100     10344 next unless $doMaker or $$et{REQ_TAG_LOOKUP}{lc($tagStr)} or $$tagInfo{BlockExtract};
      100        
6638             # extract as a block if specified
6639 204 100       1013 if ($$tagInfo{MakerNotes}) {
6640             # save maker note byte order (if it was significant and valid)
6641 20 50 33     166 if ($$subdir{ByteOrder} and not $invalid) {
6642             $$et{MAKER_NOTE_BYTE_ORDER} =
6643             defined ($$et{UnknownByteOrder}) ?
6644 20 100       112 $$et{UnknownByteOrder} : $newByteOrder;
6645             }
6646 20 50 33     203 if ($doMaker and $doMaker eq '2') {
    50 33        
6647             # extract maker notes without rebuilding (no fixup information)
6648 0         0 delete $$et{MAKER_NOTE_FIXUP};
6649             } elsif (not $$tagInfo{NotIFD} or $$tagInfo{IsPhaseOne}) {
6650             # this is a pain, but we must rebuild EXIF-type maker notes to
6651             # include all the value data if data was outside the maker notes
6652             my %makerDirInfo = (
6653             Name => $tagStr,
6654             Base => $base,
6655             DataPt => $valueDataPt,
6656             DataPos => $valueDataPos,
6657             DataLen => $valueDataLen,
6658             DirStart => $valuePtr,
6659             DirLen => $size,
6660             RAF => $raf,
6661             Parent => $dirName,
6662             DirName => 'MakerNotes',
6663             FixOffsets => $$subdir{FixOffsets},
6664 20         215 TagInfo => $tagInfo,
6665             );
6666 20         49 my $val2;
6667 20 50       121 if ($$tagInfo{IsPhaseOne}) {
6668 0         0 $$et{DropTags} = 1;
6669 0         0 $val2 = Image::ExifTool::PhaseOne::WritePhaseOne($et, \%makerDirInfo, $newTagTable);
6670 0         0 delete $$et{DropTags};
6671             } else {
6672 20 100       78 $makerDirInfo{FixBase} = 1 if $$subdir{FixBase};
6673             # rebuild maker notes (creates $$et{MAKER_NOTE_FIXUP})
6674 20         137 $val2 = RebuildMakerNotes($et, \%makerDirInfo, $newTagTable);
6675             }
6676 20 50       157 if (defined $val2) {
    0          
6677 20         112 $val = $val2;
6678             } elsif ($size > 4) {
6679 0         0 $et->Warn('Error rebuilding maker notes (may be corrupt)');
6680             }
6681             }
6682             } else {
6683             # extract this directory as a block if specified
6684 184 100       934 next unless $$tagInfo{Writable};
6685             }
6686             }
6687             #..............................................................................
6688             # convert to absolute offsets if this tag is an offset
6689             #### eval IsOffset ($val, $et)
6690 13227 100 100     35609 if ($$tagInfo{IsOffset} and eval $$tagInfo{IsOffset}) {
6691 224 100       1007 my $offsetBase = $$tagInfo{IsOffset} eq '2' ? $firstBase : $base;
6692 224         584 $offsetBase += $$et{BASE};
6693             # handle offsets which use a wrong base (Minolta A200)
6694 224 50       687 if ($$tagInfo{WrongBase}) {
6695 0         0 my $self = $et;
6696             #### eval WrongBase ($self)
6697 0   0     0 $offsetBase += eval $$tagInfo{WrongBase} || 0;
6698             }
6699 224         925 my @vals = split(' ',$val);
6700 224         597 foreach $val (@vals) {
6701 224         658 $val += $offsetBase;
6702             }
6703 224         711 $val = join(' ', @vals);
6704             }
6705 13227 100       20467 if ($validate) {
6706 70 100 66     231 if ($$tagInfo{OffsetPair}) {
    100          
6707 10         34 $offsetInfo{$tagID} = [ $tagInfo, $val ];
6708             } elsif ($saveForValidate{$tagID} and $isExif) {
6709 10         24 $offsetInfo{$tagID} = $val;
6710             }
6711             }
6712             # save the value of this tag
6713 13227         30260 $tagKey = $et->FoundTag($tagInfo, $val);
6714 13227 100       24672 if (defined $tagKey) {
6715             # set the group 1 name for tags in specified tables
6716 13216 100       37506 $et->SetGroup($tagKey, $dirName) if $$tagTablePtr{SET_GROUP1};
6717             # save original components of rational numbers (used when copying)
6718 13216 100       25186 $$et{RATIONAL}{$tagKey} = $rational if defined $rational;
6719 13216 50       35993 $$et{TAG_EXTRA}{$tagKey}{G6} = $saveFormat if $saveFormat;
6720             }
6721             }
6722              
6723             # validate image data offsets for this IFD
6724 1051 100 100     3323 if ($validate and %offsetInfo) {
6725 5         27 Image::ExifTool::Validate::ValidateOffsetInfo($et, \%offsetInfo, $$dirInfo{DirName}, $inMakerNotes)
6726             }
6727              
6728             # scan for subsequent IFD's if specified
6729 1051 100 66     4941 if ($$dirInfo{Multi} and $bytesFromEnd >= 4) {
    100          
6730             # use same directory information for trailing directory,
6731             # but change the start location (ProcessDirectory will
6732             # test to make sure we don't reprocess the same dir twice)
6733 289         2403 my %newDirInfo = %$dirInfo;
6734 289         1186 $newDirInfo{Multi} = 0; # prevent recursion
6735 289         668 $newDirInfo{OffsetName} = $nextOffName;
6736 289         1824 $$et{INDENT} =~ s/..$//; # keep indent the same
6737 289         606 for (;;) {
6738 458 100       1648 my $offset = Get32u($dataPt, $dirEnd) or last;
6739 169         481 $newDirInfo{DirStart} = $offset - $dataPos;
6740             # increment IFD number
6741 169 50       1427 my $ifdNum = $newDirInfo{DirName} =~ s/(\d+)$// ? $1 : 0;
6742 169         593 $newDirInfo{DirName} .= $ifdNum + 1;
6743             # must validate SubIFD1 because the nextIFD pointer is invalid for some RAW formats
6744 169 50 33     729 if ($newDirInfo{DirName} ne 'SubIFD1' or ValidateIFD(\%newDirInfo)) {
    0 0        
6745 169         310 my $cur = pop @{$$et{PATH}};
  169         497  
6746 169 50       703 $et->ProcessDirectory(\%newDirInfo, $tagTablePtr) or $success = 0;
6747 169         402 push @{$$et{PATH}}, $cur;
  169         484  
6748 169 50 33     959 if ($success and $newDirInfo{BytesFromEnd} >= 4) {
6749 169         495 $dataPt = $newDirInfo{DataPt};
6750 169         324 $dataPos = $newDirInfo{DataPos};
6751 169         430 $dirEnd = $newDirInfo{DirEnd};
6752 169         368 next;
6753             }
6754             } elsif ($verbose or $$et{TIFF_TYPE} eq 'TIFF') {
6755 0         0 $et->Warn('Ignored bad IFD linked from SubIFD');
6756             }
6757 0         0 last;
6758             }
6759             } elsif (defined $$dirInfo{Multi}) {
6760             # return necessary parameters for parsing next IFD
6761 170         522 $$dirInfo{DirEnd} = $dirEnd;
6762 170         353 $$dirInfo{OffsetName} = $nextOffName;
6763 170         381 $$dirInfo{BytesFromEnd} = $bytesFromEnd;
6764             }
6765 1051         4384 return $success;
6766             }
6767              
6768             1; # end
6769              
6770             __END__