degal/exif_data.py
branchnew-exif
changeset 104 6afe59e5ffae
parent 103 63e89dc2d6f1
child 105 effae6f38749
equal deleted inserted replaced
103:63e89dc2d6f1 104:6afe59e5ffae
    47 
    47 
    48 def filter_ascii (values) :
    48 def filter_ascii (values) :
    49     """
    49     """
    50         Default post-filter for ASCII values.
    50         Default post-filter for ASCII values.
    51 
    51 
    52         This takes a single item of string data, splits it up into strings by ASCII-NUL, and trims the induvidual strings
    52         This takes a single item of string data, splits it up into strings by ASCII-NUL.
    53     """
    53 
    54 
    54         These sub-strings are then decoded into unicode as ASCII, and stripped.
    55     return [string.rstrip() for string in values[0].split('\x00') if string]
    55     """
    56 
    56 
       
    57     return [string.decode('ascii', 'replace').rstrip() for string in values[0].split('\x00') if string]
    57 
    58 
    58 def build_ratio (num, denom) :
    59 def build_ratio (num, denom) :
    59     """
    60     """
    60         Builds a Decimal ratio out of the given numerator and denominator
    61         Builds a Decimal ratio out of the given numerator and denominator
    61     """
    62     """
    62 
    63     
       
    64     # XXX: this may be slow
    63     return decimal.Decimal(num) / decimal.Decimal(denom)
    65     return decimal.Decimal(num) / decimal.Decimal(denom)
    64 
    66 
    65 def filter_ratio (values) :
    67 def filter_ratio (values) :
    66     """
    68     """
    67         Default post-filter for Ratio values.
    69         Default post-filter for Ratio values.
    89     0x0008: ('h',   'Signed Short', None            ),
    91     0x0008: ('h',   'Signed Short', None            ),
    90     0x0009: ('l',   'Signed Long',  None            ),
    92     0x0009: ('l',   'Signed Long',  None            ),
    91     0x000A: ('ll',  'Signed Ratio', filter_ratio    ),
    93     0x000A: ('ll',  'Signed Ratio', filter_ratio    ),
    92 }
    94 }
    93 
    95 
    94 def map_value (spec, value) :
    96 def map_values (spec, values) :
    95     """
    97     """
    96         Map the given tag value to a printable string using the given value spec.
    98         Map the given tag value to a printable string using the given value spec.
    97     """
    99     """
       
   100 
       
   101     # XXX: ensure that this always returns a str/unicode
    98     
   102     
    99     if callable(spec):
   103     if spec is None :
       
   104         # nothing to map
       
   105         return ", ".join(str(value) for value in values)
       
   106 
       
   107     elif callable(spec):
   100         # call mapping function
   108         # call mapping function
   101         return spec(value)
   109         return spec(values)
   102 
   110 
   103     else:
   111     elif isinstance(spec, dict) :
   104         return spec.get(value, repr(value))
   112         # lookup value, default to repr
   105 
   113         return ", ".join(spec.get(value, repr(value)) for value in values)
   106 
   114 
   107 def make_string (seq):
   115     else :
   108     """
   116         # unknown kind of spec
   109         Filter a string to strip out non-printing chars
   117         raise ValueError(spec)
   110     """
   118 
       
   119 USER_COMMENT_CHARSETS = {
       
   120     'ASCII':    ('ascii',   'replace'   ),
       
   121     'JIS':      ('jis',     'error'     ),
       
   122 
       
   123     # XXX: WTF? What kind of charset is 'Unicode' supposed to be?
       
   124     # UTF-16? Little-endian? Big-endian?
       
   125     # Confusing reigns: http://www.cpanforum.com/threads/7329
       
   126     'UNICODE':  ('utf16',   'error'     ),
       
   127 }
       
   128 
       
   129 
       
   130 def decode_UserComment (values) :
       
   131     """
       
   132         A UserComment field starts with an eight-byte encoding designator.
       
   133     """
       
   134 
       
   135     # single binary string
       
   136     value, = values
   111     
   137     
   112     # screen out non-printing characters
   138     # split up
   113     str = ''.join(c for c in seq if 32 <= c < 256)
   139     charset, comment_raw = value[:8], value[8:]
   114 
   140 
   115     if not str:
   141     # strip NILs
   116         # no printing chars
   142     charset = charset.rstrip('\x00')
   117         return seq
   143 
   118 
   144     # map
   119     else :
   145     encoding, replace = USER_COMMENT_CHARSETS.get(charset, ('ascii', 'replace'))
   120         return str
   146     
   121 
   147     # decode
   122 def make_string_uc (seq) :
   148     return [comment_raw.decode(encoding, replace)]
   123     """
   149 
   124         # Special version to deal with the code in the first 8 bytes of a user comment.
   150 # Mappings of Exif tag codes to name and decoding information.
   125         # First 8 bytes gives coding system e.g. ASCII vs. JIS vs Unicode
   151 # { tag : (name, value_dict/value_func/None) }
   126 
   152 #
   127         XXX: decode?
   153 # name is the official Exif tag name
   128     """
   154 # value_dict is a { value: value_name } mapping for human-readable values
   129 
   155 # value_func is a `(values) -> values` mapping function which *overrides* the tag's type_func.
   130     code = seq[0:8]
   156 #   XXX: or does it?
   131     seq = seq[8:]
   157 # otherwise, the value is left as-is.
   132 
       
   133     ## Of course, this is only correct if ASCII, and the standard explicitly
       
   134     ## allows JIS and Unicode.
       
   135     return make_string(seq)
       
   136 
       
   137 
       
   138 # dictionary of main EXIF tag names
       
   139 # first element of tuple is tag name, optional second element is
       
   140 # another dictionary giving names to values
       
   141 # { tag_type : (name, spec?) }
       
   142 EXIF_TAGS = {
   158 EXIF_TAGS = {
   143     0x0100: ('ImageWidth', ),
   159     0x0100: ('ImageWidth', None),
   144     0x0101: ('ImageLength', ),
   160     0x0101: ('ImageLength', None),
   145     0x0102: ('BitsPerSample', ),
   161     0x0102: ('BitsPerSample', None),
   146     0x0103: ('Compression',
   162     0x0103: ('Compression',
   147              {1: 'Uncompressed',
   163              {1: 'Uncompressed',
   148               2: 'CCITT 1D',
   164               2: 'CCITT 1D',
   149               3: 'T4/Group 3 Fax',
   165               3: 'T4/Group 3 Fax',
   150               4: 'T6/Group 4 Fax',
   166               4: 'T6/Group 4 Fax',
   172               34677: 'SGILog24',
   188               34677: 'SGILog24',
   173               34712: 'JPEG 2000',
   189               34712: 'JPEG 2000',
   174               34713: 'Nikon NEF Compressed',
   190               34713: 'Nikon NEF Compressed',
   175               65000: 'Kodak DCR Compressed',
   191               65000: 'Kodak DCR Compressed',
   176               65535: 'Pentax PEF Compressed'}),
   192               65535: 'Pentax PEF Compressed'}),
   177     0x0106: ('PhotometricInterpretation', ),
   193     0x0106: ('PhotometricInterpretation', None),
   178     0x0107: ('Thresholding', ),
   194     0x0107: ('Thresholding', None),
   179     0x010A: ('FillOrder', ),
   195     0x010A: ('FillOrder', None),
   180     0x010D: ('DocumentName', ),
   196     0x010D: ('DocumentName', None),
   181     0x010E: ('ImageDescription', ),
   197     0x010E: ('ImageDescription', None),
   182     0x010F: ('Make', ),
   198     0x010F: ('Make', None),
   183     0x0110: ('Model', ),
   199     0x0110: ('Model', None),
   184     0x0111: ('StripOffsets', ),
   200     0x0111: ('StripOffsets', None),
   185     0x0112: ('Orientation',
   201     0x0112: ('Orientation',
   186              {1: 'Horizontal (normal)',
   202              {1: 'Horizontal (normal)',
   187               2: 'Mirrored horizontal',
   203               2: 'Mirrored horizontal',
   188               3: 'Rotated 180',
   204               3: 'Rotated 180',
   189               4: 'Mirrored vertical',
   205               4: 'Mirrored vertical',
   190               5: 'Mirrored horizontal then rotated 90 CCW',
   206               5: 'Mirrored horizontal then rotated 90 CCW',
   191               6: 'Rotated 90 CW',
   207               6: 'Rotated 90 CW',
   192               7: 'Mirrored horizontal then rotated 90 CW',
   208               7: 'Mirrored horizontal then rotated 90 CW',
   193               8: 'Rotated 90 CCW'}),
   209               8: 'Rotated 90 CCW'}),
   194     0x0115: ('SamplesPerPixel', ),
   210     0x0115: ('SamplesPerPixel', None),
   195     0x0116: ('RowsPerStrip', ),
   211     0x0116: ('RowsPerStrip', None),
   196     0x0117: ('StripByteCounts', ),
   212     0x0117: ('StripByteCounts', None),
   197     0x011A: ('XResolution', ),
   213     0x011A: ('XResolution', None),
   198     0x011B: ('YResolution', ),
   214     0x011B: ('YResolution', None),
   199     0x011C: ('PlanarConfiguration', ),
   215     0x011C: ('PlanarConfiguration', None),
   200     0x011D: ('PageName', make_string),
   216     0x011D: ('PageName', None),
   201     0x0128: ('ResolutionUnit',
   217     0x0128: ('ResolutionUnit',
   202              {1: 'Not Absolute',
   218              {1: 'Not Absolute',
   203               2: 'Pixels/Inch',
   219               2: 'Pixels/Inch',
   204               3: 'Pixels/Centimeter'}),
   220               3: 'Pixels/Centimeter'}),
   205     0x012D: ('TransferFunction', ),
   221     0x012D: ('TransferFunction', None),
   206     0x0131: ('Software', ),
   222     0x0131: ('Software', None),
   207     0x0132: ('DateTime', ),
   223     0x0132: ('DateTime', None),
   208     0x013B: ('Artist', ),
   224     0x013B: ('Artist', None),
   209     0x013E: ('WhitePoint', ),
   225     0x013E: ('WhitePoint', None),
   210     0x013F: ('PrimaryChromaticities', ),
   226     0x013F: ('PrimaryChromaticities', None),
   211     0x0156: ('TransferRange', ),
   227     0x0156: ('TransferRange', None),
   212     0x0200: ('JPEGProc', ),
   228     0x0200: ('JPEGProc', None),
   213     0x0201: ('JPEGInterchangeFormat', ),
   229     0x0201: ('JPEGInterchangeFormat', None),
   214     0x0202: ('JPEGInterchangeFormatLength', ),
   230     0x0202: ('JPEGInterchangeFormatLength', None),
   215     0x0211: ('YCbCrCoefficients', ),
   231     0x0211: ('YCbCrCoefficients', None),
   216     0x0212: ('YCbCrSubSampling', ),
   232     0x0212: ('YCbCrSubSampling', None),
   217     0x0213: ('YCbCrPositioning',
   233     0x0213: ('YCbCrPositioning',
   218              {1: 'Centered',
   234              {1: 'Centered',
   219               2: 'Co-sited'}),
   235               2: 'Co-sited'}),
   220     0x0214: ('ReferenceBlackWhite', ),
   236     0x0214: ('ReferenceBlackWhite', None),
   221     
   237     
   222     0x4746: ('Rating', ),
   238     0x4746: ('Rating', None),
   223     
   239     
   224     0x828D: ('CFARepeatPatternDim', ),
   240     0x828D: ('CFARepeatPatternDim', None),
   225     0x828E: ('CFAPattern', ),
   241     0x828E: ('CFAPattern', None),
   226     0x828F: ('BatteryLevel', ),
   242     0x828F: ('BatteryLevel', None),
   227     0x8298: ('Copyright', ),
   243     0x8298: ('Copyright', None),
   228     0x829A: ('ExposureTime', ),
   244     0x829A: ('ExposureTime', None),
   229     0x829D: ('FNumber', ),
   245     0x829D: ('FNumber', None),
   230     0x83BB: ('IPTC/NAA', ),
   246     0x83BB: ('IPTC/NAA', None),
   231     0x8769: ('ExifOffset', ),
   247     0x8769: ('ExifOffset', None),
   232     0x8773: ('InterColorProfile', ),
   248     0x8773: ('InterColorProfile', None),
   233     0x8822: ('ExposureProgram',
   249     0x8822: ('ExposureProgram',
   234              {0: 'Unidentified',
   250              {0: 'Unidentified',
   235               1: 'Manual',
   251               1: 'Manual',
   236               2: 'Program Normal',
   252               2: 'Program Normal',
   237               3: 'Aperture Priority',
   253               3: 'Aperture Priority',
   238               4: 'Shutter Priority',
   254               4: 'Shutter Priority',
   239               5: 'Program Creative',
   255               5: 'Program Creative',
   240               6: 'Program Action',
   256               6: 'Program Action',
   241               7: 'Portrait Mode',
   257               7: 'Portrait Mode',
   242               8: 'Landscape Mode'}),
   258               8: 'Landscape Mode'}),
   243     0x8824: ('SpectralSensitivity', ),
   259     0x8824: ('SpectralSensitivity', None),
   244     0x8825: ('GPSInfo', ),
   260     0x8825: ('GPSInfo', None),
   245     0x8827: ('ISOSpeedRatings', ),
   261     0x8827: ('ISOSpeedRatings', None),
   246     0x8828: ('OECF', ),
   262     0x8828: ('OECF', None),
   247     0x9000: ('ExifVersion', make_string),
   263     0x9000: ('ExifVersion', None),
   248     0x9003: ('DateTimeOriginal', ),
   264     0x9003: ('DateTimeOriginal', None),
   249     0x9004: ('DateTimeDigitized', ),
   265     0x9004: ('DateTimeDigitized', None),
   250     0x9101: ('ComponentsConfiguration',
   266     0x9101: ('ComponentsConfiguration',
   251              {0: '',
   267              {0: '',
   252               1: 'Y',
   268               1: 'Y',
   253               2: 'Cb',
   269               2: 'Cb',
   254               3: 'Cr',
   270               3: 'Cr',
   255               4: 'Red',
   271               4: 'Red',
   256               5: 'Green',
   272               5: 'Green',
   257               6: 'Blue'}),
   273               6: 'Blue'}),
   258     0x9102: ('CompressedBitsPerPixel', ),
   274     0x9102: ('CompressedBitsPerPixel', None),
   259     0x9201: ('ShutterSpeedValue', ),
   275     0x9201: ('ShutterSpeedValue', None),
   260     0x9202: ('ApertureValue', ),
   276     0x9202: ('ApertureValue', None),
   261     0x9203: ('BrightnessValue', ),
   277     0x9203: ('BrightnessValue', None),
   262     0x9204: ('ExposureBiasValue', ),
   278     0x9204: ('ExposureBiasValue', None),
   263     0x9205: ('MaxApertureValue', ),
   279     0x9205: ('MaxApertureValue', None),
   264     0x9206: ('SubjectDistance', ),
   280     0x9206: ('SubjectDistance', None),
   265     0x9207: ('MeteringMode',
   281     0x9207: ('MeteringMode',
   266              {0: 'Unidentified',
   282              {0: 'Unidentified',
   267               1: 'Average',
   283               1: 'Average',
   268               2: 'CenterWeightedAverage',
   284               2: 'CenterWeightedAverage',
   269               3: 'Spot',
   285               3: 'Spot',
   300               24: 'Auto Off',
   316               24: 'Auto Off',
   301               25: 'Auto Fired',
   317               25: 'Auto Fired',
   302               29: 'Auto Fired (?)',
   318               29: 'Auto Fired (?)',
   303               31: 'Auto Fired (!)',
   319               31: 'Auto Fired (!)',
   304               32: 'Not Available'}),
   320               32: 'Not Available'}),
   305     0x920A: ('FocalLength', ),
   321     0x920A: ('FocalLength', None),
   306     0x9214: ('SubjectArea', ),
   322     0x9214: ('SubjectArea', None),
   307     0x927C: ('MakerNote', ),
   323     0x927C: ('MakerNote', None),
   308     0x9286: ('UserComment', make_string_uc),
   324     0x9286: ('UserComment', decode_UserComment),
   309     0x9290: ('SubSecTime', ),
   325     0x9290: ('SubSecTime', None),
   310     0x9291: ('SubSecTimeOriginal', ),
   326     0x9291: ('SubSecTimeOriginal', None),
   311     0x9292: ('SubSecTimeDigitized', ),
   327     0x9292: ('SubSecTimeDigitized', None),
   312     
   328     
   313     # used by Windows Explorer
   329     # used by Windows Explorer
   314     0x9C9B: ('XPTitle', ),
   330     0x9C9B: ('XPTitle', None),
   315     0x9C9C: ('XPComment', ),
   331     0x9C9C: ('XPComment', None),
   316     0x9C9D: ('XPAuthor', ), #(ignored by Windows Explorer if Artist exists)
   332     0x9C9D: ('XPAuthor', None), #(ignored by Windows Explorer if Artist exists)
   317     0x9C9E: ('XPKeywords', ),
   333     0x9C9E: ('XPKeywords', None),
   318     0x9C9F: ('XPSubject', ),
   334     0x9C9F: ('XPSubject', None),
   319 
   335 
   320     0xA000: ('FlashPixVersion', make_string),
   336     0xA000: ('FlashPixVersion', None),
   321     0xA001: ('ColorSpace',
   337     0xA001: ('ColorSpace',
   322              {1: 'sRGB',
   338              {1: 'sRGB',
   323               2: 'Adobe RGB',
   339               2: 'Adobe RGB',
   324               65535: 'Uncalibrated'}),
   340               65535: 'Uncalibrated'}),
   325     0xA002: ('ExifImageWidth', ),
   341     0xA002: ('ExifImageWidth', None),
   326     0xA003: ('ExifImageLength', ),
   342     0xA003: ('ExifImageLength', None),
   327     0xA005: ('InteroperabilityOffset', ),
   343     0xA005: ('InteroperabilityOffset', None),
   328     0xA20B: ('FlashEnergy', ),               # 0x920B in TIFF/EP
   344     0xA20B: ('FlashEnergy', None),               # 0x920B in TIFF/EP
   329     0xA20C: ('SpatialFrequencyResponse', ),  # 0x920C
   345     0xA20C: ('SpatialFrequencyResponse', None),  # 0x920C
   330     0xA20E: ('FocalPlaneXResolution', ),     # 0x920E
   346     0xA20E: ('FocalPlaneXResolution', None),     # 0x920E
   331     0xA20F: ('FocalPlaneYResolution', ),     # 0x920F
   347     0xA20F: ('FocalPlaneYResolution', None),     # 0x920F
   332     0xA210: ('FocalPlaneResolutionUnit', ),  # 0x9210
   348     0xA210: ('FocalPlaneResolutionUnit', None),  # 0x9210
   333     0xA214: ('SubjectLocation', ),           # 0x9214
   349     0xA214: ('SubjectLocation', None),           # 0x9214
   334     0xA215: ('ExposureIndex', ),             # 0x9215
   350     0xA215: ('ExposureIndex', None),             # 0x9215
   335     0xA217: ('SensingMethod',                # 0x9217
   351     0xA217: ('SensingMethod',                # 0x9217
   336              {1: 'Not defined',
   352              {1: 'Not defined',
   337               2: 'One-chip color area',
   353               2: 'One-chip color area',
   338               3: 'Two-chip color area',
   354               3: 'Two-chip color area',
   339               4: 'Three-chip color area',
   355               4: 'Three-chip color area',
   344              {1: 'Film Scanner',
   360              {1: 'Film Scanner',
   345               2: 'Reflection Print Scanner',
   361               2: 'Reflection Print Scanner',
   346               3: 'Digital Camera'}),
   362               3: 'Digital Camera'}),
   347     0xA301: ('SceneType',
   363     0xA301: ('SceneType',
   348              {1: 'Directly Photographed'}),
   364              {1: 'Directly Photographed'}),
   349     0xA302: ('CVAPattern', ),
   365     0xA302: ('CVAPattern', None),
   350     0xA401: ('CustomRendered',
   366     0xA401: ('CustomRendered',
   351              {0: 'Normal',
   367              {0: 'Normal',
   352               1: 'Custom'}),
   368               1: 'Custom'}),
   353     0xA402: ('ExposureMode',
   369     0xA402: ('ExposureMode',
   354              {0: 'Auto Exposure',
   370              {0: 'Auto Exposure',
   355               1: 'Manual Exposure',
   371               1: 'Manual Exposure',
   356               2: 'Auto Bracket'}),
   372               2: 'Auto Bracket'}),
   357     0xA403: ('WhiteBalance',
   373     0xA403: ('WhiteBalance',
   358              {0: 'Auto',
   374              {0: 'Auto',
   359               1: 'Manual'}),
   375               1: 'Manual'}),
   360     0xA404: ('DigitalZoomRatio', ),
   376     0xA404: ('DigitalZoomRatio', None),
   361     0xA405: ('FocalLengthIn35mmFilm', ),
   377     0xA405: ('FocalLengthIn35mmFilm', None),
   362     0xA406: ('SceneCaptureType',
   378     0xA406: ('SceneCaptureType',
   363              {0: 'Standard',
   379              {0: 'Standard',
   364               1: 'Landscape',
   380               1: 'Landscape',
   365               2: 'Portrait',
   381               2: 'Portrait',
   366               3: 'Night)'}),
   382               3: 'Night)'}),
   380               2: 'Hard'}),
   396               2: 'Hard'}),
   381     0xA40A: ('Sharpness',
   397     0xA40A: ('Sharpness',
   382              {0: 'Normal',
   398              {0: 'Normal',
   383               1: 'Soft',
   399               1: 'Soft',
   384               2: 'Hard'}),
   400               2: 'Hard'}),
   385     0xA40B: ('DeviceSettingDescription', ),
   401     0xA40B: ('DeviceSettingDescription', None),
   386     0xA40C: ('SubjectDistanceRange', ),
   402     0xA40C: ('SubjectDistanceRange', None),
   387     0xA500: ('Gamma', ),
   403     0xA500: ('Gamma', None),
   388     0xC4A5: ('PrintIM', ),
   404     0xC4A5: ('PrintIM', None),
   389     0xEA1C:	('Padding', ),
   405     0xEA1C:	('Padding', None),
   390     }
   406     }
   391 
   407 
   392 # interoperability tags
   408 # interoperability tags
   393 INTR_TAGS = {
   409 INTR_TAGS = {
   394     0x0001: ('InteroperabilityIndex', ),
   410     0x0001: ('InteroperabilityIndex', None),
   395     0x0002: ('InteroperabilityVersion', ),
   411     0x0002: ('InteroperabilityVersion', None),
   396     0x1000: ('RelatedImageFileFormat', ),
   412     0x1000: ('RelatedImageFileFormat', None),
   397     0x1001: ('RelatedImageWidth', ),
   413     0x1001: ('RelatedImageWidth', None),
   398     0x1002: ('RelatedImageLength', ),
   414     0x1002: ('RelatedImageLength', None),
   399     }
   415     }
   400 
   416 
   401 # GPS tags (not used yet, haven't seen camera with GPS)
   417 # GPS tags (not used yet, haven't seen camera with GPS)
   402 GPS_TAGS = {
   418 GPS_TAGS = {
   403     0x0000: ('GPSVersionID', ),
   419     0x0000: ('GPSVersionID', None),
   404     0x0001: ('GPSLatitudeRef', ),
   420     0x0001: ('GPSLatitudeRef', None),
   405     0x0002: ('GPSLatitude', ),
   421     0x0002: ('GPSLatitude', None),
   406     0x0003: ('GPSLongitudeRef', ),
   422     0x0003: ('GPSLongitudeRef', None),
   407     0x0004: ('GPSLongitude', ),
   423     0x0004: ('GPSLongitude', None),
   408     0x0005: ('GPSAltitudeRef', ),
   424     0x0005: ('GPSAltitudeRef', None),
   409     0x0006: ('GPSAltitude', ),
   425     0x0006: ('GPSAltitude', None),
   410     0x0007: ('GPSTimeStamp', ),
   426     0x0007: ('GPSTimeStamp', None),
   411     0x0008: ('GPSSatellites', ),
   427     0x0008: ('GPSSatellites', None),
   412     0x0009: ('GPSStatus', ),
   428     0x0009: ('GPSStatus', None),
   413     0x000A: ('GPSMeasureMode', ),
   429     0x000A: ('GPSMeasureMode', None),
   414     0x000B: ('GPSDOP', ),
   430     0x000B: ('GPSDOP', None),
   415     0x000C: ('GPSSpeedRef', ),
   431     0x000C: ('GPSSpeedRef', None),
   416     0x000D: ('GPSSpeed', ),
   432     0x000D: ('GPSSpeed', None),
   417     0x000E: ('GPSTrackRef', ),
   433     0x000E: ('GPSTrackRef', None),
   418     0x000F: ('GPSTrack', ),
   434     0x000F: ('GPSTrack', None),
   419     0x0010: ('GPSImgDirectionRef', ),
   435     0x0010: ('GPSImgDirectionRef', None),
   420     0x0011: ('GPSImgDirection', ),
   436     0x0011: ('GPSImgDirection', None),
   421     0x0012: ('GPSMapDatum', ),
   437     0x0012: ('GPSMapDatum', None),
   422     0x0013: ('GPSDestLatitudeRef', ),
   438     0x0013: ('GPSDestLatitudeRef', None),
   423     0x0014: ('GPSDestLatitude', ),
   439     0x0014: ('GPSDestLatitude', None),
   424     0x0015: ('GPSDestLongitudeRef', ),
   440     0x0015: ('GPSDestLongitudeRef', None),
   425     0x0016: ('GPSDestLongitude', ),
   441     0x0016: ('GPSDestLongitude', None),
   426     0x0017: ('GPSDestBearingRef', ),
   442     0x0017: ('GPSDestBearingRef', None),
   427     0x0018: ('GPSDestBearing', ),
   443     0x0018: ('GPSDestBearing', None),
   428     0x0019: ('GPSDestDistanceRef', ),
   444     0x0019: ('GPSDestDistanceRef', None),
   429     0x001A: ('GPSDestDistance', ),
   445     0x001A: ('GPSDestDistance', None),
   430     0x001D: ('GPSDate', ),
   446     0x001D: ('GPSDate', None),
   431     }
   447     }
   432 
       
   433 # Ignore these tags when quick processing
       
   434 # 0x927C is MakerNote Tags
       
   435 # 0x9286 is user comment
       
   436 IGNORE_TAGS=(0x9286, 0x927C)
       
   437 
   448 
   438 # http://tomtia.plala.jp/DigitalCamera/MakerNote/index.asp
   449 # http://tomtia.plala.jp/DigitalCamera/MakerNote/index.asp
   439 def nikon_ev_bias(seq):
   450 def nikon_ev_bias (seq) :
   440     # First digit seems to be in steps of 1/6 EV.
   451     """
   441     # Does the third value mean the step size?  It is usually 6,
   452         # First digit seems to be in steps of 1/6 EV.
   442     # but it is 12 for the ExposureDifference.
   453         # Does the third value mean the step size?  It is usually 6,
   443     #
   454         # but it is 12 for the ExposureDifference.
   444     # Check for an error condition that could cause a crash.
   455     """
   445     # This only happens if something has gone really wrong in
   456 
       
   457     # check for an error condition that could cause a crash.
       
   458     # this only happens if something has gone really wrong in
   446     # reading the Nikon MakerNote.
   459     # reading the Nikon MakerNote.
   447     if len( seq ) < 4 : return ""
   460     if len(seq) < 4 : 
   448     #
   461         return ""
       
   462 
   449     if seq == [252, 1, 6, 0]:
   463     if seq == [252, 1, 6, 0]:
   450         return "-2/3 EV"
   464         return "-2/3 EV"
       
   465 
   451     if seq == [253, 1, 6, 0]:
   466     if seq == [253, 1, 6, 0]:
   452         return "-1/2 EV"
   467         return "-1/2 EV"
       
   468 
   453     if seq == [254, 1, 6, 0]:
   469     if seq == [254, 1, 6, 0]:
   454         return "-1/3 EV"
   470         return "-1/3 EV"
       
   471 
   455     if seq == [0, 1, 6, 0]:
   472     if seq == [0, 1, 6, 0]:
   456         return "0 EV"
   473         return "0 EV"
       
   474 
   457     if seq == [2, 1, 6, 0]:
   475     if seq == [2, 1, 6, 0]:
   458         return "+1/3 EV"
   476         return "+1/3 EV"
       
   477 
   459     if seq == [3, 1, 6, 0]:
   478     if seq == [3, 1, 6, 0]:
   460         return "+1/2 EV"
   479         return "+1/2 EV"
       
   480 
   461     if seq == [4, 1, 6, 0]:
   481     if seq == [4, 1, 6, 0]:
   462         return "+2/3 EV"
   482         return "+2/3 EV"
   463     # Handle combinations not in the table.
   483 
       
   484     # handle combinations not in the table.
   464     a = seq[0]
   485     a = seq[0]
   465     # Causes headaches for the +/- logic, so special case it.
   486 
       
   487     # causes headaches for the +/- logic, so special case it.
   466     if a == 0:
   488     if a == 0:
   467         return "0 EV"
   489         return "0 EV"
       
   490 
   468     if a > 127:
   491     if a > 127:
   469         a = 256 - a
   492         a = 256 - a
   470         ret_str = "-"
   493         ret_str = "-"
   471     else:
   494     else:
   472         ret_str = "+"
   495         ret_str = "+"
   473     b = seq[2]	# Assume third value means the step size
   496 
       
   497     b = seq[2]	# assume third value means the step size
       
   498 
   474     whole = a / b
   499     whole = a / b
       
   500 
   475     a = a % b
   501     a = a % b
   476     if whole != 0:
   502 
       
   503     if whole != 0 :
   477         ret_str = ret_str + str(whole) + " "
   504         ret_str = ret_str + str(whole) + " "
   478     if a == 0:
   505 
       
   506     if a == 0 :
   479         ret_str = ret_str + "EV"
   507         ret_str = ret_str + "EV"
   480     else:
   508     else :
   481         r = Ratio(a, b)
   509         r = Ratio(a, b)
   482         ret_str = ret_str + r.__repr__() + " EV"
   510         ret_str = ret_str + r.__repr__() + " EV"
       
   511 
   483     return ret_str
   512     return ret_str
   484 
   513 
   485 # Nikon E99x MakerNote Tags
   514 # Nikon E99x MakerNote Tags
   486 MAKERNOTE_NIKON_NEWER_TAGS={
   515 MAKERNOTE_NIKON_NEWER_TAGS={
   487     0x0001: ('MakernoteVersion', make_string),	# Sometimes binary
   516     0x0001: ('MakernoteVersion', None),	# Sometimes binary
   488     0x0002: ('ISOSetting', make_string),
   517     0x0002: ('ISOSetting', None),
   489     0x0003: ('ColorMode', ),
   518     0x0003: ('ColorMode', None),
   490     0x0004: ('Quality', ),
   519     0x0004: ('Quality', None),
   491     0x0005: ('Whitebalance', ),
   520     0x0005: ('Whitebalance', None),
   492     0x0006: ('ImageSharpening', ),
   521     0x0006: ('ImageSharpening', None),
   493     0x0007: ('FocusMode', ),
   522     0x0007: ('FocusMode', None),
   494     0x0008: ('FlashSetting', ),
   523     0x0008: ('FlashSetting', None),
   495     0x0009: ('AutoFlashMode', ),
   524     0x0009: ('AutoFlashMode', None),
   496     0x000B: ('WhiteBalanceBias', ),
   525     0x000B: ('WhiteBalanceBias', None),
   497     0x000C: ('WhiteBalanceRBCoeff', ),
   526     0x000C: ('WhiteBalanceRBCoeff', None),
   498     0x000D: ('ProgramShift', nikon_ev_bias),
   527     0x000D: ('ProgramShift', nikon_ev_bias),
   499     # Nearly the same as the other EV vals, but step size is 1/12 EV (?)
   528     # Nearly the same as the other EV vals, but step size is 1/12 EV (?)
   500     0x000E: ('ExposureDifference', nikon_ev_bias),
   529     0x000E: ('ExposureDifference', nikon_ev_bias),
   501     0x000F: ('ISOSelection', ),
   530     0x000F: ('ISOSelection', None),
   502     0x0011: ('NikonPreview', ),
   531     0x0011: ('NikonPreview', None),
   503     0x0012: ('FlashCompensation', nikon_ev_bias),
   532     0x0012: ('FlashCompensation', nikon_ev_bias),
   504     0x0013: ('ISOSpeedRequested', ),
   533     0x0013: ('ISOSpeedRequested', None),
   505     0x0016: ('PhotoCornerCoordinates', ),
   534     0x0016: ('PhotoCornerCoordinates', None),
   506     # 0x0017: Unknown, but most likely an EV value
   535     # 0x0017: Unknown, but most likely an EV value
   507     0x0018: ('FlashBracketCompensationApplied', nikon_ev_bias),
   536     0x0018: ('FlashBracketCompensationApplied', nikon_ev_bias),
   508     0x0019: ('AEBracketCompensationApplied', ),
   537     0x0019: ('AEBracketCompensationApplied', None),
   509     0x001A: ('ImageProcessing', ),
   538     0x001A: ('ImageProcessing', None),
   510     0x001B: ('CropHiSpeed', ),
   539     0x001B: ('CropHiSpeed', None),
   511     0x001D: ('SerialNumber', ),	# Conflict with 0x00A0 ?
   540     0x001D: ('SerialNumber', None),	# Conflict with 0x00A0 ?
   512     0x001E: ('ColorSpace', ),
   541     0x001E: ('ColorSpace', None),
   513     0x001F: ('VRInfo', ),
   542     0x001F: ('VRInfo', None),
   514     0x0020: ('ImageAuthentication', ),
   543     0x0020: ('ImageAuthentication', None),
   515     0x0022: ('ActiveDLighting', ),
   544     0x0022: ('ActiveDLighting', None),
   516     0x0023: ('PictureControl', ),
   545     0x0023: ('PictureControl', None),
   517     0x0024: ('WorldTime', ),
   546     0x0024: ('WorldTime', None),
   518     0x0025: ('ISOInfo', ),
   547     0x0025: ('ISOInfo', None),
   519     0x0080: ('ImageAdjustment', ),
   548     0x0080: ('ImageAdjustment', None),
   520     0x0081: ('ToneCompensation', ),
   549     0x0081: ('ToneCompensation', None),
   521     0x0082: ('AuxiliaryLens', ),
   550     0x0082: ('AuxiliaryLens', None),
   522     0x0083: ('LensType', ),
   551     0x0083: ('LensType', None),
   523     0x0084: ('LensMinMaxFocalMaxAperture', ),
   552     0x0084: ('LensMinMaxFocalMaxAperture', None),
   524     0x0085: ('ManualFocusDistance', ),
   553     0x0085: ('ManualFocusDistance', None),
   525     0x0086: ('DigitalZoomFactor', ),
   554     0x0086: ('DigitalZoomFactor', None),
   526     0x0087: ('FlashMode',
   555     0x0087: ('FlashMode',
   527              {0x00: 'Did Not Fire',
   556              {0x00: 'Did Not Fire',
   528               0x01: 'Fired, Manual',
   557               0x01: 'Fired, Manual',
   529               0x07: 'Fired, External',
   558               0x07: 'Fired, External',
   530               0x08: 'Fired, Commander Mode ',
   559               0x08: 'Fired, Commander Mode ',
   543               0x11: 'Continuous, exposure bracketing',
   572               0x11: 'Continuous, exposure bracketing',
   544               0x12: 'Timer, exposure bracketing',
   573               0x12: 'Timer, exposure bracketing',
   545               0x40: 'Single frame, white balance bracketing',
   574               0x40: 'Single frame, white balance bracketing',
   546               0x41: 'Continuous, white balance bracketing',
   575               0x41: 'Continuous, white balance bracketing',
   547               0x42: 'Timer, white balance bracketing'}),
   576               0x42: 'Timer, white balance bracketing'}),
   548     0x008A: ('AutoBracketRelease', ),
   577     0x008A: ('AutoBracketRelease', None),
   549     0x008B: ('LensFStops', ),
   578     0x008B: ('LensFStops', None),
   550     0x008C: ('NEFCurve1', ),	# ExifTool calls this 'ContrastCurve'
   579     0x008C: ('NEFCurve1', None),	# ExifTool calls this 'ContrastCurve'
   551     0x008D: ('ColorMode', ),
   580     0x008D: ('ColorMode', None),
   552     0x008F: ('SceneMode', ),
   581     0x008F: ('SceneMode', None),
   553     0x0090: ('LightingType', ),
   582     0x0090: ('LightingType', None),
   554     0x0091: ('ShotInfo', ),	# First 4 bytes are a version number in ASCII
   583     0x0091: ('ShotInfo', None),	# First 4 bytes are a version number in ASCII
   555     0x0092: ('HueAdjustment', ),
   584     0x0092: ('HueAdjustment', None),
   556     # ExifTool calls this 'NEFCompression', should be 1-4
   585     # ExifTool calls this 'NEFCompression', should be 1-4
   557     0x0093: ('Compression', ),
   586     0x0093: ('Compression', None),
   558     0x0094: ('Saturation',
   587     0x0094: ('Saturation',
   559              {-3: 'B&W',
   588              {-3: 'B&W',
   560               -2: '-2',
   589               -2: '-2',
   561               -1: '-1',
   590               -1: '-1',
   562               0: '0',
   591               0: '0',
   563               1: '1',
   592               1: '1',
   564               2: '2'}),
   593               2: '2'}),
   565     0x0095: ('NoiseReduction', ),
   594     0x0095: ('NoiseReduction', None),
   566     0x0096: ('NEFCurve2', ),	# ExifTool calls this 'LinearizationTable'
   595     0x0096: ('NEFCurve2', None),	# ExifTool calls this 'LinearizationTable'
   567     0x0097: ('ColorBalance', ),	# First 4 bytes are a version number in ASCII
   596     0x0097: ('ColorBalance', None),	# First 4 bytes are a version number in ASCII
   568     0x0098: ('LensData', ),	# First 4 bytes are a version number in ASCII
   597     0x0098: ('LensData', None),	# First 4 bytes are a version number in ASCII
   569     0x0099: ('RawImageCenter', ),
   598     0x0099: ('RawImageCenter', None),
   570     0x009A: ('SensorPixelSize', ),
   599     0x009A: ('SensorPixelSize', None),
   571     0x009C: ('Scene Assist', ),
   600     0x009C: ('Scene Assist', None),
   572     0x009E: ('RetouchHistory', ),
   601     0x009E: ('RetouchHistory', None),
   573     0x00A0: ('SerialNumber', ),
   602     0x00A0: ('SerialNumber', None),
   574     0x00A2: ('ImageDataSize', ),
   603     0x00A2: ('ImageDataSize', None),
   575     # 00A3: unknown - a single byte 0
   604     # 00A3: unknown - a single byte 0
   576     # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200')
   605     # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200')
   577     0x00A5: ('ImageCount', ),
   606     0x00A5: ('ImageCount', None),
   578     0x00A6: ('DeletedImageCount', ),
   607     0x00A6: ('DeletedImageCount', None),
   579     0x00A7: ('TotalShutterReleases', ),
   608     0x00A7: ('TotalShutterReleases', None),
   580     # First 4 bytes are a version number in ASCII, with version specific
   609     # First 4 bytes are a version number in ASCII, with version specific
   581     # info to follow.  Its hard to treat it as a string due to embedded nulls.
   610     # info to follow.  Its hard to treat it as a string due to embedded nulls.
   582     0x00A8: ('FlashInfo', ),
   611     0x00A8: ('FlashInfo', None),
   583     0x00A9: ('ImageOptimization', ),
   612     0x00A9: ('ImageOptimization', None),
   584     0x00AA: ('Saturation', ),
   613     0x00AA: ('Saturation', None),
   585     0x00AB: ('DigitalVariProgram', ),
   614     0x00AB: ('DigitalVariProgram', None),
   586     0x00AC: ('ImageStabilization', ),
   615     0x00AC: ('ImageStabilization', None),
   587     0x00AD: ('Responsive AF', ),	# 'AFResponse'
   616     0x00AD: ('Responsive AF', None),	# 'AFResponse'
   588     0x00B0: ('MultiExposure', ),
   617     0x00B0: ('MultiExposure', None),
   589     0x00B1: ('HighISONoiseReduction', ),
   618     0x00B1: ('HighISONoiseReduction', None),
   590     0x00B7: ('AFInfo', ),
   619     0x00B7: ('AFInfo', None),
   591     0x00B8: ('FileInfo', ),
   620     0x00B8: ('FileInfo', None),
   592     # 00B9: unknown
   621     # 00B9: unknown
   593     0x0100: ('DigitalICE', ),
   622     0x0100: ('DigitalICE', None),
   594     0x0103: ('PreviewCompression',
   623     0x0103: ('PreviewCompression',
   595              {1: 'Uncompressed',
   624              {1: 'Uncompressed',
   596               2: 'CCITT 1D',
   625               2: 'CCITT 1D',
   597               3: 'T4/Group 3 Fax',
   626               3: 'T4/Group 3 Fax',
   598               4: 'T6/Group 4 Fax',
   627               4: 'T6/Group 4 Fax',
   620               34677: 'SGILog24',
   649               34677: 'SGILog24',
   621               34712: 'JPEG 2000',
   650               34712: 'JPEG 2000',
   622               34713: 'Nikon NEF Compressed',
   651               34713: 'Nikon NEF Compressed',
   623               65000: 'Kodak DCR Compressed',
   652               65000: 'Kodak DCR Compressed',
   624               65535: 'Pentax PEF Compressed',}),
   653               65535: 'Pentax PEF Compressed',}),
   625     0x0201: ('PreviewImageStart', ),
   654     0x0201: ('PreviewImageStart', None),
   626     0x0202: ('PreviewImageLength', ),
   655     0x0202: ('PreviewImageLength', None),
   627     0x0213: ('PreviewYCbCrPositioning',
   656     0x0213: ('PreviewYCbCrPositioning',
   628              {1: 'Centered',
   657              {1: 'Centered',
   629               2: 'Co-sited'}), 
   658               2: 'Co-sited'}), 
   630     0x0010: ('DataDump', ),
   659     0x0010: ('DataDump', None),
   631     }
   660     }
   632 
   661 
   633 MAKERNOTE_NIKON_OLDER_TAGS = {
   662 MAKERNOTE_NIKON_OLDER_TAGS = {
   634     0x0003: ('Quality',
   663     0x0003: ('Quality',
   635              {1: 'VGA Basic',
   664              {1: 'VGA Basic',
   660               4: 'Fluorescent',
   689               4: 'Fluorescent',
   661               5: 'Cloudy',
   690               5: 'Cloudy',
   662               6: 'Speed Light'}),
   691               6: 'Speed Light'}),
   663     }
   692     }
   664 
   693 
   665 # decode Olympus SpecialMode tag in MakerNote
   694 def olympus_special_mode (values) :
   666 def olympus_special_mode(v):
   695     """
   667     a={
   696         Decode Olympus SpecialMode tag in MakerNote
       
   697     """
       
   698 
       
   699     a = {
   668         0: 'Normal',
   700         0: 'Normal',
   669         1: 'Unknown',
   701         1: 'Unknown',
   670         2: 'Fast',
   702         2: 'Fast',
   671         3: 'Panorama'}
   703         3: 'Panorama'
   672     b={
   704     }
       
   705 
       
   706     b = {
   673         0: 'Non-panoramic',
   707         0: 'Non-panoramic',
   674         1: 'Left to right',
   708         1: 'Left to right',
   675         2: 'Right to left',
   709         2: 'Right to left',
   676         3: 'Bottom to top',
   710         3: 'Bottom to top',
   677         4: 'Top to bottom'}
   711         4: 'Top to bottom'
       
   712     }
       
   713 
   678     if v[0] not in a or v[2] not in b:
   714     if v[0] not in a or v[2] not in b:
   679         return v
   715         return values
       
   716 
   680     return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
   717     return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
   681 
   718 
   682 MAKERNOTE_OLYMPUS_TAGS={
   719 MAKERNOTE_OLYMPUS_TAGS={
   683     # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
   720     # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
   684     # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
   721     # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
   685     0x0100: ('JPEGThumbnail', ),
   722     0x0100: ('JPEGThumbnail', None),
   686     0x0200: ('SpecialMode', olympus_special_mode),
   723     0x0200: ('SpecialMode', olympus_special_mode),
   687     0x0201: ('JPEGQual',
   724     0x0201: ('JPEGQual',
   688              {1: 'SQ',
   725              {1: 'SQ',
   689               2: 'HQ',
   726               2: 'HQ',
   690               3: 'SHQ'}),
   727               3: 'SHQ'}),
   693              1: 'Macro',
   730              1: 'Macro',
   694              2: 'SuperMacro'}),
   731              2: 'SuperMacro'}),
   695     0x0203: ('BWMode',
   732     0x0203: ('BWMode',
   696              {0: 'Off',
   733              {0: 'Off',
   697              1: 'On'}),
   734              1: 'On'}),
   698     0x0204: ('DigitalZoom', ),
   735     0x0204: ('DigitalZoom', None),
   699     0x0205: ('FocalPlaneDiagonal', ),
   736     0x0205: ('FocalPlaneDiagonal', None),
   700     0x0206: ('LensDistortionParams', ),
   737     0x0206: ('LensDistortionParams', None),
   701     0x0207: ('SoftwareRelease', ),
   738     0x0207: ('SoftwareRelease', None),
   702     0x0208: ('PictureInfo', ),
   739     0x0208: ('PictureInfo', None),
   703     0x0209: ('CameraID', make_string), # print as string
   740     0x0209: ('CameraID', None), # print as string
   704     0x0F00: ('DataDump', ),
   741     0x0F00: ('DataDump', None),
   705     0x0300: ('PreCaptureFrames', ),
   742     0x0300: ('PreCaptureFrames', None),
   706     0x0404: ('SerialNumber', ),
   743     0x0404: ('SerialNumber', None),
   707     0x1000: ('ShutterSpeedValue', ),
   744     0x1000: ('ShutterSpeedValue', None),
   708     0x1001: ('ISOValue', ),
   745     0x1001: ('ISOValue', None),
   709     0x1002: ('ApertureValue', ),
   746     0x1002: ('ApertureValue', None),
   710     0x1003: ('BrightnessValue', ),
   747     0x1003: ('BrightnessValue', None),
   711     0x1004: ('FlashMode', ),
   748     0x1004: ('FlashMode', None),
   712     0x1004: ('FlashMode',
   749     0x1004: ('FlashMode',
   713        {2: 'On',
   750        {2: 'On',
   714         3: 'Off'}),
   751         3: 'Off'}),
   715     0x1005: ('FlashDevice',
   752     0x1005: ('FlashDevice',
   716        {0: 'None',
   753        {0: 'None',
   717         1: 'Internal',
   754         1: 'Internal',
   718         4: 'External',
   755         4: 'External',
   719         5: 'Internal + External'}),
   756         5: 'Internal + External'}),
   720     0x1006: ('ExposureCompensation', ),
   757     0x1006: ('ExposureCompensation', None),
   721     0x1007: ('SensorTemperature', ),
   758     0x1007: ('SensorTemperature', None),
   722     0x1008: ('LensTemperature', ),
   759     0x1008: ('LensTemperature', None),
   723     0x100b: ('FocusMode',
   760     0x100b: ('FocusMode',
   724        {0: 'Auto',
   761        {0: 'Auto',
   725         1: 'Manual'}),
   762         1: 'Manual'}),
   726     0x1017: ('RedBalance', ),
   763     0x1017: ('RedBalance', None),
   727     0x1018: ('BlueBalance', ),
   764     0x1018: ('BlueBalance', None),
   728     0x101a: ('SerialNumber', ),
   765     0x101a: ('SerialNumber', None),
   729     0x1023: ('FlashExposureComp', ),
   766     0x1023: ('FlashExposureComp', None),
   730     0x1026: ('ExternalFlashBounce',
   767     0x1026: ('ExternalFlashBounce',
   731        {0: 'No',
   768        {0: 'No',
   732         1: 'Yes'}),
   769         1: 'Yes'}),
   733     0x1027: ('ExternalFlashZoom', ),
   770     0x1027: ('ExternalFlashZoom', None),
   734     0x1028: ('ExternalFlashMode', ),
   771     0x1028: ('ExternalFlashMode', None),
   735     0x1029: ('Contrast 	int16u',
   772     0x1029: ('Contrast 	int16u',
   736        {0: 'High',
   773        {0: 'High',
   737         1: 'Normal',
   774         1: 'Normal',
   738         2: 'Low'}),
   775         2: 'Low'}),
   739     0x102a: ('SharpnessFactor', ),
   776     0x102a: ('SharpnessFactor', None),
   740     0x102b: ('ColorControl', ),
   777     0x102b: ('ColorControl', None),
   741     0x102c: ('ValidBits', ),
   778     0x102c: ('ValidBits', None),
   742     0x102d: ('CoringFilter', ),
   779     0x102d: ('CoringFilter', None),
   743     0x102e: ('OlympusImageWidth', ),
   780     0x102e: ('OlympusImageWidth', None),
   744     0x102f: ('OlympusImageHeight', ),
   781     0x102f: ('OlympusImageHeight', None),
   745     0x1034: ('CompressionRatio', ),
   782     0x1034: ('CompressionRatio', None),
   746     0x1035: ('PreviewImageValid',
   783     0x1035: ('PreviewImageValid',
   747        {0: 'No',
   784        {0: 'No',
   748         1: 'Yes'}),
   785         1: 'Yes'}),
   749     0x1036: ('PreviewImageStart', ),
   786     0x1036: ('PreviewImageStart', None),
   750     0x1037: ('PreviewImageLength', ),
   787     0x1037: ('PreviewImageLength', None),
   751     0x1039: ('CCDScanMode',
   788     0x1039: ('CCDScanMode',
   752        {0: 'Interlaced',
   789        {0: 'Interlaced',
   753         1: 'Progressive'}),
   790         1: 'Progressive'}),
   754     0x103a: ('NoiseReduction',
   791     0x103a: ('NoiseReduction',
   755        {0: 'Off',
   792        {0: 'Off',
   756         1: 'On'}),
   793         1: 'On'}),
   757     0x103b: ('InfinityLensStep', ),
   794     0x103b: ('InfinityLensStep', None),
   758     0x103c: ('NearLensStep', ),
   795     0x103c: ('NearLensStep', None),
   759 
   796 
   760     # TODO - these need extra definitions
   797     # TODO - these need extra definitions
   761     # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html
   798     # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html
   762     0x2010: ('Equipment', ),
   799     0x2010: ('Equipment', None),
   763     0x2020: ('CameraSettings', ),
   800     0x2020: ('CameraSettings', None),
   764     0x2030: ('RawDevelopment', ),
   801     0x2030: ('RawDevelopment', None),
   765     0x2040: ('ImageProcessing', ),
   802     0x2040: ('ImageProcessing', None),
   766     0x2050: ('FocusInfo', ),
   803     0x2050: ('FocusInfo', None),
   767     0x3000: ('RawInfo ', ),
   804     0x3000: ('RawInfo ', None),
   768     }
   805     }
   769 
   806 
   770 # 0x2020 CameraSettings
   807 # 0x2020 CameraSettings
   771 MAKERNOTE_OLYMPUS_TAG_0x2020={
   808 MAKERNOTE_OLYMPUS_TAG_0x2020={
   772     0x0100: ('PreviewImageValid',
   809     0x0100: ('PreviewImageValid',
   773              {0: 'No',
   810              {0: 'No',
   774               1: 'Yes'}),
   811               1: 'Yes'}),
   775     0x0101: ('PreviewImageStart', ),
   812     0x0101: ('PreviewImageStart', None),
   776     0x0102: ('PreviewImageLength', ),
   813     0x0102: ('PreviewImageLength', None),
   777     0x0200: ('ExposureMode',
   814     0x0200: ('ExposureMode',
   778              {1: 'Manual',
   815              {1: 'Manual',
   779               2: 'Program',
   816               2: 'Program',
   780               3: 'Aperture-priority AE',
   817               3: 'Aperture-priority AE',
   781               4: 'Shutter speed priority AE',
   818               4: 'Shutter speed priority AE',
   803              {0: 'AF Not Used',
   840              {0: 'AF Not Used',
   804               1: 'AF Used'}),
   841               1: 'AF Used'}),
   805     0x0303: ('AFSearch',
   842     0x0303: ('AFSearch',
   806              {0: 'Not Ready',
   843              {0: 'Not Ready',
   807               1: 'Ready'}),
   844               1: 'Ready'}),
   808     0x0304: ('AFAreas', ),
   845     0x0304: ('AFAreas', None),
   809     0x0401: ('FlashExposureCompensation', ),
   846     0x0401: ('FlashExposureCompensation', None),
   810     0x0500: ('WhiteBalance2',
   847     0x0500: ('WhiteBalance2',
   811              {0: 'Auto',
   848              {0: 'Auto',
   812              16: '7500K (Fine Weather with Shade)',
   849              16: '7500K (Fine Weather with Shade)',
   813              17: '6000K (Cloudy)',
   850              17: '6000K (Cloudy)',
   814              18: '5300K (Fine Weather)',
   851              18: '5300K (Fine Weather)',
   823              258: 'Custom WB 3',
   860              258: 'Custom WB 3',
   824              259: 'Custom WB 4',
   861              259: 'Custom WB 4',
   825              512: 'Custom WB 5400K',
   862              512: 'Custom WB 5400K',
   826              513: 'Custom WB 2900K',
   863              513: 'Custom WB 2900K',
   827              514: 'Custom WB 8000K', }),
   864              514: 'Custom WB 8000K', }),
   828     0x0501: ('WhiteBalanceTemperature', ),
   865     0x0501: ('WhiteBalanceTemperature', None),
   829     0x0502: ('WhiteBalanceBracket', ),
   866     0x0502: ('WhiteBalanceBracket', None),
   830     0x0503: ('CustomSaturation', ), # (3 numbers: 1. CS Value, 2. Min, 3. Max)
   867     0x0503: ('CustomSaturation', None), # (3 numbers: 1. CS Value, 2. Min, 3. Max)
   831     0x0504: ('ModifiedSaturation',
   868     0x0504: ('ModifiedSaturation',
   832              {0: 'Off',
   869              {0: 'Off',
   833               1: 'CM1 (Red Enhance)',
   870               1: 'CM1 (Red Enhance)',
   834               2: 'CM2 (Green Enhance)',
   871               2: 'CM2 (Green Enhance)',
   835               3: 'CM3 (Blue Enhance)',
   872               3: 'CM3 (Blue Enhance)',
   836               4: 'CM4 (Skin Tones)'}),
   873               4: 'CM4 (Skin Tones)'}),
   837     0x0505: ('ContrastSetting', ), # (3 numbers: 1. Contrast, 2. Min, 3. Max)
   874     0x0505: ('ContrastSetting', None), # (3 numbers: 1. Contrast, 2. Min, 3. Max)
   838     0x0506: ('SharpnessSetting', ), # (3 numbers: 1. Sharpness, 2. Min, 3. Max)
   875     0x0506: ('SharpnessSetting', None), # (3 numbers: 1. Sharpness, 2. Min, 3. Max)
   839     0x0507: ('ColorSpace',
   876     0x0507: ('ColorSpace',
   840              {0: 'sRGB',
   877              {0: 'sRGB',
   841               1: 'Adobe RGB',
   878               1: 'Adobe RGB',
   842               2: 'Pro Photo RGB'}),
   879               2: 'Pro Photo RGB'}),
   843     0x0509: ('SceneMode',
   880     0x0509: ('SceneMode',
   877              {0: 'Off',
   914              {0: 'Off',
   878               1: 'On'}),
   915               1: 'On'}),
   879     0x050c: ('ShadingCompensation',
   916     0x050c: ('ShadingCompensation',
   880              {0: 'Off',
   917              {0: 'Off',
   881               1: 'On'}),
   918               1: 'On'}),
   882     0x050d: ('CompressionFactor', ),
   919     0x050d: ('CompressionFactor', None),
   883     0x050f: ('Gradation',
   920     0x050f: ('Gradation',
   884              {'-1 -1 1': 'Low Key',
   921              {'-1 -1 1': 'Low Key',
   885               '0 -1 1': 'Normal',
   922               '0 -1 1': 'Normal',
   886               '1 -1 1': 'High Key'}),
   923               '1 -1 1': 'High Key'}),
   887     0x0520: ('PictureMode',
   924     0x0520: ('PictureMode',
   888              {1: 'Vivid',
   925              {1: 'Vivid',
   889               2: 'Natural',
   926               2: 'Natural',
   890               3: 'Muted',
   927               3: 'Muted',
   891               256: 'Monotone',
   928               256: 'Monotone',
   892               512: 'Sepia'}),
   929               512: 'Sepia'}),
   893     0x0521: ('PictureModeSaturation', ),
   930     0x0521: ('PictureModeSaturation', None),
   894     0x0522: ('PictureModeHue?', ),
   931     0x0522: ('PictureModeHue?', None),
   895     0x0523: ('PictureModeContrast', ),
   932     0x0523: ('PictureModeContrast', None),
   896     0x0524: ('PictureModeSharpness', ),
   933     0x0524: ('PictureModeSharpness', None),
   897     0x0525: ('PictureModeBWFilter',
   934     0x0525: ('PictureModeBWFilter',
   898              {0: 'n/a',
   935              {0: 'n/a',
   899               1: 'Neutral',
   936               1: 'Neutral',
   900               2: 'Yellow',
   937               2: 'Yellow',
   901               3: 'Orange',
   938               3: 'Orange',
   906               1: 'Neutral',
   943               1: 'Neutral',
   907               2: 'Sepia',
   944               2: 'Sepia',
   908               3: 'Blue',
   945               3: 'Blue',
   909               4: 'Purple',
   946               4: 'Purple',
   910               5: 'Green'}),
   947               5: 'Green'}),
   911     0x0600: ('Sequence', ), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits
   948     0x0600: ('Sequence', None), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits
   912     0x0601: ('PanoramaMode', ), # (2 numbers: 1. Mode, 2. Shot number)
   949     0x0601: ('PanoramaMode', None), # (2 numbers: 1. Mode, 2. Shot number)
   913     0x0603: ('ImageQuality2',
   950     0x0603: ('ImageQuality2',
   914              {1: 'SQ',
   951              {1: 'SQ',
   915               2: 'HQ',
   952               2: 'HQ',
   916               3: 'SHQ',
   953               3: 'SHQ',
   917               4: 'RAW'}),
   954               4: 'RAW'}),
   918     0x0901: ('ManometerReading', ),
   955     0x0901: ('ManometerReading', None),
   919     }
   956     }
   920 
   957 
   921 
   958 
   922 MAKERNOTE_CASIO_TAGS={
   959 MAKERNOTE_CASIO_TAGS={
   923     0x0001: ('RecordingMode',
   960     0x0001: ('RecordingMode',
   942               4: 'Red Eye Reduction'}),
   979               4: 'Red Eye Reduction'}),
   943     0x0005: ('FlashIntensity',
   980     0x0005: ('FlashIntensity',
   944              {11: 'Weak',
   981              {11: 'Weak',
   945               13: 'Normal',
   982               13: 'Normal',
   946               15: 'Strong'}),
   983               15: 'Strong'}),
   947     0x0006: ('Object Distance', ),
   984     0x0006: ('Object Distance', None),
   948     0x0007: ('WhiteBalance',
   985     0x0007: ('WhiteBalance',
   949              {1: 'Auto',
   986              {1: 'Auto',
   950               2: 'Tungsten',
   987               2: 'Tungsten',
   951               3: 'Daylight',
   988               3: 'Daylight',
   952               4: 'Fluorescent',
   989               4: 'Fluorescent',
   972               244: '+3.0',
  1009               244: '+3.0',
   973               250: '+2.0'}),
  1010               250: '+2.0'}),
   974     }
  1011     }
   975 
  1012 
   976 MAKERNOTE_FUJIFILM_TAGS={
  1013 MAKERNOTE_FUJIFILM_TAGS={
   977     0x0000: ('NoteVersion', make_string),
  1014     0x0000: ('NoteVersion', None),
   978     0x1000: ('Quality', ),
  1015     0x1000: ('Quality', None),
   979     0x1001: ('Sharpness',
  1016     0x1001: ('Sharpness',
   980              {1: 'Soft',
  1017              {1: 'Soft',
   981               2: 'Soft',
  1018               2: 'Soft',
   982               3: 'Normal',
  1019               3: 'Normal',
   983               4: 'Hard',
  1020               4: 'Hard',
  1002     0x1010: ('FlashMode',
  1039     0x1010: ('FlashMode',
  1003              {0: 'Auto',
  1040              {0: 'Auto',
  1004               1: 'On',
  1041               1: 'On',
  1005               2: 'Off',
  1042               2: 'Off',
  1006               3: 'Red Eye Reduction'}),
  1043               3: 'Red Eye Reduction'}),
  1007     0x1011: ('FlashStrength', ),
  1044     0x1011: ('FlashStrength', None),
  1008     0x1020: ('Macro',
  1045     0x1020: ('Macro',
  1009              {0: 'Off',
  1046              {0: 'Off',
  1010               1: 'On'}),
  1047               1: 'On'}),
  1011     0x1021: ('FocusMode',
  1048     0x1021: ('FocusMode',
  1012              {0: 'Auto',
  1049              {0: 'Auto',
  1037              {0: 'Off',
  1074              {0: 'Off',
  1038               1: 'On'}),
  1075               1: 'On'}),
  1039     }
  1076     }
  1040 
  1077 
  1041 MAKERNOTE_CANON_TAGS = {
  1078 MAKERNOTE_CANON_TAGS = {
  1042     0x0006: ('ImageType', ),
  1079     0x0006: ('ImageType', None),
  1043     0x0007: ('FirmwareVersion', ),
  1080     0x0007: ('FirmwareVersion', None),
  1044     0x0008: ('ImageNumber', ),
  1081     0x0008: ('ImageNumber', None),
  1045     0x0009: ('OwnerName', ),
  1082     0x0009: ('OwnerName', None),
  1046     }
  1083     }
  1047 
  1084 
  1048 # this is in element offset, name, optional value dictionary format
  1085 # this is in element offset, name, optional value dictionary format
  1049 MAKERNOTE_CANON_TAG_0x001 = {
  1086 MAKERNOTE_CANON_TAG_0x001 = {
  1050     1: ('Macromode',
  1087     1: ('Macromode',
  1051         {1: 'Macro',
  1088         {1: 'Macro',
  1052          2: 'Normal'}),
  1089          2: 'Normal'}),
  1053     2: ('SelfTimer', ),
  1090     2: ('SelfTimer', None),
  1054     3: ('Quality',
  1091     3: ('Quality',
  1055         {2: 'Normal',
  1092         {2: 'Normal',
  1056          3: 'Fine',
  1093          3: 'Fine',
  1057          5: 'Superfine'}),
  1094          5: 'Superfine'}),
  1058     4: ('FlashMode',
  1095     4: ('FlashMode',
  1135           1: 'Program',
  1172           1: 'Program',
  1136           2: 'Tv-priority',
  1173           2: 'Tv-priority',
  1137           3: 'Av-priority',
  1174           3: 'Av-priority',
  1138           4: 'Manual',
  1175           4: 'Manual',
  1139           5: 'A-DEP'}),
  1176           5: 'A-DEP'}),
  1140     23: ('LongFocalLengthOfLensInFocalUnits', ),
  1177     23: ('LongFocalLengthOfLensInFocalUnits', None),
  1141     24: ('ShortFocalLengthOfLensInFocalUnits', ),
  1178     24: ('ShortFocalLengthOfLensInFocalUnits', None),
  1142     25: ('FocalUnitsPerMM', ),
  1179     25: ('FocalUnitsPerMM', None),
  1143     28: ('FlashActivity',
  1180     28: ('FlashActivity',
  1144          {0: 'Did Not Fire',
  1181          {0: 'Did Not Fire',
  1145           1: 'Fired'}),
  1182           1: 'Fired'}),
  1146     29: ('FlashDetails',
  1183     29: ('FlashDetails',
  1147          {14: 'External E-TTL',
  1184          {14: 'External E-TTL',
  1161          2: 'Cloudy',
  1198          2: 'Cloudy',
  1162          3: 'Tungsten',
  1199          3: 'Tungsten',
  1163          4: 'Fluorescent',
  1200          4: 'Fluorescent',
  1164          5: 'Flash',
  1201          5: 'Flash',
  1165          6: 'Custom'}),
  1202          6: 'Custom'}),
  1166     9: ('SequenceNumber', ),
  1203     9: ('SequenceNumber', None),
  1167     14: ('AFPointUsed', ),
  1204     14: ('AFPointUsed', None),
  1168     15: ('FlashBias',
  1205     15: ('FlashBias',
  1169          {0xFFC0: '-2 EV',
  1206          {0xFFC0: '-2 EV',
  1170           0xFFCC: '-1.67 EV',
  1207           0xFFCC: '-1.67 EV',
  1171           0xFFD0: '-1.50 EV',
  1208           0xFFD0: '-1.50 EV',
  1172           0xFFD4: '-1.33 EV',
  1209           0xFFD4: '-1.33 EV',
  1181           0x0020: '1 EV',
  1218           0x0020: '1 EV',
  1182           0x002C: '1.33 EV',
  1219           0x002C: '1.33 EV',
  1183           0x0030: '1.50 EV',
  1220           0x0030: '1.50 EV',
  1184           0x0034: '1.67 EV',
  1221           0x0034: '1.67 EV',
  1185           0x0040: '2 EV'}),
  1222           0x0040: '2 EV'}),
  1186     19: ('SubjectDistance', ),
  1223     19: ('SubjectDistance', None),
  1187     }
  1224     }
  1188 
  1225 
  1189 # ratio object that eventually will be able to reduce itself to lowest
  1226 # ratio object that eventually will be able to reduce itself to lowest
  1190 # common denominator for printing
  1227 # common denominator for printing
       
  1228 # XXX: unused
  1191 def gcd(a, b):
  1229 def gcd(a, b):
  1192     if b == 0:
  1230     if b == 0:
  1193         return a
  1231         return a
  1194     else:
  1232     else:
  1195         return gcd(b, a % b)
  1233         return gcd(b, a % b)