# HG changeset patch # User Tero Marttila # Date 1244915993 -10800 # Node ID effae6f387490107b0029a285feb7f89b454e52c # Parent 6afe59e5ffaea9fad817bc6f0e071272dc70fc46 refactor exif_data to use a Tag class for each tag, instead of a magic tuple diff -r 6afe59e5ffae -r effae6f38749 degal/exif.py --- a/degal/exif.py Sat Jun 13 20:31:51 2009 +0300 +++ b/degal/exif.py Sat Jun 13 20:59:53 2009 +0300 @@ -4,6 +4,8 @@ import struct, mmap, os +from utils import lazy_load, lazy_load_iter + def read_struct (file, fmt) : """ Utility function to read data from the a file using struct @@ -107,11 +109,12 @@ Represents a single Tag in an IFD """ - def __init__ (self, offset, tag, type, count, data_raw) : + def __init__ (self, ifd, offset, tag, type, count, data_raw) : """ Build a Tag with the given binary items from the IFD entry """ + self.ifd = ifd self.offset = offset self.tag = tag self.type = type @@ -126,13 +129,8 @@ self.type_format, self.type_name, self.type_func = self.type_data # lookup the tag data for this tag - self.tag_data = exif_data.EXIF_TAGS.get(tag) + self.tag_data = self.ifd.tag_dict.get(tag) - # unpack it - if self.tag_data : - # the EXIF tag name - self.tag_name, self.tag_value_spec = self.tag_data - @property def name (self) : """ @@ -140,7 +138,7 @@ """ if self.tag_data : - return self.tag_name + return self.tag_data.name else : return None @@ -166,14 +164,12 @@ """ if self.tag_data : - spec = self.tag_value_spec + # map it + return self.tag_data.map_values(values) else : - # fallback to default - spec = None - - # map it - return exif_data.map_values(spec, values) + # default value-mapping + return ", ".join(str(value) for value in values) # size of an IFD entry in bytes IFD_ENTRY_SIZE = 12 @@ -183,7 +179,7 @@ Represents an IFD (Image file directory) region in EXIF data. """ - def __init__ (self, buffer, **buffer_opts) : + def __init__ (self, buffer, tag_dict, **buffer_opts) : """ Access the IFD data from the given bufferable object with given buffer opts. @@ -192,6 +188,9 @@ # init super(IFD, self).__init__(buffer, **buffer_opts) + + # store + self.tag_dict = tag_dict # read header self.count = self.pread_item(0, 'H') @@ -199,7 +198,8 @@ # read next-offset self.next_offset = self.pread_item(0x02 + self.count * IFD_ENTRY_SIZE, 'I') - def iter_tags (self) : + @lazy_load_iter + def tags (self) : """ Iterate over all the Tag objects in this IFD """ @@ -210,7 +210,7 @@ tag, type, count, data_raw = self.pread_struct(offset, 'HHI4s') # yield the new Tag - yield Tag(offset, tag, type, count, data_raw) + yield Tag(self, offset, tag, type, count, data_raw) class EXIF (Buffer) : """ @@ -230,7 +230,8 @@ # store self.buffer = buffer - def iter_ifds (self) : + @lazy_load_iter + def ifds (self) : """ Iterate over the primary IFDs in this EXIF. """ @@ -240,7 +241,7 @@ while offset : # create and read the IFD, operating on the right sub-buffer - ifd = IFD(self.buf, offset=offset) + ifd = IFD(self.buf, exif_data.EXIF_TAGS, offset=offset) # yield it yield ifd @@ -252,8 +253,6 @@ """ Iterate over all of the IFDs contained within this EXIF, or within other IFDs. """ - - __iter__ = iter_ifds def tag_data_info (self, tag) : """ @@ -500,7 +499,7 @@ print "EXIF offset=%#08x, size=%d:" % (exif.offset, exif.size) - for i, ifd in enumerate(exif.iter_ifds()) : + for i, ifd in enumerate(exif.ifds) : print "\tIFD:%d offset=%#04x(%#08x), count=%d, next=%d:" % ( i, ifd.offset, ifd.offset + exif.offset, @@ -508,7 +507,7 @@ ifd.next_offset ) - for i, tag in enumerate(ifd.iter_tags()) : + for i, tag in enumerate(ifd.tags) : data_info = exif.tag_data_info(tag) if data_info : diff -r 6afe59e5ffae -r effae6f38749 degal/exif_data.py --- a/degal/exif_data.py Sat Jun 13 20:31:51 2009 +0300 +++ b/degal/exif_data.py Sat Jun 13 20:59:53 2009 +0300 @@ -93,28 +93,63 @@ 0x000A: ('ll', 'Signed Ratio', filter_ratio ), } -def map_values (spec, values) : +# magic value to indicate sub-IFDs +SUB_IFD_MAGIC = object() + + +class Tag (object) : """ - Map the given tag value to a printable string using the given value spec. + Represents an Exif Tag """ - # XXX: ensure that this always returns a str/unicode - - if spec is None : - # nothing to map + def __init__ (self, name) : + """ + Build Exif tag with given name, and optional external values-filter function. + """ + + self.name = name + + def map_values (self, values) : + """ + Map the given tag value to a printable string using the given value spec. + """ + + # default value-mapping return ", ".join(str(value) for value in values) - elif callable(spec): - # call mapping function - return spec(values) +class TagDict (Tag) : + """ + A tag with a dict mapping values to names + """ - elif isinstance(spec, dict) : - # lookup value, default to repr - return ", ".join(spec.get(value, repr(value)) for value in values) + def __init__ (self, name, values_dict) : + super(TagDict, self).__init__(name) - else : - # unknown kind of spec - raise ValueError(spec) + self.values_dict = values_dict + + def map_values (self, values) : + """ + Map the values through our dict, defaulting to the repr. + """ + + return ", ".join(self.values_dict.get(value, repr(value)) for value in values) + +class TagFunc (Tag) : + """ + A tag with a simple function mapping values to names + """ + + def __init__ (self, name, values_func) : + super(TagFunc, self).__init__(name) + + self.values_func = values_func + + def map_values (self, values) : + """ + Map the values through our func + """ + + return self.values_func(values) USER_COMMENT_CHARSETS = { 'ASCII': ('ascii', 'replace' ), @@ -148,18 +183,19 @@ return [comment_raw.decode(encoding, replace)] # Mappings of Exif tag codes to name and decoding information. -# { tag : (name, value_dict/value_func/None) } +# { tag : (name, value_dict/value_func/None/SUB_IFD_MAGIC) } # # name is the official Exif tag name # value_dict is a { value: value_name } mapping for human-readable values # value_func is a `(values) -> values` mapping function which *overrides* the tag's type_func. # XXX: or does it? +# SUB_IFD_MAGIC signifies that this IFD points to # otherwise, the value is left as-is. EXIF_TAGS = { - 0x0100: ('ImageWidth', None), - 0x0101: ('ImageLength', None), - 0x0102: ('BitsPerSample', None), - 0x0103: ('Compression', + 0x0100: Tag('ImageWidth'), + 0x0101: Tag('ImageLength'), + 0x0102: Tag('BitsPerSample'), + 0x0103: TagDict('Compression', {1: 'Uncompressed', 2: 'CCITT 1D', 3: 'T4/Group 3 Fax', @@ -190,15 +226,15 @@ 34713: 'Nikon NEF Compressed', 65000: 'Kodak DCR Compressed', 65535: 'Pentax PEF Compressed'}), - 0x0106: ('PhotometricInterpretation', None), - 0x0107: ('Thresholding', None), - 0x010A: ('FillOrder', None), - 0x010D: ('DocumentName', None), - 0x010E: ('ImageDescription', None), - 0x010F: ('Make', None), - 0x0110: ('Model', None), - 0x0111: ('StripOffsets', None), - 0x0112: ('Orientation', + 0x0106: Tag('PhotometricInterpretation'), + 0x0107: Tag('Thresholding'), + 0x010A: Tag('FillOrder'), + 0x010D: Tag('DocumentName'), + 0x010E: Tag('ImageDescription'), + 0x010F: Tag('Make'), + 0x0110: Tag('Model'), + 0x0111: Tag('StripOffsets'), + 0x0112: TagDict('Orientation', {1: 'Horizontal (normal)', 2: 'Mirrored horizontal', 3: 'Rotated 180', @@ -207,46 +243,46 @@ 6: 'Rotated 90 CW', 7: 'Mirrored horizontal then rotated 90 CW', 8: 'Rotated 90 CCW'}), - 0x0115: ('SamplesPerPixel', None), - 0x0116: ('RowsPerStrip', None), - 0x0117: ('StripByteCounts', None), - 0x011A: ('XResolution', None), - 0x011B: ('YResolution', None), - 0x011C: ('PlanarConfiguration', None), - 0x011D: ('PageName', None), - 0x0128: ('ResolutionUnit', + 0x0115: Tag('SamplesPerPixel'), + 0x0116: Tag('RowsPerStrip'), + 0x0117: Tag('StripByteCounts'), + 0x011A: Tag('XResolution'), + 0x011B: Tag('YResolution'), + 0x011C: Tag('PlanarConfiguration'), + 0x011D: Tag('PageName'), + 0x0128: TagDict('ResolutionUnit', {1: 'Not Absolute', 2: 'Pixels/Inch', 3: 'Pixels/Centimeter'}), - 0x012D: ('TransferFunction', None), - 0x0131: ('Software', None), - 0x0132: ('DateTime', None), - 0x013B: ('Artist', None), - 0x013E: ('WhitePoint', None), - 0x013F: ('PrimaryChromaticities', None), - 0x0156: ('TransferRange', None), - 0x0200: ('JPEGProc', None), - 0x0201: ('JPEGInterchangeFormat', None), - 0x0202: ('JPEGInterchangeFormatLength', None), - 0x0211: ('YCbCrCoefficients', None), - 0x0212: ('YCbCrSubSampling', None), - 0x0213: ('YCbCrPositioning', + 0x012D: Tag('TransferFunction'), + 0x0131: Tag('Software'), + 0x0132: Tag('DateTime'), + 0x013B: Tag('Artist'), + 0x013E: Tag('WhitePoint'), + 0x013F: Tag('PrimaryChromaticities'), + 0x0156: Tag('TransferRange'), + 0x0200: Tag('JPEGProc'), + 0x0201: Tag('JPEGInterchangeFormat'), + 0x0202: Tag('JPEGInterchangeFormatLength'), + 0x0211: Tag('YCbCrCoefficients'), + 0x0212: Tag('YCbCrSubSampling'), + 0x0213: TagDict('YCbCrPositioning', {1: 'Centered', 2: 'Co-sited'}), - 0x0214: ('ReferenceBlackWhite', None), - - 0x4746: ('Rating', None), + 0x0214: Tag('ReferenceBlackWhite'), - 0x828D: ('CFARepeatPatternDim', None), - 0x828E: ('CFAPattern', None), - 0x828F: ('BatteryLevel', None), - 0x8298: ('Copyright', None), - 0x829A: ('ExposureTime', None), - 0x829D: ('FNumber', None), - 0x83BB: ('IPTC/NAA', None), - 0x8769: ('ExifOffset', None), - 0x8773: ('InterColorProfile', None), - 0x8822: ('ExposureProgram', + 0x4746: Tag('Rating'), + + 0x828D: Tag('CFARepeatPatternDim'), + 0x828E: Tag('CFAPattern'), + 0x828F: Tag('BatteryLevel'), + 0x8298: Tag('Copyright'), + 0x829A: Tag('ExposureTime'), + 0x829D: Tag('FNumber'), + 0x83BB: Tag('IPTC/NAA'), + 0x8769: Tag('ExifOffset'), + 0x8773: Tag('InterColorProfile'), + 0x8822: TagDict('ExposureProgram', {0: 'Unidentified', 1: 'Manual', 2: 'Program Normal', @@ -256,14 +292,14 @@ 6: 'Program Action', 7: 'Portrait Mode', 8: 'Landscape Mode'}), - 0x8824: ('SpectralSensitivity', None), - 0x8825: ('GPSInfo', None), - 0x8827: ('ISOSpeedRatings', None), - 0x8828: ('OECF', None), - 0x9000: ('ExifVersion', None), - 0x9003: ('DateTimeOriginal', None), - 0x9004: ('DateTimeDigitized', None), - 0x9101: ('ComponentsConfiguration', + 0x8824: Tag('SpectralSensitivity'), + 0x8825: Tag('GPSInfo'), + 0x8827: Tag('ISOSpeedRatings'), + 0x8828: Tag('OECF'), + 0x9000: Tag('ExifVersion'), + 0x9003: Tag('DateTimeOriginal'), + 0x9004: Tag('DateTimeDigitized'), + 0x9101: TagDict('ComponentsConfiguration', {0: '', 1: 'Y', 2: 'Cb', @@ -271,21 +307,21 @@ 4: 'Red', 5: 'Green', 6: 'Blue'}), - 0x9102: ('CompressedBitsPerPixel', None), - 0x9201: ('ShutterSpeedValue', None), - 0x9202: ('ApertureValue', None), - 0x9203: ('BrightnessValue', None), - 0x9204: ('ExposureBiasValue', None), - 0x9205: ('MaxApertureValue', None), - 0x9206: ('SubjectDistance', None), - 0x9207: ('MeteringMode', + 0x9102: Tag('CompressedBitsPerPixel'), + 0x9201: Tag('ShutterSpeedValue'), + 0x9202: Tag('ApertureValue'), + 0x9203: Tag('BrightnessValue'), + 0x9204: Tag('ExposureBiasValue'), + 0x9205: Tag('MaxApertureValue'), + 0x9206: Tag('SubjectDistance'), + 0x9207: TagDict('MeteringMode', {0: 'Unidentified', 1: 'Average', 2: 'CenterWeightedAverage', 3: 'Spot', 4: 'MultiSpot', 5: 'Pattern'}), - 0x9208: ('LightSource', + 0x9208: TagDict('LightSource', {0: 'Unknown', 1: 'Daylight', 2: 'Fluorescent', @@ -304,7 +340,7 @@ 21: 'D65', 22: 'D75', 255: 'Other'}), - 0x9209: ('Flash', + 0x9209: TagDict('Flash', {0: 'No', 1: 'Fired', 5: 'Fired (?)', # no return sensed @@ -318,37 +354,37 @@ 29: 'Auto Fired (?)', 31: 'Auto Fired (!)', 32: 'Not Available'}), - 0x920A: ('FocalLength', None), - 0x9214: ('SubjectArea', None), - 0x927C: ('MakerNote', None), - 0x9286: ('UserComment', decode_UserComment), - 0x9290: ('SubSecTime', None), - 0x9291: ('SubSecTimeOriginal', None), - 0x9292: ('SubSecTimeDigitized', None), + 0x920A: Tag('FocalLength'), + 0x9214: Tag('SubjectArea'), + 0x927C: Tag('MakerNote'), + 0x9286: TagFunc('UserComment', decode_UserComment), + 0x9290: Tag('SubSecTime'), + 0x9291: Tag('SubSecTimeOriginal'), + 0x9292: Tag('SubSecTimeDigitized'), # used by Windows Explorer - 0x9C9B: ('XPTitle', None), - 0x9C9C: ('XPComment', None), - 0x9C9D: ('XPAuthor', None), #(ignored by Windows Explorer if Artist exists) - 0x9C9E: ('XPKeywords', None), - 0x9C9F: ('XPSubject', None), + 0x9C9B: Tag('XPTitle'), + 0x9C9C: Tag('XPComment'), + 0x9C9D: Tag('XPAuthor'), #(ignored by Windows Explorer if Artist exists) + 0x9C9E: Tag('XPKeywords'), + 0x9C9F: Tag('XPSubject'), - 0xA000: ('FlashPixVersion', None), - 0xA001: ('ColorSpace', + 0xA000: Tag('FlashPixVersion'), + 0xA001: TagDict('ColorSpace', {1: 'sRGB', 2: 'Adobe RGB', 65535: 'Uncalibrated'}), - 0xA002: ('ExifImageWidth', None), - 0xA003: ('ExifImageLength', None), - 0xA005: ('InteroperabilityOffset', None), - 0xA20B: ('FlashEnergy', None), # 0x920B in TIFF/EP - 0xA20C: ('SpatialFrequencyResponse', None), # 0x920C - 0xA20E: ('FocalPlaneXResolution', None), # 0x920E - 0xA20F: ('FocalPlaneYResolution', None), # 0x920F - 0xA210: ('FocalPlaneResolutionUnit', None), # 0x9210 - 0xA214: ('SubjectLocation', None), # 0x9214 - 0xA215: ('ExposureIndex', None), # 0x9215 - 0xA217: ('SensingMethod', # 0x9217 + 0xA002: Tag('ExifImageWidth'), + 0xA003: Tag('ExifImageLength'), + 0xA005: Tag('InteroperabilityOffset'), + 0xA20B: Tag('FlashEnergy'), # 0x920B in TIFF/EP + 0xA20C: Tag('SpatialFrequencyResponse'), # 0x920C + 0xA20E: Tag('FocalPlaneXResolution'), # 0x920E + 0xA20F: Tag('FocalPlaneYResolution'), # 0x920F + 0xA210: Tag('FocalPlaneResolutionUnit'), # 0x9210 + 0xA214: Tag('SubjectLocation'), # 0x9214 + 0xA215: Tag('ExposureIndex'), # 0x9215 + 0xA217: TagDict('SensingMethod', # 0x9217 {1: 'Not defined', 2: 'One-chip color area', 3: 'Two-chip color area', @@ -356,94 +392,94 @@ 5: 'Color sequential area', 7: 'Trilinear', 8: 'Color sequential linear'}), - 0xA300: ('FileSource', + 0xA300: TagDict('FileSource', {1: 'Film Scanner', 2: 'Reflection Print Scanner', 3: 'Digital Camera'}), - 0xA301: ('SceneType', + 0xA301: TagDict('SceneType', {1: 'Directly Photographed'}), - 0xA302: ('CVAPattern', None), - 0xA401: ('CustomRendered', + 0xA302: Tag('CVAPattern'), + 0xA401: TagDict('CustomRendered', {0: 'Normal', 1: 'Custom'}), - 0xA402: ('ExposureMode', + 0xA402: TagDict('ExposureMode', {0: 'Auto Exposure', 1: 'Manual Exposure', 2: 'Auto Bracket'}), - 0xA403: ('WhiteBalance', + 0xA403: TagDict('WhiteBalance', {0: 'Auto', 1: 'Manual'}), - 0xA404: ('DigitalZoomRatio', None), + 0xA404: Tag('DigitalZoomRatio'), 0xA405: ('FocalLengthIn35mmFilm', None), - 0xA406: ('SceneCaptureType', + 0xA406: TagDict('SceneCaptureType', {0: 'Standard', 1: 'Landscape', 2: 'Portrait', 3: 'Night)'}), - 0xA407: ('GainControl', + 0xA407: TagDict('GainControl', {0: 'None', 1: 'Low gain up', 2: 'High gain up', 3: 'Low gain down', 4: 'High gain down'}), - 0xA408: ('Contrast', - {0: 'Normal', - 1: 'Soft', - 2: 'Hard'}), - 0xA409: ('Saturation', + 0xA408: TagDict('Contrast', {0: 'Normal', 1: 'Soft', 2: 'Hard'}), - 0xA40A: ('Sharpness', + 0xA409: TagDict('Saturation', {0: 'Normal', 1: 'Soft', 2: 'Hard'}), - 0xA40B: ('DeviceSettingDescription', None), - 0xA40C: ('SubjectDistanceRange', None), - 0xA500: ('Gamma', None), - 0xC4A5: ('PrintIM', None), + 0xA40A: TagDict('Sharpness', + {0: 'Normal', + 1: 'Soft', + 2: 'Hard'}), + 0xA40B: Tag('DeviceSettingDescription'), + 0xA40C: Tag('SubjectDistanceRange'), + 0xA500: Tag('Gamma'), + 0xC4A5: Tag('PrintIM'), 0xEA1C: ('Padding', None), } # interoperability tags INTR_TAGS = { - 0x0001: ('InteroperabilityIndex', None), - 0x0002: ('InteroperabilityVersion', None), - 0x1000: ('RelatedImageFileFormat', None), - 0x1001: ('RelatedImageWidth', None), - 0x1002: ('RelatedImageLength', None), + 0x0001: Tag('InteroperabilityIndex'), + 0x0002: Tag('InteroperabilityVersion'), + 0x1000: Tag('RelatedImageFileFormat'), + 0x1001: Tag('RelatedImageWidth'), + 0x1002: Tag('RelatedImageLength'), } # GPS tags (not used yet, haven't seen camera with GPS) GPS_TAGS = { - 0x0000: ('GPSVersionID', None), - 0x0001: ('GPSLatitudeRef', None), - 0x0002: ('GPSLatitude', None), - 0x0003: ('GPSLongitudeRef', None), - 0x0004: ('GPSLongitude', None), - 0x0005: ('GPSAltitudeRef', None), - 0x0006: ('GPSAltitude', None), - 0x0007: ('GPSTimeStamp', None), - 0x0008: ('GPSSatellites', None), - 0x0009: ('GPSStatus', None), - 0x000A: ('GPSMeasureMode', None), - 0x000B: ('GPSDOP', None), - 0x000C: ('GPSSpeedRef', None), - 0x000D: ('GPSSpeed', None), - 0x000E: ('GPSTrackRef', None), - 0x000F: ('GPSTrack', None), - 0x0010: ('GPSImgDirectionRef', None), - 0x0011: ('GPSImgDirection', None), - 0x0012: ('GPSMapDatum', None), - 0x0013: ('GPSDestLatitudeRef', None), - 0x0014: ('GPSDestLatitude', None), - 0x0015: ('GPSDestLongitudeRef', None), - 0x0016: ('GPSDestLongitude', None), - 0x0017: ('GPSDestBearingRef', None), - 0x0018: ('GPSDestBearing', None), - 0x0019: ('GPSDestDistanceRef', None), - 0x001A: ('GPSDestDistance', None), - 0x001D: ('GPSDate', None), + 0x0000: Tag('GPSVersionID'), + 0x0001: Tag('GPSLatitudeRef'), + 0x0002: Tag('GPSLatitude'), + 0x0003: Tag('GPSLongitudeRef'), + 0x0004: Tag('GPSLongitude'), + 0x0005: Tag('GPSAltitudeRef'), + 0x0006: Tag('GPSAltitude'), + 0x0007: Tag('GPSTimeStamp'), + 0x0008: Tag('GPSSatellites'), + 0x0009: Tag('GPSStatus'), + 0x000A: Tag('GPSMeasureMode'), + 0x000B: Tag('GPSDOP'), + 0x000C: Tag('GPSSpeedRef'), + 0x000D: Tag('GPSSpeed'), + 0x000E: Tag('GPSTrackRef'), + 0x000F: Tag('GPSTrack'), + 0x0010: Tag('GPSImgDirectionRef'), + 0x0011: Tag('GPSImgDirection'), + 0x0012: Tag('GPSMapDatum'), + 0x0013: Tag('GPSDestLatitudeRef'), + 0x0014: Tag('GPSDestLatitude'), + 0x0015: Tag('GPSDestLongitudeRef'), + 0x0016: Tag('GPSDestLongitude'), + 0x0017: Tag('GPSDestBearingRef'), + 0x0018: Tag('GPSDestBearing'), + 0x0019: Tag('GPSDestDistanceRef'), + 0x001A: Tag('GPSDestDistance'), + 0x001D: Tag('GPSDate'), } # http://tomtia.plala.jp/DigitalCamera/MakerNote/index.asp @@ -513,58 +549,58 @@ # Nikon E99x MakerNote Tags MAKERNOTE_NIKON_NEWER_TAGS={ - 0x0001: ('MakernoteVersion', None), # Sometimes binary - 0x0002: ('ISOSetting', None), - 0x0003: ('ColorMode', None), - 0x0004: ('Quality', None), - 0x0005: ('Whitebalance', None), - 0x0006: ('ImageSharpening', None), - 0x0007: ('FocusMode', None), - 0x0008: ('FlashSetting', None), - 0x0009: ('AutoFlashMode', None), - 0x000B: ('WhiteBalanceBias', None), - 0x000C: ('WhiteBalanceRBCoeff', None), - 0x000D: ('ProgramShift', nikon_ev_bias), + 0x0001: Tag('MakernoteVersion'), # Sometimes binary + 0x0002: Tag('ISOSetting'), + 0x0003: Tag('ColorMode'), + 0x0004: Tag('Quality'), + 0x0005: Tag('Whitebalance'), + 0x0006: Tag('ImageSharpening'), + 0x0007: Tag('FocusMode'), + 0x0008: Tag('FlashSetting'), + 0x0009: Tag('AutoFlashMode'), + 0x000B: Tag('WhiteBalanceBias'), + 0x000C: Tag('WhiteBalanceRBCoeff'), + 0x000D: TagFunc('ProgramShift', nikon_ev_bias), # Nearly the same as the other EV vals, but step size is 1/12 EV (?) - 0x000E: ('ExposureDifference', nikon_ev_bias), - 0x000F: ('ISOSelection', None), - 0x0011: ('NikonPreview', None), - 0x0012: ('FlashCompensation', nikon_ev_bias), - 0x0013: ('ISOSpeedRequested', None), - 0x0016: ('PhotoCornerCoordinates', None), + 0x000E: TagFunc('ExposureDifference', nikon_ev_bias), + 0x000F: Tag('ISOSelection'), + 0x0011: Tag('NikonPreview'), + 0x0012: TagFunc('FlashCompensation', nikon_ev_bias), + 0x0013: Tag('ISOSpeedRequested'), + 0x0016: Tag('PhotoCornerCoordinates'), # 0x0017: Unknown, but most likely an EV value - 0x0018: ('FlashBracketCompensationApplied', nikon_ev_bias), - 0x0019: ('AEBracketCompensationApplied', None), - 0x001A: ('ImageProcessing', None), - 0x001B: ('CropHiSpeed', None), - 0x001D: ('SerialNumber', None), # Conflict with 0x00A0 ? - 0x001E: ('ColorSpace', None), - 0x001F: ('VRInfo', None), - 0x0020: ('ImageAuthentication', None), - 0x0022: ('ActiveDLighting', None), - 0x0023: ('PictureControl', None), - 0x0024: ('WorldTime', None), - 0x0025: ('ISOInfo', None), - 0x0080: ('ImageAdjustment', None), - 0x0081: ('ToneCompensation', None), - 0x0082: ('AuxiliaryLens', None), - 0x0083: ('LensType', None), - 0x0084: ('LensMinMaxFocalMaxAperture', None), - 0x0085: ('ManualFocusDistance', None), - 0x0086: ('DigitalZoomFactor', None), - 0x0087: ('FlashMode', + 0x0018: TagFunc('FlashBracketCompensationApplied', nikon_ev_bias), + 0x0019: Tag('AEBracketCompensationApplied'), + 0x001A: Tag('ImageProcessing'), + 0x001B: Tag('CropHiSpeed'), + 0x001D: Tag('SerialNumber'), # Conflict with 0x00A0 ? + 0x001E: Tag('ColorSpace'), + 0x001F: Tag('VRInfo'), + 0x0020: Tag('ImageAuthentication'), + 0x0022: Tag('ActiveDLighting'), + 0x0023: Tag('PictureControl'), + 0x0024: Tag('WorldTime'), + 0x0025: Tag('ISOInfo'), + 0x0080: Tag('ImageAdjustment'), + 0x0081: Tag('ToneCompensation'), + 0x0082: Tag('AuxiliaryLens'), + 0x0083: Tag('LensType'), + 0x0084: Tag('LensMinMaxFocalMaxAperture'), + 0x0085: Tag('ManualFocusDistance'), + 0x0086: Tag('DigitalZoomFactor'), + 0x0087: TagDict('FlashMode', {0x00: 'Did Not Fire', 0x01: 'Fired, Manual', 0x07: 'Fired, External', 0x08: 'Fired, Commander Mode ', 0x09: 'Fired, TTL Mode'}), - 0x0088: ('AFFocusPosition', + 0x0088: TagDict('AFFocusPosition', {0x0000: 'Center', 0x0100: 'Top', 0x0200: 'Bottom', 0x0300: 'Left', 0x0400: 'Right'}), - 0x0089: ('BracketingMode', + 0x0089: TagDict('BracketingMode', {0x00: 'Single frame, no bracketing', 0x01: 'Continuous, no bracketing', 0x02: 'Timer, no bracketing', @@ -574,53 +610,53 @@ 0x40: 'Single frame, white balance bracketing', 0x41: 'Continuous, white balance bracketing', 0x42: 'Timer, white balance bracketing'}), - 0x008A: ('AutoBracketRelease', None), - 0x008B: ('LensFStops', None), + 0x008A: Tag('AutoBracketRelease'), + 0x008B: Tag('LensFStops'), 0x008C: ('NEFCurve1', None), # ExifTool calls this 'ContrastCurve' - 0x008D: ('ColorMode', None), - 0x008F: ('SceneMode', None), - 0x0090: ('LightingType', None), - 0x0091: ('ShotInfo', None), # First 4 bytes are a version number in ASCII - 0x0092: ('HueAdjustment', None), + 0x008D: Tag('ColorMode'), + 0x008F: Tag('SceneMode'), + 0x0090: Tag('LightingType'), + 0x0091: Tag('ShotInfo'), # First 4 bytes are a version number in ASCII + 0x0092: Tag('HueAdjustment'), # ExifTool calls this 'NEFCompression', should be 1-4 - 0x0093: ('Compression', None), - 0x0094: ('Saturation', + 0x0093: Tag('Compression'), + 0x0094: TagDict('Saturation', {-3: 'B&W', -2: '-2', -1: '-1', 0: '0', 1: '1', 2: '2'}), - 0x0095: ('NoiseReduction', None), + 0x0095: Tag('NoiseReduction'), 0x0096: ('NEFCurve2', None), # ExifTool calls this 'LinearizationTable' - 0x0097: ('ColorBalance', None), # First 4 bytes are a version number in ASCII - 0x0098: ('LensData', None), # First 4 bytes are a version number in ASCII - 0x0099: ('RawImageCenter', None), - 0x009A: ('SensorPixelSize', None), - 0x009C: ('Scene Assist', None), - 0x009E: ('RetouchHistory', None), - 0x00A0: ('SerialNumber', None), - 0x00A2: ('ImageDataSize', None), + 0x0097: Tag('ColorBalance'), # First 4 bytes are a version number in ASCII + 0x0098: Tag('LensData'), # First 4 bytes are a version number in ASCII + 0x0099: Tag('RawImageCenter'), + 0x009A: Tag('SensorPixelSize'), + 0x009C: Tag('Scene Assist'), + 0x009E: Tag('RetouchHistory'), + 0x00A0: Tag('SerialNumber'), + 0x00A2: Tag('ImageDataSize'), # 00A3: unknown - a single byte 0 # 00A4: In NEF, looks like a 4 byte ASCII version number ('0200') - 0x00A5: ('ImageCount', None), - 0x00A6: ('DeletedImageCount', None), - 0x00A7: ('TotalShutterReleases', None), + 0x00A5: Tag('ImageCount'), + 0x00A6: Tag('DeletedImageCount'), + 0x00A7: Tag('TotalShutterReleases'), # First 4 bytes are a version number in ASCII, with version specific # info to follow. Its hard to treat it as a string due to embedded nulls. - 0x00A8: ('FlashInfo', None), - 0x00A9: ('ImageOptimization', None), - 0x00AA: ('Saturation', None), - 0x00AB: ('DigitalVariProgram', None), - 0x00AC: ('ImageStabilization', None), - 0x00AD: ('Responsive AF', None), # 'AFResponse' - 0x00B0: ('MultiExposure', None), - 0x00B1: ('HighISONoiseReduction', None), - 0x00B7: ('AFInfo', None), - 0x00B8: ('FileInfo', None), + 0x00A8: Tag('FlashInfo'), + 0x00A9: Tag('ImageOptimization'), + 0x00AA: Tag('Saturation'), + 0x00AB: Tag('DigitalVariProgram'), + 0x00AC: Tag('ImageStabilization'), + 0x00AD: Tag('Responsive AF'), # 'AFResponse' + 0x00B0: Tag('MultiExposure'), + 0x00B1: Tag('HighISONoiseReduction'), + 0x00B7: Tag('AFInfo'), + 0x00B8: Tag('FileInfo'), # 00B9: unknown - 0x0100: ('DigitalICE', None), - 0x0103: ('PreviewCompression', + 0x0100: Tag('DigitalICE'), + 0x0103: TagDict('PreviewCompression', {1: 'Uncompressed', 2: 'CCITT 1D', 3: 'T4/Group 3 Fax', @@ -651,37 +687,37 @@ 34713: 'Nikon NEF Compressed', 65000: 'Kodak DCR Compressed', 65535: 'Pentax PEF Compressed',}), - 0x0201: ('PreviewImageStart', None), - 0x0202: ('PreviewImageLength', None), - 0x0213: ('PreviewYCbCrPositioning', + 0x0201: Tag('PreviewImageStart'), + 0x0202: Tag('PreviewImageLength'), + 0x0213: TagDict('PreviewYCbCrPositioning', {1: 'Centered', 2: 'Co-sited'}), - 0x0010: ('DataDump', None), + 0x0010: Tag('DataDump'), } MAKERNOTE_NIKON_OLDER_TAGS = { - 0x0003: ('Quality', + 0x0003: TagDict('Quality', {1: 'VGA Basic', 2: 'VGA Normal', 3: 'VGA Fine', 4: 'SXGA Basic', 5: 'SXGA Normal', 6: 'SXGA Fine'}), - 0x0004: ('ColorMode', + 0x0004: TagDict('ColorMode', {1: 'Color', 2: 'Monochrome'}), - 0x0005: ('ImageAdjustment', + 0x0005: TagDict('ImageAdjustment', {0: 'Normal', 1: 'Bright+', 2: 'Bright-', 3: 'Contrast+', 4: 'Contrast-'}), - 0x0006: ('CCDSpeed', + 0x0006: TagDict('CCDSpeed', {0: 'ISO 80', 2: 'ISO 160', 4: 'ISO 320', 5: 'ISO 100'}), - 0x0007: ('WhiteBalance', + 0x0007: TagDict('WhiteBalance', {0: 'Auto', 1: 'Preset', 2: 'Daylight', @@ -719,131 +755,131 @@ MAKERNOTE_OLYMPUS_TAGS={ # ah HAH! those sneeeeeaky bastids! this is how they get past the fact # that a JPEG thumbnail is not allowed in an uncompressed TIFF file - 0x0100: ('JPEGThumbnail', None), - 0x0200: ('SpecialMode', olympus_special_mode), - 0x0201: ('JPEGQual', + 0x0100: Tag('JPEGThumbnail'), + 0x0200: TagFunc('SpecialMode', olympus_special_mode), + 0x0201: TagDict('JPEGQual', {1: 'SQ', 2: 'HQ', 3: 'SHQ'}), - 0x0202: ('Macro', + 0x0202: TagDict('Macro', {0: 'Normal', 1: 'Macro', 2: 'SuperMacro'}), - 0x0203: ('BWMode', + 0x0203: TagDict('BWMode', {0: 'Off', 1: 'On'}), - 0x0204: ('DigitalZoom', None), - 0x0205: ('FocalPlaneDiagonal', None), - 0x0206: ('LensDistortionParams', None), - 0x0207: ('SoftwareRelease', None), - 0x0208: ('PictureInfo', None), - 0x0209: ('CameraID', None), # print as string - 0x0F00: ('DataDump', None), - 0x0300: ('PreCaptureFrames', None), - 0x0404: ('SerialNumber', None), - 0x1000: ('ShutterSpeedValue', None), - 0x1001: ('ISOValue', None), - 0x1002: ('ApertureValue', None), - 0x1003: ('BrightnessValue', None), - 0x1004: ('FlashMode', None), - 0x1004: ('FlashMode', + 0x0204: Tag('DigitalZoom'), + 0x0205: Tag('FocalPlaneDiagonal'), + 0x0206: Tag('LensDistortionParams'), + 0x0207: Tag('SoftwareRelease'), + 0x0208: Tag('PictureInfo'), + 0x0209: Tag('CameraID'), # print as string + 0x0F00: Tag('DataDump'), + 0x0300: Tag('PreCaptureFrames'), + 0x0404: Tag('SerialNumber'), + 0x1000: Tag('ShutterSpeedValue'), + 0x1001: Tag('ISOValue'), + 0x1002: Tag('ApertureValue'), + 0x1003: Tag('BrightnessValue'), + 0x1004: Tag('FlashMode'), + 0x1004: TagDict('FlashMode', {2: 'On', 3: 'Off'}), - 0x1005: ('FlashDevice', + 0x1005: TagDict('FlashDevice', {0: 'None', 1: 'Internal', 4: 'External', 5: 'Internal + External'}), - 0x1006: ('ExposureCompensation', None), - 0x1007: ('SensorTemperature', None), - 0x1008: ('LensTemperature', None), - 0x100b: ('FocusMode', + 0x1006: Tag('ExposureCompensation'), + 0x1007: Tag('SensorTemperature'), + 0x1008: Tag('LensTemperature'), + 0x100b: TagDict('FocusMode', {0: 'Auto', 1: 'Manual'}), - 0x1017: ('RedBalance', None), - 0x1018: ('BlueBalance', None), - 0x101a: ('SerialNumber', None), - 0x1023: ('FlashExposureComp', None), - 0x1026: ('ExternalFlashBounce', + 0x1017: Tag('RedBalance'), + 0x1018: Tag('BlueBalance'), + 0x101a: Tag('SerialNumber'), + 0x1023: Tag('FlashExposureComp'), + 0x1026: TagDict('ExternalFlashBounce', {0: 'No', 1: 'Yes'}), - 0x1027: ('ExternalFlashZoom', None), - 0x1028: ('ExternalFlashMode', None), + 0x1027: Tag('ExternalFlashZoom'), + 0x1028: Tag('ExternalFlashMode'), 0x1029: ('Contrast int16u', {0: 'High', 1: 'Normal', 2: 'Low'}), - 0x102a: ('SharpnessFactor', None), - 0x102b: ('ColorControl', None), - 0x102c: ('ValidBits', None), - 0x102d: ('CoringFilter', None), - 0x102e: ('OlympusImageWidth', None), - 0x102f: ('OlympusImageHeight', None), - 0x1034: ('CompressionRatio', None), - 0x1035: ('PreviewImageValid', + 0x102a: Tag('SharpnessFactor'), + 0x102b: Tag('ColorControl'), + 0x102c: Tag('ValidBits'), + 0x102d: Tag('CoringFilter'), + 0x102e: Tag('OlympusImageWidth'), + 0x102f: Tag('OlympusImageHeight'), + 0x1034: Tag('CompressionRatio'), + 0x1035: TagDict('PreviewImageValid', {0: 'No', 1: 'Yes'}), - 0x1036: ('PreviewImageStart', None), - 0x1037: ('PreviewImageLength', None), - 0x1039: ('CCDScanMode', + 0x1036: Tag('PreviewImageStart'), + 0x1037: Tag('PreviewImageLength'), + 0x1039: TagDict('CCDScanMode', {0: 'Interlaced', 1: 'Progressive'}), - 0x103a: ('NoiseReduction', + 0x103a: TagDict('NoiseReduction', {0: 'Off', 1: 'On'}), - 0x103b: ('InfinityLensStep', None), - 0x103c: ('NearLensStep', None), + 0x103b: Tag('InfinityLensStep'), + 0x103c: Tag('NearLensStep'), # TODO - these need extra definitions # http://search.cpan.org/src/EXIFTOOL/Image-ExifTool-6.90/html/TagNames/Olympus.html - 0x2010: ('Equipment', None), - 0x2020: ('CameraSettings', None), - 0x2030: ('RawDevelopment', None), - 0x2040: ('ImageProcessing', None), - 0x2050: ('FocusInfo', None), - 0x3000: ('RawInfo ', None), + 0x2010: Tag('Equipment'), + 0x2020: Tag('CameraSettings'), + 0x2030: Tag('RawDevelopment'), + 0x2040: Tag('ImageProcessing'), + 0x2050: Tag('FocusInfo'), + 0x3000: Tag('RawInfo '), } # 0x2020 CameraSettings MAKERNOTE_OLYMPUS_TAG_0x2020={ - 0x0100: ('PreviewImageValid', + 0x0100: TagDict('PreviewImageValid', {0: 'No', 1: 'Yes'}), - 0x0101: ('PreviewImageStart', None), - 0x0102: ('PreviewImageLength', None), - 0x0200: ('ExposureMode', + 0x0101: Tag('PreviewImageStart'), + 0x0102: Tag('PreviewImageLength'), + 0x0200: TagDict('ExposureMode', {1: 'Manual', 2: 'Program', 3: 'Aperture-priority AE', 4: 'Shutter speed priority AE', 5: 'Program-shift'}), - 0x0201: ('AELock', + 0x0201: TagDict('AELock', {0: 'Off', 1: 'On'}), - 0x0202: ('MeteringMode', + 0x0202: TagDict('MeteringMode', {2: 'Center Weighted', 3: 'Spot', 5: 'ESP', 261: 'Pattern+AF', 515: 'Spot+Highlight control', 1027: 'Spot+Shadow control'}), - 0x0300: ('MacroMode', + 0x0300: TagDict('MacroMode', {0: 'Off', 1: 'On'}), - 0x0301: ('FocusMode', + 0x0301: TagDict('FocusMode', {0: 'Single AF', 1: 'Sequential shooting AF', 2: 'Continuous AF', 3: 'Multi AF', 10: 'MF'}), - 0x0302: ('FocusProcess', + 0x0302: TagDict('FocusProcess', {0: 'AF Not Used', 1: 'AF Used'}), - 0x0303: ('AFSearch', + 0x0303: TagDict('AFSearch', {0: 'Not Ready', 1: 'Ready'}), - 0x0304: ('AFAreas', None), - 0x0401: ('FlashExposureCompensation', None), + 0x0304: Tag('AFAreas'), + 0x0401: Tag('FlashExposureCompensation'), 0x0500: ('WhiteBalance2', {0: 'Auto', 16: '7500K (Fine Weather with Shade)', @@ -862,22 +898,22 @@ 512: 'Custom WB 5400K', 513: 'Custom WB 2900K', 514: 'Custom WB 8000K', }), - 0x0501: ('WhiteBalanceTemperature', None), - 0x0502: ('WhiteBalanceBracket', None), - 0x0503: ('CustomSaturation', None), # (3 numbers: 1. CS Value, 2. Min, 3. Max) - 0x0504: ('ModifiedSaturation', + 0x0501: Tag('WhiteBalanceTemperature'), + 0x0502: Tag('WhiteBalanceBracket'), + 0x0503: Tag('CustomSaturation'), # (3 numbers: 1. CS Value, 2. Min, 3. Max) + 0x0504: TagDict('ModifiedSaturation', {0: 'Off', 1: 'CM1 (Red Enhance)', 2: 'CM2 (Green Enhance)', 3: 'CM3 (Blue Enhance)', 4: 'CM4 (Skin Tones)'}), - 0x0505: ('ContrastSetting', None), # (3 numbers: 1. Contrast, 2. Min, 3. Max) - 0x0506: ('SharpnessSetting', None), # (3 numbers: 1. Sharpness, 2. Min, 3. Max) - 0x0507: ('ColorSpace', + 0x0505: Tag('ContrastSetting'), # (3 numbers: 1. Contrast, 2. Min, 3. Max) + 0x0506: Tag('SharpnessSetting'), # (3 numbers: 1. Sharpness, 2. Min, 3. Max) + 0x0507: TagDict('ColorSpace', {0: 'sRGB', 1: 'Adobe RGB', 2: 'Pro Photo RGB'}), - 0x0509: ('SceneMode', + 0x0509: TagDict('SceneMode', {0: 'Standard', 6: 'Auto', 7: 'Sport', @@ -903,105 +939,105 @@ 45: 'Low Key', 46: 'Children', 48: 'Nature Macro'}), - 0x050a: ('NoiseReduction', + 0x050a: TagDict('NoiseReduction', {0: 'Off', 1: 'Noise Reduction', 2: 'Noise Filter', 3: 'Noise Reduction + Noise Filter', 4: 'Noise Filter (ISO Boost)', 5: 'Noise Reduction + Noise Filter (ISO Boost)'}), - 0x050b: ('DistortionCorrection', + 0x050b: TagDict('DistortionCorrection', {0: 'Off', 1: 'On'}), - 0x050c: ('ShadingCompensation', + 0x050c: TagDict('ShadingCompensation', {0: 'Off', 1: 'On'}), - 0x050d: ('CompressionFactor', None), - 0x050f: ('Gradation', + 0x050d: Tag('CompressionFactor'), + 0x050f: TagDict('Gradation', {'-1 -1 1': 'Low Key', '0 -1 1': 'Normal', '1 -1 1': 'High Key'}), - 0x0520: ('PictureMode', + 0x0520: TagDict('PictureMode', {1: 'Vivid', 2: 'Natural', 3: 'Muted', 256: 'Monotone', 512: 'Sepia'}), - 0x0521: ('PictureModeSaturation', None), - 0x0522: ('PictureModeHue?', None), - 0x0523: ('PictureModeContrast', None), - 0x0524: ('PictureModeSharpness', None), - 0x0525: ('PictureModeBWFilter', + 0x0521: Tag('PictureModeSaturation'), + 0x0522: Tag('PictureModeHue?'), + 0x0523: Tag('PictureModeContrast'), + 0x0524: Tag('PictureModeSharpness'), + 0x0525: TagDict('PictureModeBWFilter', {0: 'n/a', 1: 'Neutral', 2: 'Yellow', 3: 'Orange', 4: 'Red', 5: 'Green'}), - 0x0526: ('PictureModeTone', + 0x0526: TagDict('PictureModeTone', {0: 'n/a', 1: 'Neutral', 2: 'Sepia', 3: 'Blue', 4: 'Purple', 5: 'Green'}), - 0x0600: ('Sequence', None), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits - 0x0601: ('PanoramaMode', None), # (2 numbers: 1. Mode, 2. Shot number) + 0x0600: Tag('Sequence'), # 2 or 3 numbers: 1. Mode, 2. Shot number, 3. Mode bits + 0x0601: Tag('PanoramaMode'), # (2 numbers: 1. Mode, 2. Shot number) 0x0603: ('ImageQuality2', {1: 'SQ', 2: 'HQ', 3: 'SHQ', 4: 'RAW'}), - 0x0901: ('ManometerReading', None), + 0x0901: Tag('ManometerReading'), } MAKERNOTE_CASIO_TAGS={ - 0x0001: ('RecordingMode', + 0x0001: TagDict('RecordingMode', {1: 'Single Shutter', 2: 'Panorama', 3: 'Night Scene', 4: 'Portrait', 5: 'Landscape'}), - 0x0002: ('Quality', + 0x0002: TagDict('Quality', {1: 'Economy', 2: 'Normal', 3: 'Fine'}), - 0x0003: ('FocusingMode', + 0x0003: TagDict('FocusingMode', {2: 'Macro', 3: 'Auto Focus', 4: 'Manual Focus', 5: 'Infinity'}), - 0x0004: ('FlashMode', + 0x0004: TagDict('FlashMode', {1: 'Auto', 2: 'On', 3: 'Off', 4: 'Red Eye Reduction'}), - 0x0005: ('FlashIntensity', + 0x0005: TagDict('FlashIntensity', {11: 'Weak', 13: 'Normal', 15: 'Strong'}), - 0x0006: ('Object Distance', None), - 0x0007: ('WhiteBalance', + 0x0006: Tag('Object Distance'), + 0x0007: TagDict('WhiteBalance', {1: 'Auto', 2: 'Tungsten', 3: 'Daylight', 4: 'Fluorescent', 5: 'Shade', 129: 'Manual'}), - 0x000B: ('Sharpness', + 0x000B: TagDict('Sharpness', {0: 'Normal', 1: 'Soft', 2: 'Hard'}), - 0x000C: ('Contrast', + 0x000C: TagDict('Contrast', {0: 'Normal', 1: 'Low', 2: 'High'}), - 0x000D: ('Saturation', + 0x000D: TagDict('Saturation', {0: 'Normal', 1: 'Low', 2: 'High'}), - 0x0014: ('CCDSpeed', + 0x0014: TagDict('CCDSpeed', {64: 'Normal', 80: 'Normal', 100: 'High', @@ -1011,15 +1047,15 @@ } MAKERNOTE_FUJIFILM_TAGS={ - 0x0000: ('NoteVersion', None), - 0x1000: ('Quality', None), - 0x1001: ('Sharpness', + 0x0000: Tag('NoteVersion'), + 0x1000: Tag('Quality'), + 0x1001: TagDict('Sharpness', {1: 'Soft', 2: 'Soft', 3: 'Normal', 4: 'Hard', 5: 'Hard'}), - 0x1002: ('WhiteBalance', + 0x1002: TagDict('WhiteBalance', {0: 'Auto', 256: 'Daylight', 512: 'Cloudy', @@ -1028,30 +1064,30 @@ 770: 'White-Fluorescent', 1024: 'Incandescent', 3840: 'Custom'}), - 0x1003: ('Color', + 0x1003: TagDict('Color', {0: 'Normal', 256: 'High', 512: 'Low'}), - 0x1004: ('Tone', + 0x1004: TagDict('Tone', {0: 'Normal', 256: 'High', 512: 'Low'}), - 0x1010: ('FlashMode', + 0x1010: TagDict('FlashMode', {0: 'Auto', 1: 'On', 2: 'Off', 3: 'Red Eye Reduction'}), - 0x1011: ('FlashStrength', None), - 0x1020: ('Macro', + 0x1011: Tag('FlashStrength'), + 0x1020: TagDict('Macro', {0: 'Off', 1: 'On'}), - 0x1021: ('FocusMode', + 0x1021: TagDict('FocusMode', {0: 'Auto', 1: 'Manual'}), - 0x1030: ('SlowSync', + 0x1030: TagDict('SlowSync', {0: 'Off', 1: 'On'}), - 0x1031: ('PictureMode', + 0x1031: TagDict('PictureMode', {0: 'Auto', 1: 'Portrait', 2: 'Landscape', @@ -1061,38 +1097,38 @@ 256: 'Aperture Priority AE', 512: 'Shutter Priority AE', 768: 'Manual Exposure'}), - 0x1100: ('MotorOrBracket', + 0x1100: TagDict('MotorOrBracket', {0: 'Off', 1: 'On'}), - 0x1300: ('BlurWarning', + 0x1300: TagDict('BlurWarning', {0: 'Off', 1: 'On'}), - 0x1301: ('FocusWarning', + 0x1301: TagDict('FocusWarning', {0: 'Off', 1: 'On'}), - 0x1302: ('AEWarning', + 0x1302: TagDict('AEWarning', {0: 'Off', 1: 'On'}), } MAKERNOTE_CANON_TAGS = { - 0x0006: ('ImageType', None), - 0x0007: ('FirmwareVersion', None), - 0x0008: ('ImageNumber', None), - 0x0009: ('OwnerName', None), + 0x0006: Tag('ImageType'), + 0x0007: Tag('FirmwareVersion'), + 0x0008: Tag('ImageNumber'), + 0x0009: Tag('OwnerName'), } # this is in element offset, name, optional value dictionary format MAKERNOTE_CANON_TAG_0x001 = { - 1: ('Macromode', + 1: TagDict('Macromode', {1: 'Macro', 2: 'Normal'}), - 2: ('SelfTimer', None), - 3: ('Quality', + 2: Tag('SelfTimer'), + 3: TagDict('Quality', {2: 'Normal', 3: 'Fine', 5: 'Superfine'}), - 4: ('FlashMode', + 4: TagDict('FlashMode', {0: 'Flash Not Fired', 1: 'Auto', 2: 'On', @@ -1101,10 +1137,10 @@ 5: 'Auto + Red-Eye Reduction', 6: 'On + Red-Eye Reduction', 16: 'external flash'}), - 5: ('ContinuousDriveMode', + 5: TagDict('ContinuousDriveMode', {0: 'Single Or Timer', 1: 'Continuous'}), - 7: ('FocusMode', + 7: TagDict('FocusMode', {0: 'One-Shot', 1: 'AI Servo', 2: 'AI Focus', @@ -1112,11 +1148,11 @@ 4: 'Single', 5: 'Continuous', 6: 'MF'}), - 10: ('ImageSize', + 10: TagDict('ImageSize', {0: 'Large', 1: 'Medium', 2: 'Small'}), - 11: ('EasyShootingMode', + 11: TagDict('EasyShootingMode', {0: 'Full Auto', 1: 'Manual', 2: 'Landscape', @@ -1129,70 +1165,70 @@ 9: 'Sports', 10: 'Macro/Close-Up', 11: 'Pan Focus'}), - 12: ('DigitalZoom', + 12: TagDict('DigitalZoom', {0: 'None', 1: '2x', 2: '4x'}), - 13: ('Contrast', + 13: TagDict('Contrast', {0xFFFF: 'Low', 0: 'Normal', 1: 'High'}), - 14: ('Saturation', + 14: TagDict('Saturation', {0xFFFF: 'Low', 0: 'Normal', 1: 'High'}), - 15: ('Sharpness', + 15: TagDict('Sharpness', {0xFFFF: 'Low', 0: 'Normal', 1: 'High'}), - 16: ('ISO', + 16: TagDict('ISO', {0: 'See ISOSpeedRatings Tag', 15: 'Auto', 16: '50', 17: '100', 18: '200', 19: '400'}), - 17: ('MeteringMode', + 17: TagDict('MeteringMode', {3: 'Evaluative', 4: 'Partial', 5: 'Center-weighted'}), - 18: ('FocusType', + 18: TagDict('FocusType', {0: 'Manual', 1: 'Auto', 3: 'Close-Up (Macro)', 8: 'Locked (Pan Mode)'}), - 19: ('AFPointSelected', + 19: TagDict('AFPointSelected', {0x3000: 'None (MF)', 0x3001: 'Auto-Selected', 0x3002: 'Right', 0x3003: 'Center', 0x3004: 'Left'}), - 20: ('ExposureMode', + 20: TagDict('ExposureMode', {0: 'Easy Shooting', 1: 'Program', 2: 'Tv-priority', 3: 'Av-priority', 4: 'Manual', 5: 'A-DEP'}), - 23: ('LongFocalLengthOfLensInFocalUnits', None), - 24: ('ShortFocalLengthOfLensInFocalUnits', None), - 25: ('FocalUnitsPerMM', None), - 28: ('FlashActivity', + 23: Tag('LongFocalLengthOfLensInFocalUnits'), + 24: Tag('ShortFocalLengthOfLensInFocalUnits'), + 25: Tag('FocalUnitsPerMM'), + 28: TagDict('FlashActivity', {0: 'Did Not Fire', 1: 'Fired'}), - 29: ('FlashDetails', + 29: TagDict('FlashDetails', {14: 'External E-TTL', 13: 'Internal Flash', 11: 'FP Sync Used', 7: '2nd("Rear")-Curtain Sync Used', 4: 'FP Sync Enabled'}), - 32: ('FocusMode', + 32: TagDict('FocusMode', {0: 'Single', 1: 'Continuous'}), } MAKERNOTE_CANON_TAG_0x004 = { - 7: ('WhiteBalance', + 7: TagDict('WhiteBalance', {0: 'Auto', 1: 'Sunny', 2: 'Cloudy', @@ -1200,9 +1236,9 @@ 4: 'Fluorescent', 5: 'Flash', 6: 'Custom'}), - 9: ('SequenceNumber', None), - 14: ('AFPointUsed', None), - 15: ('FlashBias', + 9: Tag('SequenceNumber'), + 14: Tag('AFPointUsed'), + 15: TagDict('FlashBias', {0xFFC0: '-2 EV', 0xFFCC: '-1.67 EV', 0xFFD0: '-1.50 EV', @@ -1220,7 +1256,7 @@ 0x0030: '1.50 EV', 0x0034: '1.67 EV', 0x0040: '2 EV'}), - 19: ('SubjectDistance', None), + 19: Tag('SubjectDistance'), } # ratio object that eventually will be able to reduce itself to lowest