From 2936464744fe46f38f7f943844c5bf403da6c865 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 30 Jan 2021 13:02:13 -0500 Subject: [PATCH 1/9] Add some more standard tags. Obtained from https://www.media.mit.edu/pia/Research/deepview/exif.html --- exifread/tags/exif.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/exifread/tags/exif.py b/exifread/tags/exif.py index 20f3fd19..69d6bfc3 100644 --- a/exifread/tags/exif.py +++ b/exifread/tags/exif.py @@ -181,6 +181,7 @@ 1: 'Regenerated', 2: 'Unclean' }), + 0x014A: ('SubIFDs', ), 0x0148: ('ConsecutiveBadFaxLines', ), 0x014C: ('InkSet', { 1: 'CMYK', @@ -207,9 +208,10 @@ 0x0155: ('SMaxSampleValue', ), 0x0156: ('TransferRange', ), 0x0157: ('ClipPath', ), + 0x015B: ('JPEGTables', ), 0x0200: ('JPEGProc', ), - 0x0201: ('JPEGInterchangeFormat', ), - 0x0202: ('JPEGInterchangeFormatLength', ), + 0x0201: ('JPEGInterchangeFormat', ), # JpegIFOffset + 0x0202: ('JPEGInterchangeFormatLength', ), # JpegIFByteCount 0x0211: ('YCbCrCoefficients', ), 0x0212: ('YCbCrSubSampling', ), 0x0213: ('YCbCrPositioning', { @@ -243,6 +245,9 @@ 0x8825: ('GPSInfo', GPS_INFO), # GPS tags 0x8827: ('ISOSpeedRatings', ), 0x8828: ('OECF', ), + 0x8829: ('Interlace', ), + 0x882A: ('TimeZoneOffset', ), + 0x882B: ('SelfTimerMode', ), 0x8830: ('SensitivityType', { 0: 'Unknown', 1: 'Standard Output Sensitivity', @@ -335,7 +340,15 @@ 95: 'Flash fired, auto mode, return light detected, red-eye reduction mode' }), 0x920A: ('FocalLength', ), + 0x920B: ('FlashEnergy', ), + 0x920C: ('SpatialFrequencyResponse', ), + 0x920D: ('Noise', ), + 0x9211: ('ImageNumber', ), + 0x9212: ('SecurityClassification', ), + 0x9213: ('ImageHistory', ), 0x9214: ('SubjectArea', ), + 0x9215: ('ExposureIndex', ), + 0x9216: ('TIFF/EPStandardID', ), 0x927C: ('MakerNote', ), 0x9286: ('UserComment', make_string_uc), 0x9290: ('SubSecTime', ), From 30140b4e8719966e0c99788fae59eb6b1d59b780 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 30 Jan 2021 20:28:01 -0500 Subject: [PATCH 2/9] Add missing Nikon tags. Used the following references: * exiftool * LibRAW * http://lclevy.free.fr/nef/index.html * https://www.media.mit.edu/pia/Research/deepview/exif.html * http://gvsoft.no-ip.org/exif/makernote-nikon-type2.html --- exifread/tags/makernote/nikon.py | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/exifread/tags/makernote/nikon.py b/exifread/tags/makernote/nikon.py index 9a71211d..23f6f04d 100644 --- a/exifread/tags/makernote/nikon.py +++ b/exifread/tags/makernote/nikon.py @@ -1,6 +1,7 @@ from ...utils import make_string, Ratio + def ev_bias(seq) -> str: """ First digit seems to be in steps of 1/6 EV. @@ -49,6 +50,7 @@ def ev_bias(seq) -> str: ret_str = ret_str + str(ratio) + ' EV' return ret_str + # Nikon E99x MakerNote Tags TAGS_NEW = { 0x0001: ('MakernoteVersion', make_string), # Sometimes binary @@ -60,6 +62,7 @@ def ev_bias(seq) -> str: 0x0007: ('FocusMode', ), 0x0008: ('FlashSetting', ), 0x0009: ('AutoFlashMode', ), + 0x000A: ('LensMount', ), # According to LibRAW 0x000B: ('WhiteBalanceBias', ), 0x000C: ('WhiteBalanceRBCoeff', ), 0x000D: ('ProgramShift', ev_bias), @@ -70,6 +73,7 @@ def ev_bias(seq) -> str: 0x0011: ('NikonPreview', ), 0x0012: ('FlashCompensation', ev_bias), 0x0013: ('ISOSpeedRequested', ), + 0x0014: ('ColorBalance', ), # According to LibRAW 0x0016: ('PhotoCornerCoordinates', ), 0x0017: ('ExternalFlashExposureComp', ev_bias), 0x0018: ('FlashBracketCompensationApplied', ev_bias), @@ -81,10 +85,41 @@ def ev_bias(seq) -> str: 0x001E: ('ColorSpace', ), 0x001F: ('VRInfo', ), 0x0020: ('ImageAuthentication', ), + 0x0021: ('FaceDetect', ), 0x0022: ('ActiveDLighting', ), 0x0023: ('PictureControl', ), 0x0024: ('WorldTime', ), 0x0025: ('ISOInfo', ), + 0x002A: ('VignetteControl', ), + 0x002B: ('DistortInfo', ), + 0x002C: ('UnknownInfo', ), # Using what ExifTool uses + 0x0032: ('UnknownInfo2', ), # Using what ExifTool uses + 0x0034: ('ShutterMode', ), + 0x0035: ('HDRInfo', ), + 0x0037: ('MechanicalShutterCount', ), + 0x0039: ('LocationInfo', ), + # 0x003A: unknown + 0x003B: ('MultiExposureWhiteBalance', ), + # 0x003C: unknown + 0x003D: ('BlackLevel', ), + # 0x003E: unknown + # 0x003F: unknown + # 0x0040: unknown + # 0x0041: unknown + # 0x0042: unknown + # 0x0043: unknown + # 0x0044: unknown + 0x0045: ('CropArea', ), # (left, top, width, height) / left pixel (x,y), size (width,length) + # 0x0046: unknown + # 0x0047: unknown + # 0x0048: unknown + # 0x0049: unknown + # 0x004A: unknown + # 0x004B: unknown + # 0x004C: unknown + # 0x004D: unknown + 0x004E: ('NikonSettings', ), + 0x004F: ('ColorTemperatureAuto', ), 0x0080: ('ImageAdjustment', ), 0x0081: ('ToneCompensation', ), 0x0082: ('AuxiliaryLens', ), @@ -142,6 +177,7 @@ def ev_bias(seq) -> str: 0x0099: ('RawImageCenter', ), 0x009A: ('SensorPixelSize', ), 0x009C: ('Scene Assist', ), + 0x009D: ('DateStampMode', ), 0x009E: ('RetouchHistory', ), 0x00A0: ('SerialNumber', ), 0x00A2: ('ImageDataSize', ), @@ -160,10 +196,17 @@ def ev_bias(seq) -> str: 0x00AD: ('AFResponse', ), 0x00B0: ('MultiExposure', ), 0x00B1: ('HighISONoiseReduction', ), + 0x00B3: ('ToningEffect', ), 0x00B6: ('PowerUpTime', ), 0x00B7: ('AFInfo2', ), 0x00B8: ('FileInfo', ), 0x00B9: ('AFTune', ), + 0x00BB: ('RetouchInfo', ), + # 0x00BC: unknown + 0x00BD: ('PictureControlData', ), + # 0x00BF: unknown + # 0x00C0: unknown + 0x00C3: ('BarometerInfo', ), 0x0100: ('DigitalICE', ), 0x0103: ('PreviewCompression', { 1: 'Uncompressed', @@ -203,9 +246,14 @@ def ev_bias(seq) -> str: 1: 'Centered', 2: 'Co-sited', }), + 0x0E00: ('PrintIM', ), + 0x0E01: ('InCameraEditNote', ), 0x0E09: ('NikonCaptureVersion', ), 0x0E0E: ('NikonCaptureOffsets', ), 0x0E10: ('NikonScan', ), + 0x0E13: ('NikonCaptureEditVersions', ), + 0x0E1D: ('NikonICCProfile', ), + 0x0E1E: ('NikonCaptureOutput', ), 0x0E22: ('NEFBitDepth', ), } From 7bc36228b9e368b9646b3402cca3be5564fb4993 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 20 Feb 2021 17:43:09 -0500 Subject: [PATCH 3/9] Add some Nikon field value conversions --- exifread/tags/makernote/nikon.py | 127 ++++++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 9 deletions(-) diff --git a/exifread/tags/makernote/nikon.py b/exifread/tags/makernote/nikon.py index 23f6f04d..769ea135 100644 --- a/exifread/tags/makernote/nikon.py +++ b/exifread/tags/makernote/nikon.py @@ -79,22 +79,62 @@ def ev_bias(seq) -> str: 0x0018: ('FlashBracketCompensationApplied', ev_bias), 0x0019: ('AEBracketCompensationApplied', ), 0x001A: ('ImageProcessing', ), + # CropHiSpeed is a list of values. Not sure what effects the last 4. The cropped width + # and height in all photos checked was the same as the sensor width and height, which + # is slightly larger than the image resolution height and width. + # + # * Crop style + # * Sensor resolution width + # * Sensor resolution height + # * Cropped width cropped + # * Cropped height cropped + # * Pixel X position + # * Pixel Y position 0x001B: ('CropHiSpeed', ), 0x001C: ('ExposureTuning', ), 0x001D: ('SerialNumber', ), # Conflict with 0x00A0 ? - 0x001E: ('ColorSpace', ), + 0x001E: ('ColorSpace', { + 1: 'sRGB', + 2: 'Adobe RGB' + }), 0x001F: ('VRInfo', ), - 0x0020: ('ImageAuthentication', ), + 0x0020: ('ImageAuthentication', { + 0: 'Off', + 1: 'On' + }), 0x0021: ('FaceDetect', ), - 0x0022: ('ActiveDLighting', ), + 0x0022: ('ActiveDLighting', { + 0: 'Off', + 1: 'Low', + 3: 'Normal', + 5: 'High', + 7: 'Extra High', + 8: 'Extra High 1', + 9: 'Extra High 2', + 10: 'Extra High 3', + 11: 'Extra High 4', + 65535: 'Auto' + }), 0x0023: ('PictureControl', ), 0x0024: ('WorldTime', ), 0x0025: ('ISOInfo', ), - 0x002A: ('VignetteControl', ), + 0x002A: ('VignetteControl', { + 0: 'Off', + 1: 'Low', + 3: 'Normal', + 5: 'High' + }), 0x002B: ('DistortInfo', ), 0x002C: ('UnknownInfo', ), # Using what ExifTool uses 0x0032: ('UnknownInfo2', ), # Using what ExifTool uses - 0x0034: ('ShutterMode', ), + 0x0034: ('ShutterMode', { + 0: 'Mechanical', + 16: 'Electronic', + 48: 'Electronic Front Curtain', + 64: 'Electronic (Movie)', + 80: 'Auto (Mechanical)', + 81: 'Auto (Electronic Front Curtain)', + }), 0x0035: ('HDRInfo', ), 0x0037: ('MechanicalShutterCount', ), 0x0039: ('LocationInfo', ), @@ -130,6 +170,7 @@ def ev_bias(seq) -> str: 0x0087: ('FlashMode', { 0x00: 'Did Not Fire', 0x01: 'Fired, Manual', + 0x03: 'Not Ready', 0x07: 'Fired, External', 0x08: 'Fired, Commander Mode ', 0x09: 'Fired, TTL Mode', @@ -161,7 +202,18 @@ def ev_bias(seq) -> str: 0x0091: ('ShotInfo', ), # First 4 bytes are a version number in ASCII 0x0092: ('HueAdjustment', ), # ExifTool calls this 'NEFCompression', should be 1-4 - 0x0093: ('Compression', ), + 0x0093: ('Compression', { + 1: 'Lossy (type 1)', + 2: 'Uncompressed', + 3: 'Lossless', + 4: 'Lossy (type 2)', + 5: 'Striped packed 12 bits', + 6: 'Uncompressed (reduced to 12 bit)', + 7: 'Unpacked 12 bits', + 8: 'Small', + 9: 'Packed 12 bits', + 10: 'Packed 14 bits', + }), 0x0094: ('Saturation', { -3: 'B&W', -2: '-2', @@ -177,8 +229,57 @@ def ev_bias(seq) -> str: 0x0099: ('RawImageCenter', ), 0x009A: ('SensorPixelSize', ), 0x009C: ('Scene Assist', ), - 0x009D: ('DateStampMode', ), - 0x009E: ('RetouchHistory', ), + 0x009D: ('DateStampMode', { + 0: 'Off', + 1: 'Date & Time', + 2: 'Date', + 3: 'Date Counter' + }), + 0x009E: ('RetouchHistory', { + 0: 'None', + 3: 'B & W', + 4: 'Sepia', + 5: 'Trim', + 6: 'Small Picture', + 7: 'D-Lighting', + 8: 'Red Eye', + 9: 'Cyanotype', + 10: 'Sky Light', + 11: 'Warm Tone', + 12: 'Color Custom', + 13: 'Image Overlay', + 14: 'Red Intensifier', + 15: 'Green Intensifier', + 16: 'Blue Intensifier', + 17: 'Cross Screen', + 18: 'Quick Retouch', + 19: 'NEF Processing', + 23: 'Distortion Control', + 25: 'Fisheye', + 26: 'Straighten', + 29: 'Perspective Control', + 30: 'Color Outline', + 31: 'Soft Filter', + 32: 'Resize', + 33: 'Miniature Effect', + 34: 'Skin Softening', + 35: 'Selected Frame', + 37: 'Color Sketch', + 38: 'Selective Color', + 39: 'Glamour', + 40: 'Drawing', + 44: 'Pop', + 45: 'Toy Camera Effect 1', + 46: 'Toy Camera Effect 2', + 47: 'Cross Process (red)', + 48: 'Cross Process (blue)', + 49: 'Cross Process (green)', + 50: 'Cross Process (yellow)', + 51: 'Super Vivid', + 52: 'High-contrast Monochrome', + 53: 'High Key', + 54: 'Low Key' + }), 0x00A0: ('SerialNumber', ), 0x00A2: ('ImageDataSize', ), # 00A3: unknown - a single byte 0 @@ -195,7 +296,15 @@ def ev_bias(seq) -> str: 0x00AC: ('ImageStabilization', ), 0x00AD: ('AFResponse', ), 0x00B0: ('MultiExposure', ), - 0x00B1: ('HighISONoiseReduction', ), + 0x00B1: ('HighISONoiseReduction', { + 0: 'Off', + 1: 'Minimal', + 2: 'Low', + 3: 'Medium Low', + 4: 'Normal', + 5: 'Medium High', + 6: 'High', + }), 0x00B3: ('ToningEffect', ), 0x00B6: ('PowerUpTime', ), 0x00B7: ('AFInfo2', ), From 13adc14ab31fac1060ee71935f030d1fcbc6683e Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 20 Feb 2021 17:43:55 -0500 Subject: [PATCH 4/9] Fix printable for field value lists Fixes issue when member values can be resolved to human readbable values. --- exifread/classes.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/exifread/classes.py b/exifread/classes.py index 1ee3d881..cfd11159 100644 --- a/exifread/classes.py +++ b/exifread/classes.py @@ -250,6 +250,7 @@ def _process_tag(self, ifd, ifd_name: str, tag_entry, entry, tag: int, tag_name, printable = str(values[0:-1]) else: printable = str(values) + # compute printable version of values if tag_entry: # optional 2nd tag element is present @@ -257,6 +258,7 @@ def _process_tag(self, ifd, ifd_name: str, tag_entry, entry, tag: int, tag_name, if callable(tag_entry[1]): # call mapping function printable = tag_entry[1](values) + # Tag with SubIFDs elif isinstance(tag_entry[1], tuple): ifd_info = tag_entry[1] try: @@ -264,11 +266,26 @@ def _process_tag(self, ifd, ifd_name: str, tag_entry, entry, tag: int, tag_name, self.dump_ifd(values[0], ifd_info[0], tag_dict=ifd_info[1], stop_tag=stop_tag) except IndexError: logger.warning('No values found for %s SubIFD', ifd_info[0]) - else: - printable = '' + elif isinstance(values, list): + pretty_values = [] for val in values: - # use lookup table for this tag - printable += tag_entry[1].get(val, repr(val)) + pretty_values.append(tag_entry[1].get(val, repr(val))) + + # FIXME: with the exception of ASCII fields `values` will always be a list. + # We have no way of knowing if the field is a single value or list of + # values. Also not sure if we know the difference between an empty list and + # an empty field value. We just do our best here. + if len(pretty_values) > 1: + printable = str(pretty_values) + elif len(pretty_values) == 1: + printable = str(pretty_values[0]) + else: + printable = '' + + else: + # NOTE: We shouldn't make it here. This would mean we received an ASCII + # value to be used in a lookup table it is possible. + printable = tag_entry[1].get(val, repr(values)) self.tags[ifd_name + ' ' + tag_name] = IfdTag( printable, tag, field_type, values, field_offset, count * type_length From fdfcd4bfa94a0e4798b0c5ce58ed36b01e92d312 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 27 Feb 2021 02:24:47 -0500 Subject: [PATCH 5/9] Add LensType table. --- exifread/tags/makernote/nikon.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/exifread/tags/makernote/nikon.py b/exifread/tags/makernote/nikon.py index 769ea135..61c02aa4 100644 --- a/exifread/tags/makernote/nikon.py +++ b/exifread/tags/makernote/nikon.py @@ -163,7 +163,27 @@ def ev_bias(seq) -> str: 0x0080: ('ImageAdjustment', ), 0x0081: ('ToneCompensation', ), 0x0082: ('AuxiliaryLens', ), - 0x0083: ('LensType', ), + # About the table below: + # * All G lenses are also D lenses but not vice versa. + # * G lens names do not include the D + # * All G and D lenses are also AF + # * G and D don't even refer to related feature or lens characteristics + # * Nikon doesn't differentiate AF, AF-I, or AF-S lenses but does with AF-P + # * AF-{I,S,P} are autofocus technology types + # * But sometimes Nikon likes to write AF-D or AF-G too in documentation + # * VR is an additional lens feature. + 0x0083: ('LensType', { # FIXME: We should form the string instead of listing every possible combo + + 0: 'AF', + 1: 'MF', + 2: 'AF D', + 6: 'AF G', + 8: 'VR', + 10: 'AF D VR', + 14: 'AF G VR', + 128: 'AF-P', + 142: 'AF-P G VR' + }), 0x0084: ('LensMinMaxFocalMaxAperture', ), 0x0085: ('ManualFocusDistance', ), 0x0086: ('DigitalZoomFactor', ), From 3a85369472b7d8bca1ee7e2cffa20db96e3959c6 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 27 Feb 2021 03:19:51 -0500 Subject: [PATCH 6/9] Update tags 0088 and 0089. Add comment to 00B7 The old values on 0088 and 0089 were incorrect. --- exifread/tags/makernote/nikon.py | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/exifread/tags/makernote/nikon.py b/exifread/tags/makernote/nikon.py index 61c02aa4..333a113c 100644 --- a/exifread/tags/makernote/nikon.py +++ b/exifread/tags/makernote/nikon.py @@ -173,7 +173,6 @@ def ev_bias(seq) -> str: # * But sometimes Nikon likes to write AF-D or AF-G too in documentation # * VR is an additional lens feature. 0x0083: ('LensType', { # FIXME: We should form the string instead of listing every possible combo - 0: 'AF', 1: 'MF', 2: 'AF D', @@ -195,23 +194,24 @@ def ev_bias(seq) -> str: 0x08: 'Fired, Commander Mode ', 0x09: 'Fired, TTL Mode', }), - 0x0088: ('AFFocusPosition', { - 0x0000: 'Center', - 0x0100: 'Top', - 0x0200: 'Bottom', - 0x0300: 'Left', - 0x0400: 'Right', - }), - 0x0089: ('BracketingMode', { - 0x00: 'Single frame, no bracketing', - 0x01: 'Continuous, no bracketing', - 0x02: 'Timer, no bracketing', - 0x10: 'Single frame, exposure bracketing', - 0x11: 'Continuous, exposure bracketing', - 0x12: 'Timer, exposure bracketing', - 0x40: 'Single frame, white balance bracketing', - 0x41: 'Continuous, white balance bracketing', - 0x42: 'Timer, white balance bracketing' + 0x0088: ('AFInfo', ), # FIXME: This is a list where each position has a different meaning + 0x0089: ('ShootingMode', { # FIXME: We should form the string instead of listing every possible combo + 0: 'Single frame', + 1: 'Continuous', + 2: 'Delay', + 8: 'b3 ???', + 10: 'b3 ???, Delay', + 16: 'Exposure Bracketing', + 17: 'Exposure Bracketing, Continuous', + 18: 'Exposure Bracketing, Delay', + 32: 'Auto ISO', + 33: 'Auto ISO, Continuous', + 34: 'Auto ISO, Delay', + 40: 'Auto ISO, b3 ???', + 48: 'Auto ISO, Exposure Bracketing', + 128: 'IR Control', + 256: 'b8 ???', + 272: 'b8 ???, Exposure Bracketing' }), 0x008A: ('AutoBracketRelease', ), 0x008B: ('LensFStops', ), @@ -327,7 +327,7 @@ def ev_bias(seq) -> str: }), 0x00B3: ('ToningEffect', ), 0x00B6: ('PowerUpTime', ), - 0x00B7: ('AFInfo2', ), + 0x00B7: ('AFInfo2', ), # FIXME: This is a list where each position has a different meaning 0x00B8: ('FileInfo', ), 0x00B9: ('AFTune', ), 0x00BB: ('RetouchInfo', ), From b8adfc4e57ceb3816ef8e7b55e8f074cdfa4c20b Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 27 Feb 2021 14:03:10 -0500 Subject: [PATCH 7/9] replace hex values. On byte fields the integer reprentation is still used. --- exifread/tags/makernote/nikon.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/exifread/tags/makernote/nikon.py b/exifread/tags/makernote/nikon.py index 333a113c..3c2eedcb 100644 --- a/exifread/tags/makernote/nikon.py +++ b/exifread/tags/makernote/nikon.py @@ -52,6 +52,9 @@ def ev_bias(seq) -> str: # Nikon E99x MakerNote Tags +# +# NOTE: Byte field values are actually integer representations in this module so keys should +# be integers. TAGS_NEW = { 0x0001: ('MakernoteVersion', make_string), # Sometimes binary 0x0002: ('ISOSetting', ), @@ -187,12 +190,12 @@ def ev_bias(seq) -> str: 0x0085: ('ManualFocusDistance', ), 0x0086: ('DigitalZoomFactor', ), 0x0087: ('FlashMode', { - 0x00: 'Did Not Fire', - 0x01: 'Fired, Manual', - 0x03: 'Not Ready', - 0x07: 'Fired, External', - 0x08: 'Fired, Commander Mode ', - 0x09: 'Fired, TTL Mode', + 0: 'Did Not Fire', + 1: 'Fired, Manual', + 3: 'Not Ready', + 7: 'Fired, External', + 8: 'Fired, Commander Mode ', + 9: 'Fired, TTL Mode', }), 0x0088: ('AFInfo', ), # FIXME: This is a list where each position has a different meaning 0x0089: ('ShootingMode', { # FIXME: We should form the string instead of listing every possible combo From da24b3bc17c389a501a34418eaeb9ff12dc8209d Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sat, 27 Feb 2021 15:13:45 -0500 Subject: [PATCH 8/9] Handle list fields where values have a meaning based on position. --- exifread/classes.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/exifread/classes.py b/exifread/classes.py index cfd11159..12697b93 100644 --- a/exifread/classes.py +++ b/exifread/classes.py @@ -267,9 +267,16 @@ def _process_tag(self, ifd, ifd_name: str, tag_entry, entry, tag: int, tag_name, except IndexError: logger.warning('No values found for %s SubIFD', ifd_info[0]) elif isinstance(values, list): + # A list can be a list of the same type of value or a list of values with a + # different meaning by position. + pretty_values = [] - for val in values: - pretty_values.append(tag_entry[1].get(val, repr(val))) + if isinstance(tag_entry[1], list): + for _i in range(len(values)): + pretty_values.append(tag_entry[1][_i].get(values[_i], repr(values[_i]))) + else: + for val in values: + pretty_values.append(tag_entry[1].get(val, repr(val))) # FIXME: with the exception of ASCII fields `values` will always be a list. # We have no way of knowing if the field is a single value or list of From e5b6776b4fc64f97eb827d48c5995022584d19f6 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Sun, 28 Feb 2021 18:38:50 +0000 Subject: [PATCH 9/9] Add Nikon CropHiSpeed --- exifread/tags/makernote/nikon.py | 35 +++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/exifread/tags/makernote/nikon.py b/exifread/tags/makernote/nikon.py index 3c2eedcb..27b85b82 100644 --- a/exifread/tags/makernote/nikon.py +++ b/exifread/tags/makernote/nikon.py @@ -82,18 +82,29 @@ def ev_bias(seq) -> str: 0x0018: ('FlashBracketCompensationApplied', ev_bias), 0x0019: ('AEBracketCompensationApplied', ), 0x001A: ('ImageProcessing', ), - # CropHiSpeed is a list of values. Not sure what effects the last 4. The cropped width - # and height in all photos checked was the same as the sensor width and height, which - # is slightly larger than the image resolution height and width. - # - # * Crop style - # * Sensor resolution width - # * Sensor resolution height - # * Cropped width cropped - # * Cropped height cropped - # * Pixel X position - # * Pixel Y position - 0x001B: ('CropHiSpeed', ), + 0x001B: ('CropHiSpeed', [ + { + 0: 'Off', + 1: '1.3x', + 2: 'DX', + 3: '5:4', + 4: '3:2', + 6: '16:9', + 8: '2.7x', + 9: 'DX Movie', + 10: '1.3x Movie', + 11: 'FX Uncropper', + 12: 'DX Uncropped', + 15: '1.5x Movie', + 17: '1:1' + }, + {}, + {}, + {}, + {}, + {}, + {}, + ]), 0x001C: ('ExposureTuning', ), 0x001D: ('SerialNumber', ), # Conflict with 0x00A0 ? 0x001E: ('ColorSpace', {