"Fossies" - the Fresh Open Source Software Archive

Member "Image-ExifTool-12.24/lib/Image/ExifTool/FujiFilm.pm" (13 Apr 2021, 55703 Bytes) of package /linux/misc/Image-ExifTool-12.24.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "FujiFilm.pm" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 12.23_vs_12.24.

    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 use strict;
   30 use vars qw($VERSION);
   31 use Image::ExifTool qw(:DataAccess :Utils);
   32 use Image::ExifTool::Exif;
   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 => [{
  493         Name => 'AutoBracketing',
  494         Condition => '$$self{Model} eq "X-T3"',
  495         Notes => 'X-T3 only',
  496         Writable => 'int16u',
  497         PrintConv => {
  498             0 => 'Off',
  499             1 => 'On',
  500             2 => 'Pre-shot', #12 (Electronic Shutter and Continuous High drive mode only)
  501         },
  502     },{
  503         Name => 'AutoBracketing',
  504         Notes => 'other models',
  505         Writable => 'int16u',
  506         PrintConv => {
  507             0 => 'Off',
  508             1 => 'On',
  509             2 => 'No flash & flash', #3
  510             6 => 'Pixel Shift', #IB (GFX100S)
  511         },
  512     }],
  513     0x1101 => {
  514         Name => 'SequenceNumber',
  515         Writable => 'int16u',
  516     },
  517     0x1103 => {
  518         Name => 'DriveSettings',
  519         SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::DriveSettings' },
  520     },
  521     0x1105 => { Name => 'PixelShiftShots',  Writable => 'int16u' }, #IB
  522     0x1106 => { Name => 'PixelShiftOffset', Writable => 'rational64s', Count => 2 }, #IB
  523     # (0x1150-0x1152 exist only for Pro Low-light and Pro Focus PictureModes)
  524     # 0x1150 - Pro Low-light - val=1; Pro Focus - val=2 (ref 7); HDR - val=128 (forum10799)
  525     # 0x1151 - Pro Low-light - val=4 (number of pictures taken?); Pro Focus - val=2,3 (ref 7); HDR - val=3 (forum10799)
  526     # 0x1152 - Pro Low-light - val=1,3,4 (stacked pictures used?); Pro Focus - val=1,2 (ref 7); HDR - val=3 (forum10799)
  527     0x1153 => { #forum7668
  528         Name => 'PanoramaAngle',
  529         Writable => 'int16u',
  530     },
  531     0x1154 => { #forum7668
  532         Name => 'PanoramaDirection',
  533         Writable => 'int16u',
  534         PrintConv => {
  535             1 => 'Right',
  536             2 => 'Up',
  537             3 => 'Left',
  538             4 => 'Down',
  539         },
  540     },
  541     0x1201 => { #forum6109
  542         Name => 'AdvancedFilter',
  543         Writable => 'int32u',
  544         PrintHex => 1,
  545         PrintConv => {
  546             0x10000 => 'Pop Color',
  547             0x20000 => 'Hi Key',
  548             0x30000 => 'Toy Camera',
  549             0x40000 => 'Miniature',
  550             0x50000 => 'Dynamic Tone',
  551             0x60001 => 'Partial Color Red',
  552             0x60002 => 'Partial Color Yellow',
  553             0x60003 => 'Partial Color Green',
  554             0x60004 => 'Partial Color Blue',
  555             0x60005 => 'Partial Color Orange',
  556             0x60006 => 'Partial Color Purple',
  557             0x70000 => 'Soft Focus',
  558             0x90000 => 'Low Key',
  559         },
  560     },
  561     0x1210 => { #2
  562         Name => 'ColorMode',
  563         Writable => 'int16u',
  564         PrintHex => 1,
  565         PrintConv => {
  566             0x00 => 'Standard',
  567             0x10 => 'Chrome',
  568             0x30 => 'B & W',
  569         },
  570     },
  571     0x1300 => {
  572         Name => 'BlurWarning',
  573         Writable => 'int16u',
  574         PrintConv => {
  575             0 => 'None',
  576             1 => 'Blur Warning',
  577         },
  578     },
  579     0x1301 => {
  580         Name => 'FocusWarning',
  581         Writable => 'int16u',
  582         PrintConv => {
  583             0 => 'Good',
  584             1 => 'Out of focus',
  585         },
  586     },
  587     0x1302 => {
  588         Name => 'ExposureWarning',
  589         Writable => 'int16u',
  590         PrintConv => {
  591             0 => 'Good',
  592             1 => 'Bad exposure',
  593         },
  594     },
  595     0x1304 => { #PH
  596         Name => 'GEImageSize',
  597         Condition => '$$self{Make} =~ /^GENERAL IMAGING/',
  598         Writable => 'string',
  599         Notes => 'GE models only',
  600     },
  601     0x1400 => { #2
  602         Name => 'DynamicRange',
  603         Writable => 'int16u',
  604         PrintConv => {
  605             1 => 'Standard',
  606             3 => 'Wide',
  607             # the S5Pro has 100%(STD),130%,170%,230%(W1),300%,400%(W2) - PH
  608         },
  609     },
  610     0x1401 => { #2 (this doesn't seem to work for the X100 - PH)
  611         Name => 'FilmMode',
  612         Writable => 'int16u',
  613         PrintHex => 1,
  614         PrintConv => {
  615             0x000 => 'F0/Standard (Provia)', # X-Pro2 "Provia/Standard"
  616             0x100 => 'F1/Studio Portrait',
  617             0x110 => 'F1a/Studio Portrait Enhanced Saturation',
  618             0x120 => 'F1b/Studio Portrait Smooth Skin Tone (Astia)', # X-Pro2 "Astia/Soft"
  619             0x130 => 'F1c/Studio Portrait Increased Sharpness',
  620             0x200 => 'F2/Fujichrome (Velvia)', # X-Pro2 "Velvia/Vivid"
  621             0x300 => 'F3/Studio Portrait Ex',
  622             0x400 => 'F4/Velvia',
  623             0x500 => 'Pro Neg. Std', #PH (X-Pro1)
  624             0x501 => 'Pro Neg. Hi', #PH (X-Pro1)
  625             0x600 => 'Classic Chrome', #forum6109
  626             0x700 => 'Eterna', #12
  627             0x800 => 'Classic Negative', #forum10536
  628             0x900 => 'Bleach Bypass', #forum10890
  629             0xa00 => 'Nostalgic Neg', #forum12085
  630         },
  631     },
  632     0x1402 => { #2
  633         Name => 'DynamicRangeSetting',
  634         Writable => 'int16u',
  635         PrintHex => 1,
  636         PrintConv => {
  637             0x000 => 'Auto',
  638             0x001 => 'Manual', #(ref http://forum.photome.de/viewtopic.php?f=2&t=353)
  639             0x100 => 'Standard (100%)',
  640             0x200 => 'Wide1 (230%)',
  641             0x201 => 'Wide2 (400%)',
  642             0x8000 => 'Film Simulation',
  643         },
  644     },
  645     0x1403 => { #2 (only valid for manual DR, ref 6)
  646         Name => 'DevelopmentDynamicRange',
  647         Writable => 'int16u',
  648         # (shows 200, 400 or 800 for HDR200,HDR400,HDR800, ref forum10799)
  649     },
  650     0x1404 => { #2
  651         Name => 'MinFocalLength',
  652         Writable => 'rational64s',
  653     },
  654     0x1405 => { #2
  655         Name => 'MaxFocalLength',
  656         Writable => 'rational64s',
  657     },
  658     0x1406 => { #2
  659         Name => 'MaxApertureAtMinFocal',
  660         Writable => 'rational64s',
  661     },
  662     0x1407 => { #2
  663         Name => 'MaxApertureAtMaxFocal',
  664         Writable => 'rational64s',
  665     },
  666     # 0x1408 - values: '0100', 'S100', 'VQ10'
  667     # 0x1409 - values: same as 0x1408
  668     # 0x140a - values: 0, 1, 3, 5, 7 (bit 2=red-eye detection, ref 11/13)
  669     0x140b => { #6
  670         Name => 'AutoDynamicRange',
  671         Writable => 'int16u',
  672         PrintConv => '"$val%"',
  673         PrintConvInv => '$val=~s/\s*\%$//; $val',
  674     },
  675     0x104e => { #forum10800 (X-Pro3)
  676         Name => 'ColorChromeFXBlue',
  677         Writable => 'int32s',
  678         PrintConv => {
  679             0 => 'Off',
  680             32 => 'Weak', # (NC)
  681             64 => 'Strong',
  682         },
  683     },
  684     0x1422 => { #8
  685         Name => 'ImageStabilization',
  686         Writable => 'int16u',
  687         Count => 3,
  688         PrintConv => [{
  689             0 => 'None',
  690             1 => 'Optical', #PH
  691             2 => 'Sensor-shift', #PH
  692             3 => 'OIS Lens', #forum9815 (optical+sensor?)
  693             512 => 'Digital', #PH
  694         },{
  695             0 => 'Off',
  696             1 => 'On (mode 1, continuous)',
  697             2 => 'On (mode 2, shooting only)',
  698         }],
  699     },
  700     0x1425 => { # if present and 0x1031 PictureMode is zero, then PictureMode is SR+, not Auto (ref 11)
  701         Name => 'SceneRecognition',
  702         Writable => 'int16u',
  703         PrintHex => 1,
  704         PrintConv => {
  705             0 => 'Unrecognized',
  706             0x100 => 'Portrait Image',
  707             0x103 => 'Night Portrait', #forum10651
  708             0x105 => 'Backlit Portrait', #forum10651
  709             0x200 => 'Landscape Image',
  710             0x300 => 'Night Scene',
  711             0x400 => 'Macro',
  712         },
  713     },
  714     0x1431 => { #forum6109
  715         Name => 'Rating',
  716         Groups => { 2 => 'Image' },
  717         Writable => 'int32u',
  718         Priority => 0,
  719     },
  720     0x1436 => { #8
  721         Name => 'ImageGeneration',
  722         Writable => 'int16u',
  723         PrintConv => {
  724             0 => 'Original Image',
  725             1 => 'Re-developed from RAW',
  726         },
  727     },
  728     0x1438 => { #forum6579 (X-T1 firmware version 3)
  729         Name => 'ImageCount',
  730         Notes => 'may reset to 0 when new firmware is installed',
  731         Writable => 'int16u',
  732         ValueConv => '$val & 0x7fff',
  733         ValueConvInv => '$val | 0x8000',
  734     },
  735     0x1443 => { #12 (X-T3)
  736         Name => 'DRangePriority',
  737         Writable => 'int16u',
  738         PrintConv => { 0 => 'Auto', 1 => 'Fixed' },
  739     },
  740     0x1444 => { #12 (X-T3, only exists if DRangePriority is 'Auto')
  741         Name => 'DRangePriorityAuto',
  742         Writable => 'int16u',
  743         PrintConv => {
  744             1 => 'Weak',
  745             2 => 'Strong',
  746             3 => 'Plus',    #forum10799
  747         },
  748     },
  749     0x1445 => { #12 (X-T3, only exists if DRangePriority is 'Fixed')
  750         Name => 'DRangePriorityFixed',
  751         Writable => 'int16u',
  752         PrintConv => { 1 => 'Weak', 2 => 'Strong' },
  753     },
  754     0x1446 => { #12
  755         Name => 'FlickerReduction',
  756         Writable => 'int32u',
  757         # seen values: Off=0x0000, On=0x2100,0x3100
  758         PrintConv => q{
  759             my $on = ((($val >> 8) & 0x0f) == 1) ? 'On' : 'Off';
  760             return sprintf('%s (0x%.4x)', $on, $val);
  761         },
  762         PrintConvInv => '$val=~/(0x[0-9a-f]+)/i; hex $1',
  763     },
  764     0x3803 => { #forum10037
  765         Name => 'VideoRecordingMode',
  766         Groups => { 2 => 'Video' },
  767         Writable => 'int32u',
  768         PrintHex => 1,
  769         PrintConv => {
  770             0x00 => 'Normal',
  771             0x10 => 'F-log',
  772             0x20 => 'HLG',
  773         },
  774     },
  775     0x3804 => { #forum10037
  776         Name => 'PeripheralLighting',
  777         Groups => { 2 => 'Video' },
  778         Writable => 'int16u',
  779         PrintConv => { 0 => 'Off', 1 => 'On' },
  780     },
  781     # 0x3805 - int16u: seen 1
  782     0x3806 => { #forum10037
  783         Name => 'VideoCompression',
  784         Groups => { 2 => 'Video' },
  785         Writable => 'int16u',
  786         PrintConv => {
  787             1 => 'Log GOP',
  788             2 => 'All Intra',
  789         },
  790     },
  791     # 0x3810 - int32u: related to video codec (ref forum10037)
  792     0x3820 => { #PH (HS20EXR MOV)
  793         Name => 'FrameRate',
  794         Writable => 'int16u',
  795         Groups => { 2 => 'Video' },
  796     },
  797     0x3821 => { #PH (HS20EXR MOV)
  798         Name => 'FrameWidth',
  799         Writable => 'int16u',
  800         Groups => { 2 => 'Video' },
  801     },
  802     0x3822 => { #PH (HS20EXR MOV)
  803         Name => 'FrameHeight',
  804         Writable => 'int16u',
  805         Groups => { 2 => 'Video' },
  806     },
  807     0x3824 => { #forum10480 (X series)
  808         Name => 'FullHDHighSpeedRec',
  809         Writable => 'int32u',
  810         Groups => { 2 => 'Video' },
  811         PrintConv => { 1 => 'Off', 2 => 'On' },
  812     },
  813     0x4005 => { #forum9634
  814         Name => 'FaceElementSelected', # (could be face or eye)
  815         Writable => 'int16u',
  816         Count => 4,
  817     },
  818     0x4100 => { #PH
  819         Name => 'FacesDetected',
  820         Writable => 'int16u',
  821     },
  822     0x4103 => { #PH
  823         Name => 'FacePositions',
  824         Writable => 'int16u',
  825         Count => -1,
  826         Notes => q{
  827             left, top, right and bottom coordinates in full-sized image for each face
  828             detected
  829         },
  830     },
  831     0x4200 => { #11
  832         Name => 'NumFaceElements',
  833         Writable => 'int16u',
  834     },
  835     0x4201 => { #11
  836         Name => 'FaceElementTypes',
  837         Writable => 'int8u',
  838         Count => -1,
  839         PrintConv => [{
  840             1 => 'Face',
  841             2 => 'Left Eye',
  842             3 => 'Right Eye',
  843         },'REPEAT'],
  844     },
  845     # 0x4202 int8u[-1] - number of cooredinates in each rectangle? (ref 11)
  846     0x4203 => { #11
  847         Name => 'FaceElementPositions',
  848         Writable => 'int16u',
  849         Count => -1,
  850         Notes => q{
  851             left, top, right and bottom coordinates in full-sized image for each face
  852             element
  853         },
  854     },
  855     # 0x4101-0x4105 - exist only if face detection active
  856     # 0x4104 - also related to face detection (same number of entries as FacePositions)
  857     # 0x4200 - same as 0x4100?
  858     # 0x4203 - same as 0x4103
  859     # 0x4204 - same as 0x4104
  860     0x4282 => { #PH
  861         Name => 'FaceRecInfo',
  862         SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::FaceRecInfo' },
  863     },
  864     0x8000 => { #2
  865         Name => 'FileSource',
  866         Writable => 'string',
  867     },
  868     0x8002 => { #2
  869         Name => 'OrderNumber',
  870         Writable => 'int32u',
  871     },
  872     0x8003 => { #2
  873         Name => 'FrameNumber',
  874         Writable => 'int16u',
  875     },
  876     0xb211 => { #PH
  877         Name => 'Parallax',
  878         # (value set in camera is -0.5 times this value in MPImage2... why?)
  879         Writable => 'rational64s',
  880         Notes => 'only found in MPImage2 of .MPO images',
  881     },
  882     # 0xb212 - also found in MPIMage2 images - PH
  883 );
  884 
  885 # Focus Priority settings, tag 0x102b (X-T3, ref forum 9607)
  886 %Image::ExifTool::FujiFilm::PrioritySettings = (
  887     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  888     WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
  889     CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
  890     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  891     FORMAT => 'int16u',
  892     WRITABLE => 1,
  893     0.1 => {
  894         Name => 'AF-SPriority',
  895         Mask => 0x000f,
  896         PrintConv => {
  897             1 => 'Release',
  898             2 => 'Focus',
  899         },
  900     },
  901     0.2 => {
  902         Name => 'AF-CPriority',
  903         Mask => 0x00f0,
  904         PrintConv => {
  905             1 => 'Release',
  906             2 => 'Focus',
  907         },
  908     },
  909 );
  910 
  911 # Focus settings, tag 0x102d (X-T3, ref forum 9607)
  912 %Image::ExifTool::FujiFilm::FocusSettings = (
  913     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  914     WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
  915     CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
  916     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  917     FORMAT => 'int32u',
  918     WRITABLE => 1,
  919     0.1 => {
  920         Name => 'FocusMode2',
  921         Mask => 0x0000000f,
  922         PrintConv => {
  923             0x0 => 'AF-M',
  924             0x1 => 'AF-S',
  925             0x2 => 'AF-C',
  926         },
  927     },
  928     0.2 => {
  929         Name => 'PreAF',
  930         Mask => 0x00f0,
  931         PrintConv => {
  932             0 => 'Off',
  933             1 => 'On',
  934         },
  935     },
  936     0.3 => {
  937         Name => 'AFAreaMode',
  938         Mask => 0x0f00,
  939         PrintConv => {
  940             0 => 'Single Point',
  941             1 => 'Zone',
  942             2 => 'Wide/Tracking',
  943         },
  944     },
  945     0.4 => {
  946         Name => 'AFAreaPointSize',
  947         Mask => 0xf000,
  948         PrintConv => {
  949             0 => 'n/a',
  950             OTHER => sub { return $_[0] },
  951         },
  952     },
  953     0.5 => {
  954         Name => 'AFAreaZoneSize',
  955         Mask => 0xf0000,
  956         PrintConv => {
  957             0 => 'n/a',
  958             OTHER => sub {
  959                 my ($val, $inv) = @_;
  960                 return "$val x $val" unless $inv;
  961                 $val =~ s/ ?x.*//;
  962                 return $val;
  963             },
  964         },
  965     },
  966 );
  967 
  968 # AF-C settings, tag 0x102e (ref forum 9607)
  969 %Image::ExifTool::FujiFilm::AFCSettings = (
  970     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
  971     WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
  972     CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
  973     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
  974     FORMAT => 'int32u',
  975     WRITABLE => 1,
  976     0 => {
  977         Name => 'AF-CSetting',
  978         PrintHex => 3,
  979         PrintSort => 1, # sort PrintConv by value
  980         # decode in-camera preset values (X-T3)
  981         PrintConv => {
  982             0x102 => 'Set 1 (multi-purpose)',              # (2,0,Auto)
  983             0x203 => 'Set 2 (ignore obstacles)',           # (3,0,Center)
  984             0x122 => 'Set 3 (accelerating subject)',       # (2,2,Auto)
  985             0x010 => 'Set 4 (suddenly appearing subject)', # (0,1,Front)
  986             0x123 => 'Set 5 (erratic motion)',             # (3,2,Auto)
  987             OTHER => sub {
  988                 my ($val, $inv) = @_;
  989                 return $val =~ /(0x\w+)/ ? hex $1 : undef if $inv;
  990                 return sprintf 'Set 6 (custom 0x%.3x)', $val;
  991             },
  992         },
  993     },
  994     0.1 => {
  995         Name => 'AF-CTrackingSensitivity',
  996         Mask => 0x000f, # (values 0-4)
  997     },
  998     0.2 => {
  999         Name => 'AF-CSpeedTrackingSensitivity',
 1000         Mask => 0x00f0,
 1001         # (values 0-2)
 1002     },
 1003     0.3 => {
 1004         Name => 'AF-CZoneAreaSwitching',
 1005         Mask => 0x0f00,
 1006         PrintConv => {
 1007             0 => 'Front',
 1008             1 => 'Auto',
 1009             2 => 'Center',
 1010         },
 1011     },
 1012 );
 1013 
 1014 # DriveMode settings, tag 0x1103 (X-T3, ref forum 9607)
 1015 %Image::ExifTool::FujiFilm::DriveSettings = (
 1016     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
 1017     WRITE_PROC => \&Image::ExifTool::WriteBinaryData,
 1018     CHECK_PROC => \&Image::ExifTool::CheckBinaryData,
 1019     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
 1020     FORMAT => 'int32u',
 1021     WRITABLE => 1,
 1022     0.1 => {
 1023         Name => 'DriveMode',
 1024         Mask => 0x000000ff,
 1025         PrintConv => {
 1026             0 => 'Single',
 1027             1 => 'Continuous Low',
 1028             2 => 'Continuous High',
 1029         },
 1030     },
 1031     0.2 => {
 1032         Name => 'DriveSpeed',
 1033         Mask => 0xff000000,
 1034         PrintConv => {
 1035             0 => 'n/a',
 1036             OTHER => sub {
 1037                 my ($val, $inv) = @_;
 1038                 return "$val fps" unless $inv;
 1039                 $val =~ s/ ?fps$//;
 1040                 return $val;
 1041             },
 1042         },
 1043     },
 1044 );
 1045 
 1046 # Face recognition information from FinePix F550EXR (ref PH)
 1047 %Image::ExifTool::FujiFilm::FaceRecInfo = (
 1048     PROCESS_PROC => \&ProcessFaceRec,
 1049     GROUPS => { 0 => 'MakerNotes', 2 => 'Image' },
 1050     VARS => { NO_ID => 1 },
 1051     NOTES => 'Face recognition information.',
 1052     Face1Name => { },
 1053     Face2Name => { },
 1054     Face3Name => { },
 1055     Face4Name => { },
 1056     Face5Name => { },
 1057     Face6Name => { },
 1058     Face7Name => { },
 1059     Face8Name => { },
 1060     Face1Category => { %faceCategories },
 1061     Face2Category => { %faceCategories },
 1062     Face3Category => { %faceCategories },
 1063     Face4Category => { %faceCategories },
 1064     Face5Category => { %faceCategories },
 1065     Face6Category => { %faceCategories },
 1066     Face7Category => { %faceCategories },
 1067     Face8Category => { %faceCategories },
 1068     Face1Birthday => { },
 1069     Face2Birthday => { },
 1070     Face3Birthday => { },
 1071     Face4Birthday => { },
 1072     Face5Birthday => { },
 1073     Face6Birthday => { },
 1074     Face7Birthday => { },
 1075     Face8Birthday => { },
 1076 );
 1077 
 1078 # tags in RAF images (ref 5)
 1079 %Image::ExifTool::FujiFilm::RAF = (
 1080     PROCESS_PROC => \&ProcessFujiDir,
 1081     GROUPS => { 0 => 'RAF', 1 => 'RAF', 2 => 'Image' },
 1082     PRIORITY => 0, # so the first RAF directory takes precedence
 1083     NOTES => q{
 1084         FujiFilm RAF images contain meta information stored in a proprietary
 1085         FujiFilm RAF format, as well as EXIF information stored inside an embedded
 1086         JPEG preview image.  The table below lists tags currently decoded from the
 1087         RAF-format information.
 1088     },
 1089     0x100 => {
 1090         Name => 'RawImageFullSize',
 1091         Format => 'int16u',
 1092         Groups => { 1 => 'RAF2' }, # (so RAF2 shows up in family 1 list)
 1093         Count => 2,
 1094         Notes => 'including borders',
 1095         ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first
 1096         PrintConv => '$val=~tr/ /x/; $val',
 1097     },
 1098     0x110 => {
 1099         Name => 'RawImageCropTopLeft',
 1100         Format => 'int16u',
 1101         Count => 2,
 1102         Notes => 'top margin first, then left margin',
 1103     },
 1104     0x111 => {
 1105         Name => 'RawImageCroppedSize',
 1106         Format => 'int16u',
 1107         Count => 2,
 1108         Notes => 'including borders',
 1109         ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first
 1110         PrintConv => '$val=~tr/ /x/; $val',
 1111     },
 1112     0x115 => {
 1113         Name => 'RawImageAspectRatio',
 1114         Format => 'int16u',
 1115         Count => 2,
 1116         ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first
 1117         PrintConv => '$val=~tr/ /:/; $val',
 1118     },
 1119     0x121 => [
 1120         {
 1121             Name => 'RawImageSize',
 1122             Condition => '$$self{Model} eq "FinePixS2Pro"',
 1123             Format => 'int16u',
 1124             Count => 2,
 1125             ValueConv => q{
 1126                 my @v=split(" ",$val);
 1127                 $v[0]*=2, $v[1]/=2;
 1128                 return "@v";
 1129             },
 1130             PrintConv => '$val=~tr/ /x/; $val',
 1131         },
 1132         {
 1133             Name => 'RawImageSize',
 1134             Format => 'int16u',
 1135             Count => 2,
 1136             # values are height then width, adjusted for the layout
 1137             ValueConv => q{
 1138                 my @v=reverse split(" ",$val);
 1139                 $$self{FujiLayout} and $v[0]/=2, $v[1]*=2;
 1140                 return "@v";
 1141             },
 1142             PrintConv => '$val=~tr/ /x/; $val',
 1143         },
 1144     ],
 1145     0x130 => {
 1146         Name => 'FujiLayout',
 1147         Format => 'int8u',
 1148         RawConv => q{
 1149             my ($v) = split ' ', $val;
 1150             $$self{FujiLayout} = $v & 0x80 ? 1 : 0;
 1151             return $val;
 1152         },
 1153     },
 1154     0x131 => { #5
 1155         Name => 'XTransLayout',
 1156         Description => 'X-Trans Layout',
 1157         Format => 'int8u',
 1158         Count => 36,
 1159         PrintConv => '$val =~ tr/012 /RGB/d; join " ", $val =~ /....../g',
 1160     },
 1161     0x2000 => { #IB
 1162         Name => 'WB_GRGBLevelsAuto',
 1163         Format => 'int16u',
 1164         Count => 4, # (ignore the duplicate values)
 1165     },
 1166     0x2100 => { #IB
 1167         Name => 'WB_GRGBLevelsDaylight',
 1168         Format => 'int16u',
 1169         Count => 4,
 1170     },
 1171     0x2200 => { #IB
 1172         Name => 'WB_GRGBLevelsCloudy',
 1173         Format => 'int16u',
 1174         Count => 4,
 1175     },
 1176     0x2300 => { #IB
 1177         Name => 'WB_GRGBLevelsDaylightFluor',
 1178         Format => 'int16u',
 1179         Count => 4,
 1180     },
 1181     0x2301 => { #IB
 1182         Name => 'WB_GRGBLevelsDayWhiteFluor',
 1183         Format => 'int16u',
 1184         Count => 4,
 1185     },
 1186     0x2302 => { #IB
 1187         Name => 'WB_GRGBLevelsWhiteFluorescent',
 1188         Format => 'int16u',
 1189         Count => 4,
 1190     },
 1191     0x2310 => { #IB
 1192         Name => 'WB_GRGBLevelsWarmWhiteFluor',
 1193         Format => 'int16u',
 1194         Count => 4,
 1195     },
 1196     0x2311 => { #IB
 1197         Name => 'WB_GRGBLevelsLivingRoomWarmWhiteFluor',
 1198         Format => 'int16u',
 1199         Count => 4,
 1200     },
 1201     0x2400 => { #IB
 1202         Name => 'WB_GRGBLevelsTungsten',
 1203         Format => 'int16u',
 1204         Count => 4,
 1205     },
 1206     # 0x2f00 => WB_GRGBLevelsCustom: int32u count, then count * (int16u GRGBGRGB), ref IB
 1207     0x2ff0 => {
 1208         Name => 'WB_GRGBLevels',
 1209         Format => 'int16u',
 1210         Count => 4,
 1211     },
 1212     0x9200 => { #Frank Markesteijn
 1213         Name => 'RelativeExposure',
 1214         Format => 'rational32s',
 1215         ValueConv => 'log($val) / log(2)',
 1216         ValueConvInv => 'exp($val * log(2))',
 1217         PrintConv => '$val ? sprintf("%+.1f",$val) : 0',
 1218         PrintConvInv => '$val',
 1219     },
 1220     # 0x9200 - relative exposure? (ref Frank Markesteijn)
 1221     0x9650 => { #Frank Markesteijn
 1222         Name => 'RawExposureBias',
 1223         Format => 'rational32s',
 1224         PrintConv => '$val ? sprintf("%+.1f",$val) : 0',
 1225         PrintConvInv => '$val',
 1226     },
 1227     0xc000 => {
 1228         Name => 'RAFData',
 1229         SubDirectory => {
 1230             TagTable => 'Image::ExifTool::FujiFilm::RAFData',
 1231             ByteOrder => 'Little-endian',
 1232         }
 1233     },
 1234 );
 1235 
 1236 %Image::ExifTool::FujiFilm::RAFData = (
 1237     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
 1238     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
 1239     DATAMEMBER => [ 0, 4, 8 ],
 1240     FIRST_ENTRY => 0,
 1241     # (FujiFilm image dimensions are REALLY confusing)
 1242     # --> this needs some cleaning up
 1243     # [Note to self: See email from Iliah Borg for more information about WB settings in this data]
 1244     0 => {
 1245         Name => 'RawImageWidth',
 1246         Format => 'int32u',
 1247         DataMember => 'FujiWidth',
 1248         RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #5
 1249         ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
 1250     },
 1251     4 => [
 1252         {
 1253             Name => 'RawImageWidth',
 1254             Condition => 'not $$self{FujiWidth}',
 1255             Format => 'int32u',
 1256             DataMember => 'FujiWidth',
 1257             RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #PH
 1258             ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
 1259         },
 1260         {
 1261             Name => 'RawImageHeight',
 1262             Format => 'int32u',
 1263             DataMember => 'FujiHeight',
 1264             RawConv => '$$self{FujiHeight} = $val',
 1265             ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
 1266         },
 1267     ],
 1268     8 => [
 1269         {
 1270             Name => 'RawImageWidth',
 1271             Condition => 'not $$self{FujiWidth}',
 1272             Format => 'int32u',
 1273             DataMember => 'FujiWidth',
 1274             RawConv => '$val < 10000 ? $$self{FujiWidth} = $val : undef', #PH
 1275             ValueConv => '$$self{FujiLayout} ? ($val / 2) : $val',
 1276         },
 1277         {
 1278             Name => 'RawImageHeight',
 1279             Condition => 'not $$self{FujiHeight}',
 1280             Format => 'int32u',
 1281             DataMember => 'FujiHeight',
 1282             RawConv => '$$self{FujiHeight} = $val',
 1283             ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
 1284         },
 1285     ],
 1286     12 => {
 1287         Name => 'RawImageHeight',
 1288         Condition => 'not $$self{FujiHeight}',
 1289         Format => 'int32u',
 1290         ValueConv => '$$self{FujiLayout} ? ($val * 2) : $val',
 1291     },
 1292 );
 1293 
 1294 # TIFF IFD-format information stored in FujiFilm RAF images (ref 5)
 1295 %Image::ExifTool::FujiFilm::IFD = (
 1296     PROCESS_PROC => \&Image::ExifTool::Exif::ProcessExif,
 1297     GROUPS => { 0 => 'RAF', 1 => 'FujiIFD', 2 => 'Image' },
 1298     NOTES => 'Tags found in the FujiIFD information of RAF images from some models.',
 1299     0xf000 => {
 1300         Name => 'FujiIFD',
 1301         Groups => { 1 => 'FujiIFD' },
 1302         Flags => 'SubIFD',
 1303         SubDirectory => {
 1304             TagTable => 'Image::ExifTool::FujiFilm::IFD',
 1305             DirName => 'FujiSubIFD',
 1306             Start => '$val',
 1307         },
 1308     },
 1309     0xf001 => 'RawImageFullWidth',
 1310     0xf002 => 'RawImageFullHeight',
 1311     0xf003 => 'BitsPerSample',
 1312     # 0xf004 - values: 4
 1313     # 0xf005 - values: 1374, 1668
 1314     # 0xf006 - some sort of flag indicating packed format?
 1315     0xf007 => {
 1316         Name => 'StripOffsets',
 1317         IsOffset => 1,
 1318         OffsetPair => 0xf008,  # point to associated byte counts
 1319     },
 1320     0xf008 => {
 1321         Name => 'StripByteCounts',
 1322         OffsetPair => 0xf007,  # point to associated offsets
 1323     },
 1324     # 0xf009 - values: 0, 3
 1325     0xf00a => 'BlackLevel', #IB
 1326     0xf00b => 'GeometricDistortionParams', #9 (rational64s[23, 35 or 43])
 1327     0xf00c => 'WB_GRBLevelsStandard', #IB (GRBXGRBX; X=17 is standard illuminant A, X=21 is D65)
 1328     0xf00d => 'WB_GRBLevelsAuto', #IB
 1329     0xf00e => 'WB_GRBLevels',
 1330     0xf00f => 'ChromaticAberrationParams', # (rational64s[23])
 1331     0xf010 => 'VignettingParams', #9 (rational64s[31 or 64])
 1332 );
 1333 
 1334 # information found in FFMV atom of MOV videos
 1335 %Image::ExifTool::FujiFilm::FFMV = (
 1336     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
 1337     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
 1338     FIRST_ENTRY => 0,
 1339     NOTES => 'Information found in the FFMV atom of MOV videos.',
 1340     0 => {
 1341         Name => 'MovieStreamName',
 1342         Format => 'string[34]',
 1343     },
 1344 );
 1345 
 1346 # tags in FujiFilm QuickTime videos (ref PH)
 1347 # (similar information in Kodak,Minolta,Nikon,Olympus,Pentax and Sanyo videos)
 1348 %Image::ExifTool::FujiFilm::MOV = (
 1349     PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData,
 1350     GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' },
 1351     FIRST_ENTRY => 0,
 1352     NOTES => 'This information is found in MOV videos from some FujiFilm cameras.',
 1353     0x00 => {
 1354         Name => 'Make',
 1355         Format => 'string[24]',
 1356     },
 1357     0x18 => {
 1358         Name => 'Model',
 1359         Description => 'Camera Model Name',
 1360         Format => 'string[16]',
 1361     },
 1362     0x2e => { # (NC)
 1363         Name => 'ExposureTime',
 1364         Format => 'int32u',
 1365         ValueConv => '$val ? 1 / $val : 0',
 1366         PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)',
 1367     },
 1368     0x32 => {
 1369         Name => 'FNumber',
 1370         Format => 'rational64u',
 1371         PrintConv => 'sprintf("%.1f",$val)',
 1372     },
 1373     0x3a => { # (NC)
 1374         Name => 'ExposureCompensation',
 1375         Format => 'rational64s',
 1376         PrintConv => '$val ? sprintf("%+.1f", $val) : 0',
 1377     },
 1378 );
 1379 
 1380 #------------------------------------------------------------------------------
 1381 # decode information from FujiFilm face recognition information
 1382 # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
 1383 # Returns: 1
 1384 sub ProcessFaceRec($$$)
 1385 {
 1386     my ($et, $dirInfo, $tagTablePtr) = @_;
 1387     my $dataPt = $$dirInfo{DataPt};
 1388     my $dataPos = $$dirInfo{DataPos} + ($$dirInfo{Base} || 0);
 1389     my $dirStart = $$dirInfo{DirStart};
 1390     my $dirLen = $$dirInfo{DirLen};
 1391     my $pos = $dirStart;
 1392     my $end = $dirStart + $dirLen;
 1393     my ($i, $n, $p, $val);
 1394     $et->VerboseDir('FaceRecInfo');
 1395     for ($i=1; ; ++$i) {
 1396         last if $pos + 8 > $end;
 1397         my $off = Get32u($dataPt, $pos) + $dirStart;
 1398         my $len = Get32u($dataPt, $pos + 4);
 1399         last if $len==0 or $off>$end or $off+$len>$end or $len < 62;
 1400         # values observed for each offset (always zero if not listed):
 1401         # 0=5; 3=1; 4=4; 6=1; 10-13=numbers(constant for a given registered face)
 1402         # 15=16; 16=3; 18=1; 22=nameLen; 26=1; 27=16; 28=7; 30-33=nameLen(int32u)
 1403         # 34-37=nameOffset(int32u); 38=32; 39=16; 40=4; 42=1; 46=0,2,4,8(category)
 1404         # 50=33; 51=16; 52=7; 54-57=dateLen(int32u); 58-61=dateOffset(int32u)
 1405         $n = Get32u($dataPt, $off + 30);
 1406         $p = Get32u($dataPt, $off + 34) + $dirStart;
 1407         last if $p < $dirStart or $p + $n > $end;
 1408         $val = substr($$dataPt, $p, $n);
 1409         $et->HandleTag($tagTablePtr, "Face${i}Name", $val,
 1410             DataPt  => $dataPt,
 1411             DataPos => $dataPos,
 1412             Start   => $p,
 1413             Size    => $n,
 1414         );
 1415         $n = Get32u($dataPt, $off + 54);
 1416         $p = Get32u($dataPt, $off + 58) + $dirStart;
 1417         last if $p < $dirStart or $p + $n > $end;
 1418         $val = substr($$dataPt, $p, $n);
 1419         $val =~ s/(\d{4})(\d{2})(\d{2})/$1:$2:$2/;
 1420         $et->HandleTag($tagTablePtr, "Face${i}Birthday", $val,
 1421             DataPt  => $dataPt,
 1422             DataPos => $dataPos,
 1423             Start   => $p,
 1424             Size    => $n,
 1425         );
 1426         $et->HandleTag($tagTablePtr, "Face${i}Category", undef,
 1427             DataPt  => $dataPt,
 1428             DataPos => $dataPos,
 1429             Start   => $off + 46,
 1430             Size    => 1,
 1431         );
 1432         $pos += 8;
 1433     }
 1434     return 1;
 1435 }
 1436 
 1437 #------------------------------------------------------------------------------
 1438 # get information from FujiFilm RAF directory
 1439 # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref
 1440 # Returns: 1 if this was a valid FujiFilm directory
 1441 sub ProcessFujiDir($$$)
 1442 {
 1443     my ($et, $dirInfo, $tagTablePtr) = @_;
 1444     my $raf = $$dirInfo{RAF};
 1445     my $offset = $$dirInfo{DirStart};
 1446     $raf->Seek($offset, 0) or return 0;
 1447     my ($buff, $index);
 1448     $raf->Read($buff, 4) or return 0;
 1449     my $entries = unpack 'N', $buff;
 1450     $entries < 256 or return 0;
 1451     $et->Options('Verbose') and $et->VerboseDir('Fuji', $entries);
 1452     SetByteOrder('MM');
 1453     my $pos = $offset + 4;
 1454     for ($index=0; $index<$entries; ++$index) {
 1455         $raf->Read($buff,4) or return 0;
 1456         $pos += 4;
 1457         my ($tag, $len) = unpack 'nn', $buff;
 1458         my ($val, $vbuf);
 1459         $raf->Read($vbuf, $len) or return 0;
 1460         my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag);
 1461         if ($tagInfo and $$tagInfo{Format}) {
 1462             $val = ReadValue(\$vbuf, 0, $$tagInfo{Format}, $$tagInfo{Count}, $len);
 1463             next unless defined $val;
 1464         } elsif ($len == 4) {
 1465             # interpret unknown 4-byte values as int32u
 1466             $val = Get32u(\$vbuf, 0);
 1467         } else {
 1468             # treat other unknown values as binary data
 1469             $val = \$vbuf;
 1470         }
 1471         $et->HandleTag($tagTablePtr, $tag, $val,
 1472             Index   => $index,
 1473             DataPt  => \$vbuf,
 1474             DataPos => $pos,
 1475             Size    => $len,
 1476             TagInfo => $tagInfo,
 1477         );
 1478         $pos += $len;
 1479     }
 1480     return 1;
 1481 }
 1482 
 1483 #------------------------------------------------------------------------------
 1484 # write information to FujiFilm RAW file (RAF)
 1485 # Inputs: 0) ExifTool object reference, 1) dirInfo reference
 1486 # Returns: 1 on success, 0 if this wasn't a valid RAF file, or -1 on write error
 1487 sub WriteRAF($$)
 1488 {
 1489     my ($et, $dirInfo) = @_;
 1490     my $raf = $$dirInfo{RAF};
 1491     my ($hdr, $jpeg, $outJpeg, $offset, $err, $buff);
 1492 
 1493     $raf->Read($hdr,0x94) == 0x94  or return 0;
 1494     $hdr =~ /^FUJIFILM/            or return 0;
 1495     my $ver = substr($hdr, 0x3c, 4);
 1496     $ver =~ /^\d{4}$/ or $testedRAF{$ver} or return 0;
 1497 
 1498     # get the position and size of embedded JPEG
 1499     my ($jpos, $jlen) = unpack('x84NN', $hdr);
 1500     # check to be sure the JPEG starts in the expected location
 1501     if ($jpos > 0x94 or $jpos < 0x68 or $jpos & 0x03) {
 1502         $et->Error("Unsupported or corrupted RAF image (version $ver)");
 1503         return 1;
 1504     }
 1505     # check to make sure this version of RAF has been tested
 1506     #(removed in ExifTool 11.70)
 1507     #unless ($testedRAF{$ver}) {
 1508     #    $et->Warn("RAF version $ver not yet tested", 1);
 1509     #}
 1510     # read the embedded JPEG
 1511     unless ($raf->Seek($jpos, 0) and $raf->Read($jpeg, $jlen) == $jlen) {
 1512         $et->Error('Error reading RAF meta information');
 1513         return 1;
 1514     }
 1515     # use same write directories as JPEG
 1516     $et->InitWriteDirs('JPEG');
 1517     # rewrite the embedded JPEG in memory
 1518     my %jpegInfo = (
 1519         Parent  => 'RAF',
 1520         RAF     => new File::RandomAccess(\$jpeg),
 1521         OutFile => \$outJpeg,
 1522     );
 1523     $$et{FILE_TYPE} = 'JPEG';
 1524     my $success = $et->WriteJPEG(\%jpegInfo);
 1525     $$et{FILE_TYPE} = 'RAF';
 1526     unless ($success and $outJpeg) {
 1527         $et->Error("Invalid RAF format");
 1528         return 1;
 1529     }
 1530     return -1 if $success < 0;
 1531 
 1532     # rewrite the RAF image
 1533     SetByteOrder('MM');
 1534     my $jpegLen = length $outJpeg;
 1535     # pad JPEG to an even 4 bytes (ALWAYS use padding as Fuji does)
 1536     my $pad = "\0" x (4 - ($jpegLen % 4));
 1537     # update JPEG size in header (size without padding)
 1538     Set32u(length($outJpeg), \$hdr, 0x58);
 1539     # get pointer to start of the next RAF block
 1540     my $nextPtr = Get32u(\$hdr, 0x5c);
 1541     # determine the length of padding at the end of the original JPEG
 1542     my $oldPadLen = $nextPtr - ($jpos + $jlen);
 1543     if ($oldPadLen) {
 1544         if ($oldPadLen > 1000000 or $oldPadLen < 0 or
 1545             not $raf->Seek($jpos+$jlen, 0) or
 1546             $raf->Read($buff, $oldPadLen) != $oldPadLen)
 1547         {
 1548             $et->Error('Bad RAF pointer at 0x5c');
 1549             return 1;
 1550         }
 1551         # make sure padding is only zero bytes (can be >100k for HS10)
 1552         # (have seen non-null padding in X-Pro1)
 1553         if ($buff =~ /[^\0]/) {
 1554             return 1 if $et->Error('Non-null bytes found in padding', 2);
 1555         }
 1556     }
 1557     # calculate offset difference due to change in JPEG size
 1558     my $ptrDiff = length($outJpeg) + length($pad) - ($jlen + $oldPadLen);
 1559     # update necessary pointers in header
 1560     foreach $offset (0x5c, 0x64, 0x78, 0x80) {
 1561         last if $offset >= $jpos;   # some versions have a short header
 1562         my $oldPtr = Get32u(\$hdr, $offset);
 1563         next unless $oldPtr;        # don't update if pointer is zero
 1564         Set32u($oldPtr + $ptrDiff, \$hdr, $offset);
 1565     }
 1566     # write the new header
 1567     my $outfile = $$dirInfo{OutFile};
 1568     Write($outfile, substr($hdr, 0, $jpos)) or $err = 1;
 1569     # write the updated JPEG plus padding
 1570     Write($outfile, $outJpeg, $pad) or $err = 1;
 1571     # copy over the rest of the RAF image
 1572     unless ($raf->Seek($nextPtr, 0)) {
 1573         $et->Error('Error reading RAF image');
 1574         return 1;
 1575     }
 1576     while ($raf->Read($buff, 65536)) {
 1577         Write($outfile, $buff) or $err = 1, last;
 1578     }
 1579     return $err ? -1 : 1;
 1580 }
 1581 
 1582 #------------------------------------------------------------------------------
 1583 # get information from FujiFilm RAW file (RAF)
 1584 # Inputs: 0) ExifTool object reference, 1) dirInfo reference
 1585 # Returns: 1 if this was a valid RAF file
 1586 sub ProcessRAF($$)
 1587 {
 1588     my ($et, $dirInfo) = @_;
 1589     my ($buff, $jpeg, $warn, $offset);
 1590 
 1591     my $raf = $$dirInfo{RAF};
 1592     $raf->Read($buff,0x5c) == 0x5c    or return 0;
 1593     $buff =~ /^FUJIFILM/              or return 0;
 1594     my ($jpos, $jlen) = unpack('x84NN', $buff);
 1595     $jpos & 0x8000                   and return 0;
 1596     $raf->Seek($jpos, 0)              or return 0;
 1597     $raf->Read($jpeg, $jlen) == $jlen or return 0;
 1598 
 1599     $et->SetFileType();
 1600     $et->FoundTag('RAFVersion', substr($buff, 0x3c, 4));
 1601 
 1602     # extract information from embedded JPEG
 1603     my %dirInfo = (
 1604         Parent => 'RAF',
 1605         RAF    => new File::RandomAccess(\$jpeg),
 1606     );
 1607     $$et{BASE} += $jpos;
 1608     my $rtnVal = $et->ProcessJPEG(\%dirInfo);
 1609     $$et{BASE} -= $jpos;
 1610     $et->FoundTag('PreviewImage', \$jpeg) if $rtnVal;
 1611 
 1612     # extract information from Fuji RAF and TIFF directories
 1613     my ($rafNum, $ifdNum) = ('','');
 1614     foreach $offset (0x5c, 0x64, 0x78, 0x80) {
 1615         last if $offset >= $jpos;
 1616         unless ($raf->Seek($offset, 0) and $raf->Read($buff, 4)) {
 1617             $warn = 1;
 1618             last;
 1619         }
 1620         my $start = unpack('N',$buff);
 1621         next unless $start;
 1622         if ($offset == 0x64 or $offset == 0x80) {
 1623             # parse FujiIFD directory
 1624             %dirInfo = (
 1625                 RAF  => $raf,
 1626                 Base => $start,
 1627             );
 1628             $$et{SET_GROUP1} = "FujiIFD$ifdNum";
 1629             my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::IFD');
 1630             # this is TIFF-format data only for some models, so no warning if it fails
 1631             $et->ProcessTIFF(\%dirInfo, $tagTablePtr, \&Image::ExifTool::ProcessTIFF);
 1632             delete $$et{SET_GROUP1};
 1633             $ifdNum = ($ifdNum || 1) + 1;
 1634         } else {
 1635             # parse RAF directory
 1636             %dirInfo = (
 1637                 RAF      => $raf,
 1638                 DirStart => $start,
 1639             );
 1640             $$et{SET_GROUP1} = "RAF$rafNum";
 1641             my $tagTablePtr = GetTagTable('Image::ExifTool::FujiFilm::RAF');
 1642             $et->ProcessDirectory(\%dirInfo, $tagTablePtr) or $warn = 1;
 1643             delete $$et{SET_GROUP1};
 1644             $rafNum = ($rafNum || 1) + 1;
 1645         }
 1646     }
 1647     $warn and $et->Warn('Possibly corrupt RAF information');
 1648 
 1649     return $rtnVal;
 1650 }
 1651 
 1652 1; # end
 1653 
 1654 __END__
 1655 
 1656 =head1 NAME
 1657 
 1658 Image::ExifTool::FujiFilm - Read/write FujiFilm maker notes and RAF images
 1659 
 1660 =head1 SYNOPSIS
 1661 
 1662 This module is loaded automatically by Image::ExifTool when required.
 1663 
 1664 =head1 DESCRIPTION
 1665 
 1666 This module contains definitions required by Image::ExifTool to interpret
 1667 FujiFilm maker notes in EXIF information, and to read/write FujiFilm RAW
 1668 (RAF) images.
 1669 
 1670 =head1 AUTHOR
 1671 
 1672 Copyright 2003-2021, Phil Harvey (philharvey66 at gmail.com)
 1673 
 1674 This library is free software; you can redistribute it and/or modify it
 1675 under the same terms as Perl itself.
 1676 
 1677 =head1 REFERENCES
 1678 
 1679 =over 4
 1680 
 1681 =item L<http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html>
 1682 
 1683 =item L<http://homepage3.nifty.com/kamisaka/makernote/makernote_fuji.htm>
 1684 
 1685 =item L<http://www.cybercom.net/~dcoffin/dcraw/>
 1686 
 1687 =item (...plus testing with my own FinePix 2400 Zoom)
 1688 
 1689 =back
 1690 
 1691 =head1 ACKNOWLEDGEMENTS
 1692 
 1693 Thanks to Michael Meissner, Paul Samuelson and Jens Duttke for help decoding
 1694 some FujiFilm information.
 1695 
 1696 =head1 SEE ALSO
 1697 
 1698 L<Image::ExifTool::TagNames/FujiFilm Tags>,
 1699 L<Image::ExifTool(3pm)|Image::ExifTool>
 1700 
 1701 =cut