Skip to content

Commit 215a463

Browse files
committed
Fix up Canon MakerTags
1 parent ea29bac commit 215a463

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 = ''
@@ -509,47 +513,43 @@ def decode_maker_note(self) -> None:
509513
self.dump_ifd(note.field_offset, 'MakerNote',
510514
tag_dict=makernote.canon.TAGS)
511515

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

528533
# TODO Decode Olympus MakerNote tag based on offset within tag.
529534
# def _olympus_decode_tag(self, value, mn_tags):
530535
# pass
531536

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

554554
def _canon_decode_camera_info(self, camera_info_tag):
555555
"""
@@ -591,7 +591,8 @@ def _canon_decode_camera_info(self, camera_info_tag):
591591
tag_value = tag[2].get(tag_value, tag_value)
592592
logger.debug(" %s %s", tag_name, tag_value)
593593

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

596597
def parse_xmp(self, xmp_bytes: bytes):
597598
"""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)