Skip to content

Commit d17ebab

Browse files
Knioianare
authored andcommitted
Fix up Canon MakerTags
1 parent ff1913a commit d17ebab

File tree

2 files changed

+85
-43
lines changed

2 files changed

+85
-43
lines changed

exifread/classes.py

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,14 @@ def _process_field(self, tag_name, count, field_type, type_length, offset):
152152
for _ in range(count):
153153
if field_type in (5, 10):
154154
# a ratio
155-
value = Fraction(
155+
value = [
156156
self.s2n(offset, 4, signed),
157157
self.s2n(offset + 4, 4, signed)
158-
)
158+
]
159+
try:
160+
value = Fraction(*value)
161+
except ZeroDivisionError:
162+
pass
159163
elif field_type in (11, 12):
160164
# a float or double
161165
unpack_format = ''
@@ -512,47 +516,43 @@ def decode_maker_note(self) -> None:
512516
self.dump_ifd(note.field_offset, 'MakerNote',
513517
tag_dict=makernote.canon.TAGS)
514518

515-
for i in (('MakerNote Tag 0x0001', makernote.canon.CAMERA_SETTINGS),
516-
('MakerNote Tag 0x0002', makernote.canon.FOCAL_LENGTH),
517-
('MakerNote Tag 0x0004', makernote.canon.SHOT_INFO),
518-
('MakerNote Tag 0x0026', makernote.canon.AF_INFO_2),
519-
('MakerNote Tag 0x0093', makernote.canon.FILE_INFO)):
520-
if i[0] in self.tags:
521-
logger.debug('Canon %s', i[0])
522-
self._canon_decode_tag(self.tags[i[0]].values, i[1])
523-
del self.tags[i[0]]
524-
if makernote.canon.CAMERA_INFO_TAG_NAME in self.tags:
525-
tag = self.tags[makernote.canon.CAMERA_INFO_TAG_NAME]
519+
for tag_name, tag_def in (('MakerNote CameraSettings', makernote.canon.CAMERA_SETTINGS),
520+
('MakerNote FocalLength', makernote.canon.FOCAL_LENGTH),
521+
('MakerNote ShotInfo', makernote.canon.SHOT_INFO),
522+
('MakerNote AFInfo2', makernote.canon.AF_INFO_2),
523+
('MakerNote FileInfo', makernote.canon.FILE_INFO)):
524+
if tag_name in self.tags:
525+
logger.debug('Canon %s', tag_name)
526+
self._canon_decode_tag(tag_name, self.tags[tag_name].values, tag_def)
527+
del self.tags[tag_name]
528+
ccitn = makernote.canon.CAMERA_INFO_TAG_NAME
529+
if tag := self.tags.get(ccitn):
526530
logger.debug('Canon CameraInfo')
527-
self._canon_decode_camera_info(tag)
528-
del self.tags[makernote.canon.CAMERA_INFO_TAG_NAME]
531+
if self._canon_decode_camera_info(tag):
532+
del self.tags[ccitn]
533+
529534
return
530535

531536
# TODO Decode Olympus MakerNote tag based on offset within tag.
532537
# def _olympus_decode_tag(self, value, mn_tags):
533538
# pass
534539

535-
def _canon_decode_tag(self, value, mn_tags):
540+
def _canon_decode_tag(self, tag_name, value, mn_tags):
536541
"""
537542
Decode Canon MakerNote tag based on offset within tag.
538543
539544
See http://www.burren.cx/david/canon.html by David Burren
540545
"""
541-
for i in range(1, len(value)):
542-
tag = mn_tags.get(i, ('Unknown', ))
543-
name = tag[0]
544-
if len(tag) > 1:
545-
val = tag[1].get(value[i], 'Unknown')
546-
else:
547-
val = value[i]
548-
try:
549-
logger.debug(" %s %s %s", i, name, hex(value[i]))
550-
except TypeError:
551-
logger.debug(" %s %s %s", i, name, value[i])
552-
546+
for i, val in enumerate(value):
547+
if not i:
548+
# skip id 0
549+
continue
550+
name, *enum = mn_tags.get(i + 1, (f'Unknown {i+1:3d}', ))
551+
if enum:
552+
val = enum[0].get(val, f'Unknown 0x{val:x}')
553553
# It's not a real IFD Tag but we fake one to make everybody happy.
554554
# This will have a "proprietary" type
555-
self.tags['MakerNote ' + name] = IfdTag(str(val), 0, 0, val, 0, 0)
555+
self.tags[f'{tag_name} {name}'] = IfdTag(str(val), 0, 0, val, 0, 0)
556556

557557
def _canon_decode_camera_info(self, camera_info_tag):
558558
"""
@@ -594,7 +594,8 @@ def _canon_decode_camera_info(self, camera_info_tag):
594594
tag_value = tag[2].get(tag_value, tag_value)
595595
logger.debug(" %s %s", tag_name, tag_value)
596596

597-
self.tags['MakerNote ' + tag_name] = IfdTag(str(tag_value), 0, 0, tag_value, 0, 0)
597+
self.tags[f'MakerNote CanonCameraInfo {tag_name}'] = IfdTag(str(tag_value), 0, 0, tag_value, 0, 0)
598+
return True
598599

599600
def parse_xmp(self, xmp_bytes: bytes):
600601
"""Adobe's Extensible Metadata Platform, just dump the pretty XML."""

exifread/tags/makernote/canon.py

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@
55
"""
66

77
TAGS = {
8+
0x0001: ('CameraSettings',), # see CAMERA_SETTINGS
9+
0x0002: ('FocalLength',), # see FOCAL_LENGTH
810
0x0003: ('FlashInfo',),
11+
0x0004: ('ShotInfo',), # see SHOT_INFO
912
0x0006: ('ImageType', ),
1013
0x0007: ('FirmwareVersion', ),
1114
0x0008: ('ImageNumber', ),
1215
0x0009: ('OwnerName', ),
1316
0x000c: ('SerialNumber', ),
1417
0x000e: ('FileLength', ),
18+
0x000d: ('CanonCameraInfo', ), # see
1519
0x0010: ('ModelID', {
1620
0x1010000: 'PowerShot A30',
1721
0x1040000: 'PowerShot S300 / Digital IXUS 300 / IXY Digital 300',
@@ -161,8 +165,8 @@
161165
0x3090000: 'PowerShot SX150 IS',
162166
0x3100000: 'PowerShot ELPH 510 HS / IXUS 1100 HS / IXY 51S',
163167
0x3110000: 'PowerShot S100 (new)',
164-
0x3130000: 'PowerShot SX40 HS',
165168
0x3120000: 'PowerShot ELPH 310 HS / IXUS 230 HS / IXY 600F',
169+
0x3130000: 'PowerShot SX40 HS',
166170
0x3160000: 'PowerShot A1300',
167171
0x3170000: 'PowerShot A810',
168172
0x3180000: 'PowerShot ELPH 320 HS / IXUS 240 HS / IXY 420F',
@@ -220,7 +224,9 @@
220224
0x3890000: 'PowerShot ELPH 170 IS / IXUS 170',
221225
0x3910000: 'PowerShot SX410 IS',
222226
0x4040000: 'PowerShot G1',
227+
223228
0x6040000: 'PowerShot S100 / Digital IXUS / IXY Digital',
229+
224230
0x4007d673: 'DC19/DC21/DC22',
225231
0x4007d674: 'XH A1',
226232
0x4007d675: 'HV10',
@@ -250,6 +256,7 @@
250256
0x4007da90: 'HF S20/S21/S200',
251257
0x4007da92: 'FS31/FS36/FS37/FS300/FS305/FS306/FS307',
252258
0x4007dda9: 'HF G25',
259+
253260
0x80000001: 'EOS-1D',
254261
0x80000167: 'EOS-1DS',
255262
0x80000168: 'EOS 10D',
@@ -293,13 +300,15 @@
293300
0x80000326: 'EOS Rebel T5i / 700D / Kiss X7i',
294301
0x80000327: 'EOS Rebel T5 / 1200D / Kiss X70',
295302
0x80000331: 'EOS M',
296-
0x80000355: 'EOS M2',
297303
0x80000346: 'EOS Rebel SL1 / 100D / Kiss X7',
298304
0x80000347: 'EOS Rebel T6s / 760D / 8000D',
305+
0x80000349: 'EOS 5D Mark IV',
306+
0x80000355: 'EOS M2',
299307
0x80000382: 'EOS 5DS',
300308
0x80000393: 'EOS Rebel T6i / 750D / Kiss X8i',
301309
0x80000401: 'EOS 5DS R',
302310
}),
311+
0x0012: ('AFInfo', ),
303312
0x0013: ('ThumbnailImageValidArea', ),
304313
0x0015: ('SerialNumberFormat', {
305314
0x90000000: 'Format 1',
@@ -316,16 +325,21 @@
316325
2: 'Date & Time',
317326
}),
318327
0x001e: ('FirmwareRevision', ),
328+
0x0026: ('AFInfo2', ), # see AF_INFO_2
319329
0x0028: ('ImageUniqueID', ),
330+
0x0035: ('TimeInfo', ),
331+
0x0093: ('FileInfo', ), # see FILE_INFO
320332
0x0095: ('LensModel', ),
321-
0x0096: ('InternalSerialNumber ', ),
322-
0x0097: ('DustRemovalData ', ),
323-
0x0098: ('CropInfo ', ),
333+
0x0096: ('InternalSerialNumber', ),
334+
0x0097: ('DustRemovalData', ),
335+
0x0098: ('CropInfo', ),
324336
0x009a: ('AspectInfo', ),
325337
0x00b4: ('ColorSpace', {
326338
1: 'sRGB',
327339
2: 'Adobe RGB'
328340
}),
341+
0x4019: ('LensInfo', ),
342+
329343
}
330344

331345
# this is in element offset, name, optional value dictionary format
@@ -523,12 +537,27 @@
523537
SHOT_INFO = {
524538
7: ('WhiteBalance', {
525539
0: 'Auto',
526-
1: 'Sunny',
540+
1: 'Daylight',
527541
2: 'Cloudy',
528542
3: 'Tungsten',
529543
4: 'Fluorescent',
530544
5: 'Flash',
531-
6: 'Custom'
545+
6: 'Custom',
546+
7: 'Black & White',
547+
8: 'Shade',
548+
9: 'Manual Temperature (Kelvin)',
549+
10: 'PC Set 1',
550+
11: 'PC Set 2',
551+
12: 'PC Set 3',
552+
14: 'Daylight Fluorescent',
553+
15: 'Custom 1',
554+
16: 'Custom 2',
555+
17: 'Underwater',
556+
18: 'Custom 3',
557+
19: 'Custom 4',
558+
20: 'PC Set 4',
559+
21: 'PC Set 5',
560+
23: 'Auto (ambience priority)',
532561
}),
533562
8: ('SlowShutter', {
534563
-1: 'n/a',
@@ -563,7 +592,7 @@
563592

564593
# 0x0026
565594
AF_INFO_2 = {
566-
2: ('AFAreaMode', {
595+
1: ('AFAreaMode', {
567596
0: 'Off (Manual Focus)',
568597
2: 'Single-point AF',
569598
4: 'Multi-point AF or AI AF',
@@ -575,15 +604,26 @@
575604
11: 'Flexizone Multi',
576605
13: 'Flexizone Single',
577606
}),
578-
3: ('NumAFPoints', ),
579-
4: ('ValidAFPoints', ),
580-
5: ('CanonImageWidth', ),
607+
2: ('NumAFPoints', ),
608+
3: ('ValidAFPoints', ),
609+
4: ('CanonImageWidth', ),
610+
5: ('CanonImageHeight', ),
611+
6: ('AFImageWidth', ),
612+
7: ('AFImageHeight', ),
613+
8: ('AFAreaWidths', ),
614+
9: ('AFAreaHeights', ),
615+
10: ('AFAreaXPositions', ),
616+
11: ('AFAreaYPositions', ),
617+
12: ('AFPointsInFocus', ),
618+
13: ('AFPointsSelected', ),
619+
14: ('PrimaryAFPoint', ),
581620
}
621+
AF_INFO_2 = {k+1: v for k, v in AF_INFO_2.items()}
582622

583623
# 0x0093
584624
FILE_INFO = {
585625
1: ('FileNumber', ),
586-
3: ('BracketMode', {
626+
2: ('BracketMode', {
587627
0: 'Off',
588628
1: 'AEB',
589629
2: 'FEB',
@@ -674,7 +714,7 @@ def convert_temp(value):
674714
# byte offset: (item name, data item type, decoding map).
675715
# Note that the data item type is fed directly to struct.unpack at the
676716
# specified offset.
677-
CAMERA_INFO_TAG_NAME = 'MakerNote Tag 0x000D'
717+
CAMERA_INFO_TAG_NAME = 'MakerNote CanonCameraInfo'
678718

679719
CAMERA_INFO_5D = {
680720
23: ('CameraTemperature', '<B', convert_temp),
@@ -708,4 +748,5 @@ def convert_temp(value):
708748
r'EOS 5D Mark II$': CAMERA_INFO_5DMKII,
709749
r'EOS 5D Mark III$': CAMERA_INFO_5DMKIII,
710750
r'\b(600D|REBEL T3i|Kiss X5)\b': CAMERA_INFO_600D,
751+
r'EOS 5D Mark IV$': CAMERA_INFO_5DMKIII,
711752
}

0 commit comments

Comments
 (0)