| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Image::TIFF; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | # Copyright 1999-2001, Gisle Aas. | 
| 4 |  |  |  |  |  |  | # Copyright 2006, 2007 Tels | 
| 5 |  |  |  |  |  |  | # | 
| 6 |  |  |  |  |  |  | # This library is free software; you can redistribute it and/or | 
| 7 |  |  |  |  |  |  | # modify it under the same terms as Perl v5.8.8 itself. | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 9 |  |  | 9 |  | 54 | use strict; | 
|  | 9 |  |  |  |  | 14 |  | 
|  | 9 |  |  |  |  | 347 |  | 
| 10 | 9 |  |  | 9 |  | 48 | use vars qw($VERSION); | 
|  | 9 |  |  |  |  | 14 |  | 
|  | 9 |  |  |  |  | 8712 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | $VERSION = '1.11'; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | my @types = ( | 
| 15 |  |  |  |  |  |  | [ "BYTE",      "C1", 1], | 
| 16 |  |  |  |  |  |  | [ "ASCII",     "A1", 1], | 
| 17 |  |  |  |  |  |  | [ "SHORT",     "n1", 2], | 
| 18 |  |  |  |  |  |  | [ "LONG",      "N1", 4], | 
| 19 |  |  |  |  |  |  | [ "RATIONAL",  "N2", 8], | 
| 20 |  |  |  |  |  |  | [ "SBYTE",     "c1", 1], | 
| 21 |  |  |  |  |  |  | [ "UNDEFINED", "a1", 1], | 
| 22 |  |  |  |  |  |  | [ "BINARY",    "a1", 1],  # treat binary data as UNDEFINED | 
| 23 |  |  |  |  |  |  | [ "SSHORT",    "n1", 2], | 
| 24 |  |  |  |  |  |  | [ "SLONG",     "N1", 4], | 
| 25 |  |  |  |  |  |  | [ "SRATIONAL", "N2", 8], | 
| 26 |  |  |  |  |  |  | [ "FLOAT",     "f1", 4],  # XXX 4-byte IEEE format | 
| 27 |  |  |  |  |  |  | [ "DOUBLE",    "d1", 8],  # XXX 8-byte IEEE format | 
| 28 |  |  |  |  |  |  | # XXX TODO: | 
| 29 |  |  |  |  |  |  | #  [ "IFD",      "??", ?],  # See ExifTool | 
| 30 |  |  |  |  |  |  | ); | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | my %nikon1_tags = ( | 
| 33 |  |  |  |  |  |  | 0x0003 => "Quality", | 
| 34 |  |  |  |  |  |  | 0x0004 => "ColorMode", | 
| 35 |  |  |  |  |  |  | 0x0005 => "ImageAdjustment", | 
| 36 |  |  |  |  |  |  | 0x0006 => "CCDSensitivity", | 
| 37 |  |  |  |  |  |  | 0x0007 => "Whitebalance", | 
| 38 |  |  |  |  |  |  | 0x0008 => "Focus", | 
| 39 |  |  |  |  |  |  | 0x000A => "DigitalZoom", | 
| 40 |  |  |  |  |  |  | 0x000B => "Converter", | 
| 41 |  |  |  |  |  |  | ); | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | my %nikon2_tags = ( | 
| 44 |  |  |  |  |  |  | 0x0001 => "NikonVersion", | 
| 45 |  |  |  |  |  |  | 0x0002 => "ISOSetting", | 
| 46 |  |  |  |  |  |  | 0x0003 => "ColorMode", | 
| 47 |  |  |  |  |  |  | 0x0004 => "Quality", | 
| 48 |  |  |  |  |  |  | 0x0005 => "Whitebalance", | 
| 49 |  |  |  |  |  |  | 0x0006 => "ImageSharpening", | 
| 50 |  |  |  |  |  |  | 0x0007 => "FocusMode", | 
| 51 |  |  |  |  |  |  | 0x0008 => "FlashSetting", | 
| 52 |  |  |  |  |  |  | 0x0009 => "FlashMetering", | 
| 53 |  |  |  |  |  |  | 0x000B => "WBAdjustment", | 
| 54 |  |  |  |  |  |  | 0x000F => "ISOSelection", | 
| 55 |  |  |  |  |  |  | 0x0080 => "ImageAdjustment", | 
| 56 |  |  |  |  |  |  | 0x0082 => "AuxiliaryLens", | 
| 57 |  |  |  |  |  |  | 0x0084 => "Lens", | 
| 58 |  |  |  |  |  |  | 0x0085 => "ManualFocusDistance", | 
| 59 |  |  |  |  |  |  | 0x0086 => "DigitalZoom", | 
| 60 |  |  |  |  |  |  | 0x0088 => { __TAG__ => "AFFocusPosition", | 
| 61 |  |  |  |  |  |  | pack("xCxx",0) => "Center", | 
| 62 |  |  |  |  |  |  | pack("xCxx",1) => "Top", | 
| 63 |  |  |  |  |  |  | pack("xCxx",2) => "Bottom", | 
| 64 |  |  |  |  |  |  | pack("xCxx",3) => "Left", | 
| 65 |  |  |  |  |  |  | pack("xCxx",4) => "Right", | 
| 66 |  |  |  |  |  |  | }, | 
| 67 |  |  |  |  |  |  | 0x008d => "ColorMode", | 
| 68 |  |  |  |  |  |  | 0x0090 => "FlashType", | 
| 69 |  |  |  |  |  |  | 0x0095 => "NoiseReduction", | 
| 70 |  |  |  |  |  |  | 0x0010 => "DataDump", | 
| 71 |  |  |  |  |  |  | ); | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | my %olympus_tags = ( | 
| 74 |  |  |  |  |  |  | 0x0200 => "SpecialMode", | 
| 75 |  |  |  |  |  |  | 0x0201 => { __TAG__ => "JpegQual", 0 => "SQ", 1 => "HQ", 2 => "SHQ" }, | 
| 76 |  |  |  |  |  |  | 0x0202 => { __TAG__ => "Macro", 0 => "Normal", 1 => "Macro" }, | 
| 77 |  |  |  |  |  |  | 0x0204 => "DigiZoom", | 
| 78 |  |  |  |  |  |  | 0x0207 => "SoftwareRelease", | 
| 79 |  |  |  |  |  |  | 0x0208 => "PictInfo", | 
| 80 |  |  |  |  |  |  | 0x0209 => "CameraID", | 
| 81 |  |  |  |  |  |  | 0x0f00 => "DataDump", | 
| 82 |  |  |  |  |  |  | ); | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | my %fujifilm_tags = ( | 
| 85 |  |  |  |  |  |  | 0x0000 => "Version", | 
| 86 |  |  |  |  |  |  | 0x1000 => "Quality", | 
| 87 |  |  |  |  |  |  | 0x1001 => { __TAG__ => "Sharpness", | 
| 88 |  |  |  |  |  |  | 1 => "Very Soft", | 
| 89 |  |  |  |  |  |  | 2 => "Soft", | 
| 90 |  |  |  |  |  |  | 3 => "Normal", | 
| 91 |  |  |  |  |  |  | 4 => "Hard", | 
| 92 |  |  |  |  |  |  | 5 => "Very Hard", | 
| 93 |  |  |  |  |  |  | }, | 
| 94 |  |  |  |  |  |  | 0x1002 => { __TAG__ => "WhiteBalance", | 
| 95 |  |  |  |  |  |  | 0    => "Auto", | 
| 96 |  |  |  |  |  |  | 256  => "Daylight", | 
| 97 |  |  |  |  |  |  | 512  => "Cloudy", | 
| 98 |  |  |  |  |  |  | 768  => "DaylightColor-fluorescence", | 
| 99 |  |  |  |  |  |  | 769  => "DaywhiteColor-fluorescence", | 
| 100 |  |  |  |  |  |  | 770  => "White-fluorescence", | 
| 101 |  |  |  |  |  |  | 1024 => "Incandenscense", | 
| 102 |  |  |  |  |  |  | 3840 => "Custom white balance", | 
| 103 |  |  |  |  |  |  | }, | 
| 104 |  |  |  |  |  |  | 0x1003 => { __TAG__ => "Color", 0 => "Normal", 256 => "High", 512 => "Low" }, | 
| 105 |  |  |  |  |  |  | 0x1004 => { __TAG__ => "Tone" , 0 => "Normal", 256 => "High", 512 => "Low" }, | 
| 106 |  |  |  |  |  |  | 0x1010 => { __TAG__ => "FlashMode", 0 => "Auto", 1 => "On", 2 => "Off", 3 => "Red-eye reduction" }, | 
| 107 |  |  |  |  |  |  | 0x1011 => "FlashStrength", | 
| 108 |  |  |  |  |  |  | 0x1020 => { __TAG__ => "Macro", 0 => "Off", 1 => "On"}, | 
| 109 |  |  |  |  |  |  | 0x1021 => { __TAG__ => "FocusMode", 0 => "Auto", 1 => "Manual" }, | 
| 110 |  |  |  |  |  |  | 0x1030 => { __TAG__ => "SlowSync", 0 => "Off", 1 => "On"}, | 
| 111 |  |  |  |  |  |  | 0x1031 => { __TAG__ => "PictureMode", | 
| 112 |  |  |  |  |  |  | 0   => "Auto", | 
| 113 |  |  |  |  |  |  | 1   => "Portrait", | 
| 114 |  |  |  |  |  |  | 2   => "Landscape", | 
| 115 |  |  |  |  |  |  | 4   => "Sports", | 
| 116 |  |  |  |  |  |  | 5   => "Night", | 
| 117 |  |  |  |  |  |  | 6   => "Program AE", | 
| 118 |  |  |  |  |  |  | 256 => "Aperture priority", | 
| 119 |  |  |  |  |  |  | 512 => "Shutter priority", | 
| 120 |  |  |  |  |  |  | 768 => "Manual", | 
| 121 |  |  |  |  |  |  | }, | 
| 122 |  |  |  |  |  |  | 0x1100 => { __TAG__ => "AutoBracketing", 0 => "Off", 1 => "On"}, | 
| 123 |  |  |  |  |  |  | 0x1300 => { __TAG__ => "BlurWarning", 0 => "No", 1 => "Yes"}, | 
| 124 |  |  |  |  |  |  | 0x1301 => { __TAG__ => "FocusWarning", 0 => "No", 1 => "Yes"}, | 
| 125 |  |  |  |  |  |  | 0x1302 => { __TAG__ => "AEWarning", 0 => "No", 1 => "Yes"}, | 
| 126 |  |  |  |  |  |  | ); | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | my %casio_tags = ( | 
| 129 |  |  |  |  |  |  | 0x0001 => { __TAG__ => "RecordingMode", | 
| 130 |  |  |  |  |  |  | 1 => "SingleShutter", | 
| 131 |  |  |  |  |  |  | 2 => "Panorama", | 
| 132 |  |  |  |  |  |  | 3 => "Night scene", | 
| 133 |  |  |  |  |  |  | 4 => "Portrait", | 
| 134 |  |  |  |  |  |  | 5 => "Landscape", | 
| 135 |  |  |  |  |  |  | }, | 
| 136 |  |  |  |  |  |  | 0x0002 => { __TAG__ => "Quality", 1 => "Economy", 2 => "Normal", 3 => "Fine" }, | 
| 137 |  |  |  |  |  |  | 0x0003 => { __TAG__ => "FocusingMode", | 
| 138 |  |  |  |  |  |  | 2 => "Macro", | 
| 139 |  |  |  |  |  |  | 3 => "Auto", | 
| 140 |  |  |  |  |  |  | 4 => "Manual", | 
| 141 |  |  |  |  |  |  | 5 => "Infinity", | 
| 142 |  |  |  |  |  |  | }, | 
| 143 |  |  |  |  |  |  | 0x0004 => { __TAG__ => "FlashMode", 1 => "Auto", 2 => "On", 3 => "Off", 4 => "Red-eye reduction" }, | 
| 144 |  |  |  |  |  |  | 0x0005 => { __TAG__ => "FlashIntensity", 11 => "Weak", 13 => "Normal", 15 => "Strong" }, | 
| 145 |  |  |  |  |  |  | 0x0006 => "ObjectDistance", | 
| 146 |  |  |  |  |  |  | 0x0007 => { __TAG__ => "WhiteBalance", | 
| 147 |  |  |  |  |  |  | 1 => "Auto", | 
| 148 |  |  |  |  |  |  | 2 => "Tungsten", | 
| 149 |  |  |  |  |  |  | 3 => "Daylight", | 
| 150 |  |  |  |  |  |  | 4 => "Fluorescent", | 
| 151 |  |  |  |  |  |  | 5 => "Shade", | 
| 152 |  |  |  |  |  |  | 129 => "Manual", | 
| 153 |  |  |  |  |  |  | }, | 
| 154 |  |  |  |  |  |  | 0x000a => { __TAG__ => "DigitalZoom", 65536 => "Off", 65537 => "2X" }, | 
| 155 |  |  |  |  |  |  | 0x000b => { __TAG__ => "Sharpness", 0 => "Normal", 1 => "Soft", 2 => "Hard" }, | 
| 156 |  |  |  |  |  |  | 0x000c => { __TAG__ => "Contrast"  , 0 => "Normal", 1 => "Low", 2 => "High" }, | 
| 157 |  |  |  |  |  |  | 0x000d => { __TAG__ => "Saturation", 0 => "Normal", 1 => "Low", 2 => "High" }, | 
| 158 |  |  |  |  |  |  | 0x0014 => { __TAG__ => "CCDSensitivity", | 
| 159 |  |  |  |  |  |  | 64  => "Normal", | 
| 160 |  |  |  |  |  |  | 125 => "+1.0", | 
| 161 |  |  |  |  |  |  | 250 => "+2.0", | 
| 162 |  |  |  |  |  |  | 244 => "+3.0", | 
| 163 |  |  |  |  |  |  | 80  => "Normal", | 
| 164 |  |  |  |  |  |  | 100 => "High", | 
| 165 |  |  |  |  |  |  | }, | 
| 166 |  |  |  |  |  |  | ); | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | my %canon_0x0001_tags = ( | 
| 169 |  |  |  |  |  |  | 0 => { __TAG__ => "MacroMode", 1 => "Macro", 2 => "Normal" }, | 
| 170 |  |  |  |  |  |  | 1 => "SelfTimer", | 
| 171 |  |  |  |  |  |  | 2 => { __TAG__ => "Quality", 2 => "Normal", 3 => "Fine", 5 => "SuperFine" }, | 
| 172 |  |  |  |  |  |  | 3 => 'Tag-0x0001-03', | 
| 173 |  |  |  |  |  |  | 4 => { __TAG__ => 'FlashMode', | 
| 174 |  |  |  |  |  |  | 0 => 'Flash Not Fired', | 
| 175 |  |  |  |  |  |  | 1 => 'Auto', | 
| 176 |  |  |  |  |  |  | 2 => 'On', | 
| 177 |  |  |  |  |  |  | 3 => 'Red-Eye Reduction', | 
| 178 |  |  |  |  |  |  | 4 => 'Slow Synchro', | 
| 179 |  |  |  |  |  |  | 5 => 'Auto + Red-Eye Reduction', | 
| 180 |  |  |  |  |  |  | 6 => 'On + Red-Eye Reduction', | 
| 181 |  |  |  |  |  |  | 16 => 'External Flash' | 
| 182 |  |  |  |  |  |  | }, | 
| 183 |  |  |  |  |  |  | 5 => { __TAG__ => 'ContinuousDriveMode', 0 => 'Single Or Timer', 1 => 'Continuous' }, | 
| 184 |  |  |  |  |  |  | 6 => 'Tag-0x0001-06', | 
| 185 |  |  |  |  |  |  | 7 => { __TAG__ => 'FocusMode', | 
| 186 |  |  |  |  |  |  | 0 => 'One-Shot', | 
| 187 |  |  |  |  |  |  | 1 => 'AI Servo', | 
| 188 |  |  |  |  |  |  | 2 => 'AI Focus', | 
| 189 |  |  |  |  |  |  | 3 => 'MF', | 
| 190 |  |  |  |  |  |  | 4 => 'Single', | 
| 191 |  |  |  |  |  |  | 5 => 'Continuous', | 
| 192 |  |  |  |  |  |  | 6 => 'MF' | 
| 193 |  |  |  |  |  |  | }, | 
| 194 |  |  |  |  |  |  | 8 => 'Tag-0x0001-08', | 
| 195 |  |  |  |  |  |  | 9 => 'Tag-0x0001-09', | 
| 196 |  |  |  |  |  |  | 10 => { __TAG__ => 'ImageSize', 0 => 'Large', 1 => 'Medium', 2 => 'Small' }, | 
| 197 |  |  |  |  |  |  | 11 => { __TAG__ => 'EasyShootingMode', | 
| 198 |  |  |  |  |  |  | 0 => 'Full Auto', | 
| 199 |  |  |  |  |  |  | 1 => 'Manual', | 
| 200 |  |  |  |  |  |  | 2 => 'Landscape', | 
| 201 |  |  |  |  |  |  | 3 => 'Fast Shutter', | 
| 202 |  |  |  |  |  |  | 4 => 'Slow Shutter', | 
| 203 |  |  |  |  |  |  | 5 => 'Night', | 
| 204 |  |  |  |  |  |  | 6 => 'B&W', | 
| 205 |  |  |  |  |  |  | 7 => 'Sepia', | 
| 206 |  |  |  |  |  |  | 8 => 'Portrait', | 
| 207 |  |  |  |  |  |  | 9 => 'Sports', | 
| 208 |  |  |  |  |  |  | 10 => 'Macro/Close-Up', | 
| 209 |  |  |  |  |  |  | 11 => 'Pan Focus' | 
| 210 |  |  |  |  |  |  | }, | 
| 211 |  |  |  |  |  |  | 12 => { __TAG__ => 'DigitalZoom', 0 => 'None', 1 => '2x', 2 => '4x' }, | 
| 212 |  |  |  |  |  |  | 13 => { __TAG__ => 'Contrast', 0xFFFF => 'Low', 0 => 'Normal', 1 => 'High' }, | 
| 213 |  |  |  |  |  |  | 14 => { __TAG__ => 'Saturation', 0xFFFF => 'Low', 0 => 'Normal', 1 => 'High' }, | 
| 214 |  |  |  |  |  |  | 15 => { __TAG__ => 'Sharpness', 0xFFFF => 'Low', 0 => 'Normal', 1 => 'High' }, | 
| 215 |  |  |  |  |  |  | 16 => { __TAG__ => 'ISO', | 
| 216 |  |  |  |  |  |  | 0 => 'See ISOSpeedRatings Tag', | 
| 217 |  |  |  |  |  |  | 15 => 'Auto', | 
| 218 |  |  |  |  |  |  | 16 => '50', | 
| 219 |  |  |  |  |  |  | 17 => '100', | 
| 220 |  |  |  |  |  |  | 18 => '200', | 
| 221 |  |  |  |  |  |  | 19 => '400' | 
| 222 |  |  |  |  |  |  | }, | 
| 223 |  |  |  |  |  |  | 17 => { __TAG__ => 'MeteringMode', 3 => 'Evaluative', 4 => 'Partial', 5 => 'Center-Weighted' }, | 
| 224 |  |  |  |  |  |  | 18 => { __TAG__ => 'FocusType', | 
| 225 |  |  |  |  |  |  | 0 => 'Manual', | 
| 226 |  |  |  |  |  |  | 1 => 'Auto', | 
| 227 |  |  |  |  |  |  | 3 => 'Close-Up (Macro)', | 
| 228 |  |  |  |  |  |  | 8 => 'Locked (Pan Mode)' | 
| 229 |  |  |  |  |  |  | }, | 
| 230 |  |  |  |  |  |  | 19 => { __TAG__ => 'AFPointSelected', | 
| 231 |  |  |  |  |  |  | 0x3000 => 'None { __TAG__ => MF)', | 
| 232 |  |  |  |  |  |  | 0x3001 => 'Auto-Selected', | 
| 233 |  |  |  |  |  |  | 0x3002 => 'Right', | 
| 234 |  |  |  |  |  |  | 0x3003 => 'Center', | 
| 235 |  |  |  |  |  |  | 0x3004 => 'Left' | 
| 236 |  |  |  |  |  |  | }, | 
| 237 |  |  |  |  |  |  | 20 => { __TAG__ => 'ExposureMode', | 
| 238 |  |  |  |  |  |  | 0 => 'Easy Shooting', | 
| 239 |  |  |  |  |  |  | 1 => 'Program', | 
| 240 |  |  |  |  |  |  | 2 => 'Tv-priority', | 
| 241 |  |  |  |  |  |  | 3 => 'Av-priority', | 
| 242 |  |  |  |  |  |  | 4 => 'Manual', | 
| 243 |  |  |  |  |  |  | 5 => 'A-DEP' | 
| 244 |  |  |  |  |  |  | }, | 
| 245 |  |  |  |  |  |  | 21 => 'Tag-0x0001-21', | 
| 246 |  |  |  |  |  |  | 22 => 'Tag-0x0001-22', | 
| 247 |  |  |  |  |  |  | 23 => 'LongFocalLengthOfLensInFocalUnits', | 
| 248 |  |  |  |  |  |  | 24 => 'ShortFocalLengthOfLensInFocalUnits', | 
| 249 |  |  |  |  |  |  | 25 => 'FocalUnitsPerMM', | 
| 250 |  |  |  |  |  |  | 26 => 'Tag-0x0001-26', | 
| 251 |  |  |  |  |  |  | 27 => 'Tag-0x0001-27', | 
| 252 |  |  |  |  |  |  | 28 => { __TAG__ => 'FlashActivity', 0 => 'Did Not Fire', 1 => 'Fired' }, | 
| 253 |  |  |  |  |  |  | 29 => { __TAG__ => 'FlashDetails', | 
| 254 |  |  |  |  |  |  | 14 => 'External E-TTL', | 
| 255 |  |  |  |  |  |  | 13 => 'Internal Flash', | 
| 256 |  |  |  |  |  |  | 11 => 'FP Sync Used', | 
| 257 |  |  |  |  |  |  | 7 => '2nd ("Rear")-Curtain Sync Used', | 
| 258 |  |  |  |  |  |  | 4 => 'FP Sync Enabled' | 
| 259 |  |  |  |  |  |  | }, | 
| 260 |  |  |  |  |  |  | 30 => 'Tag-0x0001-30', | 
| 261 |  |  |  |  |  |  | 31 => 'Tag-0x0001-31', | 
| 262 |  |  |  |  |  |  | 32 => { __TAG__ => 'FocusMode', 0 => 'Single', 1 => 'Continuous' }, | 
| 263 |  |  |  |  |  |  | ); | 
| 264 |  |  |  |  |  |  |  | 
| 265 |  |  |  |  |  |  | my %canon_0x0004_tags = ( | 
| 266 |  |  |  |  |  |  | 7 => { __TAG__ => 'WhiteBalance', | 
| 267 |  |  |  |  |  |  | 0 => 'Auto', | 
| 268 |  |  |  |  |  |  | 1 => 'Sunny', | 
| 269 |  |  |  |  |  |  | 2 => 'Cloudy', | 
| 270 |  |  |  |  |  |  | 3 => 'Tungsten', | 
| 271 |  |  |  |  |  |  | 4 => 'Fluorescent', | 
| 272 |  |  |  |  |  |  | 5 => 'Flash', | 
| 273 |  |  |  |  |  |  | 6 => 'Custom' | 
| 274 |  |  |  |  |  |  | }, | 
| 275 |  |  |  |  |  |  | 9 => 'SequenceNumber', | 
| 276 |  |  |  |  |  |  | 14 => 'AFPointUsed', | 
| 277 |  |  |  |  |  |  | 15 => { __TAG__ => 'FlashBias', | 
| 278 |  |  |  |  |  |  | 0xFFC0 => '-2 EV', | 
| 279 |  |  |  |  |  |  | 0xFFCC => '-1.67 EV', | 
| 280 |  |  |  |  |  |  | 0xFFD0 => '-1.50 EV', | 
| 281 |  |  |  |  |  |  | 0xFFD4 => '-1.33 EV', | 
| 282 |  |  |  |  |  |  | 0xFFE0 => '-1 EV', | 
| 283 |  |  |  |  |  |  | 0xFFEC => '-0.67 EV', | 
| 284 |  |  |  |  |  |  | 0xFFF0 => '-0.50 EV', | 
| 285 |  |  |  |  |  |  | 0xFFF4 => '-0.33 EV', | 
| 286 |  |  |  |  |  |  | 0x0000 => '0 EV', | 
| 287 |  |  |  |  |  |  | 0x000C => '0.33 EV', | 
| 288 |  |  |  |  |  |  | 0x0010 => '0.50 EV', | 
| 289 |  |  |  |  |  |  | 0x0014 => '0.67 EV', | 
| 290 |  |  |  |  |  |  | 0x0020 => '1 EV', | 
| 291 |  |  |  |  |  |  | 0x002C => '1.33 EV', | 
| 292 |  |  |  |  |  |  | 0x0030 => '1.50 EV', | 
| 293 |  |  |  |  |  |  | 0x0034 => '1.67 EV', | 
| 294 |  |  |  |  |  |  | 0x0040 => '2 EV', | 
| 295 |  |  |  |  |  |  | }, | 
| 296 |  |  |  |  |  |  | 19 => 'SubjectDistance' | 
| 297 |  |  |  |  |  |  | ); | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | my %canon_tags = ( | 
| 301 |  |  |  |  |  |  | 0x0001 => { __TAG__ => "Custom_0x0001", __ARRAYOFFSET__ => \%canon_0x0001_tags }, | 
| 302 |  |  |  |  |  |  | 0x0004 => { __TAG__ => "Custom_0x0004", __ARRAYOFFSET__ => \%canon_0x0004_tags }, | 
| 303 |  |  |  |  |  |  | 0x0006 => "ImageType", | 
| 304 |  |  |  |  |  |  | 0x0007 => "FirmwareVersion", | 
| 305 |  |  |  |  |  |  | 0x0008 => "ImageNumber", | 
| 306 |  |  |  |  |  |  | 0x0009 => "OwnerName", | 
| 307 |  |  |  |  |  |  | 0x000c => "SerialNumber", | 
| 308 |  |  |  |  |  |  | ); | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | # see http://www.compton.nu/panasonic.html | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | my %panasonic_tags = ( | 
| 313 |  |  |  |  |  |  | 0x0001 => { __TAG__ => "ImageQuality", | 
| 314 |  |  |  |  |  |  | 2 => 'High', | 
| 315 |  |  |  |  |  |  | 3 => 'Normal', | 
| 316 |  |  |  |  |  |  | 6 => 'Very High',	#3 (Leica) | 
| 317 |  |  |  |  |  |  | 7 => 'Raw', 		#3 (Leica) | 
| 318 |  |  |  |  |  |  | }, | 
| 319 |  |  |  |  |  |  | 0x0002 => "FirmwareVersion", | 
| 320 |  |  |  |  |  |  | 0x0003 => { __TAG__ => "WhiteBalance", | 
| 321 |  |  |  |  |  |  | 1 => 'Auto', | 
| 322 |  |  |  |  |  |  | 2 => 'Daylight', | 
| 323 |  |  |  |  |  |  | 3 => 'Cloudy', | 
| 324 |  |  |  |  |  |  | 4 => 'Halogen', | 
| 325 |  |  |  |  |  |  | 5 => 'Manual', | 
| 326 |  |  |  |  |  |  | 8 => 'Flash', | 
| 327 |  |  |  |  |  |  | 10 => 'Black & White', #3 (Leica) | 
| 328 |  |  |  |  |  |  | }, | 
| 329 |  |  |  |  |  |  | 0x0007 => { __TAG__ => "FocusMode", | 
| 330 |  |  |  |  |  |  | 1 => 'Auto', | 
| 331 |  |  |  |  |  |  | 2 => 'Manual', | 
| 332 |  |  |  |  |  |  | 5 => 'Auto, Continuous', | 
| 333 |  |  |  |  |  |  | 4 => 'Auto, Focus button', | 
| 334 |  |  |  |  |  |  | }, | 
| 335 |  |  |  |  |  |  | 0x000f => { __TAG__ => "SpotMode", | 
| 336 |  |  |  |  |  |  | # XXX TODO: does not decode properly | 
| 337 |  |  |  |  |  |  | "0,1" => 'On', | 
| 338 |  |  |  |  |  |  | "0,16" => 'Off', | 
| 339 |  |  |  |  |  |  | }, | 
| 340 |  |  |  |  |  |  | 0x001a => { __TAG__ => "ImageStabilizer", | 
| 341 |  |  |  |  |  |  | 2 => 'On, Mode 1', | 
| 342 |  |  |  |  |  |  | 3 => 'Off', | 
| 343 |  |  |  |  |  |  | 4 => 'On, Mode 2', | 
| 344 |  |  |  |  |  |  | }, | 
| 345 |  |  |  |  |  |  | 0x001c => { __TAG__ => "MacroMode", | 
| 346 |  |  |  |  |  |  | 1 => 'On', | 
| 347 |  |  |  |  |  |  | 2 => 'Off', | 
| 348 |  |  |  |  |  |  | }, | 
| 349 |  |  |  |  |  |  | 0x001f => { __TAG__ => "ShootingMode", | 
| 350 |  |  |  |  |  |  | 1  => 'Normal', | 
| 351 |  |  |  |  |  |  | 2  => 'Portrait', | 
| 352 |  |  |  |  |  |  | 3  => 'Scenery', | 
| 353 |  |  |  |  |  |  | 4  => 'Sports', | 
| 354 |  |  |  |  |  |  | 5  => 'Night Portrait', | 
| 355 |  |  |  |  |  |  | 6  => 'Program', | 
| 356 |  |  |  |  |  |  | 7  => 'Aperture Priority', | 
| 357 |  |  |  |  |  |  | 8  => 'Shutter Priority', | 
| 358 |  |  |  |  |  |  | 9  => 'Macro', | 
| 359 |  |  |  |  |  |  | 11 => 'Manual', | 
| 360 |  |  |  |  |  |  | 13 => 'Panning', | 
| 361 |  |  |  |  |  |  | 18 => 'Fireworks', | 
| 362 |  |  |  |  |  |  | 19 => 'Party', | 
| 363 |  |  |  |  |  |  | 20 => 'Snow', | 
| 364 |  |  |  |  |  |  | 21 => 'Night Scenery', | 
| 365 |  |  |  |  |  |  | }, | 
| 366 |  |  |  |  |  |  | 0x0020 => { __TAG__ => "Audio", | 
| 367 |  |  |  |  |  |  | 1 => 'Yes', | 
| 368 |  |  |  |  |  |  | 2 => 'No', | 
| 369 |  |  |  |  |  |  | }, | 
| 370 |  |  |  |  |  |  | 0x0021 => "DataDump", | 
| 371 |  |  |  |  |  |  | 0x0022 => "Panasonic 0x0022", | 
| 372 |  |  |  |  |  |  | 0x0023 => "WhiteBalanceBias", | 
| 373 |  |  |  |  |  |  | 0x0024 => "FlashBias", | 
| 374 |  |  |  |  |  |  | 0x0025 => "SerialNumber", | 
| 375 |  |  |  |  |  |  | 0x0026 => "Panasonic 0x0026", | 
| 376 |  |  |  |  |  |  | 0x0027 => "Panasonic 0x0027", | 
| 377 |  |  |  |  |  |  | 0x0028 => { __TAG__ => "ColorEffect", | 
| 378 |  |  |  |  |  |  | 1 => 'Off', | 
| 379 |  |  |  |  |  |  | 2 => 'Warm', | 
| 380 |  |  |  |  |  |  | 3 => 'Cool', | 
| 381 |  |  |  |  |  |  | 4 => 'Black & White', | 
| 382 |  |  |  |  |  |  | 5 => 'Sepia', | 
| 383 |  |  |  |  |  |  | }, | 
| 384 |  |  |  |  |  |  | 0x0029 => "Panasonic 0x0029", | 
| 385 |  |  |  |  |  |  | 0x002a => { __TAG__ => "BurstMode", | 
| 386 |  |  |  |  |  |  | 0 => 'Off', | 
| 387 |  |  |  |  |  |  | 1 => 'Low/High Quality', | 
| 388 |  |  |  |  |  |  | 2 => 'Infinite', | 
| 389 |  |  |  |  |  |  | }, | 
| 390 |  |  |  |  |  |  | 0x002b => "ImageSequenceNumber", | 
| 391 |  |  |  |  |  |  | 0x002c => { __TAG__ => "Contrast", | 
| 392 |  |  |  |  |  |  | 0 => 'Normal', | 
| 393 |  |  |  |  |  |  | 1 => 'Low', | 
| 394 |  |  |  |  |  |  | 2 => 'High', | 
| 395 |  |  |  |  |  |  | 0x100 => 'Low',		# Leica | 
| 396 |  |  |  |  |  |  | 0x110 => 'Normal',	# Leica | 
| 397 |  |  |  |  |  |  | 0x120 => 'High',	# Leica | 
| 398 |  |  |  |  |  |  | }, | 
| 399 |  |  |  |  |  |  | 0x002d => { __TAG__ => "NoiseReduction", | 
| 400 |  |  |  |  |  |  | 0 => 'Standard', | 
| 401 |  |  |  |  |  |  | 1 => 'Low', | 
| 402 |  |  |  |  |  |  | 2 => 'High', | 
| 403 |  |  |  |  |  |  | }, | 
| 404 |  |  |  |  |  |  | 0x002e => { __TAG__ => "SelfTimer", | 
| 405 |  |  |  |  |  |  | 1 => 'Off', | 
| 406 |  |  |  |  |  |  | 2 => '10s', | 
| 407 |  |  |  |  |  |  | 3 => '2s', | 
| 408 |  |  |  |  |  |  | }, | 
| 409 |  |  |  |  |  |  | 0x002f => "Panasonic 0x002f", | 
| 410 |  |  |  |  |  |  | 0x0030 => "Panasonic 0x0030", | 
| 411 |  |  |  |  |  |  | 0x0031 => "Panasonic 0x0031", | 
| 412 |  |  |  |  |  |  | 0x0032 => "Panasonic 0x0032", | 
| 413 |  |  |  |  |  |  | ); | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | # format: | 
| 416 |  |  |  |  |  |  | #    "Make Model" => [ Offset, 'Tag_prefix', ptr to tags ] | 
| 417 |  |  |  |  |  |  | # Offset is either 0, or a positive number of Bytes. | 
| 418 |  |  |  |  |  |  | # Offset -1 or -2 means a kludge for Fuji or Nikon | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | my %makernotes = ( | 
| 421 |  |  |  |  |  |  | "NIKON CORPORATION NIKON D1"	=> [0,  'NikonD1', \%nikon2_tags], | 
| 422 |  |  |  |  |  |  | "NIKON CORPORATION NIKON D70"	=> [-2, 'NikonD1', \%nikon2_tags], | 
| 423 |  |  |  |  |  |  | "NIKON CORPORATION NIKON D100"	=> [-2, 'NikonD1', \%nikon2_tags], | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | # For the following manufacturers we simple discard the model and always | 
| 426 |  |  |  |  |  |  | # decode the MakerNote in the same manner. This makes it work with all | 
| 427 |  |  |  |  |  |  | # models, even yet unreleased ones. (That's better than the very limited | 
| 428 |  |  |  |  |  |  | # list of models we previously had) | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | "CANON"		=> [0, 'Canon', \%canon_tags], | 
| 431 |  |  |  |  |  |  | 'PANASONIC'		=> [12, 'Panasonic', \%panasonic_tags], | 
| 432 |  |  |  |  |  |  | "FUJIFILM"		=> [-1, 'FinePix', \%fujifilm_tags], | 
| 433 |  |  |  |  |  |  | "CASIO"		=> [0, 'Casio', \%casio_tags], | 
| 434 |  |  |  |  |  |  | "OLYMPUS"		=> [8, 'Olympus', \%olympus_tags], | 
| 435 |  |  |  |  |  |  | ); | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | BEGIN | 
| 438 |  |  |  |  |  |  | { | 
| 439 |  |  |  |  |  |  | # add some Nikon cameras | 
| 440 | 9 |  |  | 9 |  | 37 | for my $model (qw/E700 E800 E900 E900S E910 E950/) | 
| 441 |  |  |  |  |  |  | { | 
| 442 | 54 |  |  |  |  | 137 | $makernotes{'NIKON ' . $model} = [8, 'CoolPix', \%nikon1_tags]; | 
| 443 |  |  |  |  |  |  | } | 
| 444 | 9 |  |  |  |  | 19 | for my $model (qw/E880 E990 E995/) | 
| 445 |  |  |  |  |  |  | { | 
| 446 | 27 |  |  |  |  | 21145 | $makernotes{'NIKON ' . $model} = [0, 'CoolPix', \%nikon2_tags]; | 
| 447 |  |  |  |  |  |  | } | 
| 448 |  |  |  |  |  |  | } | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | my %exif_intr_tags = ( | 
| 451 |  |  |  |  |  |  | 0x1    => "InteroperabilityIndex", | 
| 452 |  |  |  |  |  |  | 0x2    => "InteroperabilityVersion", | 
| 453 |  |  |  |  |  |  | 0x1000 => "RelatedImageFileFormat", | 
| 454 |  |  |  |  |  |  | 0x1001 => "RelatedImageWidth", | 
| 455 |  |  |  |  |  |  | 0x1002 => "RelatedImageLength", | 
| 456 |  |  |  |  |  |  | ); | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | # Tag decode helpers | 
| 459 |  |  |  |  |  |  | sub components_configuration_decoder; | 
| 460 |  |  |  |  |  |  | sub file_source_decoder; | 
| 461 |  |  |  |  |  |  | sub scene_type_decoder; | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | my %exif_tags = ( | 
| 464 |  |  |  |  |  |  | 0x828D => "CFARepeatPatternDim", | 
| 465 |  |  |  |  |  |  | 0x828E => "CFAPattern", | 
| 466 |  |  |  |  |  |  | 0x828F => "BatteryLevel", | 
| 467 |  |  |  |  |  |  | 0x8298 => "Copyright", | 
| 468 |  |  |  |  |  |  | 0x829A => "ExposureTime", | 
| 469 |  |  |  |  |  |  | 0x829D => "FNumber", | 
| 470 |  |  |  |  |  |  | 0x83BB => "IPTC/NAA", | 
| 471 |  |  |  |  |  |  | 0x8769 => "ExifOffset", | 
| 472 |  |  |  |  |  |  | 0x8773 => "InterColorProfile", | 
| 473 |  |  |  |  |  |  | 0x8822 => { __TAG__ => "ExposureProgram", | 
| 474 |  |  |  |  |  |  | 0 => "unknown", | 
| 475 |  |  |  |  |  |  | 1 => "Manual", | 
| 476 |  |  |  |  |  |  | 2 => "Program", | 
| 477 |  |  |  |  |  |  | 3 => "Aperture priority", | 
| 478 |  |  |  |  |  |  | 4 => "Shutter priority", | 
| 479 |  |  |  |  |  |  | 5 => "Program creative", | 
| 480 |  |  |  |  |  |  | 6 => "Program action", | 
| 481 |  |  |  |  |  |  | 7 => "Portrait", | 
| 482 |  |  |  |  |  |  | 8 => "Landscape", | 
| 483 |  |  |  |  |  |  | # 9 .. 255 reserved | 
| 484 |  |  |  |  |  |  | }, | 
| 485 |  |  |  |  |  |  | 0x8824 => "SpectralSensitivity", | 
| 486 |  |  |  |  |  |  | 0x8827 => "ISOSpeedRatings", | 
| 487 |  |  |  |  |  |  | 0x8828 => "OECF", | 
| 488 |  |  |  |  |  |  | 0x9000 => "ExifVersion", | 
| 489 |  |  |  |  |  |  | 0x9003 => "DateTimeOriginal", | 
| 490 |  |  |  |  |  |  | 0x9004 => "DateTimeDigitized", | 
| 491 |  |  |  |  |  |  | 0x9101 => { __TAG__ => "ComponentsConfiguration", | 
| 492 |  |  |  |  |  |  | DECODER => \&components_configuration_decoder, | 
| 493 |  |  |  |  |  |  | }, | 
| 494 |  |  |  |  |  |  | 0x9102 => "CompressedBitsPerPixel", | 
| 495 |  |  |  |  |  |  | 0x9201 => "ShutterSpeedValue", | 
| 496 |  |  |  |  |  |  | 0x9202 => "ApertureValue", | 
| 497 |  |  |  |  |  |  | 0x9203 => "BrightnessValue", | 
| 498 |  |  |  |  |  |  | 0x9204 => "ExposureBiasValue", | 
| 499 |  |  |  |  |  |  | 0x9205 => "MaxApertureValue", | 
| 500 |  |  |  |  |  |  | 0x9206 => "SubjectDistance", | 
| 501 |  |  |  |  |  |  | 0x9207 => { __TAG__ => "MeteringMode", | 
| 502 |  |  |  |  |  |  | 0 => "unknown", | 
| 503 |  |  |  |  |  |  | 1 => "Average", | 
| 504 |  |  |  |  |  |  | 2 => "CenterWeightedAverage", | 
| 505 |  |  |  |  |  |  | 3 => "Spot", | 
| 506 |  |  |  |  |  |  | 4 => "MultiSpot", | 
| 507 |  |  |  |  |  |  | 5 => "Pattern", | 
| 508 |  |  |  |  |  |  | 6 => "Partial", | 
| 509 |  |  |  |  |  |  | # 7 .. 254 reserved in EXIF 1.2 | 
| 510 |  |  |  |  |  |  | 255 => "other", | 
| 511 |  |  |  |  |  |  | }, | 
| 512 |  |  |  |  |  |  | 0x9208 => { __TAG__ => "LightSource", | 
| 513 |  |  |  |  |  |  | 0 => "unknown", | 
| 514 |  |  |  |  |  |  | 1 => "Daylight", | 
| 515 |  |  |  |  |  |  | 2 => "Fluorescent", | 
| 516 |  |  |  |  |  |  | 3 => "Tungsten", | 
| 517 |  |  |  |  |  |  | 4 => "Flash", | 
| 518 |  |  |  |  |  |  | # 5 .. 8 reserved in EXIF 2.2 | 
| 519 |  |  |  |  |  |  | 9 => "Fine weather", | 
| 520 |  |  |  |  |  |  | 10 => "Cloudy weather", | 
| 521 |  |  |  |  |  |  | 11 => "Shade", | 
| 522 |  |  |  |  |  |  | 12 => "Daylight fluorescent (D 5700-7100K)", | 
| 523 |  |  |  |  |  |  | 13 => "Day white fluorescent (N 4600-5400K)", | 
| 524 |  |  |  |  |  |  | 14 => "Cool white fluorescent (W 3900-4500K)", | 
| 525 |  |  |  |  |  |  | 15 => "White fluorescent (WW 3200-3700K)", | 
| 526 |  |  |  |  |  |  | 17 => "Standard light A", | 
| 527 |  |  |  |  |  |  | 18 => "Standard light B", | 
| 528 |  |  |  |  |  |  | 19 => "Standard light C", | 
| 529 |  |  |  |  |  |  | 20 => "D55", | 
| 530 |  |  |  |  |  |  | 21 => "D65", | 
| 531 |  |  |  |  |  |  | 22 => "D75", | 
| 532 |  |  |  |  |  |  | 23 => "D50", | 
| 533 |  |  |  |  |  |  | 24 => "ISO studio tungesten", | 
| 534 |  |  |  |  |  |  | # 25 .. 254 reserved in EXIF 2.2 | 
| 535 |  |  |  |  |  |  | 255 => "other light source", | 
| 536 |  |  |  |  |  |  | }, | 
| 537 |  |  |  |  |  |  | 0x9209 => { __TAG__ => "Flash", | 
| 538 |  |  |  |  |  |  | 0x0000 => "Flash did not fire", | 
| 539 |  |  |  |  |  |  | 0x0001 => "Flash fired", | 
| 540 |  |  |  |  |  |  | 0x0005 => "Strobe return light not detected", | 
| 541 |  |  |  |  |  |  | 0x0007 => "Strobe return light detected", | 
| 542 |  |  |  |  |  |  | 0x0009 => "Flash fired, compulsory flash mode", | 
| 543 |  |  |  |  |  |  | 0x000D => "Flash fired, compulsory flash mode, return light not detected", | 
| 544 |  |  |  |  |  |  | 0x000F => "Flash fired, compulsory flash mode, return light detected", | 
| 545 |  |  |  |  |  |  | 0x0010 => "Flash did not fire, compulsory flash mode", | 
| 546 |  |  |  |  |  |  | 0x0018 => "Flash did not fire, auto mode", | 
| 547 |  |  |  |  |  |  | 0x0019 => "Flash fired, auto mode", | 
| 548 |  |  |  |  |  |  | 0x001D => "Flash fired, auto mode, return light not detected", | 
| 549 |  |  |  |  |  |  | 0x001F => "Flash fired, auto mode, return light detected", | 
| 550 |  |  |  |  |  |  | 0x0020 => "No flash function", | 
| 551 |  |  |  |  |  |  | 0x0041 => "Flash fired, red-eye reduction mode", | 
| 552 |  |  |  |  |  |  | 0x0045 => "Flash fired, red-eye reduction mode, return light not detected", | 
| 553 |  |  |  |  |  |  | 0x0047 => "Flash fired, red-eye reduction mode, return light detected", | 
| 554 |  |  |  |  |  |  | 0x0049 => "Flash fired, compulsory flash mode, red-eye reduction mode", | 
| 555 |  |  |  |  |  |  | 0x004D => "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected", | 
| 556 |  |  |  |  |  |  | 0x004F => "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected", | 
| 557 |  |  |  |  |  |  | 0x0059 => "Flash fired, auto mode, red-eye reduction mode", | 
| 558 |  |  |  |  |  |  | 0x005D => "Flash fired, auto mode, return light not detected, red-eye reduction mode", | 
| 559 |  |  |  |  |  |  | 0x005F => "Flash fired, auto mode, return light detected, red-eye reduction mode" | 
| 560 |  |  |  |  |  |  | }, | 
| 561 |  |  |  |  |  |  | 0x920A => "FocalLength", | 
| 562 |  |  |  |  |  |  | 0x9214 => "SubjectArea", | 
| 563 |  |  |  |  |  |  | 0x927C => "MakerNote", | 
| 564 |  |  |  |  |  |  | 0x9286 => "UserComment", | 
| 565 |  |  |  |  |  |  | 0x9290 => "SubSecTime", | 
| 566 |  |  |  |  |  |  | 0x9291 => "SubSecTimeOriginal", | 
| 567 |  |  |  |  |  |  | 0x9292 => "SubSecTimeDigitized", | 
| 568 |  |  |  |  |  |  | 0xA000 => "FlashPixVersion", | 
| 569 |  |  |  |  |  |  | 0xA001 => "ColorSpace", | 
| 570 |  |  |  |  |  |  | 0xA002 => "ExifImageWidth", | 
| 571 |  |  |  |  |  |  | 0xA003 => "ExifImageLength", | 
| 572 |  |  |  |  |  |  | 0xA004 => "RelatedAudioFile", | 
| 573 |  |  |  |  |  |  | 0xA005 => {__TAG__ => "InteroperabilityOffset", | 
| 574 |  |  |  |  |  |  | __SUBIFD__ => \%exif_intr_tags, | 
| 575 |  |  |  |  |  |  | }, | 
| 576 |  |  |  |  |  |  | 0xA20B => "FlashEnergy",                  # 0x920B in TIFF/EP | 
| 577 |  |  |  |  |  |  | 0xA20C => "SpatialFrequencyResponse",     # 0x920C    -  - | 
| 578 |  |  |  |  |  |  | 0xA20E => "FocalPlaneXResolution",        # 0x920E    -  - | 
| 579 |  |  |  |  |  |  | 0xA20F => "FocalPlaneYResolution",        # 0x920F    -  - | 
| 580 |  |  |  |  |  |  | 0xA210 => { __TAG__ => "FocalPlaneResolutionUnit",     # 0x9210    -  - | 
| 581 |  |  |  |  |  |  | 1 => "pixels", | 
| 582 |  |  |  |  |  |  | 2 => "dpi", | 
| 583 |  |  |  |  |  |  | 3 => "dpcm", | 
| 584 |  |  |  |  |  |  | }, | 
| 585 |  |  |  |  |  |  | 0xA214 => "SubjectLocation",              # 0x9214    -  - | 
| 586 |  |  |  |  |  |  | 0xA215 => "ExposureIndex",                # 0x9215    -  - | 
| 587 |  |  |  |  |  |  | 0xA217 => {__TAG__ => "SensingMethod", | 
| 588 |  |  |  |  |  |  | 1 => "Not defined", | 
| 589 |  |  |  |  |  |  | 2 => "One-chip color area sensor", | 
| 590 |  |  |  |  |  |  | 3 => "Two-chip color area sensor", | 
| 591 |  |  |  |  |  |  | 4 => "Three-chip color area sensor", | 
| 592 |  |  |  |  |  |  | 5 => "Color sequential area sensor", | 
| 593 |  |  |  |  |  |  | 7 => "Trilinear sensor", | 
| 594 |  |  |  |  |  |  | 8 => "Color sequential linear sensor" | 
| 595 |  |  |  |  |  |  | }, | 
| 596 |  |  |  |  |  |  | 0xA300 => {__TAG__ => "FileSource", | 
| 597 |  |  |  |  |  |  | DECODER => \&file_source_decoder, | 
| 598 |  |  |  |  |  |  | }, | 
| 599 |  |  |  |  |  |  | 0xA301 => {__TAG__ => "SceneType", | 
| 600 |  |  |  |  |  |  | DECODER => \&scene_type_decoder, | 
| 601 |  |  |  |  |  |  | }, | 
| 602 |  |  |  |  |  |  | 0xA302 => "CFAPattern", | 
| 603 |  |  |  |  |  |  | 0xA401 => {__TAG__ => "CustomRendered", | 
| 604 |  |  |  |  |  |  | 0 => "Normal process", | 
| 605 |  |  |  |  |  |  | 1 => "Custom process" | 
| 606 |  |  |  |  |  |  | }, | 
| 607 |  |  |  |  |  |  | 0xA402 => {__TAG__ => "ExposureMode", | 
| 608 |  |  |  |  |  |  | 0 => "Auto exposure", | 
| 609 |  |  |  |  |  |  | 1 => "Manual exposure", | 
| 610 |  |  |  |  |  |  | 2 => "Auto bracket" | 
| 611 |  |  |  |  |  |  | }, | 
| 612 |  |  |  |  |  |  | 0xA403 => {__TAG__ => "WhiteBalance", | 
| 613 |  |  |  |  |  |  | 0 => "Auto white balance", | 
| 614 |  |  |  |  |  |  | 1 => "Manual white balance" | 
| 615 |  |  |  |  |  |  | }, | 
| 616 |  |  |  |  |  |  | 0xA404 => "DigitalZoomRatio", | 
| 617 |  |  |  |  |  |  | 0xA405 => "FocalLengthIn35mmFilm", | 
| 618 |  |  |  |  |  |  | 0xA406 => {__TAG__ => "SceneCaptureType", | 
| 619 |  |  |  |  |  |  | 0 => "Standard", | 
| 620 |  |  |  |  |  |  | 1 => "Landscape", | 
| 621 |  |  |  |  |  |  | 2 => "Portrait", | 
| 622 |  |  |  |  |  |  | 3 => "Night Scene" | 
| 623 |  |  |  |  |  |  | }, | 
| 624 |  |  |  |  |  |  | 0xA407 => {__TAG__ => "GainControl", | 
| 625 |  |  |  |  |  |  | 0 => "None", | 
| 626 |  |  |  |  |  |  | 1 => "Low gain up", | 
| 627 |  |  |  |  |  |  | 2 => "High gain up", | 
| 628 |  |  |  |  |  |  | 3 => "Low gain down", | 
| 629 |  |  |  |  |  |  | 4 => "High gain down" | 
| 630 |  |  |  |  |  |  | }, | 
| 631 |  |  |  |  |  |  | 0xA408 => {__TAG__ => "Contrast", | 
| 632 |  |  |  |  |  |  | 0 => "Normal", | 
| 633 |  |  |  |  |  |  | 1 => "Soft", | 
| 634 |  |  |  |  |  |  | 2 => "Hard" | 
| 635 |  |  |  |  |  |  | }, | 
| 636 |  |  |  |  |  |  | 0xA409 => {__TAG__ => "Saturation", | 
| 637 |  |  |  |  |  |  | 0 => "Normal", | 
| 638 |  |  |  |  |  |  | 1 => "Low saturation", | 
| 639 |  |  |  |  |  |  | 2 => "High saturation" | 
| 640 |  |  |  |  |  |  | }, | 
| 641 |  |  |  |  |  |  | 0xA40A => {__TAG__ => "Sharpness", | 
| 642 |  |  |  |  |  |  | 0 => "Normal", | 
| 643 |  |  |  |  |  |  | 1 => "Soft", | 
| 644 |  |  |  |  |  |  | 2 => "Hard" | 
| 645 |  |  |  |  |  |  | }, | 
| 646 |  |  |  |  |  |  | 0xA40B => "DeviceSettingDescription", | 
| 647 |  |  |  |  |  |  | 0xA40C => {__TAG__ => "SubjectDistanceRange", | 
| 648 |  |  |  |  |  |  | 0 => "Unknown", | 
| 649 |  |  |  |  |  |  | 1 => "Macro", | 
| 650 |  |  |  |  |  |  | 2 => "Close view", | 
| 651 |  |  |  |  |  |  | 3 => "Distant view" | 
| 652 |  |  |  |  |  |  | }, | 
| 653 |  |  |  |  |  |  | 0xA420 => "ImageUniqueID", | 
| 654 |  |  |  |  |  |  | ); | 
| 655 |  |  |  |  |  |  |  | 
| 656 |  |  |  |  |  |  | my %gps_tags = ( | 
| 657 |  |  |  |  |  |  | 0x0000 => 'GPSVersionID', | 
| 658 |  |  |  |  |  |  | 0x0001 => 'GPSLatitudeRef', | 
| 659 |  |  |  |  |  |  | 0x0002 => 'GPSLatitude', | 
| 660 |  |  |  |  |  |  | 0x0003 => 'GPSLongitudeRef', | 
| 661 |  |  |  |  |  |  | 0x0004 => 'GPSLongitude', | 
| 662 |  |  |  |  |  |  | 0x0005 => 'GPSAltitudeRef', | 
| 663 |  |  |  |  |  |  | 0x0006 => 'GPSAltitude', | 
| 664 |  |  |  |  |  |  | 0x0007 => 'GPSTimeStamp', | 
| 665 |  |  |  |  |  |  | 0x0008 => 'GPSSatellites', | 
| 666 |  |  |  |  |  |  | 0x0009 => 'GPSStatus', | 
| 667 |  |  |  |  |  |  | 0x000A => 'GPSMeasureMode', | 
| 668 |  |  |  |  |  |  | 0x000B => 'GPSDOP', | 
| 669 |  |  |  |  |  |  | 0x000C => 'GPSSpeedRef', | 
| 670 |  |  |  |  |  |  | 0x000D => 'GPSSpeed', | 
| 671 |  |  |  |  |  |  | 0x000E => 'GPSTrackRef', | 
| 672 |  |  |  |  |  |  | 0x000F => 'GPSTrack', | 
| 673 |  |  |  |  |  |  | 0x0010 => 'GPSImgDirectionRef', | 
| 674 |  |  |  |  |  |  | 0x0011 => 'GPSImgDirection', | 
| 675 |  |  |  |  |  |  | 0x0012 => 'GPSMapDatum', | 
| 676 |  |  |  |  |  |  | 0x0013 => 'GPSDestLatitudeRef', | 
| 677 |  |  |  |  |  |  | 0x0014 => 'GPSDestLatitude', | 
| 678 |  |  |  |  |  |  | 0x0015 => 'GPSDestLongitudeRef', | 
| 679 |  |  |  |  |  |  | 0x0016 => 'GPSDestLongitude', | 
| 680 |  |  |  |  |  |  | 0x0017 => 'GPSDestBearingRef', | 
| 681 |  |  |  |  |  |  | 0x0018 => 'GPSDestBearing', | 
| 682 |  |  |  |  |  |  | 0x0019 => 'GPSDestDistanceRef', | 
| 683 |  |  |  |  |  |  | 0x001A => 'GPSDestDistance', | 
| 684 |  |  |  |  |  |  | 0x001B => 'GPSProcessingMethod', | 
| 685 |  |  |  |  |  |  | 0x001C => 'GPSAreaInformation', | 
| 686 |  |  |  |  |  |  | 0x001D => 'GPSDateStamp', | 
| 687 |  |  |  |  |  |  | 0x001E => 'GPSDifferential', | 
| 688 |  |  |  |  |  |  | ); | 
| 689 |  |  |  |  |  |  |  | 
| 690 |  |  |  |  |  |  | my %tiff_tags = ( | 
| 691 |  |  |  |  |  |  | 254   => { __TAG__ => "NewSubfileType", | 
| 692 |  |  |  |  |  |  | 1 => "ReducedResolution", | 
| 693 |  |  |  |  |  |  | 2 => "SinglePage", | 
| 694 |  |  |  |  |  |  | 4 => "TransparencyMask", | 
| 695 |  |  |  |  |  |  | }, | 
| 696 |  |  |  |  |  |  | 255   => { __TAG__ => "SubfileType", | 
| 697 |  |  |  |  |  |  | 1 => "FullResolution", | 
| 698 |  |  |  |  |  |  | 2 => "ReducedResolution", | 
| 699 |  |  |  |  |  |  | 3 => "SinglePage", | 
| 700 |  |  |  |  |  |  | }, | 
| 701 |  |  |  |  |  |  | 256   => "width", | 
| 702 |  |  |  |  |  |  | 257   => "height", | 
| 703 |  |  |  |  |  |  | 258   => "BitsPerSample", | 
| 704 |  |  |  |  |  |  | 259   => { __TAG__ => "Compression", | 
| 705 |  |  |  |  |  |  | 1 => "PackBytes", | 
| 706 |  |  |  |  |  |  | 2 => "CCITT Group3", | 
| 707 |  |  |  |  |  |  | 3 => "CCITT T4", | 
| 708 |  |  |  |  |  |  | 4 => "CCITT T6", | 
| 709 |  |  |  |  |  |  | 5 => "LZW", | 
| 710 |  |  |  |  |  |  | 6 => "JPEG", | 
| 711 |  |  |  |  |  |  | 7 => "JPEG DCT", | 
| 712 |  |  |  |  |  |  | 8 => "Deflate (Adobe)", | 
| 713 |  |  |  |  |  |  | 32766 => "NeXT 2-bit RLE", | 
| 714 |  |  |  |  |  |  | 32771 => "#1 w/ word alignment", | 
| 715 |  |  |  |  |  |  | 32773 => "PackBits (Macintosh RLE)", | 
| 716 |  |  |  |  |  |  | 32809 => "ThunderScan RLE", | 
| 717 |  |  |  |  |  |  | 32895 => "IT8 CT w/padding", | 
| 718 |  |  |  |  |  |  | 32896 => "IT8 Linework RLE", | 
| 719 |  |  |  |  |  |  | 32897 => "IT8 Monochrome picture", | 
| 720 |  |  |  |  |  |  | 32898 => "IT8 Binary line art", | 
| 721 |  |  |  |  |  |  | 32908 => "Pixar companded 10bit LZW", | 
| 722 |  |  |  |  |  |  | 32909 => "Pixar companded 11bit ZIP", | 
| 723 |  |  |  |  |  |  | 32946 => "Deflate", | 
| 724 |  |  |  |  |  |  | }, | 
| 725 |  |  |  |  |  |  | 262   => { __TAG__ => "PhotometricInterpretation", | 
| 726 |  |  |  |  |  |  | 0 => "WhiteIsZero", | 
| 727 |  |  |  |  |  |  | 1 => "BlackIsZero", | 
| 728 |  |  |  |  |  |  | 2 => "RGB", | 
| 729 |  |  |  |  |  |  | 3 => "RGB Palette", | 
| 730 |  |  |  |  |  |  | 4 => "Transparency Mask", | 
| 731 |  |  |  |  |  |  | 5 => "CMYK", | 
| 732 |  |  |  |  |  |  | 6 => "YCbCr", | 
| 733 |  |  |  |  |  |  | 8 => "CIELab", | 
| 734 |  |  |  |  |  |  | }, | 
| 735 |  |  |  |  |  |  | 263   => { __TAG__ => "Threshholding", | 
| 736 |  |  |  |  |  |  | 1 => "NoDithering", | 
| 737 |  |  |  |  |  |  | 2 => "OrderedDither", | 
| 738 |  |  |  |  |  |  | 3 => "Randomized", | 
| 739 |  |  |  |  |  |  | }, | 
| 740 |  |  |  |  |  |  | 266   => { __TAG__ => "FillOrder", | 
| 741 |  |  |  |  |  |  | 1 => "LowInHigh", | 
| 742 |  |  |  |  |  |  | 2 => "HighInLow", | 
| 743 |  |  |  |  |  |  | }, | 
| 744 |  |  |  |  |  |  | 269   => "DocumentName", | 
| 745 |  |  |  |  |  |  | 270   => "ImageDescription", | 
| 746 |  |  |  |  |  |  | 271   => "Make", | 
| 747 |  |  |  |  |  |  | 272   => "Model", | 
| 748 |  |  |  |  |  |  | 273   => "StripOffsets", | 
| 749 |  |  |  |  |  |  | 274   => { __TAG__ => "Orientation", | 
| 750 |  |  |  |  |  |  | 1 => "top_left", | 
| 751 |  |  |  |  |  |  | 2 => "top_right", | 
| 752 |  |  |  |  |  |  | 3 => "bot_right", | 
| 753 |  |  |  |  |  |  | 4 => "bot_left", | 
| 754 |  |  |  |  |  |  | 5 => "left_top", | 
| 755 |  |  |  |  |  |  | 6 => "right_top", | 
| 756 |  |  |  |  |  |  | 7 => "right_bot", | 
| 757 |  |  |  |  |  |  | 8 => "left_bot", | 
| 758 |  |  |  |  |  |  | }, | 
| 759 |  |  |  |  |  |  | 277   => "SamplesPerPixel", | 
| 760 |  |  |  |  |  |  | 278   => "RowsPerStrip", | 
| 761 |  |  |  |  |  |  | 279   => "StripByteCounts", | 
| 762 |  |  |  |  |  |  | 282   => "XResolution", | 
| 763 |  |  |  |  |  |  | 283   => "YResolution", | 
| 764 |  |  |  |  |  |  | 284   => {__TAG__ => "PlanarConfiguration", | 
| 765 |  |  |  |  |  |  | 1 => "Chunky", 2 => "Planar", | 
| 766 |  |  |  |  |  |  | }, | 
| 767 |  |  |  |  |  |  | 296   => {__TAG__ => "ResolutionUnit", | 
| 768 |  |  |  |  |  |  | 1 => "pixels", 2 => "dpi", 3 => "dpcm", | 
| 769 |  |  |  |  |  |  | }, | 
| 770 |  |  |  |  |  |  | 297   => "PageNumber", | 
| 771 |  |  |  |  |  |  | 301   => "TransferFunction", | 
| 772 |  |  |  |  |  |  | 305   => "Software", | 
| 773 |  |  |  |  |  |  | 306   => "DateTime", | 
| 774 |  |  |  |  |  |  | 315   => "Artist", | 
| 775 |  |  |  |  |  |  | 316   => "Host", | 
| 776 |  |  |  |  |  |  | 318   => "WhitePoint", | 
| 777 |  |  |  |  |  |  | 319   => "PrimaryChromaticities", | 
| 778 |  |  |  |  |  |  | 320   => "ColorMap", | 
| 779 |  |  |  |  |  |  | 513   => "JPEGInterchangeFormat", | 
| 780 |  |  |  |  |  |  | 514   => "JPEGInterchangeFormatLength", | 
| 781 |  |  |  |  |  |  | 529   => "YCbCrCoefficients", | 
| 782 |  |  |  |  |  |  | 530   => "YCbCrSubSampling", | 
| 783 |  |  |  |  |  |  | 531   => "YCbCrPositioning", | 
| 784 |  |  |  |  |  |  | 532   => "ReferenceBlackWhite", | 
| 785 |  |  |  |  |  |  | 33432 => "Copyright", | 
| 786 |  |  |  |  |  |  | 34665 => { __TAG__ => "ExifOffset", | 
| 787 |  |  |  |  |  |  | __SUBIFD__ => \%exif_tags, | 
| 788 |  |  |  |  |  |  | }, | 
| 789 |  |  |  |  |  |  | 34853 => { __TAG__ => "GPSInfo", | 
| 790 |  |  |  |  |  |  | __SUBIFD__ => \%gps_tags, | 
| 791 |  |  |  |  |  |  | }, | 
| 792 |  |  |  |  |  |  | ); | 
| 793 |  |  |  |  |  |  |  | 
| 794 |  |  |  |  |  |  |  | 
| 795 |  |  |  |  |  |  | sub new | 
| 796 |  |  |  |  |  |  | { | 
| 797 | 14 |  |  | 14 | 0 | 36 | my $class = shift; | 
| 798 | 14 |  |  |  |  | 18 | my $source = shift; | 
| 799 |  |  |  |  |  |  |  | 
| 800 | 14 | 50 |  |  |  | 48 | if (!ref($source)) { | 
| 801 | 0 |  |  |  |  | 0 | local(*F); | 
| 802 | 0 | 0 |  |  |  | 0 | open(F, $source) || return; | 
| 803 | 0 |  |  |  |  | 0 | binmode(F); | 
| 804 | 0 |  |  |  |  | 0 | $source = \*F; | 
| 805 |  |  |  |  |  |  | } | 
| 806 |  |  |  |  |  |  |  | 
| 807 | 14 | 50 |  |  |  | 41 | if (ref($source) ne "SCALAR") { | 
| 808 |  |  |  |  |  |  | # XXX should really only read the file on demand | 
| 809 | 0 |  |  |  |  | 0 | local($/);  # slurp mode | 
| 810 | 0 |  |  |  |  | 0 | my $data = <$source>; | 
| 811 | 0 |  |  |  |  | 0 | $source = \$data; | 
| 812 |  |  |  |  |  |  | } | 
| 813 |  |  |  |  |  |  |  | 
| 814 | 14 |  |  |  |  | 45 | my $self = bless { source => $source }, $class; | 
| 815 |  |  |  |  |  |  |  | 
| 816 | 14 |  |  |  |  | 40 | for ($$source) { | 
| 817 | 14 |  |  |  |  | 37 | my $byte_order = substr($_, 0, 2); | 
| 818 | 14 |  |  |  |  | 66 | $self->{little_endian} = ($byte_order eq "II"); | 
| 819 | 14 |  |  |  |  | 54 | $self->{version} = $self->unpack("n", substr($_, 2, 2)); | 
| 820 |  |  |  |  |  |  |  | 
| 821 | 14 |  |  |  |  | 43 | my $ifd = $self->unpack("N", substr($_, 4, 4)); | 
| 822 | 14 |  |  |  |  | 42 | while ($ifd) { | 
| 823 | 28 |  |  |  |  | 36 | push(@{$self->{ifd}}, $ifd); | 
|  | 28 |  |  |  |  | 56 |  | 
| 824 | 28 |  |  |  |  | 76 | my($num_fields) = $self->unpack("x$ifd n", $_); | 
| 825 |  |  |  |  |  |  |  | 
| 826 | 28 |  |  |  |  | 99 | my $substr_ifd = substr($_, $ifd + 2 + $num_fields*12, 4); | 
| 827 | 28 | 100 |  |  |  | 236 | last unless defined $substr_ifd; # bad TIFF header, eg: substr idx > length($substr_ifd) | 
| 828 |  |  |  |  |  |  |  | 
| 829 | 27 |  |  |  |  | 58 | my $next_ifd = $self->unpack("N", $substr_ifd); | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | # guard against (bug #26127) | 
| 832 | 27 | 50 |  |  |  | 63 | $next_ifd = 0 if $next_ifd > length($_); | 
| 833 |  |  |  |  |  |  | # guard against looping ifd (bug #26130) | 
| 834 | 27 | 100 |  |  |  | 49 | if ($next_ifd <= $ifd) { | 
| 835 |  |  |  |  |  |  | # bad TIFF header - would cause a loop or strange results | 
| 836 | 13 |  |  |  |  | 29 | last; | 
| 837 |  |  |  |  |  |  | } | 
| 838 | 14 |  |  |  |  | 28 | $ifd = $next_ifd; | 
| 839 |  |  |  |  |  |  | } | 
| 840 |  |  |  |  |  |  | } | 
| 841 |  |  |  |  |  |  |  | 
| 842 | 14 |  |  |  |  | 35 | $self; | 
| 843 |  |  |  |  |  |  | } | 
| 844 |  |  |  |  |  |  |  | 
| 845 |  |  |  |  |  |  | sub unpack | 
| 846 |  |  |  |  |  |  | { | 
| 847 | 1588 |  |  | 1588 | 0 | 1573 | my $self = shift; | 
| 848 | 1588 |  |  |  |  | 1529 | my $template = shift; | 
| 849 | 1588 | 100 |  |  |  | 2145 | if ($self->{little_endian}) { | 
| 850 | 1555 |  |  |  |  | 1651 | $template =~ tr/nN/vV/; | 
| 851 |  |  |  |  |  |  | } | 
| 852 |  |  |  |  |  |  | #print "UNPACK $template\n"; | 
| 853 | 1588 |  |  |  |  | 3597 | CORE::unpack($template, $_[0]); | 
| 854 |  |  |  |  |  |  | } | 
| 855 |  |  |  |  |  |  |  | 
| 856 |  |  |  |  |  |  | sub num_ifds | 
| 857 |  |  |  |  |  |  | { | 
| 858 | 14 |  |  | 14 | 0 | 21 | my $self = shift; | 
| 859 | 14 |  |  |  |  | 17 | scalar @{$self->{ifd}}; | 
|  | 14 |  |  |  |  | 62 |  | 
| 860 |  |  |  |  |  |  | } | 
| 861 |  |  |  |  |  |  |  | 
| 862 |  |  |  |  |  |  | sub ifd | 
| 863 |  |  |  |  |  |  | { | 
| 864 | 28 |  |  | 28 | 0 | 44 | my $self = shift; | 
| 865 | 28 |  | 100 |  |  | 87 | my $num = shift || 0; | 
| 866 | 28 |  |  |  |  | 33 | my @ifd; | 
| 867 |  |  |  |  |  |  |  | 
| 868 | 28 |  |  |  |  | 82 | $self->add_fields($self->{ifd}[$num], \@ifd); | 
| 869 |  |  |  |  |  |  | } | 
| 870 |  |  |  |  |  |  |  | 
| 871 |  |  |  |  |  |  | sub tagname | 
| 872 |  |  |  |  |  |  | { | 
| 873 | 68 | 50 |  | 68 | 0 | 339 | $tiff_tags{$_[1]} || sprintf "Tag-0x%04x",$_[1]; | 
| 874 |  |  |  |  |  |  | } | 
| 875 |  |  |  |  |  |  |  | 
| 876 |  |  |  |  |  |  | sub exif_tagname | 
| 877 |  |  |  |  |  |  | { | 
| 878 | 203 | 100 | 66 | 203 | 0 | 573 | $tiff_tags{$_[1]} || $exif_tags{$_[1]} || sprintf "Tag-0x%04x",$_[1]; | 
| 879 |  |  |  |  |  |  | } | 
| 880 |  |  |  |  |  |  |  | 
| 881 |  |  |  |  |  |  | sub add_fields | 
| 882 |  |  |  |  |  |  | { | 
| 883 | 61 |  |  | 61 | 0 | 123 | my($self, $offset, $ifds, $tags, $voff_plus) = @_; | 
| 884 | 61 | 50 |  |  |  | 99 | return unless $offset; | 
| 885 |  |  |  |  |  |  | # guard against finding the same offset twice (bug #29088) | 
| 886 | 61 | 50 |  |  |  | 208 | return if $self->{seen_offset}{$offset}++; | 
| 887 | 61 |  | 100 |  |  | 167 | $tags ||= \%tiff_tags; | 
| 888 |  |  |  |  |  |  |  | 
| 889 | 61 |  |  |  |  | 55 | for (${$self->{source}}) {  # alias as $_ | 
|  | 61 |  |  |  |  | 119 |  | 
| 890 | 61 | 100 |  |  |  | 118 | last if $offset > length($_) - 2;  # bad offset | 
| 891 | 60 |  |  |  |  | 132 | my $entries = $self->unpack("x$offset n", $_); | 
| 892 | 60 |  |  |  |  | 152 | my $max_entries = int((length($_) - $offset - 2) / 12); | 
| 893 |  |  |  |  |  |  | # print "ENTRIES $entries $max_entries\n"; | 
| 894 | 60 | 100 |  |  |  | 93 | if ($entries > $max_entries) { | 
| 895 |  |  |  |  |  |  | # Hmmm, something smells bad here...  parsing garbage | 
| 896 | 8 |  |  |  |  | 10 | $entries = $max_entries; | 
| 897 | 8 |  |  |  |  | 19 | last; | 
| 898 |  |  |  |  |  |  | } | 
| 899 |  |  |  |  |  |  | FIELD: | 
| 900 | 52 |  |  |  |  | 102 | for my $i (0 .. $entries-1) { | 
| 901 | 706 |  |  |  |  | 810 | my $entry_offset = 2 + $offset + $i*12; | 
| 902 | 706 |  |  |  |  | 1233 | my($tag, $type, $count, $voff) = | 
| 903 |  |  |  |  |  |  | $self->unpack("nnNN", substr($_, $entry_offset, 12)); | 
| 904 |  |  |  |  |  |  | #print STDERR "TAG $tag $type $count $voff\n"; | 
| 905 |  |  |  |  |  |  |  | 
| 906 | 706 | 100 | 100 |  |  | 1903 | if ($type == 0 || $type > @types) { | 
| 907 |  |  |  |  |  |  | # unknown type code might indicate that we are parsing garbage | 
| 908 | 2 |  |  |  |  | 258 | print STDERR "# Ignoring unknown type code $type\n"; | 
| 909 | 2 |  |  |  |  | 10 | next; | 
| 910 |  |  |  |  |  |  | } | 
| 911 |  |  |  |  |  |  |  | 
| 912 |  |  |  |  |  |  | # extract type information | 
| 913 | 704 |  |  |  |  | 728 | my($tmpl, $vlen); | 
| 914 | 704 |  |  |  |  | 594 | ($type, $tmpl, $vlen) = @{$types[$type-1]}; | 
|  | 704 |  |  |  |  | 1008 |  | 
| 915 |  |  |  |  |  |  |  | 
| 916 | 704 | 50 |  |  |  | 888 | die "Undefined type while parsing" unless $type; | 
| 917 |  |  |  |  |  |  |  | 
| 918 | 704 | 100 |  |  |  | 1011 | if ($count * $vlen <= 4) { | 
|  |  | 50 |  |  |  |  |  | 
| 919 | 420 |  |  |  |  | 414 | $voff = $entry_offset + 8; | 
| 920 |  |  |  |  |  |  | } | 
| 921 |  |  |  |  |  |  | elsif ($voff + $count * $vlen > length($_)) { | 
| 922 |  |  |  |  |  |  | # offset points outside of string, corrupt entry ignore | 
| 923 | 0 |  |  |  |  | 0 | print STDERR "# ignoring offset pointer outside of string\n"; | 
| 924 | 0 |  |  |  |  | 0 | next; | 
| 925 |  |  |  |  |  |  | } | 
| 926 |  |  |  |  |  |  | else { | 
| 927 | 284 |  | 50 |  |  | 532 | $voff += $voff_plus || 0; | 
| 928 |  |  |  |  |  |  | } | 
| 929 |  |  |  |  |  |  |  | 
| 930 | 704 |  |  |  |  | 2142 | $tmpl =~ s/(\d+)$/$count*$1/e; | 
|  | 704 |  |  |  |  | 1446 |  | 
| 931 |  |  |  |  |  |  |  | 
| 932 | 704 |  |  |  |  | 1427 | my @v = $self->unpack("x$voff $tmpl", $_); | 
| 933 |  |  |  |  |  |  |  | 
| 934 | 704 | 100 |  |  |  | 1467 | if ($type =~ /^S(SHORT|LONG|RATIONAL)/) { | 
| 935 | 40 | 50 |  |  |  | 87 | my $max = 2 ** ($1 eq "SHORT" ? 15 : 31); | 
| 936 | 40 | 50 |  |  |  | 77 | $v[0] -= ($max * 2) if $v[0] >= $max; | 
| 937 |  |  |  |  |  |  | } | 
| 938 |  |  |  |  |  |  |  | 
| 939 | 704 | 100 |  |  |  | 960 | my $val = (@v > 1) ? \@v : $v[0]; | 
| 940 | 704 | 100 |  |  |  | 1109 | if ($type =~ /^S?RATIONAL$/) { | 
| 941 | 135 | 50 |  |  |  | 211 | if (ref $val) { | 
| 942 | 135 |  |  |  |  | 191 | bless $val, "Image::TIFF::Rational"; | 
| 943 |  |  |  |  |  |  | } else { | 
| 944 | 0 |  |  |  |  | 0 | print STDERR "# invalid rational value\n"; | 
| 945 | 0 |  |  |  |  | 0 | $val = undef; | 
| 946 |  |  |  |  |  |  | } | 
| 947 |  |  |  |  |  |  | } | 
| 948 |  |  |  |  |  |  |  | 
| 949 | 704 | 100 | 100 |  |  | 1515 | if ($type eq 'ASCII' || $type eq 'UNDEFINED') | 
| 950 |  |  |  |  |  |  | { | 
| 951 | 195 | 100 |  |  |  | 830 | if ($val =~ /\0[^\0]+\z/) | 
| 952 |  |  |  |  |  |  | { | 
| 953 |  |  |  |  |  |  | # cut out the first "ASCII\0" and take the remaining text | 
| 954 |  |  |  |  |  |  | # (fix bug #29243 parsing of UserComment) | 
| 955 |  |  |  |  |  |  | # XXX TODO: this needs to handle UNICODE, too: | 
| 956 | 13 |  |  |  |  | 39 | $val =~ /\0([^\0]+)/; | 
| 957 | 13 |  | 50 |  |  | 54 | $val = '' . ($1 || ''); | 
| 958 |  |  |  |  |  |  | } | 
| 959 |  |  |  |  |  |  | else | 
| 960 |  |  |  |  |  |  | { | 
| 961 |  |  |  |  |  |  | # avoid things like "Foo\x00\x00\x00" by removing trailing nulls | 
| 962 |  |  |  |  |  |  | # this needs to handle UNICODE, too: | 
| 963 | 182 |  |  |  |  | 337 | $val =~ /^([^\0]*)/; | 
| 964 | 182 |  | 100 |  |  | 435 | $val = '' . ($1 || ''); | 
| 965 |  |  |  |  |  |  | } | 
| 966 |  |  |  |  |  |  | } | 
| 967 |  |  |  |  |  |  |  | 
| 968 | 704 |  | 66 |  |  | 1495 | $tag = $tags->{$tag} || $self->tagname($tag); | 
| 969 |  |  |  |  |  |  |  | 
| 970 | 704 | 100 |  |  |  | 1023 | if ($tag eq 'MakerNote') | 
| 971 |  |  |  |  |  |  | { | 
| 972 | 12 |  | 50 |  |  | 46 | my $maker = uc($self->{Make} || ''); | 
| 973 | 12 |  | 50 |  |  | 32 | $maker =~ /^([A-Z]+)/; $maker = $1 || ''; # "OLYMPUS ..." > "OLYMPUS" | 
|  | 12 |  |  |  |  | 48 |  | 
| 974 |  |  |  |  |  |  |  | 
| 975 |  |  |  |  |  |  | # if 'Panasonic' doesn't exist, try 'Panasonic DMC-FZ5' | 
| 976 | 0 | 0 |  |  |  | 0 | $maker = join " ", grep { defined && m/\S/ } $self->{Make}, $self->{Model} | 
| 977 | 12 | 50 |  |  |  | 37 | unless exists $makernotes{$maker}; | 
| 978 |  |  |  |  |  |  |  | 
| 979 | 12 | 50 |  |  |  | 32 | if (exists $makernotes{$maker}) { | 
| 980 | 12 |  |  |  |  | 19 | my ($ifd_off, $tag_prefix, $sub) = @{$makernotes{$maker}}; | 
|  | 12 |  |  |  |  | 33 |  | 
| 981 |  |  |  |  |  |  |  | 
| 982 |  |  |  |  |  |  | #print STDERR "# Decoding Makernotes from $maker\n"; | 
| 983 |  |  |  |  |  |  |  | 
| 984 | 12 |  |  |  |  | 38 | $self->{tag_prefix} = $tag_prefix; | 
| 985 | 12 | 50 | 66 |  |  | 70 | if ($ifd_off == -1 && length($val) >= 12) { | 
|  |  | 50 |  |  |  |  |  | 
| 986 |  |  |  |  |  |  | # fuji kludge -  http://www.butaman.ne.jp/~tsuruzoh/Computer/Digicams/exif-e.html#APP4 | 
| 987 | 0 |  |  |  |  | 0 | my $save_endian = $self->{little_endian}; | 
| 988 | 0 |  |  |  |  | 0 | $self->{little_endian} = 1; | 
| 989 | 0 |  |  |  |  | 0 | $ifd_off = $self->unpack("N", substr($val, 8, 4)); | 
| 990 | 0 |  |  |  |  | 0 | $self->add_fields($voff+$ifd_off, $ifds, $sub, $voff); | 
| 991 | 0 |  |  |  |  | 0 | $self->{little_endian} = $save_endian; | 
| 992 |  |  |  |  |  |  | } elsif ($ifd_off == -2) { | 
| 993 |  |  |  |  |  |  | # Nikon D70/D100 kludge -- word "Nikon" and 5 | 
| 994 |  |  |  |  |  |  | # bytes of data is tacked to the front of MakerNote; | 
| 995 |  |  |  |  |  |  | # all EXIF offsets are relative to MakerNote section | 
| 996 | 0 |  |  |  |  | 0 | my ($nikon_voff); | 
| 997 | 0 |  |  |  |  | 0 | $nikon_voff = 0; | 
| 998 | 0 | 0 |  |  |  | 0 | if (substr($val, 0, 5) eq 'Nikon') { | 
| 999 | 0 |  |  |  |  | 0 | $nikon_voff = $voff+10; | 
| 1000 |  |  |  |  |  |  | } | 
| 1001 |  |  |  |  |  |  | #print "IFD_OFF $ifd_off NIKON_VOFF $nikon_voff\n"; | 
| 1002 | 0 |  |  |  |  | 0 | $self->add_fields($voff+18, $ifds, $sub, $nikon_voff); | 
| 1003 |  |  |  |  |  |  | } else { | 
| 1004 | 12 |  |  |  |  | 100 | $self->add_fields($voff+$ifd_off, $ifds, $sub) | 
| 1005 |  |  |  |  |  |  | } | 
| 1006 | 12 |  |  |  |  | 25 | delete $self->{tag_prefix}; | 
| 1007 | 12 |  |  |  |  | 50 | next FIELD; | 
| 1008 |  |  |  |  |  |  | } | 
| 1009 |  |  |  |  |  |  | } | 
| 1010 |  |  |  |  |  |  |  | 
| 1011 | 692 | 100 |  |  |  | 919 | if (ref($tag)) { | 
| 1012 | 205 | 50 |  |  |  | 314 | die "Assert" unless ref($tag) eq "HASH"; | 
| 1013 | 205 | 100 |  |  |  | 383 | if (my $sub = $tag->{__SUBIFD__}) { | 
| 1014 | 21 | 50 | 33 |  |  | 97 | next if $val < 0 || $val > length($_); | 
| 1015 |  |  |  |  |  |  | #print "SUBIFD $tag->{__TAG__} $val ", length($_), "\n"; | 
| 1016 | 21 |  |  |  |  | 126 | $self->add_fields($val, $ifds, $sub); | 
| 1017 | 21 |  |  |  |  | 53 | next FIELD; | 
| 1018 |  |  |  |  |  |  | } | 
| 1019 | 184 | 100 |  |  |  | 276 | if (my $sub = $tag->{__ARRAYOFFSET__}) { | 
| 1020 | 2 | 50 |  |  |  | 3 | my $prefix; $prefix = $tag = $self->{tag_prefix} . '-' if $self->{tag_prefix}; | 
|  | 2 |  |  |  |  | 7 |  | 
| 1021 | 2 |  |  |  |  | 6 | for (my $i=0; $i < @$val; $i++) { | 
| 1022 | 82 | 100 |  |  |  | 134 | if ( exists($sub->{$i}) ) | 
| 1023 | 38 | 100 | 66 |  |  | 81 | { if ( ref($sub->{$i}) eq "HASH" && exists($sub->{$i}->{__TAG__}) ) | 
| 1024 | 21 | 100 |  |  |  | 40 | { if ( exists($sub->{$i}->{$val->[$i]}) ) | 
| 1025 |  |  |  |  |  |  | { | 
| 1026 |  |  |  |  |  |  | push @$ifds, [ $prefix . $sub->{$i}->{__TAG__}, $type, $count, | 
| 1027 | 13 |  |  |  |  | 42 | $sub->{$i}->{$val->[$i]} ]; | 
| 1028 |  |  |  |  |  |  | } | 
| 1029 |  |  |  |  |  |  | else | 
| 1030 |  |  |  |  |  |  | { | 
| 1031 | 8 |  |  |  |  | 27 | push @$ifds, [ $prefix . $sub->{$i}->{__TAG__}, $type, $count, | 
| 1032 |  |  |  |  |  |  | "Unknown (" . $val->[$i] . ")" ]; | 
| 1033 |  |  |  |  |  |  | } | 
| 1034 |  |  |  |  |  |  | } | 
| 1035 |  |  |  |  |  |  | else | 
| 1036 | 17 |  |  |  |  | 44 | { push @$ifds, [ $prefix . $sub->{$i}, $type, $count, $val->[$i] ]; } | 
| 1037 |  |  |  |  |  |  | } | 
| 1038 |  |  |  |  |  |  | } | 
| 1039 | 2 |  |  |  |  | 9 | next FIELD; | 
| 1040 |  |  |  |  |  |  | } | 
| 1041 |  |  |  |  |  |  | #hack for UNDEFINED values, they all have different | 
| 1042 |  |  |  |  |  |  | #meanings depending on tag | 
| 1043 | 182 | 100 |  |  |  | 279 | $val = &{$tag->{DECODER}}($self,$val) if defined($tag->{DECODER}); | 
|  | 35 |  |  |  |  | 96 |  | 
| 1044 | 182 | 100 |  |  |  | 365 | $val = $tag->{$val} if exists $tag->{$val}; | 
| 1045 | 182 |  |  |  |  | 222 | $tag = $tag->{__TAG__}; | 
| 1046 |  |  |  |  |  |  | } | 
| 1047 |  |  |  |  |  |  |  | 
| 1048 | 669 | 100 |  |  |  | 877 | $tag = $self->{tag_prefix} . '-' . $tag if $self->{tag_prefix}; | 
| 1049 |  |  |  |  |  |  |  | 
| 1050 |  |  |  |  |  |  | #if ( $val =~ m/ARRAY/ ) { $val = join(', ',@$val); } | 
| 1051 | 669 |  |  |  |  | 1514 | push @$ifds, [ $tag, $type, $count, $val ]; | 
| 1052 |  |  |  |  |  |  |  | 
| 1053 | 669 | 100 | 100 |  |  | 1976 | $self->{$tag} = $val if ($tag eq 'Make' or $tag eq 'Model'); | 
| 1054 |  |  |  |  |  |  | } | 
| 1055 |  |  |  |  |  |  | } | 
| 1056 |  |  |  |  |  |  |  | 
| 1057 | 61 |  |  |  |  | 137 | $ifds; | 
| 1058 |  |  |  |  |  |  | } | 
| 1059 |  |  |  |  |  |  |  | 
| 1060 |  |  |  |  |  |  | sub components_configuration_decoder | 
| 1061 |  |  |  |  |  |  | { | 
| 1062 | 12 |  |  | 12 | 0 | 17 | my $self = shift; | 
| 1063 | 12 |  |  |  |  | 18 | my $val = shift; | 
| 1064 | 12 |  |  |  |  | 19 | my $rv = ""; | 
| 1065 | 12 |  |  |  |  | 76 | my %v = ( | 
| 1066 |  |  |  |  |  |  | 0 => undef, | 
| 1067 |  |  |  |  |  |  | 1 => 'Y', | 
| 1068 |  |  |  |  |  |  | 2 => 'Cb', | 
| 1069 |  |  |  |  |  |  | 3 => 'Cr', | 
| 1070 |  |  |  |  |  |  | 4 => 'R', | 
| 1071 |  |  |  |  |  |  | 5 => 'G', | 
| 1072 |  |  |  |  |  |  | 6 => 'B', | 
| 1073 |  |  |  |  |  |  | ); | 
| 1074 | 12 | 50 |  |  |  | 30 | return join ( '', map { $v{$_} if defined($v{$_}) } $self->unpack('c4',$val) ); | 
|  | 36 |  |  |  |  | 239 |  | 
| 1075 |  |  |  |  |  |  | } | 
| 1076 |  |  |  |  |  |  |  | 
| 1077 |  |  |  |  |  |  | sub file_source_decoder | 
| 1078 |  |  |  |  |  |  | { | 
| 1079 | 12 |  |  | 12 | 0 | 27 | my $self = shift; | 
| 1080 | 12 |  |  |  |  | 22 | my $val = shift; | 
| 1081 | 12 |  |  |  |  | 38 | my %v = ( | 
| 1082 |  |  |  |  |  |  | 3 => "(DSC) Digital Still Camera", | 
| 1083 |  |  |  |  |  |  | ); | 
| 1084 | 12 |  |  |  |  | 41 | $val = $self->unpack('c',$val); | 
| 1085 | 12 | 50 |  |  |  | 77 | return $v{$val} if $v{$val}; | 
| 1086 | 0 |  |  |  |  | 0 | "Other"; | 
| 1087 |  |  |  |  |  |  | } | 
| 1088 |  |  |  |  |  |  |  | 
| 1089 |  |  |  |  |  |  | sub scene_type_decoder | 
| 1090 |  |  |  |  |  |  | { | 
| 1091 | 11 |  |  | 11 | 0 | 17 | my $self = shift; | 
| 1092 | 11 |  |  |  |  | 17 | my $val = shift; | 
| 1093 | 11 |  |  |  |  | 21 | my %v = ( | 
| 1094 |  |  |  |  |  |  | 1 => "Directly Photographed Image", | 
| 1095 |  |  |  |  |  |  | ); | 
| 1096 | 11 |  |  |  |  | 25 | $val = $self->unpack('c',$val); | 
| 1097 | 11 | 50 |  |  |  | 36 | return $v{$val} if $v{$val}; | 
| 1098 | 0 |  |  |  |  | 0 | "Other"; | 
| 1099 |  |  |  |  |  |  | } | 
| 1100 |  |  |  |  |  |  |  | 
| 1101 |  |  |  |  |  |  | package Image::TIFF::Rational; | 
| 1102 |  |  |  |  |  |  |  | 
| 1103 | 9 |  |  |  |  | 144 | use overload '""' => \&as_string, | 
| 1104 |  |  |  |  |  |  | '0+' => \&as_float, | 
| 1105 | 9 |  |  | 9 |  | 112 | fallback => 1; | 
|  | 9 |  |  |  |  | 26 |  | 
| 1106 |  |  |  |  |  |  |  | 
| 1107 |  |  |  |  |  |  | sub new { | 
| 1108 | 22 |  |  | 22 |  | 35 | my($class, $a, $b) = @_; | 
| 1109 | 22 |  |  |  |  | 65 | bless [$a, $b], $class; | 
| 1110 |  |  |  |  |  |  | } | 
| 1111 |  |  |  |  |  |  |  | 
| 1112 |  |  |  |  |  |  | sub as_string { | 
| 1113 | 68 |  |  | 68 |  | 18825 | my $self = shift; | 
| 1114 |  |  |  |  |  |  | #warn "@$self"; | 
| 1115 | 68 |  |  |  |  | 1230 | "$self->[0]/$self->[1]"; | 
| 1116 |  |  |  |  |  |  | } | 
| 1117 |  |  |  |  |  |  |  | 
| 1118 |  |  |  |  |  |  | sub as_float { | 
| 1119 | 94 |  |  | 94 |  | 119 | my $self = shift; | 
| 1120 |  |  |  |  |  |  |  | 
| 1121 |  |  |  |  |  |  | # We check here because some stupid cameras (Samsung Digimax 200) | 
| 1122 |  |  |  |  |  |  | # use rationals with 0 denominator (found in thumbnail resolution spec). | 
| 1123 | 94 | 50 |  |  |  | 146 | if ($self->[1]) { | 
| 1124 | 94 |  |  |  |  | 263 | return $self->[0] / $self->[1]; | 
| 1125 |  |  |  |  |  |  | } | 
| 1126 |  |  |  |  |  |  | else { | 
| 1127 | 0 |  |  |  |  |  | return $self->[0]; | 
| 1128 |  |  |  |  |  |  | } | 
| 1129 |  |  |  |  |  |  | } | 
| 1130 |  |  |  |  |  |  |  | 
| 1131 |  |  |  |  |  |  | 1; |