degal/lib/exif_data.py
branchnew-exif
changeset 108 f74d8cf678ce
parent 106 a4f605bd122c
equal deleted inserted replaced
107:2e2ef5c99985 108:f74d8cf678ce
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 """
       
     5     EXIF file format data, including tag names, types, etc.
       
     6 
       
     7     Most of this was copied with modifications from EXIFpy:
       
     8         # Library to extract EXIF information from digital camera image files
       
     9         # http://sourceforge.net/projects/exif-py/
       
    10         #
       
    11         # VERSION 1.1.0
       
    12         #
       
    13         # Copyright (c) 2002-2007 Gene Cash All rights reserved
       
    14         # Copyright (c) 2007-2008 Ianaré Sévi All rights reserved
       
    15         #
       
    16         # Redistribution and use in source and binary forms, with or without
       
    17         # modification, are permitted provided that the following conditions
       
    18         # are met:
       
    19         #
       
    20         #  1. Redistributions of source code must retain the above copyright
       
    21         #     notice, this list of conditions and the following disclaimer.
       
    22         #
       
    23         #  2. Redistributions in binary form must reproduce the above
       
    24         #     copyright notice, this list of conditions and the following
       
    25         #     disclaimer in the documentation and/or other materials provided
       
    26         #     with the distribution.
       
    27         #
       
    28         #  3. Neither the name of the authors nor the names of its contributors
       
    29         #     may be used to endorse or promote products derived from this
       
    30         #     software without specific prior written permission.
       
    31         #
       
    32         # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    33         # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    34         # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    35         # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
       
    36         # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    37         # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
       
    38         # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
       
    39         # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    40         # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    41         # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    42         # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    43 
       
    44 """
       
    45 
       
    46 import decimal, itertools
       
    47 
       
    48 def filter_ascii (values) :
       
    49     """
       
    50         Default post-filter for ASCII values.
       
    51 
       
    52         This takes a single item of string data, splits it up into strings by ASCII-NUL.
       
    53 
       
    54         These sub-strings are then decoded into unicode as ASCII, and stripped.
       
    55     """
       
    56 
       
    57     return [string.decode('ascii', 'replace').rstrip() for string in values[0].split('\x00') if string]
       
    58 
       
    59 def build_ratio (num, denom) :
       
    60     """
       
    61         Builds a Decimal ratio out of the given numerator and denominator
       
    62     """
       
    63     
       
    64     # XXX: this may be slow
       
    65     return decimal.Decimal(num) / decimal.Decimal(denom)
       
    66 
       
    67 def filter_ratio (values) :
       
    68     """
       
    69         Default post-filter for Ratio values.
       
    70 
       
    71         This takes the pairs of numerator/denominator values and builds Decimals out of them
       
    72     """
       
    73 
       
    74     return [build_ratio(values[i], values[i + 1]) for i in xrange(0, len(values), 2)]
       
    75 
       
    76 
       
    77 # IFD Tag type information, indexed by code
       
    78 #  { type_code: (type_fmt, name, filter_func) }
       
    79 #
       
    80 # type_fmt's that are one char will be prefixed with the count for use with struct.unpack, those with more chars will
       
    81 # be repeated as many times for use with struct.unpack.
       
    82 FIELD_TYPES = {
       
    83 #    0x0000: (None,  'Proprietary'   ), # ??? no such type
       
    84     0x0001: ('B',   'Byte',         None            ),
       
    85     0x0002: ('s',   'ASCII',        filter_ascii    ),
       
    86     0x0003: ('H',   'Short',        None            ),
       
    87     0x0004: ('L',   'Long',         None            ),
       
    88     0x0005: ('LL',  'Ratio',        filter_ratio    ),
       
    89     0x0006: ('b',   'Signed Byte',  None            ),
       
    90     0x0007: ('s',   'Undefined',    None            ),
       
    91     0x0008: ('h',   'Signed Short', None            ),
       
    92     0x0009: ('l',   'Signed Long',  None            ),
       
    93     0x000A: ('ll',  'Signed Ratio', filter_ratio    ),
       
    94 }
       
    95 
       
    96 # magic value to indicate sub-IFDs
       
    97 SUB_IFD_MAGIC = object()
       
    98 
       
    99 
       
   100 class Tag (object) :
       
   101     """
       
   102         Represents an Exif Tag
       
   103     """
       
   104 
       
   105     def __init__ (self, name) :
       
   106         """
       
   107             Build Exif tag with given name, and optional external values-filter function.
       
   108         """
       
   109 
       
   110         self.name = name
       
   111 
       
   112     def map_values (self, values) :
       
   113         """
       
   114             Map the given tag value to a printable string using the given value spec.
       
   115         """
       
   116 
       
   117         # default value-mapping
       
   118         return ", ".join(str(value) for value in values)
       
   119 
       
   120 class TagDict (Tag) :
       
   121     """
       
   122         A tag with a dict mapping values to names
       
   123     """
       
   124 
       
   125     def __init__ (self, name, values_dict) :
       
   126         super(TagDict, self).__init__(name)
       
   127 
       
   128         self.values_dict = values_dict
       
   129 
       
   130     def map_values (self, values) :
       
   131         """
       
   132             Map the values through our dict, defaulting to the repr.
       
   133         """
       
   134 
       
   135         return ", ".join(self.values_dict.get(value, repr(value)) for value in values)
       
   136 
       
   137 class TagFunc (Tag) :
       
   138     """
       
   139         A tag with a simple function mapping values to names
       
   140     """
       
   141 
       
   142     def __init__ (self, name, values_func) :
       
   143         super(TagFunc, self).__init__(name)
       
   144 
       
   145         self.values_func = values_func
       
   146 
       
   147     def map_values (self, values) :
       
   148         """
       
   149             Map the values through our func
       
   150         """
       
   151 
       
   152         return self.values_func(values)
       
   153 
       
   154 class IFDTag (Tag) :
       
   155     """
       
   156         A tag that references another IFD
       
   157     """
       
   158 
       
   159     def __init__ (self, name, ifd_tags=None) :
       
   160         """
       
   161             A tag that points to another IFD block. `ifd_tags`, if given, lists the tags for that block, otherwise,
       
   162             the same tags as for the current block are used.
       
   163         """
       
   164 
       
   165         super(IFDTag, self).__init__(name)
       
   166 
       
   167         self.ifd_tags = ifd_tags
       
   168 
       
   169 USER_COMMENT_CHARSETS = {
       
   170     'ASCII':    ('ascii',   'replace'   ),
       
   171     'JIS':      ('jis',     'error'     ),
       
   172 
       
   173     # XXX: WTF? What kind of charset is 'Unicode' supposed to be?
       
   174     # UTF-16? Little-endian? Big-endian?
       
   175     # Confusing reigns: http://www.cpanforum.com/threads/7329
       
   176     'UNICODE':  ('utf16',   'error'     ),
       
   177 }
       
   178 
       
   179 
       
   180 def decode_UserComment (values) :
       
   181     """
       
   182         A UserComment field starts with an eight-byte encoding designator.
       
   183     """
       
   184 
       
   185     # single binary string
       
   186     value, = values
       
   187     
       
   188     # split up
       
   189     charset, comment_raw = value[:8], value[8:]
       
   190 
       
   191     # strip NILs
       
   192     charset = charset.rstrip('\x00')
       
   193 
       
   194     # map
       
   195     encoding, replace = USER_COMMENT_CHARSETS.get(charset, ('ascii', 'replace'))
       
   196     
       
   197     # decode
       
   198     return [comment_raw.decode(encoding, replace)]
       
   199 
       
   200 # Mappings of Exif tag codes to name and decoding information.
       
   201 # { tag : (name, value_dict/value_func/None/SUB_IFD_MAGIC) }
       
   202 #
       
   203 # name is the official Exif tag name
       
   204 # value_dict is a { value: value_name } mapping for human-readable values
       
   205 # value_func is a `(values) -> values` mapping function which *overrides* the tag's type_func.
       
   206 #   XXX: or does it?
       
   207 # SUB_IFD_MAGIC signifies that this IFD points to 
       
   208 # otherwise, the value is left as-is.
       
   209 # interoperability tags
       
   210 INTR_TAGS = {
       
   211     0x0001: Tag('InteroperabilityIndex'),
       
   212     0x0002: Tag('InteroperabilityVersion'),
       
   213     0x1000: Tag('RelatedImageFileFormat'),
       
   214     0x1001: Tag('RelatedImageWidth'),
       
   215     0x1002: Tag('RelatedImageLength'),
       
   216     }
       
   217 
       
   218 # GPS tags (not used yet, haven't seen camera with GPS)
       
   219 GPS_TAGS = {
       
   220     0x0000: Tag('GPSVersionID'),
       
   221     0x0001: Tag('GPSLatitudeRef'),
       
   222     0x0002: Tag('GPSLatitude'),
       
   223     0x0003: Tag('GPSLongitudeRef'),
       
   224     0x0004: Tag('GPSLongitude'),
       
   225     0x0005: Tag('GPSAltitudeRef'),
       
   226     0x0006: Tag('GPSAltitude'),
       
   227     0x0007: Tag('GPSTimeStamp'),
       
   228     0x0008: Tag('GPSSatellites'),
       
   229     0x0009: Tag('GPSStatus'),
       
   230     0x000A: Tag('GPSMeasureMode'),
       
   231     0x000B: Tag('GPSDOP'),
       
   232     0x000C: Tag('GPSSpeedRef'),
       
   233     0x000D: Tag('GPSSpeed'),
       
   234     0x000E: Tag('GPSTrackRef'),
       
   235     0x000F: Tag('GPSTrack'),
       
   236     0x0010: Tag('GPSImgDirectionRef'),
       
   237     0x0011: Tag('GPSImgDirection'),
       
   238     0x0012: Tag('GPSMapDatum'),
       
   239     0x0013: Tag('GPSDestLatitudeRef'),
       
   240     0x0014: Tag('GPSDestLatitude'),
       
   241     0x0015: Tag('GPSDestLongitudeRef'),
       
   242     0x0016: Tag('GPSDestLongitude'),
       
   243     0x0017: Tag('GPSDestBearingRef'),
       
   244     0x0018: Tag('GPSDestBearing'),
       
   245     0x0019: Tag('GPSDestDistanceRef'),
       
   246     0x001A: Tag('GPSDestDistance'),
       
   247     0x001D: Tag('GPSDate'),
       
   248     }
       
   249 
       
   250 
       
   251 EXIF_TAGS = {
       
   252     0x0100: Tag('ImageWidth'),
       
   253     0x0101: Tag('ImageLength'),
       
   254     0x0102: Tag('BitsPerSample'),
       
   255     0x0103: TagDict('Compression',
       
   256              {1: 'Uncompressed',
       
   257               2: 'CCITT 1D',
       
   258               3: 'T4/Group 3 Fax',
       
   259               4: 'T6/Group 4 Fax',
       
   260               5: 'LZW',
       
   261               6: 'JPEG (old-style)',
       
   262               7: 'JPEG',
       
   263               8: 'Adobe Deflate',
       
   264               9: 'JBIG B&W',
       
   265               10: 'JBIG Color',
       
   266               32766: 'Next',
       
   267               32769: 'Epson ERF Compressed',
       
   268               32771: 'CCIRLEW',
       
   269               32773: 'PackBits',
       
   270               32809: 'Thunderscan',
       
   271               32895: 'IT8CTPAD',
       
   272               32896: 'IT8LW',
       
   273               32897: 'IT8MP',
       
   274               32898: 'IT8BL',
       
   275               32908: 'PixarFilm',
       
   276               32909: 'PixarLog',
       
   277               32946: 'Deflate',
       
   278               32947: 'DCS',
       
   279               34661: 'JBIG',
       
   280               34676: 'SGILog',
       
   281               34677: 'SGILog24',
       
   282               34712: 'JPEG 2000',
       
   283               34713: 'Nikon NEF Compressed',
       
   284               65000: 'Kodak DCR Compressed',
       
   285               65535: 'Pentax PEF Compressed'}),
       
   286     0x0106: Tag('PhotometricInterpretation'),
       
   287     0x0107: Tag('Thresholding'),
       
   288     0x010A: Tag('FillOrder'),
       
   289     0x010D: Tag('DocumentName'),
       
   290     0x010E: Tag('ImageDescription'),
       
   291     0x010F: Tag('Make'),
       
   292     0x0110: Tag('Model'),
       
   293     0x0111: Tag('StripOffsets'),
       
   294     0x0112: TagDict('Orientation',
       
   295              {1: 'Horizontal (normal)',
       
   296               2: 'Mirrored horizontal',
       
   297               3: 'Rotated 180',
       
   298               4: 'Mirrored vertical',
       
   299               5: 'Mirrored horizontal then rotated 90 CCW',
       
   300               6: 'Rotated 90 CW',
       
   301               7: 'Mirrored horizontal then rotated 90 CW',
       
   302               8: 'Rotated 90 CCW'}),
       
   303     0x0115: Tag('SamplesPerPixel'),
       
   304     0x0116: Tag('RowsPerStrip'),
       
   305     0x0117: Tag('StripByteCounts'),
       
   306     0x011A: Tag('XResolution'),
       
   307     0x011B: Tag('YResolution'),
       
   308     0x011C: Tag('PlanarConfiguration'),
       
   309     0x011D: Tag('PageName'),
       
   310     0x0128: TagDict('ResolutionUnit',
       
   311              {1: 'Not Absolute',
       
   312               2: 'Pixels/Inch',
       
   313               3: 'Pixels/Centimeter'}),
       
   314     0x012D: Tag('TransferFunction'),
       
   315     0x0131: Tag('Software'),
       
   316     0x0132: Tag('DateTime'),
       
   317     0x013B: Tag('Artist'),
       
   318     0x013E: Tag('WhitePoint'),
       
   319     0x013F: Tag('PrimaryChromaticities'),
       
   320     0x0156: Tag('TransferRange'),
       
   321     0x0200: Tag('JPEGProc'),
       
   322     0x0201: Tag('JPEGInterchangeFormat'),
       
   323     0x0202: Tag('JPEGInterchangeFormatLength'),
       
   324     0x0211: Tag('YCbCrCoefficients'),
       
   325     0x0212: Tag('YCbCrSubSampling'),
       
   326     0x0213: TagDict('YCbCrPositioning',
       
   327              {1: 'Centered',
       
   328               2: 'Co-sited'}),
       
   329     0x0214: Tag('ReferenceBlackWhite'),
       
   330     
       
   331     0x4746: Tag('Rating'),
       
   332     
       
   333     0x828D: Tag('CFARepeatPatternDim'),
       
   334     0x828E: Tag('CFAPattern'),
       
   335     0x828F: Tag('BatteryLevel'),
       
   336     0x8298: Tag('Copyright'),
       
   337     0x829A: Tag('ExposureTime'),
       
   338     0x829D: Tag('FNumber'),
       
   339     0x83BB: Tag('IPTC/NAA'),
       
   340     0x8769: IFDTag('ExifOffset', None),
       
   341     0x8773: Tag('InterColorProfile'),
       
   342     0x8822: TagDict('ExposureProgram',
       
   343              {0: 'Unidentified',
       
   344               1: 'Manual',
       
   345               2: 'Program Normal',
       
   346               3: 'Aperture Priority',
       
   347               4: 'Shutter Priority',
       
   348               5: 'Program Creative',
       
   349               6: 'Program Action',
       
   350               7: 'Portrait Mode',
       
   351               8: 'Landscape Mode'}),
       
   352     0x8824: Tag('SpectralSensitivity'),
       
   353     0x8825: IFDTag('GPSInfo', GPS_TAGS),
       
   354     0x8827: Tag('ISOSpeedRatings'),
       
   355     0x8828: Tag('OECF'),
       
   356     0x9000: Tag('ExifVersion'),
       
   357     0x9003: Tag('DateTimeOriginal'),
       
   358     0x9004: Tag('DateTimeDigitized'),
       
   359     0x9101: TagDict('ComponentsConfiguration',
       
   360              {0: '',
       
   361               1: 'Y',
       
   362               2: 'Cb',
       
   363               3: 'Cr',
       
   364               4: 'Red',
       
   365               5: 'Green',
       
   366               6: 'Blue'}),
       
   367     0x9102: Tag('CompressedBitsPerPixel'),
       
   368     0x9201: Tag('ShutterSpeedValue'),
       
   369     0x9202: Tag('ApertureValue'),
       
   370     0x9203: Tag('BrightnessValue'),
       
   371     0x9204: Tag('ExposureBiasValue'),
       
   372     0x9205: Tag('MaxApertureValue'),
       
   373     0x9206: Tag('SubjectDistance'),
       
   374     0x9207: TagDict('MeteringMode',
       
   375              {0: 'Unidentified',
       
   376               1: 'Average',
       
   377               2: 'CenterWeightedAverage',
       
   378               3: 'Spot',
       
   379               4: 'MultiSpot',
       
   380               5: 'Pattern'}),
       
   381     0x9208: TagDict('LightSource',
       
   382              {0: 'Unknown',
       
   383               1: 'Daylight',
       
   384               2: 'Fluorescent',
       
   385               3: 'Tungsten',
       
   386               9: 'Fine Weather',
       
   387               10: 'Flash',
       
   388               11: 'Shade',
       
   389               12: 'Daylight Fluorescent',
       
   390               13: 'Day White Fluorescent',
       
   391               14: 'Cool White Fluorescent',
       
   392               15: 'White Fluorescent',
       
   393               17: 'Standard Light A',
       
   394               18: 'Standard Light B',
       
   395               19: 'Standard Light C',
       
   396               20: 'D55',
       
   397               21: 'D65',
       
   398               22: 'D75',
       
   399               255: 'Other'}),
       
   400     0x9209: TagDict('Flash',
       
   401              {0: 'No',
       
   402               1: 'Fired',
       
   403               5: 'Fired (?)', # no return sensed
       
   404               7: 'Fired (!)', # return sensed
       
   405               9: 'Fill Fired',
       
   406               13: 'Fill Fired (?)',
       
   407               15: 'Fill Fired (!)',
       
   408               16: 'Off',
       
   409               24: 'Auto Off',
       
   410               25: 'Auto Fired',
       
   411               29: 'Auto Fired (?)',
       
   412               31: 'Auto Fired (!)',
       
   413               32: 'Not Available'}),
       
   414     0x920A: Tag('FocalLength'),
       
   415     0x9214: Tag('SubjectArea'),
       
   416     0x927C: Tag('MakerNote'),
       
   417     0x9286: TagFunc('UserComment', decode_UserComment),
       
   418     0x9290: Tag('SubSecTime'),
       
   419     0x9291: Tag('SubSecTimeOriginal'),
       
   420     0x9292: Tag('SubSecTimeDigitized'),
       
   421     
       
   422     # used by Windows Explorer
       
   423     0x9C9B: Tag('XPTitle'),
       
   424     0x9C9C: Tag('XPComment'),
       
   425     0x9C9D: Tag('XPAuthor'), #(ignored by Windows Explorer if Artist exists)
       
   426     0x9C9E: Tag('XPKeywords'),
       
   427     0x9C9F: Tag('XPSubject'),
       
   428 
       
   429     0xA000: Tag('FlashPixVersion'),
       
   430     0xA001: TagDict('ColorSpace',
       
   431              {1: 'sRGB',
       
   432               2: 'Adobe RGB',
       
   433               65535: 'Uncalibrated'}),
       
   434     0xA002: Tag('ExifImageWidth'),
       
   435     0xA003: Tag('ExifImageLength'),
       
   436     0xA005: IFDTag('InteroperabilityOffset', INTR_TAGS),
       
   437     0xA20B: Tag('FlashEnergy'),               # 0x920B in TIFF/EP
       
   438     0xA20C: Tag('SpatialFrequencyResponse'),  # 0x920C
       
   439     0xA20E: Tag('FocalPlaneXResolution'),     # 0x920E
       
   440     0xA20F: Tag('FocalPlaneYResolution'),     # 0x920F
       
   441     0xA210: Tag('FocalPlaneResolutionUnit'),  # 0x9210
       
   442     0xA214: Tag('SubjectLocation'),           # 0x9214
       
   443     0xA215: Tag('ExposureIndex'),             # 0x9215
       
   444     0xA217: TagDict('SensingMethod',                # 0x9217
       
   445              {1: 'Not defined',
       
   446               2: 'One-chip color area',
       
   447               3: 'Two-chip color area',
       
   448               4: 'Three-chip color area',
       
   449               5: 'Color sequential area',
       
   450               7: 'Trilinear',
       
   451               8: 'Color sequential linear'}),             
       
   452     0xA300: TagDict('FileSource',
       
   453              {1: 'Film Scanner',
       
   454               2: 'Reflection Print Scanner',
       
   455               3: 'Digital Camera'}),
       
   456     0xA301: TagDict('SceneType',
       
   457              {1: 'Directly Photographed'}),
       
   458     0xA302: Tag('CVAPattern'),
       
   459     0xA401: TagDict('CustomRendered',
       
   460              {0: 'Normal',
       
   461               1: 'Custom'}),
       
   462     0xA402: TagDict('ExposureMode',
       
   463              {0: 'Auto Exposure',
       
   464               1: 'Manual Exposure',
       
   465               2: 'Auto Bracket'}),
       
   466     0xA403: TagDict('WhiteBalance',
       
   467              {0: 'Auto',
       
   468               1: 'Manual'}),
       
   469     0xA404: Tag('DigitalZoomRatio'),
       
   470     0xA405: ('FocalLengthIn35mmFilm', None),
       
   471     0xA406: TagDict('SceneCaptureType',
       
   472              {0: 'Standard',
       
   473               1: 'Landscape',
       
   474               2: 'Portrait',
       
   475               3: 'Night)'}),
       
   476     0xA407: TagDict('GainControl',
       
   477              {0: 'None',
       
   478               1: 'Low gain up',
       
   479               2: 'High gain up',
       
   480               3: 'Low gain down',
       
   481               4: 'High gain down'}),
       
   482     0xA408: TagDict('Contrast',
       
   483              {0: 'Normal',
       
   484               1: 'Soft',
       
   485               2: 'Hard'}),
       
   486     0xA409: TagDict('Saturation',
       
   487              {0: 'Normal',
       
   488               1: 'Soft',
       
   489               2: 'Hard'}),
       
   490     0xA40A: TagDict('Sharpness',
       
   491              {0: 'Normal',
       
   492               1: 'Soft',
       
   493               2: 'Hard'}),
       
   494     0xA40B: Tag('DeviceSettingDescription'),
       
   495     0xA40C: Tag('SubjectDistanceRange'),
       
   496     0xA500: Tag('Gamma'),
       
   497     0xC4A5: Tag('PrintIM'),
       
   498     0xEA1C:	('Padding', None),
       
   499     }
       
   500 
       
   501 # http://tomtia.plala.jp/DigitalCamera/MakerNote/index.asp
       
   502 def nikon_ev_bias (seq) :
       
   503     """
       
   504         # First digit seems to be in steps of 1/6 EV.
       
   505         # Does the third value mean the step size?  It is usually 6,
       
   506         # but it is 12 for the ExposureDifference.
       
   507     """
       
   508 
       
   509     # check for an error condition that could cause a crash.
       
   510     # this only happens if something has gone really wrong in
       
   511     # reading the Nikon MakerNote.
       
   512     if len(seq) < 4 : 
       
   513         return ""
       
   514 
       
   515     if seq == [252, 1, 6, 0]:
       
   516         return "-2/3 EV"
       
   517 
       
   518     if seq == [253, 1, 6, 0]:
       
   519         return "-1/2 EV"
       
   520 
       
   521     if seq == [254, 1, 6, 0]:
       
   522         return "-1/3 EV"
       
   523 
       
   524     if seq == [0, 1, 6, 0]:
       
   525         return "0 EV"
       
   526 
       
   527     if seq == [2, 1, 6, 0]:
       
   528         return "+1/3 EV"
       
   529 
       
   530     if seq == [3, 1, 6, 0]:
       
   531         return "+1/2 EV"
       
   532 
       
   533     if seq == [4, 1, 6, 0]:
       
   534         return "+2/3 EV"
       
   535 
       
   536     # handle combinations not in the table.
       
   537     a = seq[0]
       
   538 
       
   539     # causes headaches for the +/- logic, so special case it.
       
   540     if a == 0:
       
   541         return "0 EV"
       
   542 
       
   543     if a > 127:
       
   544         a = 256 - a
       
   545         ret_str = "-"
       
   546     else:
       
   547         ret_str = "+"
       
   548 
       
   549     b = seq[2]	# assume third value means the step size
       
   550 
       
   551     whole = a / b
       
   552 
       
   553     a = a % b
       
   554 
       
   555     if whole != 0 :
       
   556         ret_str = ret_str + str(whole) + " "
       
   557 
       
   558     if a == 0 :
       
   559         ret_str = ret_str + "EV"
       
   560     else :
       
   561         r = Ratio(a, b)
       
   562         ret_str = ret_str + r.__repr__() + " EV"
       
   563 
       
   564     return ret_str
       
   565 
       
   566 # Nikon E99x MakerNote Tags
       
   567 MAKERNOTE_NIKON_NEWER_TAGS={
       
   568     0x0001: Tag('MakernoteVersion'),	# Sometimes binary
       
   569     0x0002: Tag('ISOSetting'),
       
   570     0x0003: Tag('ColorMode'),
       
   571     0x0004: Tag('Quality'),
       
   572     0x0005: Tag('Whitebalance'),
       
   573     0x0006: Tag('ImageSharpening'),
       
   574     0x0007: Tag('FocusMode'),
       
   575     0x0008: Tag('FlashSetting'),
       
   576     0x0009: Tag('AutoFlashMode'),
       
   577     0x000B: Tag('WhiteBalanceBias'),
       
   578     0x000C: Tag('WhiteBalanceRBCoeff'),
       
   579     0x000D: TagFunc('ProgramShift', nikon_ev_bias),
       
   580     # Nearly the same as the other EV vals, but step size is 1/12 EV (?)
       
   581     0x000E: TagFunc('ExposureDifference', nikon_ev_bias),
       
   582     0x000F: Tag('ISOSelection'),
       
   583     0x0011: Tag('NikonPreview'),
       
   584     0x0012: TagFunc('FlashCompensation', nikon_ev_bias),
       
   585     0x0013: Tag('ISOSpeedRequested'),
       
   586     0x0016: Tag('PhotoCornerCoordinates'),
       
   587     # 0x0017: Unknown, but most likely an EV value
       
   588     0x0018: TagFunc('FlashBracketCompensationApplied', nikon_ev_bias),
       
   589     0x0019: Tag('AEBracketCompensationApplied'),
       
   590     0x001A: Tag('ImageProcessing'),
       
   591     0x001B: Tag('CropHiSpeed'),
       
   592     0x001D: Tag('SerialNumber'),	# Conflict with 0x00A0 ?
       
   593     0x001E: Tag('ColorSpace'),
       
   594     0x001F: Tag('VRInfo'),
       
   595     0x0020: Tag('ImageAuthentication'),
       
   596     0x0022: Tag('ActiveDLighting'),
       
   597     0x0023: Tag('PictureControl'),
       
   598     0x0024: Tag('WorldTime'),
       
   599     0x0025: Tag('ISOInfo'),
       
   600     0x0080: Tag('ImageAdjustment'),
       
   601     0x0081: Tag('ToneCompensation'),
       
   602     0x0082: Tag('AuxiliaryLens'),
       
   603     0x0083: Tag('LensType'),
       
   604     0x0084: Tag('LensMinMaxFocalMaxAperture'),
       
   605     0x0085: Tag('ManualFocusDistance'),
       
   606     0x0086: Tag('DigitalZoomFactor'),
       
   607     0x0087: TagDict('FlashMode',
       
   608              {0x00: 'Did Not Fire',
       
   609               0x01: 'Fired, Manual',
       
   610               0x07: 'Fired, External',
       
   611               0x08: 'Fired, Commander Mode ',
       
   612               0x09: 'Fired, TTL Mode'}),
       
   613     0x0088: TagDict('AFFocusPosition',
       
   614              {0x0000: 'Center',
       
   615               0x0100: 'Top',
       
   616               0x0200: 'Bottom',
       
   617               0x0300: 'Left',
       
   618               0x0400: 'Right'}),
       
   619     0x0089: TagDict('BracketingMode',
       
   620              {0x00: 'Single frame, no bracketing',
       
   621               0x01: 'Continuous, no bracketing',
       
   622               0x02: 'Timer, no bracketing',
       
   623               0x10: 'Single frame, exposure bracketing',
       
   624               0x11: 'Continuous, exposure bracketing',
       
   625               0x12: 'Timer, exposure bracketing',
       
   626               0x40: 'Single frame, white balance bracketing',
       
   627               0x41: 'Continuous, white balance bracketing',
       
   628               0x42: 'Timer, white balance bracketing'}),
       
   629     0x008A: Tag('AutoBracketRelease'),
       
   630     0x008B: Tag('LensFStops'),
       
   631     0x008C: ('NEFCurve1', None),	# ExifTool calls this 'ContrastCurve'
       
   632     0x008D: Tag('ColorMode'),
       
   633     0x008F: Tag('SceneMode'),
       
   634     0x0090: Tag('LightingType'),
       
   635     0x0091: Tag('ShotInfo'),	# First 4 bytes are a version number in ASCII
       
   636     0x0092: Tag('HueAdjustment'),
       
   637     # ExifTool calls this 'NEFCompression', should be 1-4
       
   638     0x0093: Tag('Compression'),
       
   639     0x0094: TagDict('Saturation',
       
   640              {-3: 'B&W',
       
   641               -2: '-2',
       
   642               -1: '-1',
       
   643               0: '0',
       
   644               1: '1',
       
   645               2: '2'}),
       
   646     0x0095: Tag('NoiseReduction'),
       
   647     0x0096: ('NEFCurve2', None),	# ExifTool calls this 'LinearizationTable'
       
   648     0x0097: Tag('ColorBalance'),	# First 4 bytes are a version number in ASCII
       
   649     0x0098: Tag('LensData'),	# First 4 bytes are a version number in ASCII
       
   650     0x0099: Tag('RawImageCenter'),
       
   651     0x009A: Tag('SensorPixelSize'),
       
   652     0x009C: Tag('Scene Assist'),
       
   653     0x009E: Tag('RetouchHistory'),
       
   654     0x00A0: Tag('SerialNumber'),
       
   655     0x00A2: Tag('ImageDataSize'),
       
   656     # 00A3: unknown - a single byte 0
       
   657     # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200')
       
   658     0x00A5: Tag('ImageCount'),
       
   659     0x00A6: Tag('DeletedImageCount'),
       
   660     0x00A7: Tag('TotalShutterReleases'),
       
   661     # First 4 bytes are a version number in ASCII, with version specific
       
   662     # info to follow.  Its hard to treat it as a string due to embedded nulls.
       
   663     0x00A8: Tag('FlashInfo'),
       
   664     0x00A9: Tag('ImageOptimization'),
       
   665     0x00AA: Tag('Saturation'),
       
   666     0x00AB: Tag('DigitalVariProgram'),
       
   667     0x00AC: Tag('ImageStabilization'),
       
   668     0x00AD: Tag('Responsive AF'),	# 'AFResponse'
       
   669     0x00B0: Tag('MultiExposure'),
       
   670     0x00B1: Tag('HighISONoiseReduction'),
       
   671     0x00B7: Tag('AFInfo'),
       
   672     0x00B8: Tag('FileInfo'),
       
   673     # 00B9: unknown
       
   674     0x0100: Tag('DigitalICE'),
       
   675     0x0103: TagDict('PreviewCompression',
       
   676              {1: 'Uncompressed',
       
   677               2: 'CCITT 1D',
       
   678               3: 'T4/Group 3 Fax',
       
   679               4: 'T6/Group 4 Fax',
       
   680               5: 'LZW',
       
   681               6: 'JPEG (old-style)',
       
   682               7: 'JPEG',
       
   683               8: 'Adobe Deflate',
       
   684               9: 'JBIG B&W',
       
   685               10: 'JBIG Color',
       
   686               32766: 'Next',
       
   687               32769: 'Epson ERF Compressed',
       
   688               32771: 'CCIRLEW',
       
   689               32773: 'PackBits',
       
   690               32809: 'Thunderscan',
       
   691               32895: 'IT8CTPAD',
       
   692               32896: 'IT8LW',
       
   693               32897: 'IT8MP',
       
   694               32898: 'IT8BL',
       
   695               32908: 'PixarFilm',
       
   696               32909: 'PixarLog',
       
   697               32946: 'Deflate',
       
   698               32947: 'DCS',
       
   699               34661: 'JBIG',
       
   700               34676: 'SGILog',
       
   701               34677: 'SGILog24',
       
   702               34712: 'JPEG 2000',
       
   703               34713: 'Nikon NEF Compressed',
       
   704               65000: 'Kodak DCR Compressed',
       
   705               65535: 'Pentax PEF Compressed',}),
       
   706     0x0201: Tag('PreviewImageStart'),
       
   707     0x0202: Tag('PreviewImageLength'),
       
   708     0x0213: TagDict('PreviewYCbCrPositioning',
       
   709              {1: 'Centered',
       
   710               2: 'Co-sited'}), 
       
   711     0x0010: Tag('DataDump'),
       
   712     }
       
   713 
       
   714 MAKERNOTE_NIKON_OLDER_TAGS = {
       
   715     0x0003: TagDict('Quality',
       
   716              {1: 'VGA Basic',
       
   717               2: 'VGA Normal',
       
   718               3: 'VGA Fine',
       
   719               4: 'SXGA Basic',
       
   720               5: 'SXGA Normal',
       
   721               6: 'SXGA Fine'}),
       
   722     0x0004: TagDict('ColorMode',
       
   723              {1: 'Color',
       
   724               2: 'Monochrome'}),
       
   725     0x0005: TagDict('ImageAdjustment',
       
   726              {0: 'Normal',
       
   727               1: 'Bright+',
       
   728               2: 'Bright-',
       
   729               3: 'Contrast+',
       
   730               4: 'Contrast-'}),
       
   731     0x0006: TagDict('CCDSpeed',
       
   732              {0: 'ISO 80',
       
   733               2: 'ISO 160',
       
   734               4: 'ISO 320',
       
   735               5: 'ISO 100'}),
       
   736     0x0007: TagDict('WhiteBalance',
       
   737              {0: 'Auto',
       
   738               1: 'Preset',
       
   739               2: 'Daylight',
       
   740               3: 'Incandescent',
       
   741               4: 'Fluorescent',
       
   742               5: 'Cloudy',
       
   743               6: 'Speed Light'}),
       
   744     }
       
   745 
       
   746 def olympus_special_mode (values) :
       
   747     """
       
   748         Decode Olympus SpecialMode tag in MakerNote
       
   749     """
       
   750 
       
   751     a = {
       
   752         0: 'Normal',
       
   753         1: 'Unknown',
       
   754         2: 'Fast',
       
   755         3: 'Panorama'
       
   756     }
       
   757 
       
   758     b = {
       
   759         0: 'Non-panoramic',
       
   760         1: 'Left to right',
       
   761         2: 'Right to left',
       
   762         3: 'Bottom to top',
       
   763         4: 'Top to bottom'
       
   764     }
       
   765 
       
   766     if v[0] not in a or v[2] not in b:
       
   767         return values
       
   768 
       
   769     return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
       
   770 
       
   771 MAKERNOTE_OLYMPUS_TAGS={
       
   772     # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
       
   773     # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
       
   774     0x0100: Tag('JPEGThumbnail'),
       
   775     0x0200: TagFunc('SpecialMode', olympus_special_mode),
       
   776     0x0201: TagDict('JPEGQual',
       
   777              {1: 'SQ',
       
   778               2: 'HQ',
       
   779               3: 'SHQ'}),
       
   780     0x0202: TagDict('Macro',
       
   781              {0: 'Normal',
       
   782              1: 'Macro',
       
   783              2: 'SuperMacro'}),
       
   784     0x0203: TagDict('BWMode',
       
   785              {0: 'Off',
       
   786              1: 'On'}),
       
   787     0x0204: Tag('DigitalZoom'),
       
   788     0x0205: Tag('FocalPlaneDiagonal'),
       
   789     0x0206: Tag('LensDistortionParams'),
       
   790     0x0207: Tag('SoftwareRelease'),
       
   791     0x0208: Tag('PictureInfo'),
       
   792     0x0209: Tag('CameraID'), # print as string
       
   793     0x0F00: Tag('DataDump'),
       
   794     0x0300: Tag('PreCaptureFrames'),
       
   795     0x0404: Tag('SerialNumber'),
       
   796     0x1000: Tag('ShutterSpeedValue'),
       
   797     0x1001: Tag('ISOValue'),
       
   798     0x1002: Tag('ApertureValue'),
       
   799     0x1003: Tag('BrightnessValue'),
       
   800     0x1004: Tag('FlashMode'),
       
   801     0x1004: TagDict('FlashMode',
       
   802        {2: 'On',
       
   803         3: 'Off'}),
       
   804     0x1005: TagDict('FlashDevice',
       
   805        {0: 'None',
       
   806         1: 'Internal',
       
   807         4: 'External',
       
   808         5: 'Internal + External'}),
       
   809     0x1006: Tag('ExposureCompensation'),
       
   810     0x1007: Tag('SensorTemperature'),
       
   811     0x1008: Tag('LensTemperature'),
       
   812     0x100b: TagDict('FocusMode',
       
   813        {0: 'Auto',
       
   814         1: 'Manual'}),
       
   815     0x1017: Tag('RedBalance'),
       
   816     0x1018: Tag('BlueBalance'),
       
   817     0x101a: Tag('SerialNumber'),
       
   818     0x1023: Tag('FlashExposureComp'),
       
   819     0x1026: TagDict('ExternalFlashBounce',
       
   820        {0: 'No',
       
   821         1: 'Yes'}),
       
   822     0x1027: Tag('ExternalFlashZoom'),
       
   823     0x1028: Tag('ExternalFlashMode'),
       
   824     0x1029: ('Contrast 	int16u',
       
   825        {0: 'High',
       
   826         1: 'Normal',
       
   827         2: 'Low'}),
       
   828     0x102a: Tag('SharpnessFactor'),
       
   829     0x102b: Tag('ColorControl'),
       
   830     0x102c: Tag('ValidBits'),
       
   831     0x102d: Tag('CoringFilter'),
       
   832     0x102e: Tag('OlympusImageWidth'),
       
   833     0x102f: Tag('OlympusImageHeight'),
       
   834     0x1034: Tag('CompressionRatio'),
       
   835     0x1035: TagDict('PreviewImageValid',
       
   836        {0: 'No',
       
   837         1: 'Yes'}),
       
   838     0x1036: Tag('PreviewImageStart'),
       
   839     0x1037: Tag('PreviewImageLength'),
       
   840     0x1039: TagDict('CCDScanMode',
       
   841        {0: 'Interlaced',
       
   842         1: 'Progressive'}),
       
   843     0x103a: TagDict('NoiseReduction',
       
   844        {0: 'Off',
       
   845         1: 'On'}),
       
   846     0x103b: Tag('InfinityLensStep'),
       
   847     0x103c: Tag('NearLensStep'),
       
   848 
       
   849     # TODO - these need extra definitions
       
   850     # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html
       
   851     0x2010: Tag('Equipment'),
       
   852     0x2020: Tag('CameraSettings'),
       
   853     0x2030: Tag('RawDevelopment'),
       
   854     0x2040: Tag('ImageProcessing'),
       
   855     0x2050: Tag('FocusInfo'),
       
   856     0x3000: Tag('RawInfo '),
       
   857     }
       
   858 
       
   859 # 0x2020 CameraSettings
       
   860 MAKERNOTE_OLYMPUS_TAG_0x2020={
       
   861     0x0100: TagDict('PreviewImageValid',
       
   862              {0: 'No',
       
   863               1: 'Yes'}),
       
   864     0x0101: Tag('PreviewImageStart'),
       
   865     0x0102: Tag('PreviewImageLength'),
       
   866     0x0200: TagDict('ExposureMode',
       
   867              {1: 'Manual',
       
   868               2: 'Program',
       
   869               3: 'Aperture-priority AE',
       
   870               4: 'Shutter speed priority AE',
       
   871               5: 'Program-shift'}),
       
   872     0x0201: TagDict('AELock',
       
   873              {0: 'Off',
       
   874               1: 'On'}),
       
   875     0x0202: TagDict('MeteringMode',
       
   876              {2: 'Center Weighted',
       
   877               3: 'Spot',
       
   878               5: 'ESP',
       
   879               261: 'Pattern+AF',
       
   880               515: 'Spot+Highlight control',
       
   881               1027: 'Spot+Shadow control'}),
       
   882     0x0300: TagDict('MacroMode',
       
   883              {0: 'Off',
       
   884               1: 'On'}),
       
   885     0x0301: TagDict('FocusMode',
       
   886              {0: 'Single AF',
       
   887               1: 'Sequential shooting AF',
       
   888               2: 'Continuous AF',
       
   889               3: 'Multi AF',
       
   890               10: 'MF'}),
       
   891     0x0302: TagDict('FocusProcess',
       
   892              {0: 'AF Not Used',
       
   893               1: 'AF Used'}),
       
   894     0x0303: TagDict('AFSearch',
       
   895              {0: 'Not Ready',
       
   896               1: 'Ready'}),
       
   897     0x0304: Tag('AFAreas'),
       
   898     0x0401: Tag('FlashExposureCompensation'),
       
   899     0x0500: ('WhiteBalance2',
       
   900              {0: 'Auto',
       
   901              16: '7500K (Fine Weather with Shade)',
       
   902              17: '6000K (Cloudy)',
       
   903              18: '5300K (Fine Weather)',
       
   904              20: '3000K (Tungsten light)',
       
   905              21: '3600K (Tungsten light-like)',
       
   906              33: '6600K (Daylight fluorescent)',
       
   907              34: '4500K (Neutral white fluorescent)',
       
   908              35: '4000K (Cool white fluorescent)',
       
   909              48: '3600K (Tungsten light-like)',
       
   910              256: 'Custom WB 1',
       
   911              257: 'Custom WB 2',
       
   912              258: 'Custom WB 3',
       
   913              259: 'Custom WB 4',
       
   914              512: 'Custom WB 5400K',
       
   915              513: 'Custom WB 2900K',
       
   916              514: 'Custom WB 8000K', }),
       
   917     0x0501: Tag('WhiteBalanceTemperature'),
       
   918     0x0502: Tag('WhiteBalanceBracket'),
       
   919     0x0503: Tag('CustomSaturation'), # (3 numbers: 1. CS Value, 2. Min, 3. Max)
       
   920     0x0504: TagDict('ModifiedSaturation',
       
   921              {0: 'Off',
       
   922               1: 'CM1 (Red Enhance)',
       
   923               2: 'CM2 (Green Enhance)',
       
   924               3: 'CM3 (Blue Enhance)',
       
   925               4: 'CM4 (Skin Tones)'}),
       
   926     0x0505: Tag('ContrastSetting'), # (3 numbers: 1. Contrast, 2. Min, 3. Max)
       
   927     0x0506: Tag('SharpnessSetting'), # (3 numbers: 1. Sharpness, 2. Min, 3. Max)
       
   928     0x0507: TagDict('ColorSpace',
       
   929              {0: 'sRGB',
       
   930               1: 'Adobe RGB',
       
   931               2: 'Pro Photo RGB'}),
       
   932     0x0509: TagDict('SceneMode',
       
   933              {0: 'Standard',
       
   934               6: 'Auto',
       
   935               7: 'Sport',
       
   936               8: 'Portrait',
       
   937               9: 'Landscape+Portrait',
       
   938              10: 'Landscape',
       
   939              11: 'Night scene',
       
   940              13: 'Panorama',
       
   941              16: 'Landscape+Portrait',
       
   942              17: 'Night+Portrait',
       
   943              19: 'Fireworks',
       
   944              20: 'Sunset',
       
   945              22: 'Macro',
       
   946              25: 'Documents',
       
   947              26: 'Museum',
       
   948              28: 'Beach&Snow',
       
   949              30: 'Candle',
       
   950              35: 'Underwater Wide1',
       
   951              36: 'Underwater Macro',
       
   952              39: 'High Key',
       
   953              40: 'Digital Image Stabilization',
       
   954              44: 'Underwater Wide2',
       
   955              45: 'Low Key',
       
   956              46: 'Children',
       
   957              48: 'Nature Macro'}),
       
   958     0x050a: TagDict('NoiseReduction',
       
   959              {0: 'Off',
       
   960               1: 'Noise Reduction',
       
   961               2: 'Noise Filter',
       
   962               3: 'Noise Reduction + Noise Filter',
       
   963               4: 'Noise Filter (ISO Boost)',
       
   964               5: 'Noise Reduction + Noise Filter (ISO Boost)'}),
       
   965     0x050b: TagDict('DistortionCorrection',
       
   966              {0: 'Off',
       
   967               1: 'On'}),
       
   968     0x050c: TagDict('ShadingCompensation',
       
   969              {0: 'Off',
       
   970               1: 'On'}),
       
   971     0x050d: Tag('CompressionFactor'),
       
   972     0x050f: TagDict('Gradation',
       
   973              {'-1 -1 1': 'Low Key',
       
   974               '0 -1 1': 'Normal',
       
   975               '1 -1 1': 'High Key'}),
       
   976     0x0520: TagDict('PictureMode',
       
   977              {1: 'Vivid',
       
   978               2: 'Natural',
       
   979               3: 'Muted',
       
   980               256: 'Monotone',
       
   981               512: 'Sepia'}),
       
   982     0x0521: Tag('PictureModeSaturation'),
       
   983     0x0522: Tag('PictureModeHue?'),
       
   984     0x0523: Tag('PictureModeContrast'),
       
   985     0x0524: Tag('PictureModeSharpness'),
       
   986     0x0525: TagDict('PictureModeBWFilter',
       
   987              {0: 'n/a',
       
   988               1: 'Neutral',
       
   989               2: 'Yellow',
       
   990               3: 'Orange',
       
   991               4: 'Red',
       
   992               5: 'Green'}),
       
   993     0x0526: TagDict('PictureModeTone',
       
   994              {0: 'n/a',
       
   995               1: 'Neutral',
       
   996               2: 'Sepia',
       
   997               3: 'Blue',
       
   998               4: 'Purple',
       
   999               5: 'Green'}),
       
  1000     0x0600: Tag('Sequence'), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits
       
  1001     0x0601: Tag('PanoramaMode'), # (2 numbers: 1. Mode, 2. Shot number)
       
  1002     0x0603: ('ImageQuality2',
       
  1003              {1: 'SQ',
       
  1004               2: 'HQ',
       
  1005               3: 'SHQ',
       
  1006               4: 'RAW'}),
       
  1007     0x0901: Tag('ManometerReading'),
       
  1008     }
       
  1009 
       
  1010 
       
  1011 MAKERNOTE_CASIO_TAGS={
       
  1012     0x0001: TagDict('RecordingMode',
       
  1013              {1: 'Single Shutter',
       
  1014               2: 'Panorama',
       
  1015               3: 'Night Scene',
       
  1016               4: 'Portrait',
       
  1017               5: 'Landscape'}),
       
  1018     0x0002: TagDict('Quality',
       
  1019              {1: 'Economy',
       
  1020               2: 'Normal',
       
  1021               3: 'Fine'}),
       
  1022     0x0003: TagDict('FocusingMode',
       
  1023              {2: 'Macro',
       
  1024               3: 'Auto Focus',
       
  1025               4: 'Manual Focus',
       
  1026               5: 'Infinity'}),
       
  1027     0x0004: TagDict('FlashMode',
       
  1028              {1: 'Auto',
       
  1029               2: 'On',
       
  1030               3: 'Off',
       
  1031               4: 'Red Eye Reduction'}),
       
  1032     0x0005: TagDict('FlashIntensity',
       
  1033              {11: 'Weak',
       
  1034               13: 'Normal',
       
  1035               15: 'Strong'}),
       
  1036     0x0006: Tag('Object Distance'),
       
  1037     0x0007: TagDict('WhiteBalance',
       
  1038              {1: 'Auto',
       
  1039               2: 'Tungsten',
       
  1040               3: 'Daylight',
       
  1041               4: 'Fluorescent',
       
  1042               5: 'Shade',
       
  1043               129: 'Manual'}),
       
  1044     0x000B: TagDict('Sharpness',
       
  1045              {0: 'Normal',
       
  1046               1: 'Soft',
       
  1047               2: 'Hard'}),
       
  1048     0x000C: TagDict('Contrast',
       
  1049              {0: 'Normal',
       
  1050               1: 'Low',
       
  1051               2: 'High'}),
       
  1052     0x000D: TagDict('Saturation',
       
  1053              {0: 'Normal',
       
  1054               1: 'Low',
       
  1055               2: 'High'}),
       
  1056     0x0014: TagDict('CCDSpeed',
       
  1057              {64: 'Normal',
       
  1058               80: 'Normal',
       
  1059               100: 'High',
       
  1060               125: '+1.0',
       
  1061               244: '+3.0',
       
  1062               250: '+2.0'}),
       
  1063     }
       
  1064 
       
  1065 MAKERNOTE_FUJIFILM_TAGS={
       
  1066     0x0000: Tag('NoteVersion'),
       
  1067     0x1000: Tag('Quality'),
       
  1068     0x1001: TagDict('Sharpness',
       
  1069              {1: 'Soft',
       
  1070               2: 'Soft',
       
  1071               3: 'Normal',
       
  1072               4: 'Hard',
       
  1073               5: 'Hard'}),
       
  1074     0x1002: TagDict('WhiteBalance',
       
  1075              {0: 'Auto',
       
  1076               256: 'Daylight',
       
  1077               512: 'Cloudy',
       
  1078               768: 'DaylightColor-Fluorescent',
       
  1079               769: 'DaywhiteColor-Fluorescent',
       
  1080               770: 'White-Fluorescent',
       
  1081               1024: 'Incandescent',
       
  1082               3840: 'Custom'}),
       
  1083     0x1003: TagDict('Color',
       
  1084              {0: 'Normal',
       
  1085               256: 'High',
       
  1086               512: 'Low'}),
       
  1087     0x1004: TagDict('Tone',
       
  1088              {0: 'Normal',
       
  1089               256: 'High',
       
  1090               512: 'Low'}),
       
  1091     0x1010: TagDict('FlashMode',
       
  1092              {0: 'Auto',
       
  1093               1: 'On',
       
  1094               2: 'Off',
       
  1095               3: 'Red Eye Reduction'}),
       
  1096     0x1011: Tag('FlashStrength'),
       
  1097     0x1020: TagDict('Macro',
       
  1098              {0: 'Off',
       
  1099               1: 'On'}),
       
  1100     0x1021: TagDict('FocusMode',
       
  1101              {0: 'Auto',
       
  1102               1: 'Manual'}),
       
  1103     0x1030: TagDict('SlowSync',
       
  1104              {0: 'Off',
       
  1105               1: 'On'}),
       
  1106     0x1031: TagDict('PictureMode',
       
  1107              {0: 'Auto',
       
  1108               1: 'Portrait',
       
  1109               2: 'Landscape',
       
  1110               4: 'Sports',
       
  1111               5: 'Night',
       
  1112               6: 'Program AE',
       
  1113               256: 'Aperture Priority AE',
       
  1114               512: 'Shutter Priority AE',
       
  1115               768: 'Manual Exposure'}),
       
  1116     0x1100: TagDict('MotorOrBracket',
       
  1117              {0: 'Off',
       
  1118               1: 'On'}),
       
  1119     0x1300: TagDict('BlurWarning',
       
  1120              {0: 'Off',
       
  1121               1: 'On'}),
       
  1122     0x1301: TagDict('FocusWarning',
       
  1123              {0: 'Off',
       
  1124               1: 'On'}),
       
  1125     0x1302: TagDict('AEWarning',
       
  1126              {0: 'Off',
       
  1127               1: 'On'}),
       
  1128     }
       
  1129 
       
  1130 MAKERNOTE_CANON_TAGS = {
       
  1131     0x0006: Tag('ImageType'),
       
  1132     0x0007: Tag('FirmwareVersion'),
       
  1133     0x0008: Tag('ImageNumber'),
       
  1134     0x0009: Tag('OwnerName'),
       
  1135     }
       
  1136 
       
  1137 # this is in element offset, name, optional value dictionary format
       
  1138 MAKERNOTE_CANON_TAG_0x001 = {
       
  1139     1: TagDict('Macromode',
       
  1140         {1: 'Macro',
       
  1141          2: 'Normal'}),
       
  1142     2: Tag('SelfTimer'),
       
  1143     3: TagDict('Quality',
       
  1144         {2: 'Normal',
       
  1145          3: 'Fine',
       
  1146          5: 'Superfine'}),
       
  1147     4: TagDict('FlashMode',
       
  1148         {0: 'Flash Not Fired',
       
  1149          1: 'Auto',
       
  1150          2: 'On',
       
  1151          3: 'Red-Eye Reduction',
       
  1152          4: 'Slow Synchro',
       
  1153          5: 'Auto + Red-Eye Reduction',
       
  1154          6: 'On + Red-Eye Reduction',
       
  1155          16: 'external flash'}),
       
  1156     5: TagDict('ContinuousDriveMode',
       
  1157         {0: 'Single Or Timer',
       
  1158          1: 'Continuous'}),
       
  1159     7: TagDict('FocusMode',
       
  1160         {0: 'One-Shot',
       
  1161          1: 'AI Servo',
       
  1162          2: 'AI Focus',
       
  1163          3: 'MF',
       
  1164          4: 'Single',
       
  1165          5: 'Continuous',
       
  1166          6: 'MF'}),
       
  1167     10: TagDict('ImageSize',
       
  1168          {0: 'Large',
       
  1169           1: 'Medium',
       
  1170           2: 'Small'}),
       
  1171     11: TagDict('EasyShootingMode',
       
  1172          {0: 'Full Auto',
       
  1173           1: 'Manual',
       
  1174           2: 'Landscape',
       
  1175           3: 'Fast Shutter',
       
  1176           4: 'Slow Shutter',
       
  1177           5: 'Night',
       
  1178           6: 'B&W',
       
  1179           7: 'Sepia',
       
  1180           8: 'Portrait',
       
  1181           9: 'Sports',
       
  1182           10: 'Macro/Close-Up',
       
  1183           11: 'Pan Focus'}),
       
  1184     12: TagDict('DigitalZoom',
       
  1185          {0: 'None',
       
  1186           1: '2x',
       
  1187           2: '4x'}),
       
  1188     13: TagDict('Contrast',
       
  1189          {0xFFFF: 'Low',
       
  1190           0: 'Normal',
       
  1191           1: 'High'}),
       
  1192     14: TagDict('Saturation',
       
  1193          {0xFFFF: 'Low',
       
  1194           0: 'Normal',
       
  1195           1: 'High'}),
       
  1196     15: TagDict('Sharpness',
       
  1197          {0xFFFF: 'Low',
       
  1198           0: 'Normal',
       
  1199           1: 'High'}),
       
  1200     16: TagDict('ISO',
       
  1201          {0: 'See ISOSpeedRatings Tag',
       
  1202           15: 'Auto',
       
  1203           16: '50',
       
  1204           17: '100',
       
  1205           18: '200',
       
  1206           19: '400'}),
       
  1207     17: TagDict('MeteringMode',
       
  1208          {3: 'Evaluative',
       
  1209           4: 'Partial',
       
  1210           5: 'Center-weighted'}),
       
  1211     18: TagDict('FocusType',
       
  1212          {0: 'Manual',
       
  1213           1: 'Auto',
       
  1214           3: 'Close-Up (Macro)',
       
  1215           8: 'Locked (Pan Mode)'}),
       
  1216     19: TagDict('AFPointSelected',
       
  1217          {0x3000: 'None (MF)',
       
  1218           0x3001: 'Auto-Selected',
       
  1219           0x3002: 'Right',
       
  1220           0x3003: 'Center',
       
  1221           0x3004: 'Left'}),
       
  1222     20: TagDict('ExposureMode',
       
  1223          {0: 'Easy Shooting',
       
  1224           1: 'Program',
       
  1225           2: 'Tv-priority',
       
  1226           3: 'Av-priority',
       
  1227           4: 'Manual',
       
  1228           5: 'A-DEP'}),
       
  1229     23: Tag('LongFocalLengthOfLensInFocalUnits'),
       
  1230     24: Tag('ShortFocalLengthOfLensInFocalUnits'),
       
  1231     25: Tag('FocalUnitsPerMM'),
       
  1232     28: TagDict('FlashActivity',
       
  1233          {0: 'Did Not Fire',
       
  1234           1: 'Fired'}),
       
  1235     29: TagDict('FlashDetails',
       
  1236          {14: 'External E-TTL',
       
  1237           13: 'Internal Flash',
       
  1238           11: 'FP Sync Used',
       
  1239           7: '2nd("Rear")-Curtain Sync Used',
       
  1240           4: 'FP Sync Enabled'}),
       
  1241     32: TagDict('FocusMode',
       
  1242          {0: 'Single',
       
  1243           1: 'Continuous'}),
       
  1244     }
       
  1245 
       
  1246 MAKERNOTE_CANON_TAG_0x004 = {
       
  1247     7: TagDict('WhiteBalance',
       
  1248         {0: 'Auto',
       
  1249          1: 'Sunny',
       
  1250          2: 'Cloudy',
       
  1251          3: 'Tungsten',
       
  1252          4: 'Fluorescent',
       
  1253          5: 'Flash',
       
  1254          6: 'Custom'}),
       
  1255     9: Tag('SequenceNumber'),
       
  1256     14: Tag('AFPointUsed'),
       
  1257     15: TagDict('FlashBias',
       
  1258          {0xFFC0: '-2 EV',
       
  1259           0xFFCC: '-1.67 EV',
       
  1260           0xFFD0: '-1.50 EV',
       
  1261           0xFFD4: '-1.33 EV',
       
  1262           0xFFE0: '-1 EV',
       
  1263           0xFFEC: '-0.67 EV',
       
  1264           0xFFF0: '-0.50 EV',
       
  1265           0xFFF4: '-0.33 EV',
       
  1266           0x0000: '0 EV',
       
  1267           0x000C: '0.33 EV',
       
  1268           0x0010: '0.50 EV',
       
  1269           0x0014: '0.67 EV',
       
  1270           0x0020: '1 EV',
       
  1271           0x002C: '1.33 EV',
       
  1272           0x0030: '1.50 EV',
       
  1273           0x0034: '1.67 EV',
       
  1274           0x0040: '2 EV'}),
       
  1275     19: Tag('SubjectDistance'),
       
  1276     }
       
  1277 
       
  1278 # ratio object that eventually will be able to reduce itself to lowest
       
  1279 # common denominator for printing
       
  1280 # XXX: unused
       
  1281 def gcd(a, b):
       
  1282     if b == 0:
       
  1283         return a
       
  1284     else:
       
  1285         return gcd(b, a % b)
       
  1286 
       
  1287 class Ratio:
       
  1288     def __init__(self, num, den):
       
  1289         self.num = num
       
  1290         self.den = den
       
  1291 
       
  1292     def __repr__(self):
       
  1293         self.reduce()
       
  1294         if self.den == 1:
       
  1295             return str(self.num)
       
  1296         return '%d/%d' % (self.num, self.den)
       
  1297 
       
  1298     def reduce(self):
       
  1299         div = gcd(self.num, self.den)
       
  1300         if div > 1:
       
  1301             self.num = self.num / div
       
  1302             self.den = self.den / div
       
  1303 
       
  1304