File Coverage

blib/lib/Image/ExifTool/FujiFilm.pm
Criterion Covered Total %
statement 114 155 73.5
branch 40 86 46.5
condition 18 54 33.3
subroutine 7 8 87.5
pod 0 4 0.0
total 179 307 58.3


line stmt bran cond sub pod time code
1             #------------------------------------------------------------------------------
2             # File: FujiFilm.pm
3             #
4             # Description: Read/write FujiFilm maker notes and RAF images
5             #
6             # Revisions: 11/25/2003 - P. Harvey Created
7             # 11/14/2007 - PH Added ability to write RAF images
8             #
9             # References: 1) http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
10             # 2) http://homepage3.nifty.com/kamisaka/makernote/makernote_fuji.htm (2007/09/11)
11             # 3) Michael Meissner private communication
12             # 4) Paul Samuelson private communication (S5)
13             # 5) http://www.cybercom.net/~dcoffin/dcraw/
14             # 6) http://forums.dpreview.com/forums/readflat.asp?forum=1012&thread=31350384
15             # and http://forum.photome.de/viewtopic.php?f=2&t=353&p=742#p740
16             # 7) Kai Lappalainen private communication
17             # 8) https://exiftool.org/forum/index.php/topic,5223.0.html
18             # 9) Zilvinas Brobliauskas private communication
19             # 10) Albert Shan private communication
20             # 11) https://exiftool.org/forum/index.php/topic,8377.0.html
21             # 12) https://exiftool.org/forum/index.php/topic,9607.0.html
22             # 13) https://exiftool.org/forum/index.php/topic=10481.0.html
23             # IB) Iliah Borg private communication (LibRaw)
24             # JD) Jens Duttke private communication
25             #------------------------------------------------------------------------------
26              
27             package Image::ExifTool::FujiFilm;
28              
29 19     19   3733 use strict;
  19         40  
  19         624  
30 19     19   93 use vars qw($VERSION);
  19         41  
  19         836  
31 19     19   103 use Image::ExifTool qw(:DataAccess :Utils);
  19         35  
  19         3841  
32 19     19   1137 use Image::ExifTool::Exif;
  19         74  
  19         65945  
33              
34             $VERSION = '1.80';
35              
36             sub ProcessFujiDir($$$);
37             sub ProcessFaceRec($$$);
38              
39             # the following RAF version numbers have been tested for writing:
40             # (as of ExifTool 11.70, this lookup is no longer used if the version number is numerical)
41             my %testedRAF = (
42             '0100' => 'E550, E900, F770, S5600, S6000fd, S6500fd, HS10/HS11, HS30, S200EXR, X100, XF1, X-Pro1, X-S1, XQ2 Ver1.00, X-T100, GFX 50R, XF10',
43             '0101' => 'X-E1, X20 Ver1.01, X-T3',
44             '0102' => 'S100FS, X10 Ver1.02',
45             '0103' => 'IS Pro Ver1.03',
46             '0104' => 'S5Pro Ver1.04',
47             '0106' => 'S5Pro Ver1.06',
48             '0111' => 'S5Pro Ver1.11',
49             '0114' => 'S9600 Ver1.00',
50             '0132' => 'X-T2 Ver1.32',
51             '0144' => 'X100T Ver1.44',
52             '0159' => 'S2Pro Ver1.00',
53             '0200' => 'X10 Ver2.00',
54             '0201' => 'X-H1 Ver2.01',
55             '0212' => 'S3Pro Ver2.12',
56             '0216' => 'S3Pro Ver2.16', # (NC)
57             '0218' => 'S3Pro Ver2.18',
58             '0240' => 'X-E1 Ver2.40',
59             '0264' => 'F700 Ver2.00',
60             '0266' => 'S9500 Ver1.01',
61             '0261' => 'X-E1 Ver2.61',
62             '0269' => 'S9500 Ver1.02',
63             '0271' => 'S3Pro Ver2.71', # UV/IR model?
64             '0300' => 'X-E2',
65             # 0400 - expect to see this for X-T1
66             '0540' => 'X-T1 Ver5.40',
67             '0712' => 'S5000 Ver3.00',
68             '0716' => 'S5000 Ver3.00', # (yes, 2 RAF versions with the same Software version)
69             '0Dgi' => 'X-A10 Ver1.01 and X-A3 Ver1.02', # (yes, non-digits in the firmware number)
70             );
71              
72             my %faceCategories = (
73             Format => 'int8u',
74             PrintConv => { BITMASK => {
75             1 => 'Partner',
76             2 => 'Family',
77             3 => 'Friend',
78             }},
79             );
80              
81             # FujiFilm MakerNotes tags
82             %Image::ExifTool::FujiFilm::Main = (
83             WRITE_PROC => \&Image::ExifTool::Exif::WriteExif,
84             CHECK_PROC => \&Image::ExifTool::Exif::CheckExif,
85             WRITABLE => 1,
86             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
87             0x0 => {
88             Name => 'Version',
89             Writable => 'undef',
90             },
91             0x0010 => { #PH/IB
92             Name => 'InternalSerialNumber',
93             Writable => 'string',
94             Notes => q{
95             this number is unique for most models, and contains the camera model ID and
96             the date of manufacture
97             },
98             # eg) "FPX20017035 592D31313034060427796060110384"
99             # "FPX 20495643 592D313335310701318AD010110047" (F40fd)
100             # HHHHHHHHHHHHyymmdd
101             # HHHHHHHHHHHH = camera body number in hex
102             # yymmdd = date of manufacture
103             PrintConv => q{
104             if ($val =~ /^(.*?\s*)([0-9a-fA-F]*)(\d{2})(\d{2})(\d{2})(.{12})\s*\0*$/s
105             and $4 >= 1 and $4 <= 12 and $5 >= 1 and $5 <= 31)
106             {
107             my $yr = $3 + ($3 < 70 ? 2000 : 1900);
108             my $sn = pack 'H*', $2;
109             return "$1$sn $yr:$4:$5 $6";
110             } else {
111             # handle a couple of models which use a slightly different format
112             $val =~ s/\b(592D(3[0-9])+)/pack("H*",$1).' '/e;
113             }
114             return $val;
115             },
116             # (this inverse conversion doesn't work in all cases, so it is best to write
117             # the ValueConv value if an authentic internal serial number is required)
118             PrintConvInv => '$_=$val; s/(\S+) (19|20)(\d{2}):(\d{2}):(\d{2}) /unpack("H*",$1)."$3$4$5"/e; $_',
119             },
120             0x1000 => {
121             Name => 'Quality',
122             Writable => 'string',
123             },
124             0x1001 => {
125             Name => 'Sharpness',
126             Flags => 'PrintHex',
127             Writable => 'int16u',
128             PrintConv => {
129             0x00 => '-4 (softest)', #10
130             0x01 => '-3 (very soft)',
131             0x02 => '-2 (soft)',
132             0x03 => '0 (normal)',
133             0x04 => '+2 (hard)',
134             0x05 => '+3 (very hard)',
135             0x06 => '+4 (hardest)',
136             0x82 => '-1 (medium soft)', #2
137             0x84 => '+1 (medium hard)', #2
138             0x8000 => 'Film Simulation', #2
139             0xffff => 'n/a', #2
140             },
141             },
142             0x1002 => {
143             Name => 'WhiteBalance',
144             Flags => 'PrintHex',
145             Writable => 'int16u',
146             PrintConv => {
147             0x0 => 'Auto',
148             0x1 => 'Auto (white priority)', #forum10890
149             0x2 => 'Auto (ambiance priority)', #forum10890
150             0x100 => 'Daylight',
151             0x200 => 'Cloudy',
152             0x300 => 'Daylight Fluorescent',
153             0x301 => 'Day White Fluorescent',
154             0x302 => 'White Fluorescent',
155             0x303 => 'Warm White Fluorescent', #2/PH (S5)
156             0x304 => 'Living Room Warm White Fluorescent', #2/PH (S5)
157             0x400 => 'Incandescent',
158             0x500 => 'Flash', #4
159             0x600 => 'Underwater', #forum6109
160             0xf00 => 'Custom',
161             0xf01 => 'Custom2', #2
162             0xf02 => 'Custom3', #2
163             0xf03 => 'Custom4', #2
164             0xf04 => 'Custom5', #2
165             # 0xfe0 => 'Gray Point?', #2
166             0xff0 => 'Kelvin', #4
167             },
168             },
169             0x1003 => {
170             Name => 'Saturation',
171             Flags => 'PrintHex',
172             Writable => 'int16u',
173             PrintConv => {
174             0x0 => '0 (normal)', # # ("Color 0", ref 8)
175             0x080 => '+1 (medium high)', #2 ("Color +1", ref 8)
176             0x100 => '+2 (high)', # ("Color +2", ref 8)
177             0x0c0 => '+3 (very high)',
178             0x0e0 => '+4 (highest)',
179             0x180 => '-1 (medium low)', #2 ("Color -1", ref 8)
180             0x200 => 'Low',
181             0x300 => 'None (B&W)', #2
182             0x301 => 'B&W Red Filter', #PH/8
183             0x302 => 'B&W Yellow Filter', #PH (X100)
184             0x303 => 'B&W Green Filter', #PH/8
185             0x310 => 'B&W Sepia', #PH (X100)
186             0x400 => '-2 (low)', #8 ("Color -2")
187             0x4c0 => '-3 (very low)',
188             0x4e0 => '-4 (lowest)',
189             0x500 => 'Acros', #PH (X-Pro2)
190             0x501 => 'Acros Red Filter', #PH (X-Pro2)
191             0x502 => 'Acros Yellow Filter', #PH (X-Pro2)
192             0x503 => 'Acros Green Filter', #PH (X-Pro2)
193             0x8000 => 'Film Simulation', #2
194             },
195             },
196             0x1004 => {
197             Name => 'Contrast',
198             Flags => 'PrintHex',
199             Writable => 'int16u',
200             PrintConv => {
201             0x0 => 'Normal',
202             0x080 => 'Medium High', #2
203             0x100 => 'High',
204             0x180 => 'Medium Low', #2
205             0x200 => 'Low',
206             0x8000 => 'Film Simulation', #2
207             },
208             },
209             0x1005 => { #4
210             Name => 'ColorTemperature',
211             Writable => 'int16u',
212             },
213             0x1006 => { #JD
214             Name => 'Contrast',
215             Flags => 'PrintHex',
216             Writable => 'int16u',
217             PrintConv => {
218             0x0 => 'Normal',
219             0x100 => 'High',
220             0x300 => 'Low',
221             },
222             },
223             0x100a => { #2
224             Name => 'WhiteBalanceFineTune',
225             Writable => 'int32s',
226             Count => 2,
227             PrintConv => 'sprintf("Red %+d, Blue %+d", split(" ", $val))',
228             PrintConvInv => 'my @v=($val=~/-?\d+/g);"@v"',
229             },
230             0x100b => { #2
231             Name => 'NoiseReduction',
232             Flags => 'PrintHex',
233             Writable => 'int16u',
234             RawConv => '$val == 0x100 ? undef : $val',
235             PrintConv => {
236             0x40 => 'Low',
237             0x80 => 'Normal',
238             0x100 => 'n/a', #PH (NC) (all X100 samples)
239             },
240             },
241             0x100e => { #PH (X100)
242             Name => 'NoiseReduction',
243             Flags => 'PrintHex',
244             Writable => 'int16u',
245             PrintConv => {
246             0x000 => '0 (normal)', # ("NR 0, ref 8)
247             0x100 => '+2 (strong)', # ("NR+2, ref 8)
248             0x180 => '+1 (medium strong)', #8 ("NR+1")
249             0x1c0 => '+3 (very strong)',
250             0x1e0 => '+4 (strongest)',
251             0x200 => '-2 (weak)', # ("NR-2, ref 8)
252             0x280 => '-1 (medium weak)', #8 ("NR-1")
253             0x2c0 => '-3 (very weak)', #10 (-3)
254             0x2e0 => '-4 (weakest)', #10 (-4)
255             },
256             },
257             0x1010 => {
258             Name => 'FujiFlashMode',
259             Writable => 'int16u',
260             PrintHex => 1,
261             PrintConv => {
262             0 => 'Auto',
263             1 => 'On',
264             2 => 'Off',
265             3 => 'Red-eye reduction',
266             4 => 'External', #JD
267             16 => 'Commander',
268             0x8000 => 'Not Attached', #10 (X-T2) (or external flash off)
269             0x8120 => 'TTL', #10 (X-T2)
270             0x8320 => 'TTL Auto - Did not fire',
271             0x9840 => 'Manual', #10 (X-T2)
272             0x9860 => 'Flash Commander', #13
273             0x9880 => 'Multi-flash', #10 (X-T2)
274             0xa920 => '1st Curtain (front)', #10 (EF-X500 flash)
275             0xaa20 => 'TTL Slow - 1st Curtain (front)', #13
276             0xab20 => 'TTL Auto - 1st Curtain (front)', #13
277             0xad20 => 'TTL - Red-eye Flash - 1st Curtain (front)', #13
278             0xae20 => 'TTL Slow - Red-eye Flash - 1st Curtain (front)', #13
279             0xaf20 => 'TTL Auto - Red-eye Flash - 1st Curtain (front)', #13
280             0xc920 => '2nd Curtain (rear)', #10
281             0xca20 => 'TTL Slow - 2nd Curtain (rear)', #13
282             0xcb20 => 'TTL Auto - 2nd Curtain (rear)', #13
283             0xcd20 => 'TTL - Red-eye Flash - 2nd Curtain (rear)', #13
284             0xce20 => 'TTL Slow - Red-eye Flash - 2nd Curtain (rear)', #13
285             0xcf20 => 'TTL Auto - Red-eye Flash - 2nd Curtain (rear)', #13
286             0xe920 => 'High Speed Sync (HSS)', #10
287             },
288             },
289             0x1011 => {
290             Name => 'FlashExposureComp', #JD
291             Writable => 'rational64s',
292             },
293             0x1020 => {
294             Name => 'Macro',
295             Writable => 'int16u',
296             PrintConv => {
297             0 => 'Off',
298             1 => 'On',
299             },
300             },
301             0x1021 => {
302             Name => 'FocusMode',
303             Writable => 'int16u',
304             PrintConv => {
305             0 => 'Auto',
306             1 => 'Manual',
307             65535 => 'Movie', #forum10766
308             },
309             },
310             0x1022 => { #8/forum6579
311             Name => 'AFMode',
312             Writable => 'int16u',
313             Notes => '"No" for manual and some AF-multi focus modes',
314             PrintConv => {
315             0 => 'No',
316             1 => 'Single Point',
317             256 => 'Zone',
318             512 => 'Wide/Tracking',
319             },
320             },
321             0x102b => {
322             Name => 'PrioritySettings',
323             SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::PrioritySettings' },
324             },
325             0x102d => {
326             Name => 'FocusSettings',
327             SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FocusSettings' },
328             },
329             0x102e => {
330             Name => 'AFCSettings',
331             SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::AFCSettings' },
332             },
333             0x1023 => { #2
334             Name => 'FocusPixel',
335             Writable => 'int16u',
336             Count => 2,
337             },
338             0x1030 => {
339             Name => 'SlowSync',
340             Writable => 'int16u',
341             PrintConv => {
342             0 => 'Off',
343             1 => 'On',
344             },
345             },
346             0x1031 => {
347             Name => 'PictureMode',
348             Flags => 'PrintHex',
349             Writable => 'int16u',
350             PrintConv => {
351             0x0 => 'Auto', # (or 'SR+' if SceneRecognition present, ref 11)
352             0x1 => 'Portrait',
353             0x2 => 'Landscape',
354             0x3 => 'Macro', #JD
355             0x4 => 'Sports',
356             0x5 => 'Night Scene',
357             0x6 => 'Program AE',
358             0x7 => 'Natural Light', #3
359             0x8 => 'Anti-blur', #3
360             0x9 => 'Beach & Snow', #JD
361             0xa => 'Sunset', #3
362             0xb => 'Museum', #3
363             0xc => 'Party', #3
364             0xd => 'Flower', #3
365             0xe => 'Text', #3
366             0xf => 'Natural Light & Flash', #3
367             0x10 => 'Beach', #3
368             0x11 => 'Snow', #3
369             0x12 => 'Fireworks', #3
370             0x13 => 'Underwater', #3
371             0x14 => 'Portrait with Skin Correction', #7
372             0x16 => 'Panorama', #PH (X100)
373             0x17 => 'Night (tripod)', #7
374             0x18 => 'Pro Low-light', #7
375             0x19 => 'Pro Focus', #7
376             0x1a => 'Portrait 2', #PH (NC, T500, maybe "Smile & Shoot"?)
377             0x1b => 'Dog Face Detection', #7
378             0x1c => 'Cat Face Detection', #7
379             0x30 => 'HDR', #forum10799
380             0x40 => 'Advanced Filter',
381             0x100 => 'Aperture-priority AE',
382             0x200 => 'Shutter speed priority AE',
383             0x300 => 'Manual',
384             },
385             },
386             0x1032 => { #8
387             Name => 'ExposureCount',
388             Writable => 'int16u',
389             Notes => 'number of exposures used for this image',
390             },
391             0x1033 => { #6
392             Name => 'EXRAuto',
393             Writable => 'int16u',
394             PrintConv => {
395             0 => 'Auto',
396             1 => 'Manual',
397             },
398             },
399             0x1034 => { #6
400             Name => 'EXRMode',
401             Writable => 'int16u',
402             PrintHex => 1,
403             PrintConv => {
404             0x100 => 'HR (High Resolution)',
405             0x200 => 'SN (Signal to Noise priority)',
406             0x300 => 'DR (Dynamic Range priority)',
407             },
408             },
409             0x1040 => { #8
410             Name => 'ShadowTone',
411             Writable => 'int32s',
412             PrintConv => {
413             -64 => '+4 (hardest)',
414             -48 => '+3 (very hard)',
415             -32 => '+2 (hard)',
416             -16 => '+1 (medium hard)',
417             0 => '0 (normal)',
418             16 => '-1 (medium soft)',
419             32 => '-2 (soft)',
420             },
421             },
422             0x1041 => { #8
423             Name => 'HighlightTone',
424             Writable => 'int32s',
425             PrintConv => {
426             -64 => '+4 (hardest)',
427             -48 => '+3 (very hard)',
428             -32 => '+2 (hard)',
429             -16 => '+1 (medium hard)',
430             0 => '0 (normal)',
431             16 => '-1 (medium soft)',
432             32 => '-2 (soft)',
433             },
434             },
435             0x1044 => { #forum7668
436             Name => 'DigitalZoom',
437             Writable => 'int32u',
438             ValueConv => '$val / 8',
439             ValueConvInv => '$val * 8',
440             },
441             0x1045 => { #12
442             Name => 'LensModulationOptimizer',
443             Writable => 'int32u',
444             PrintConv => { 0 => 'Off', 1 => 'On' },
445             },
446             0x1047 => { #12
447             Name => 'GrainEffect',
448             Writable => 'int32s',
449             PrintConv => {
450             0 => 'Off',
451             32 => 'Weak',
452             64 => 'Strong',
453             },
454             },
455             0x1048 => { #12
456             Name => 'ColorChromeEffect',
457             Writable => 'int32s',
458             PrintConv => {
459             0 => 'Off',
460             32 => 'Weak',
461             64 => 'Strong',
462             },
463             },
464             0x1049 => { #12
465             Name => 'BWAdjustment',
466             Notes => 'positive values are warm, negative values are cool',
467             Format => 'int8s',
468             PrintConv => '$val > 0 ? "+$val" : $val',
469             PrintConvInv => '$val + 0',
470             },
471             # 0x104b - BWAdjustment for Green->Magenta (forum10800)
472             0x104d => { #forum9634
473             Name => 'CropMode',
474             Writable => 'int16u',
475             PrintConv => { # (perhaps this is a bit mask?)
476             0 => 'n/a',
477             1 => 'Full-frame on GFX', #IB
478             2 => 'Sports Finder Mode', # (mechanical shutter)
479             4 => 'Electronic Shutter 1.25x Crop', # (continuous high)
480             },
481             },
482             0x1050 => { #forum6109
483             Name => 'ShutterType',
484             Writable => 'int16u',
485             PrintConv => {
486             0 => 'Mechanical',
487             1 => 'Electronic',
488             2 => 'Electronic (long shutter speed)', #12
489             3 => 'Electronic Front Curtain', #10
490             },
491             },
492             # 0x1100 - This may not work well for newer cameras (ref forum12682)
493             0x1100 => [{
494             Name => 'AutoBracketing',
495             Condition => '$$self{Model} eq "X-T3"',
496             Notes => 'X-T3 only',
497             Writable => 'int16u',
498             PrintConv => {
499             0 => 'Off',
500             1 => 'On',
501             2 => 'Pre-shot', #12 (Electronic Shutter and Continuous High drive mode only)
502             },
503             },{
504             Name => 'AutoBracketing',
505             Notes => 'other models',
506             Writable => 'int16u',
507             PrintConv => {
508             0 => 'Off',
509             1 => 'On',
510             2 => 'No flash & flash', #3
511             6 => 'Pixel Shift', #IB (GFX100S)
512             },
513             }],
514             0x1101 => {
515             Name => 'SequenceNumber',
516             Writable => 'int16u',
517             },
518             0x1103 => {
519             Name => 'DriveSettings',
520             SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::DriveSettings' },
521             },
522             0x1105 => { Name => 'PixelShiftShots', Writable => 'int16u' }, #IB
523             0x1106 => { Name => 'PixelShiftOffset', Writable => 'rational64s', Count => 2 }, #IB
524             # (0x1150-0x1152 exist only for Pro Low-light and Pro Focus PictureModes)
525             # 0x1150 - Pro Low-light - val=1; Pro Focus - val=2 (ref 7); HDR - val=128 (forum10799)
526             # 0x1151 - Pro Low-light - val=4 (number of pictures taken?); Pro Focus - val=2,3 (ref 7); HDR - val=3 (forum10799)
527             # 0x1152 - Pro Low-light - val=1,3,4 (stacked pictures used?); Pro Focus - val=1,2 (ref 7); HDR - val=3 (forum10799)
528             0x1153 => { #forum7668
529             Name => 'PanoramaAngle',
530             Writable => 'int16u',
531             },
532             0x1154 => { #forum7668
533             Name => 'PanoramaDirection',
534             Writable => 'int16u',
535             PrintConv => {
536             1 => 'Right',
537             2 => 'Up',
538             3 => 'Left',
539             4 => 'Down',
540             },
541             },
542             0x1201 => { #forum6109
543             Name => 'AdvancedFilter',
544             Writable => 'int32u',
545             PrintHex => 1,
546             PrintConv => {
547             0x10000 => 'Pop Color',
548             0x20000 => 'Hi Key',
549             0x30000 => 'Toy Camera',
550             0x40000 => 'Miniature',
551             0x50000 => 'Dynamic Tone',
552             0x60001 => 'Partial Color Red',
553             0x60002 => 'Partial Color Yellow',
554             0x60003 => 'Partial Color Green',
555             0x60004 => 'Partial Color Blue',
556             0x60005 => 'Partial Color Orange',
557             0x60006 => 'Partial Color Purple',
558             0x70000 => 'Soft Focus',
559             0x90000 => 'Low Key',
560             },
561             },
562             0x1210 => { #2
563             Name => 'ColorMode',
564             Writable => 'int16u',
565             PrintHex => 1,
566             PrintConv => {
567             0x00 => 'Standard',
568             0x10 => 'Chrome',
569             0x30 => 'B & W',
570             },
571             },
572             0x1300 => {
573             Name => 'BlurWarning',
574             Writable => 'int16u',
575             PrintConv => {
576             0 => 'None',
577             1 => 'Blur Warning',
578             },
579             },
580             0x1301 => {
581             Name => 'FocusWarning',
582             Writable => 'int16u',
583             PrintConv => {
584             0 => 'Good',
585             1 => 'Out of focus',
586             },
587             },
588             0x1302 => {
589             Name => 'ExposureWarning',
590             Writable => 'int16u',
591             PrintConv => {
592             0 => 'Good',
593             1 => 'Bad exposure',
594             },
595             },
596             0x1304 => { #PH
597             Name => 'GEImageSize',
598             Condition => '$$self{Make} =~ /^GENERAL IMAGING/',
599             Writable => 'string',
600             Notes => 'GE models only',
601             },
602             0x1400 => { #2
603             Name => 'DynamicRange',
604             Writable => 'int16u',
605             PrintConv => {
606             1 => 'Standard',
607             3 => 'Wide',
608             # the S5Pro has 100%(STD),130%,170%,230%(W1),300%,400%(W2) - PH
609             },
610             },
611             0x1401 => { #2 (this doesn't seem to work for the X100 - PH)
612             Name => 'FilmMode',
613             Writable => 'int16u',
614             PrintHex => 1,
615             PrintConv => {
616             0x000 => 'F0/Standard (Provia)', # X-Pro2 "Provia/Standard"
617             0x100 => 'F1/Studio Portrait',
618             0x110 => 'F1a/Studio Portrait Enhanced Saturation',
619             0x120 => 'F1b/Studio Portrait Smooth Skin Tone (Astia)', # X-Pro2 "Astia/Soft"
620             0x130 => 'F1c/Studio Portrait Increased Sharpness',
621             0x200 => 'F2/Fujichrome (Velvia)', # X-Pro2 "Velvia/Vivid"
622             0x300 => 'F3/Studio Portrait Ex',
623             0x400 => 'F4/Velvia',
624             0x500 => 'Pro Neg. Std', #PH (X-Pro1)
625             0x501 => 'Pro Neg. Hi', #PH (X-Pro1)
626             0x600 => 'Classic Chrome', #forum6109
627             0x700 => 'Eterna', #12
628             0x800 => 'Classic Negative', #forum10536
629             0x900 => 'Bleach Bypass', #forum10890
630             0xa00 => 'Nostalgic Neg', #forum12085
631             },
632             },
633             0x1402 => { #2
634             Name => 'DynamicRangeSetting',
635             Writable => 'int16u',
636             PrintHex => 1,
637             PrintConv => {
638             0x000 => 'Auto',
639             0x001 => 'Manual', #(ref http://forum.photome.de/viewtopic.php?f=2&t=353)
640             0x100 => 'Standard (100%)',
641             0x200 => 'Wide1 (230%)',
642             0x201 => 'Wide2 (400%)',
643             0x8000 => 'Film Simulation',
644             },
645             },
646             0x1403 => { #2 (only valid for manual DR, ref 6)
647             Name => 'DevelopmentDynamicRange',
648             Writable => 'int16u',
649             # (shows 200, 400 or 800 for HDR200,HDR400,HDR800, ref forum10799)
650             },
651             0x1404 => { #2
652             Name => 'MinFocalLength',
653             Writable => 'rational64s',
654             },
655             0x1405 => { #2
656             Name => 'MaxFocalLength',
657             Writable => 'rational64s',
658             },
659             0x1406 => { #2
660             Name => 'MaxApertureAtMinFocal',
661             Writable => 'rational64s',
662             },
663             0x1407 => { #2
664             Name => 'MaxApertureAtMaxFocal',
665             Writable => 'rational64s',
666             },
667             # 0x1408 - values: '0100', 'S100', 'VQ10'
668             # 0x1409 - values: same as 0x1408
669             # 0x140a - values: 0, 1, 3, 5, 7 (bit 2=red-eye detection, ref 11/13)
670             0x140b => { #6
671             Name => 'AutoDynamicRange',
672             Writable => 'int16u',
673             PrintConv => '"$val%"',
674             PrintConvInv => '$val=~s/\s*\%$//; $val',
675             },
676             0x104e => { #forum10800 (X-Pro3)
677             Name => 'ColorChromeFXBlue',
678             Writable => 'int32s',
679             PrintConv => {
680             0 => 'Off',
681             32 => 'Weak', # (NC)
682             64 => 'Strong',
683             },
684             },
685             0x1422 => { #8
686             Name => 'ImageStabilization',
687             Writable => 'int16u',
688             Count => 3,
689             PrintConv => [{
690             0 => 'None',
691             1 => 'Optical', #PH
692             2 => 'Sensor-shift', #PH
693             3 => 'OIS Lens', #forum9815 (optical+sensor?)
694             512 => 'Digital', #PH
695             },{
696             0 => 'Off',
697             1 => 'On (mode 1, continuous)',
698             2 => 'On (mode 2, shooting only)',
699             }],
700             },
701             0x1425 => { # if present and 0x1031 PictureMode is zero, then PictureMode is SR+, not Auto (ref 11)
702             Name => 'SceneRecognition',
703             Writable => 'int16u',
704             PrintHex => 1,
705             PrintConv => {
706             0 => 'Unrecognized',
707             0x100 => 'Portrait Image',
708             0x103 => 'Night Portrait', #forum10651
709             0x105 => 'Backlit Portrait', #forum10651
710             0x200 => 'Landscape Image',
711             0x300 => 'Night Scene',
712             0x400 => 'Macro',
713             },
714             },
715             0x1431 => { #forum6109
716             Name => 'Rating',
717             Groups => { 2 => 'Image' },
718             Writable => 'int32u',
719             Priority => 0,
720             },
721             0x1436 => { #8
722             Name => 'ImageGeneration',
723             Writable => 'int16u',
724             PrintConv => {
725             0 => 'Original Image',
726             1 => 'Re-developed from RAW',
727             },
728             },
729             0x1438 => { #forum6579 (X-T1 firmware version 3)
730             Name => 'ImageCount',
731             Notes => 'may reset to 0 when new firmware is installed',
732             Writable => 'int16u',
733             ValueConv => '$val & 0x7fff',
734             ValueConvInv => '$val | 0x8000',
735             },
736             0x1443 => { #12 (X-T3)
737             Name => 'DRangePriority',
738             Writable => 'int16u',
739             PrintConv => { 0 => 'Auto', 1 => 'Fixed' },
740             },
741             0x1444 => { #12 (X-T3, only exists if DRangePriority is 'Auto')
742             Name => 'DRangePriorityAuto',
743             Writable => 'int16u',
744             PrintConv => {
745             1 => 'Weak',
746             2 => 'Strong',
747             3 => 'Plus', #forum10799
748             },
749             },
750             0x1445 => { #12 (X-T3, only exists if DRangePriority is 'Fixed')
751             Name => 'DRangePriorityFixed',
752             Writable => 'int16u',
753             PrintConv => { 1 => 'Weak', 2 => 'Strong' },
754             },
755             0x1446 => { #12
756             Name => 'FlickerReduction',
757             Writable => 'int32u',
758             # seen values: Off=0x0000, On=0x2100,0x3100
759             PrintConv => q{
760             my $on = ((($val >> 8) & 0x0f) == 1) ? 'On' : 'Off';
761             return sprintf('%s (0x%.4x)', $on, $val);
762             },
763             PrintConvInv => '$val=~/(0x[0-9a-f]+)/i; hex $1',
764             },
765             0x3803 => { #forum10037
766             Name => 'VideoRecordingMode',
767             Groups => { 2 => 'Video' },
768             Writable => 'int32u',
769             PrintHex => 1,
770             PrintConv => {
771             0x00 => 'Normal',
772             0x10 => 'F-log',
773             0x20 => 'HLG',
774             },
775             },
776             0x3804 => { #forum10037
777             Name => 'PeripheralLighting',
778             Groups => { 2 => 'Video' },
779             Writable => 'int16u',
780             PrintConv => { 0 => 'Off', 1 => 'On' },
781             },
782             # 0x3805 - int16u: seen 1
783             0x3806 => { #forum10037
784             Name => 'VideoCompression',
785             Groups => { 2 => 'Video' },
786             Writable => 'int16u',
787             PrintConv => {
788             1 => 'Log GOP',
789             2 => 'All Intra',
790             },
791             },
792             # 0x3810 - int32u: related to video codec (ref forum10037)
793             0x3820 => { #PH (HS20EXR MOV)
794             Name => 'FrameRate',
795             Writable => 'int16u',
796             Groups => { 2 => 'Video' },
797             },
798             0x3821 => { #PH (HS20EXR MOV)
799             Name => 'FrameWidth',
800             Writable => 'int16u',
801             Groups => { 2 => 'Video' },
802             },
803             0x3822 => { #PH (HS20EXR MOV)
804             Name => 'FrameHeight',
805             Writable => 'int16u',
806             Groups => { 2 => 'Video' },
807             },
808             0x3824 => { #forum10480 (X series)
809             Name => 'FullHDHighSpeedRec',
810             Writable => 'int32u',
811             Groups => { 2 => 'Video' },
812             PrintConv => { 1 => 'Off', 2 => 'On' },
813             },
814             0x4005 => { #forum9634
815             Name => 'FaceElementSelected', # (could be face or eye)
816             Writable => 'int16u',
817             Count => 4,
818             },
819             0x4100 => { #PH
820             Name => 'FacesDetected',
821             Writable => 'int16u',
822             },
823             0x4103 => { #PH
824             Name => 'FacePositions',
825             Writable => 'int16u',
826             Count => -1,
827             Notes => q{
828             left, top, right and bottom coordinates in full-sized image for each face
829             detected
830             },
831             },
832             0x4200 => { #11
833             Name => 'NumFaceElements',
834             Writable => 'int16u',
835             },
836             0x4201 => { #11
837             Name => 'FaceElementTypes',
838             Writable => 'int8u',
839             Count => -1,
840             PrintConv => [{
841             1 => 'Face',
842             2 => 'Left Eye',
843             3 => 'Right Eye',
844             },'REPEAT'],
845             },
846             # 0x4202 int8u[-1] - number of cooredinates in each rectangle? (ref 11)
847             0x4203 => { #11
848             Name => 'FaceElementPositions',
849             Writable => 'int16u',
850             Count => -1,
851             Notes => q{
852             left, top, right and bottom coordinates in full-sized image for each face
853             element
854             },
855             },
856             # 0x4101-0x4105 - exist only if face detection active
857             # 0x4104 - also related to face detection (same number of entries as FacePositions)
858             # 0x4200 - same as 0x4100?
859             # 0x4203 - same as 0x4103
860             # 0x4204 - same as 0x4104
861             0x4282 => { #PH
862             Name => 'FaceRecInfo',
863             SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FaceRecInfo' },
864             },
865             0x8000 => { #2
866             Name => 'FileSource',
867             Writable => 'string',
868             },
869             0x8002 => { #2
870             Name => 'OrderNumber',
871             Writable => 'int32u',
872             },
873             0x8003 => { #2
874             Name => 'FrameNumber',
875             Writable => 'int16u',
876             },
877             0xb211 => { #PH
878             Name => 'Parallax',
879             # (value set in camera is -0.5 times this value in MPImage2... why?)
880             Writable => 'rational64s',
881             Notes => 'only found in MPImage2 of .MPO images',
882             },
883             # 0xb212 - also found in MPIMage2 images - PH
884             );
885              
886             # Focus Priority settings, tag 0x102b (X-T3, ref forum 9607)
887             %Image::ExifTool::FujiFilm::PrioritySettings = (
888             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
889             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
890             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
891             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
892             FORMAT => 'int16u',
893             WRITABLE => 1,
894             0.1 => {
895             Name => 'AF-SPriority',
896             Mask => 0x000f,
897             PrintConv => {
898             1 => 'Release',
899             2 => 'Focus',
900             },
901             },
902             0.2 => {
903             Name => 'AF-CPriority',
904             Mask => 0x00f0,
905             PrintConv => {
906             1 => 'Release',
907             2 => 'Focus',
908             },
909             },
910             );
911              
912             # Focus settings, tag 0x102d (X-T3, ref forum 9607)
913             %Image::ExifTool::FujiFilm::FocusSettings = (
914             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
915             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
916             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
917             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
918             FORMAT => 'int32u',
919             WRITABLE => 1,
920             0.1 => {
921             Name => 'FocusMode2',
922             Mask => 0x0000000f,
923             PrintConv => {
924             0x0 => 'AF-M',
925             0x1 => 'AF-S',
926             0x2 => 'AF-C',
927             },
928             },
929             0.2 => {
930             Name => 'PreAF',
931             Mask => 0x00f0,
932             PrintConv => {
933             0 => 'Off',
934             1 => 'On',
935             },
936             },
937             0.3 => {
938             Name => 'AFAreaMode',
939             Mask => 0x0f00,
940             PrintConv => {
941             0 => 'Single Point',
942             1 => 'Zone',
943             2 => 'Wide/Tracking',
944             },
945             },
946             0.4 => {
947             Name => 'AFAreaPointSize',
948             Mask => 0xf000,
949             PrintConv => {
950             0 => 'n/a',
951             OTHER => sub { return $_[0] },
952             },
953             },
954             0.5 => {
955             Name => 'AFAreaZoneSize',
956             Mask => 0xf0000,
957             PrintConv => {
958             0 => 'n/a',
959             OTHER => sub {
960             my ($val, $inv) = @_;
961             return "$val x $val" unless $inv;
962             $val =~ s/ ?x.*//;
963             return $val;
964             },
965             },
966             },
967             );
968              
969             # AF-C settings, tag 0x102e (ref forum 9607)
970             %Image::ExifTool::FujiFilm::AFCSettings = (
971             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
972             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
973             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
974             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
975             FORMAT => 'int32u',
976             WRITABLE => 1,
977             0 => {
978             Name => 'AF-CSetting',
979             PrintHex => 3,
980             PrintSort => 1, # sort PrintConv by value
981             # decode in-camera preset values (X-T3)
982             PrintConv => {
983             0x102 => 'Set 1 (multi-purpose)', # (2,0,Auto)
984             0x203 => 'Set 2 (ignore obstacles)', # (3,0,Center)
985             0x122 => 'Set 3 (accelerating subject)', # (2,2,Auto)
986             0x010 => 'Set 4 (suddenly appearing subject)', # (0,1,Front)
987             0x123 => 'Set 5 (erratic motion)', # (3,2,Auto)
988             OTHER => sub {
989             my ($val, $inv) = @_;
990             return $val =~ /(0x\w+)/ ? hex $1 : undef if $inv;
991             return sprintf 'Set 6 (custom 0x%.3x)', $val;
992             },
993             },
994             },
995             0.1 => {
996             Name => 'AF-CTrackingSensitivity',
997             Mask => 0x000f, # (values 0-4)
998             },
999             0.2 => {
1000             Name => 'AF-CSpeedTrackingSensitivity',
1001             Mask => 0x00f0,
1002             # (values 0-2)
1003             },
1004             0.3 => {
1005             Name => 'AF-CZoneAreaSwitching',
1006             Mask => 0x0f00,
1007             PrintConv => {
1008             0 => 'Front',
1009             1 => 'Auto',
1010             2 => 'Center',
1011             },
1012             },
1013             );
1014              
1015             # DriveMode settings, tag 0x1103 (X-T3, ref forum 9607)
1016             %Image::ExifTool::FujiFilm::DriveSettings = (
1017             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1018             WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
1019             CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
1020             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
1021             FORMAT => 'int32u',
1022             WRITABLE => 1,
1023             0.1 => {
1024             Name => 'DriveMode',
1025             Mask => 0x000000ff,
1026             PrintConv => {
1027             0 => 'Single',
1028             1 => 'Continuous Low',
1029             2 => 'Continuous High',
1030             },
1031             },
1032             0.2 => {
1033             Name => 'DriveSpeed',
1034             Mask => 0xff000000,
1035             PrintConv => {
1036             0 => 'n/a',
1037             OTHER => sub {
1038             my ($val, $inv) = @_;
1039             return "$val fps" unless $inv;
1040             $val =~ s/ ?fps$//;
1041             return $val;
1042             },
1043             },
1044             },
1045             );
1046              
1047             # Face recognition information from FinePix F550EXR (ref PH)
1048             %Image::ExifTool::FujiFilm::FaceRecInfo = (
1049             PROCESS_PROC => \&ProcessFaceRec,
1050             GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
1051             VARS => { NO_ID => 1 },
1052             NOTES => 'Face recognition information.',
1053             Face1Name => { },
1054             Face2Name => { },
1055             Face3Name => { },
1056             Face4Name => { },
1057             Face5Name => { },
1058             Face6Name => { },
1059             Face7Name => { },
1060             Face8Name => { },
1061             Face1Category => { %faceCategories },
1062             Face2Category => { %faceCategories },
1063             Face3Category => { %faceCategories },
1064             Face4Category => { %faceCategories },
1065             Face5Category => { %faceCategories },
1066             Face6Category => { %faceCategories },
1067             Face7Category => { %faceCategories },
1068             Face8Category => { %faceCategories },
1069             Face1Birthday => { },
1070             Face2Birthday => { },
1071             Face3Birthday => { },
1072             Face4Birthday => { },
1073             Face5Birthday => { },
1074             Face6Birthday => { },
1075             Face7Birthday => { },
1076             Face8Birthday => { },
1077             );
1078              
1079             # tags in RAF images (ref 5)
1080             %Image::ExifTool::FujiFilm::RAF = (
1081             PROCESS_PROC => \&ProcessFujiDir,
1082             GROUPS => { 0 => 'RAF', 1 => 'RAF', 2 => 'Image' },
1083             PRIORITY => 0, # so the first RAF directory takes precedence
1084             NOTES => q{
1085             FujiFilm RAF images contain meta information stored in a proprietary
1086             FujiFilm RAF format, as well as EXIF information stored inside an embedded
1087             JPEG preview image. The table below lists tags currently decoded from the
1088             RAF-format information.
1089             },
1090             0x100 => {
1091             Name => 'RawImageFullSize',
1092             Format => 'int16u',
1093             Groups => { 1 => 'RAF2' }, # (so RAF2 shows up in family 1 list)
1094             Count => 2,
1095             Notes => 'including borders',
1096             ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first
1097             PrintConv => '$val=~tr/ /x/; $val',
1098             },
1099             0x110 => {
1100             Name => 'RawImageCropTopLeft',
1101             Format => 'int16u',
1102             Count => 2,
1103             Notes => 'top margin first, then left margin',
1104             },
1105             0x111 => {
1106             Name => 'RawImageCroppedSize',
1107             Format => 'int16u',
1108             Count => 2,
1109             Notes => 'including borders',
1110             ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first
1111             PrintConv => '$val=~tr/ /x/; $val',
1112             },
1113             0x115 => {
1114             Name => 'RawImageAspectRatio',
1115             Format => 'int16u',
1116             Count => 2,
1117             ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first
1118             PrintConv => '$val=~tr/ /:/; $val',
1119             },
1120             0x121 => [
1121             {
1122             Name => 'RawImageSize',
1123             Condition => '$$self{Model} eq "FinePixS2Pro"',
1124             Format => 'int16u',
1125             Count => 2,
1126             ValueConv => q{
1127             my @v=split(" ",$val);
1128             $v[0]*=2, $v[1]/=2;
1129             return "@v";
1130             },
1131             PrintConv => '$val=~tr/ /x/; $val',
1132             },
1133             {
1134             Name => 'RawImageSize',
1135             Format => 'int16u',
1136             Count => 2,
1137             # values are height then width, adjusted for the layout
1138             ValueConv => q{
1139             my @v=reverse split(" ",$val);
1140             $$self{FujiLayout} and $v[0]/=2, $v[1]*=2;
1141             return "@v";
1142             },
1143             PrintConv => '$val=~tr/ /x/; $val',
1144             },
1145             ],
1146             0x130 => {
1147             Name => 'FujiLayout',
1148             Format => 'int8u',
1149             RawConv => q{
1150             my ($v) = split ' ', $val;
1151             $$self{FujiLayout} = $v & 0x80 ? 1 : 0;
1152             return $val;
1153             },
1154             },
1155             0x131 => { #5
1156             Name => 'XTransLayout',
1157             Description => 'X-Trans Layout',
1158             Format => 'int8u',
1159             Count => 36,
1160             PrintConv => '$val =~ tr/012 /RGB/d; join " ", $val =~ /....../g',
1161             },
1162             0x2000 => { #IB
1163             Name => 'WB_GRGBLevelsAuto',
1164             Format => 'int16u',
1165             Count => 4, # (ignore the duplicate values)
1166             },
1167             0x2100 => { #IB
1168             Name => 'WB_GRGBLevelsDaylight',
1169             Format => 'int16u',
1170             Count => 4,
1171             },
1172             0x2200 => { #IB
1173             Name => 'WB_GRGBLevelsCloudy',
1174             Format => 'int16u',
1175             Count => 4,
1176             },
1177             0x2300 => { #IB
1178             Name => 'WB_GRGBLevelsDaylightFluor',
1179             Format => 'int16u',
1180             Count => 4,
1181             },
1182             0x2301 => { #IB
1183             Name => 'WB_GRGBLevelsDayWhiteFluor',
1184             Format => 'int16u',
1185             Count => 4,
1186             },
1187             0x2302 => { #IB
1188             Name => 'WB_GRGBLevelsWhiteFluorescent',
1189             Format => 'int16u',
1190             Count => 4,
1191             },
1192             0x2310 => { #IB
1193             Name => 'WB_GRGBLevelsWarmWhiteFluor',
1194             Format => 'int16u',
1195             Count => 4,
1196             },
1197             0x2311 => { #IB
1198             Name => 'WB_GRGBLevelsLivingRoomWarmWhiteFluor',
1199             Format => 'int16u',
1200             Count => 4,
1201             },
1202             0x2400 => { #IB
1203             Name => 'WB_GRGBLevelsTungsten',
1204             Format => 'int16u',
1205             Count => 4,
1206             },
1207             # 0x2f00 => WB_GRGBLevelsCustom: int32u count, then count * (int16u GRGBGRGB), ref IB
1208             0x2ff0 => {
1209             Name => 'WB_GRGBLevels',
1210             Format => 'int16u',
1211             Count => 4,
1212             },
1213             0x9200 => { #Frank Markesteijn
1214             Name => 'RelativeExposure',
1215             Format => 'rational32s',
1216             ValueConv => 'log($val) / log(2)',
1217             ValueConvInv => 'exp($val * log(2))',
1218             PrintConv => '$val ? sprintf("%+.1f",$val) : 0',
1219             PrintConvInv => '$val',
1220             },
1221             # 0x9200 - relative exposure? (ref Frank Markesteijn)
1222             0x9650 => { #Frank Markesteijn
1223             Name => 'RawExposureBias',
1224             Format => 'rational32s',
1225             PrintConv => '$val ? sprintf("%+.1f",$val) : 0',
1226             PrintConvInv => '$val',
1227             },
1228             0xc000 => {
1229             Name => 'RAFData',
1230             SubDirectory => {
1231             TagTable => 'Image::ExifTool::FujiFilm::RAFData',
1232             ByteOrder => 'Little-endian',
1233             }
1234             },
1235             );
1236              
1237             %Image::ExifTool::FujiFilm::RAFData = (
1238             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1239             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
1240             DATAMEMBER => [ 0, 4, 8 ],
1241             FIRST_ENTRY => 0,
1242             # (FujiFilm image dimensions are REALLY confusing)
1243             # --> this needs some cleaning up
1244             # [Note to self: See email from Iliah Borg for more information about WB settings in this data]
1245             0 => {
1246             Name => 'RawImageWidth',
1247             Format => 'int32u',
1248             DataMember => 'FujiWidth',
1249             RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #5
1250             ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
1251             },
1252             4 => [
1253             {
1254             Name => 'RawImageWidth',
1255             Condition => 'not $$self{FujiWidth}',
1256             Format => 'int32u',
1257             DataMember => 'FujiWidth',
1258             RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #PH
1259             ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
1260             },
1261             {
1262             Name => 'RawImageHeight',
1263             Format => 'int32u',
1264             DataMember => 'FujiHeight',
1265             RawConv => '$$self{FujiHeight} = $val',
1266             ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
1267             },
1268             ],
1269             8 => [
1270             {
1271             Name => 'RawImageWidth',
1272             Condition => 'not $$self{FujiWidth}',
1273             Format => 'int32u',
1274             DataMember => 'FujiWidth',
1275             RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #PH
1276             ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
1277             },
1278             {
1279             Name => 'RawImageHeight',
1280             Condition => 'not $$self{FujiHeight}',
1281             Format => 'int32u',
1282             DataMember => 'FujiHeight',
1283             RawConv => '$$self{FujiHeight} = $val',
1284             ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
1285             },
1286             ],
1287             12 => {
1288             Name => 'RawImageHeight',
1289             Condition => 'not $$self{FujiHeight}',
1290             Format => 'int32u',
1291             ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
1292             },
1293             );
1294              
1295             # TIFF IFD-format information stored in FujiFilm RAF images (ref 5)
1296             %Image::ExifTool::FujiFilm::IFD = (
1297             PROCESS_PROC => \&Image::ExifTool::Exif::ProcessExif,
1298             GROUPS => { 0 => 'RAF', 1 => 'FujiIFD', 2 => 'Image' },
1299             NOTES => 'Tags found in the FujiIFD information of RAF images from some models.',
1300             0xf000 => {
1301             Name => 'FujiIFD',
1302             Groups => { 1 => 'FujiIFD' },
1303             Flags => 'SubIFD',
1304             SubDirectory => {
1305             TagTable => 'Image::ExifTool::FujiFilm::IFD',
1306             DirName => 'FujiSubIFD',
1307             Start => '$val',
1308             },
1309             },
1310             0xf001 => 'RawImageFullWidth',
1311             0xf002 => 'RawImageFullHeight',
1312             0xf003 => 'BitsPerSample',
1313             # 0xf004 - values: 4
1314             # 0xf005 - values: 1374, 1668
1315             # 0xf006 - some sort of flag indicating packed format?
1316             0xf007 => {
1317             Name => 'StripOffsets',
1318             IsOffset => 1,
1319             OffsetPair => 0xf008, # point to associated byte counts
1320             },
1321             0xf008 => {
1322             Name => 'StripByteCounts',
1323             OffsetPair => 0xf007, # point to associated offsets
1324             },
1325             # 0xf009 - values: 0, 3
1326             0xf00a => 'BlackLevel', #IB
1327             0xf00b => 'GeometricDistortionParams', #9 (rational64s[23, 35 or 43])
1328             0xf00c => 'WB_GRBLevelsStandard', #IB (GRBXGRBX; X=17 is standard illuminant A, X=21 is D65)
1329             0xf00d => 'WB_GRBLevelsAuto', #IB
1330             0xf00e => 'WB_GRBLevels',
1331             0xf00f => 'ChromaticAberrationParams', # (rational64s[23])
1332             0xf010 => 'VignettingParams', #9 (rational64s[31 or 64])
1333             );
1334              
1335             # information found in FFMV atom of MOV videos
1336             %Image::ExifTool::FujiFilm::FFMV = (
1337             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1338             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
1339             FIRST_ENTRY => 0,
1340             NOTES => 'Information found in the FFMV atom of MOV videos.',
1341             0 => {
1342             Name => 'MovieStreamName',
1343             Format => 'string[34]',
1344             },
1345             );
1346              
1347             # tags in FujiFilm QuickTime videos (ref PH)
1348             # (similar information in Kodak,Minolta,Nikon,Olympus,Pentax and Sanyo videos)
1349             %Image::ExifTool::FujiFilm::MOV = (
1350             PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
1351             GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
1352             FIRST_ENTRY => 0,
1353             NOTES => 'This information is found in MOV videos from some FujiFilm cameras.',
1354             0x00 => {
1355             Name => 'Make',
1356             Format => 'string[24]',
1357             },
1358             0x18 => {
1359             Name => 'Model',
1360             Description => 'Camera Model Name',
1361             Format => 'string[16]',
1362             },
1363             0x2e => { # (NC)
1364             Name => 'ExposureTime',
1365             Format => 'int32u',
1366             ValueConv => '$val ? 1 / $val : 0',
1367             PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
1368             },
1369             0x32 => {
1370             Name => 'FNumber',
1371             Format => 'rational64u',
1372             PrintConv => 'sprintf("%.1f",$val)',
1373             },
1374             0x3a => { # (NC)
1375             Name => 'ExposureCompensation',
1376             Format => 'rational64s',
1377             PrintConv => '$val ? sprintf("%+.1f", $val) : 0',
1378             },
1379             );
1380              
1381             #------------------------------------------------------------------------------
1382             # decode information from FujiFilm face recognition information
1383             # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
1384             # Returns: 1
1385             sub ProcessFaceRec($$$)
1386             {
1387 0     0 0 0 my ($et, $dirInfo, $tagTablePtr) = @_;
1388 0         0 my $dataPt = $$dirInfo{DataPt};
1389 0   0     0 my $dataPos = $$dirInfo{DataPos} + ($$dirInfo{Base} || 0);
1390 0         0 my $dirStart = $$dirInfo{DirStart};
1391 0         0 my $dirLen = $$dirInfo{DirLen};
1392 0         0 my $pos = $dirStart;
1393 0         0 my $end = $dirStart + $dirLen;
1394 0         0 my ($i, $n, $p, $val);
1395 0         0 $et->VerboseDir('FaceRecInfo');
1396 0         0 for ($i=1; ; ++$i) {
1397 0 0       0 last if $pos + 8 > $end;
1398 0         0 my $off = Get32u($dataPt, $pos) + $dirStart;
1399 0         0 my $len = Get32u($dataPt, $pos + 4);
1400 0 0 0     0 last if $len==0 or $off>$end or $off+$len>$end or $len < 62;
      0        
      0        
1401             # values observed for each offset (always zero if not listed):
1402             # 0=5; 3=1; 4=4; 6=1; 10-13=numbers(constant for a given registered face)
1403             # 15=16; 16=3; 18=1; 22=nameLen; 26=1; 27=16; 28=7; 30-33=nameLen(int32u)
1404             # 34-37=nameOffset(int32u); 38=32; 39=16; 40=4; 42=1; 46=0,2,4,8(category)
1405             # 50=33; 51=16; 52=7; 54-57=dateLen(int32u); 58-61=dateOffset(int32u)
1406 0         0 $n = Get32u($dataPt, $off + 30);
1407 0         0 $p = Get32u($dataPt, $off + 34) + $dirStart;
1408 0 0 0     0 last if $p < $dirStart or $p + $n > $end;
1409 0         0 $val = substr($$dataPt, $p, $n);
1410 0         0 $et->HandleTag($tagTablePtr, "Face${i}Name", $val,
1411             DataPt => $dataPt,
1412             DataPos => $dataPos,
1413             Start => $p,
1414             Size => $n,
1415             );
1416 0         0 $n = Get32u($dataPt, $off + 54);
1417 0         0 $p = Get32u($dataPt, $off + 58) + $dirStart;
1418 0 0 0     0 last if $p < $dirStart or $p + $n > $end;
1419 0         0 $val = substr($$dataPt, $p, $n);
1420 0         0 $val =~ s/(\d{4})(\d{2})(\d{2})/$1:$2:$2/;
1421 0         0 $et->HandleTag($tagTablePtr, "Face${i}Birthday", $val,
1422             DataPt => $dataPt,
1423             DataPos => $dataPos,
1424             Start => $p,
1425             Size => $n,
1426             );
1427 0         0 $et->HandleTag($tagTablePtr, "Face${i}Category", undef,
1428             DataPt => $dataPt,
1429             DataPos => $dataPos,
1430             Start => $off + 46,
1431             Size => 1,
1432             );
1433 0         0 $pos += 8;
1434             }
1435 0         0 return 1;
1436             }
1437              
1438             #------------------------------------------------------------------------------
1439             # get information from FujiFilm RAF directory
1440             # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
1441             # Returns: 1 if this was a valid FujiFilm directory
1442             sub ProcessFujiDir($$$)
1443             {
1444 6     6 0 13 my ($et, $dirInfo, $tagTablePtr) = @_;
1445 6         13 my $raf = $$dirInfo{RAF};
1446 6         10 my $offset = $$dirInfo{DirStart};
1447 6 50       18 $raf->Seek($offset, 0) or return 0;
1448 6         13 my ($buff, $index);
1449 6 50       16 $raf->Read($buff, 4) or return 0;
1450 6         16 my $entries = unpack 'N', $buff;
1451 6 50       24 $entries < 256 or return 0;
1452 6 50       16 $et->Options('Verbose') and $et->VerboseDir('Fuji', $entries);
1453 6         21 SetByteOrder('MM');
1454 6         19 my $pos = $offset + 4;
1455 6         19 for ($index=0; $index<$entries; ++$index) {
1456 792 50       1513 $raf->Read($buff,4) or return 0;
1457 792         963 $pos += 4;
1458 792         1597 my ($tag, $len) = unpack 'nn', $buff;
1459 792         1008 my ($val, $vbuf);
1460 792 50       1236 $raf->Read($vbuf, $len) or return 0;
1461 792         1404 my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
1462 792 100 66     1818 if ($tagInfo and $$tagInfo{Format}) {
    100          
1463 102         257 $val = ReadValue(\$vbuf, 0, $$tagInfo{Format}, $$tagInfo{Count}, $len);
1464 102 50       242 next unless defined $val;
1465             } elsif ($len == 4) {
1466             # interpret unknown 4-byte values as int32u
1467 234         405 $val = Get32u(\$vbuf, 0);
1468             } else {
1469             # treat other unknown values as binary data
1470 456         612 $val = \$vbuf;
1471             }
1472 792         1883 $et->HandleTag($tagTablePtr, $tag, $val,
1473             Index => $index,
1474             DataPt => \$vbuf,
1475             DataPos => $pos,
1476             Size => $len,
1477             TagInfo => $tagInfo,
1478             );
1479 792         1572 $pos += $len;
1480             }
1481 6         12 return 1;
1482             }
1483              
1484             #------------------------------------------------------------------------------
1485             # write information to FujiFilm RAW file (RAF)
1486             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
1487             # Returns: 1 on success, 0 if this wasn't a valid RAF file, or -1 on write error
1488             sub WriteRAF($$)
1489             {
1490 2     2 0 6 my ($et, $dirInfo) = @_;
1491 2         6 my $raf = $$dirInfo{RAF};
1492 2         4 my ($hdr, $jpeg, $outJpeg, $offset, $err, $buff);
1493              
1494 2 50       7 $raf->Read($hdr,0x94) == 0x94 or return 0;
1495 2 50       14 $hdr =~ /^FUJIFILM/ or return 0;
1496 2         7 my $ver = substr($hdr, 0x3c, 4);
1497 2 0 33     10 $ver =~ /^\d{4}$/ or $testedRAF{$ver} or return 0;
1498              
1499             # get the position and size of embedded JPEG
1500 2         11 my ($jpos, $jlen) = unpack('x84NN', $hdr);
1501             # check to be sure the JPEG starts in the expected location
1502 2 50 33     33 if ($jpos > 0x94 or $jpos < 0x68 or $jpos & 0x03) {
      33        
1503 0         0 $et->Error("Unsupported or corrupted RAF image (version $ver)");
1504 0         0 return 1;
1505             }
1506             # check to make sure this version of RAF has been tested
1507             #(removed in ExifTool 11.70)
1508             #unless ($testedRAF{$ver}) {
1509             # $et->Warn("RAF version $ver not yet tested", 1);
1510             #}
1511             # read the embedded JPEG
1512 2 50 33     9 unless ($raf->Seek($jpos, 0) and $raf->Read($jpeg, $jlen) == $jlen) {
1513 0         0 $et->Error('Error reading RAF meta information');
1514 0         0 return 1;
1515             }
1516             # use same write directories as JPEG
1517 2         13 $et->InitWriteDirs('JPEG');
1518             # rewrite the embedded JPEG in memory
1519 2         10 my %jpegInfo = (
1520             Parent => 'RAF',
1521             RAF => new File::RandomAccess(\$jpeg),
1522             OutFile => \$outJpeg,
1523             );
1524 2         5 $$et{FILE_TYPE} = 'JPEG';
1525 2         11 my $success = $et->WriteJPEG(\%jpegInfo);
1526 2         7 $$et{FILE_TYPE} = 'RAF';
1527 2 50 33     11 unless ($success and $outJpeg) {
1528 0         0 $et->Error("Invalid RAF format");
1529 0         0 return 1;
1530             }
1531 2 50       7 return -1 if $success < 0;
1532              
1533             # rewrite the RAF image
1534 2         8 SetByteOrder('MM');
1535 2         4 my $jpegLen = length $outJpeg;
1536             # pad JPEG to an even 4 bytes (ALWAYS use padding as Fuji does)
1537 2         8 my $pad = "\0" x (4 - ($jpegLen % 4));
1538             # update JPEG size in header (size without padding)
1539 2         9 Set32u(length($outJpeg), \$hdr, 0x58);
1540             # get pointer to start of the next RAF block
1541 2         7 my $nextPtr = Get32u(\$hdr, 0x5c);
1542             # determine the length of padding at the end of the original JPEG
1543 2         7 my $oldPadLen = $nextPtr - ($jpos + $jlen);
1544 2 50       5 if ($oldPadLen) {
1545 2 50 33     17 if ($oldPadLen > 1000000 or $oldPadLen < 0 or
      33        
      33        
1546             not $raf->Seek($jpos+$jlen, 0) or
1547             $raf->Read($buff, $oldPadLen) != $oldPadLen)
1548             {
1549 0         0 $et->Error('Bad RAF pointer at 0x5c');
1550 0         0 return 1;
1551             }
1552             # make sure padding is only zero bytes (can be >100k for HS10)
1553             # (have seen non-null padding in X-Pro1)
1554 2 50       12 if ($buff =~ /[^\0]/) {
1555 0 0       0 return 1 if $et->Error('Non-null bytes found in padding', 2);
1556             }
1557             }
1558             # calculate offset difference due to change in JPEG size
1559 2         7 my $ptrDiff = length($outJpeg) + length($pad) - ($jlen + $oldPadLen);
1560             # update necessary pointers in header
1561 2         6 foreach $offset (0x5c, 0x64, 0x78, 0x80) {
1562 8 50       19 last if $offset >= $jpos; # some versions have a short header
1563 8         14 my $oldPtr = Get32u(\$hdr, $offset);
1564 8 50       18 next unless $oldPtr; # don't update if pointer is zero
1565 8         14 Set32u($oldPtr + $ptrDiff, \$hdr, $offset);
1566             }
1567             # write the new header
1568 2         5 my $outfile = $$dirInfo{OutFile};
1569 2 50       10 Write($outfile, substr($hdr, 0, $jpos)) or $err = 1;
1570             # write the updated JPEG plus padding
1571 2 50       33 Write($outfile, $outJpeg, $pad) or $err = 1;
1572             # copy over the rest of the RAF image
1573 2 50       11 unless ($raf->Seek($nextPtr, 0)) {
1574 0         0 $et->Error('Error reading RAF image');
1575 0         0 return 1;
1576             }
1577 2         9 while ($raf->Read($buff, 65536)) {
1578 2 50       9 Write($outfile, $buff) or $err = 1, last;
1579             }
1580 2 50       16 return $err ? -1 : 1;
1581             }
1582              
1583             #------------------------------------------------------------------------------
1584             # get information from FujiFilm RAW file (RAF)
1585             # Inputs: 0) ExifTool object reference, 1) dirInfo reference
1586             # Returns: 1 if this was a valid RAF file
1587             sub ProcessRAF($$)
1588             {
1589 3     3 0 9 my ($et, $dirInfo) = @_;
1590 3         8 my ($buff, $jpeg, $warn, $offset);
1591              
1592 3         9 my $raf = $$dirInfo{RAF};
1593 3 50       10 $raf->Read($buff,0x5c) == 0x5c or return 0;
1594 3 50       17 $buff =~ /^FUJIFILM/ or return 0;
1595 3         17 my ($jpos, $jlen) = unpack('x84NN', $buff);
1596 3 50       11 $jpos & 0x8000 and return 0;
1597 3 50       11 $raf->Seek($jpos, 0) or return 0;
1598 3 50       14 $raf->Read($jpeg, $jlen) == $jlen or return 0;
1599              
1600 3         16 $et->SetFileType();
1601 3         18 $et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
1602              
1603             # extract information from embedded JPEG
1604 3         14 my %dirInfo = (
1605             Parent => 'RAF',
1606             RAF => new File::RandomAccess(\$jpeg),
1607             );
1608 3         9 $$et{BASE} += $jpos;
1609 3         13 my $rtnVal = $et->ProcessJPEG(\%dirInfo);
1610 3         8 $$et{BASE} -= $jpos;
1611 3 50       18 $et->FoundTag('PreviewImage', \$jpeg) if $rtnVal;
1612              
1613             # extract information from Fuji RAF and TIFF directories
1614 3         22 my ($rafNum, $ifdNum) = ('','');
1615 3         12 foreach $offset (0x5c, 0x64, 0x78, 0x80) {
1616 12 50       25 last if $offset >= $jpos;
1617 12 50 33     32 unless ($raf->Seek($offset, 0) and $raf->Read($buff, 4)) {
1618 0         0 $warn = 1;
1619 0         0 last;
1620             }
1621 12         35 my $start = unpack('N',$buff);
1622 12 50       25 next unless $start;
1623 12 100 100     58 if ($offset == 0x64 or $offset == 0x80) {
1624             # parse FujiIFD directory
1625 6         22 %dirInfo = (
1626             RAF => $raf,
1627             Base => $start,
1628             );
1629 6         20 $$et{SET_GROUP1} = "FujiIFD$ifdNum";
1630 6         18 my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::IFD');
1631             # this is TIFF-format data only for some models, so no warning if it fails
1632 6         28 $et->ProcessTIFF(\%dirInfo, $tagTablePtr, \&Image::ExifTool::ProcessTIFF);
1633 6         12 delete $$et{SET_GROUP1};
1634 6   100     34 $ifdNum = ($ifdNum || 1) + 1;
1635             } else {
1636             # parse RAF directory
1637 6         28 %dirInfo = (
1638             RAF => $raf,
1639             DirStart => $start,
1640             );
1641 6         20 $$et{SET_GROUP1} = "RAF$rafNum";
1642 6         18 my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::RAF');
1643 6 50       18 $et->ProcessDirectory(\%dirInfo, $tagTablePtr) or $warn = 1;
1644 6         21 delete $$et{SET_GROUP1};
1645 6   100     22 $rafNum = ($rafNum || 1) + 1;
1646             }
1647             }
1648 3 50       11 $warn and $et->Warn('Possibly corrupt RAF information');
1649              
1650 3         10 return $rtnVal;
1651             }
1652              
1653             1; # end
1654              
1655             __END__