1
1
# Library to extract EXIF information in digital camera image files
3
# To use this library call with:
4
# f=open(path_name, 'rb')
5
# tags=EXIF.process_file(f)
6
# tags will now be a dictionary mapping names of EXIF tags to their
7
# values in the file named by path_name. You can process the tags
8
# as you wish. In particular, you can iterate through all the tags with:
9
# for tag in tags.keys():
10
# if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename',
12
# print "Key: %s, value %s" % (tag, tags[tag])
13
# (This code uses the if statement to avoid printing out a few of the
14
# tags that tend to be long or boring.)
16
# The tags dictionary will include keys for all of the usual EXIF
17
# tags, and will also include keys for Makernotes used by some
18
# cameras, for which we have a good specification.
3
20
# Contains code from "exifdump.py" originally written by Thierry Bousch
4
21
# <bousch@topo.math.u-psud.fr> and released into the public domain.
6
23
# Updated and turned into general-purpose library by Gene Cash
7
# <email gcash cfl.rr.com>
9
# This copyright license is intended to be similar to the FreeBSD license.
11
# Copyright 2002 Gene Cash All rights reserved.
24
# <email gcash at cfl.rr.com>
26
# This copyright license is intended to be similar to the FreeBSD license.
28
# Copyright 2002 Gene Cash All rights reserved.
13
30
# Redistribution and use in source and binary forms, with or without
14
31
# modification, are permitted provided that the following conditions are
36
53
# This means you may do anything you want with this code, except claim you
37
54
# wrote it. Also, if it breaks you get to keep both pieces.
57
# * Simon J. Gerraty <sjg@crufty.net>
58
# s2n fix & orientation decode
59
# * John T. Riedl <riedl@cs.umn.edu>
60
# Added support for newer Nikon type 3 Makernote format for D70 and some
61
# other Nikon cameras.
62
# * Joerg Schaefer <schaeferj@gmx.net>
63
# Fixed subtle bug when faking an EXIF header, which affected maker notes
64
# using relative offsets, and a fix for Nikon D100.
39
66
# 21-AUG-99 TB Last update by Thierry Bousch to his code.
40
67
# 17-JAN-02 CEC Discovered code on web.
41
68
# Commented everything.
58
85
# 26-JAN-02 CEC Added ability to extract TIFF thumbnails.
59
86
# Added Nikon, Fujifilm, Casio MakerNotes.
60
87
# 30-NOV-03 CEC Fixed problem with canon_decode_tag() not creating an
61
# IFD_Tag() object. Fixed bit shift warning.
89
# 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L.
64
# * Better printing of ratios
66
92
# field type descriptions as (length, abbreviation, full name) tuples
95
121
0x010F: ('Make', ),
96
122
0x0110: ('Model', ),
97
123
0x0111: ('StripOffsets', ),
98
0x0112: ('Orientation', ),
124
0x0112: ('Orientation',
125
{1: 'Horizontal (normal)',
126
2: 'Mirrored horizontal',
128
4: 'Mirrored vertical',
129
5: 'Mirrored horizontal then rotated 90 CCW',
131
7: 'Mirrored horizontal then rotated 90 CW',
132
8: 'Rotated 90 CCW'}),
99
133
0x0115: ('SamplesPerPixel', ),
100
134
0x0116: ('RowsPerStrip', ),
101
135
0x0117: ('StripByteCounts', ),
271
306
0x0006: ('ImageSharpening', ),
272
307
0x0007: ('FocusMode', ),
273
308
0x0008: ('FlashSetting', ),
309
0x0009: ('AutoFlashMode', ),
310
0x000B: ('WhiteBalanceBias', ),
311
0x000C: ('WhiteBalanceRBCoeff', ),
274
312
0x000F: ('ISOSelection', ),
313
0x0012: ('FlashCompensation', ),
314
0x0013: ('ISOSpeedRequested', ),
315
0x0016: ('PhotoCornerCoordinates', ),
316
0x0018: ('FlashBracketCompensationApplied', ),
317
0x0019: ('AEBracketCompensationApplied', ),
275
318
0x0080: ('ImageAdjustment', ),
319
0x0081: ('ToneCompensation', ),
276
320
0x0082: ('AuxiliaryLens', ),
321
0x0083: ('LensType', ),
322
0x0084: ('LensMinMaxFocalMaxAperture', ),
277
323
0x0085: ('ManualFocusDistance', ),
278
324
0x0086: ('DigitalZoomFactor', ),
279
325
0x0088: ('AFFocusPosition',
282
328
0x0200: 'Bottom',
284
330
0x0400: 'Right'}),
331
0x0089: ('BracketingMode',
332
{0x00: 'Single frame, no bracketing',
333
0x01: 'Continuous, no bracketing',
334
0x02: 'Timer, no bracketing',
335
0x10: 'Single frame, exposure bracketing',
336
0x11: 'Continuous, exposure bracketing',
337
0x12: 'Timer, exposure bracketing',
338
0x40: 'Single frame, white balance bracketing',
339
0x41: 'Continuous, white balance bracketing',
340
0x42: 'Timer, white balance bracketing'}),
341
0x008D: ('ColorMode', ),
342
0x008F: ('SceneMode?', ),
343
0x0090: ('LightingType', ),
344
0x0092: ('HueAdjustment', ),
285
345
0x0094: ('Saturation',
292
352
0x0095: ('NoiseReduction', ),
353
0x00A7: ('TotalShutterReleases', ),
354
0x00A9: ('ImageOptimization', ),
355
0x00AA: ('Saturation', ),
356
0x00AB: ('DigitalVariProgram', ),
293
357
0x0010: ('DataDump', )
698
762
# class that handles an EXIF header
699
763
class EXIF_header:
700
def __init__(self, file, endian, offset, debug=0):
764
def __init__(self, file, endian, offset, fake_exif, debug=0):
702
766
self.endian=endian
703
767
self.offset=offset
768
self.fake_exif=fake_exif
707
772
# convert slice to integer, based on sign and endian flags
773
# usually this offset is assumed to be relative to the beginning of the
774
# start of the EXIF information. For some cameras that use relative tags,
775
# this offset may be relative to some other starting point.
708
776
def s2n(self, offset, length, signed=0):
709
777
self.file.seek(self.offset+offset)
710
778
slice=self.file.read(length)
752
819
# return list of entries in this IFD
753
def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS):
820
def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0):
754
821
entries=self.s2n(ifd, 2)
755
822
for i in range(entries):
823
# entry is index of start of this IFD in the file
757
825
tag=self.s2n(entry, 2)
826
# get tag name. We do it early to make debugging easier
827
tag_entry=dict.get(tag)
829
tag_name=tag_entry[0]
831
tag_name='Tag 0x%04X' % tag
758
832
field_type=self.s2n(entry+2, 2)
759
833
if not 0 < field_type < len(FIELD_TYPES):
760
834
# unknown field type
764
838
count=self.s2n(entry+4, 4)
766
840
if count*typelen > 4:
767
# not the value, it's a pointer to the value
768
offset=self.s2n(offset, 4)
841
# offset is not the value; it's a pointer to the value
842
# if relative we set things up so s2n will seek to the right
843
# place when it adds self.offset. Note that this 'relative'
844
# is for the Nikon type 3 makernote. Other cameras may use
845
# other relative offsets, which would have to be computed here
846
# slightly differently.
848
tmp_offset=self.s2n(offset, 4)
849
offset=tmp_offset+ifd-self.offset+4
853
offset=self.s2n(offset, 4)
769
854
field_offset=offset
770
855
if field_type == 2:
771
856
# special case: null-terminated ASCII string
773
858
self.file.seek(self.offset+offset)
774
values=self.file.read(count).strip().replace('\x00','')
859
values=self.file.read(count)
860
values=values.strip().replace('\x00','')
806
# use LUT for this tag
890
# use lookup table for this tag
807
891
printable+=tag_entry[1].get(i, repr(i))
809
tag_name='Tag 0x%04X' % tag
810
892
self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag,
812
894
values, field_offset,
815
print ' %s: %s' % (tag_name,
816
repr(self.tags[ifd_name+' '+tag_name]))
897
print ' debug: %s: %s' % (tag_name,
898
repr(self.tags[ifd_name+' '+tag_name]))
818
900
# extract uncompressed TIFF thumbnail (like pulling teeth)
819
901
# we take advantage of the pre-existing layout in the thumbnail IFD as
872
954
self.tags['TIFFThumbnail']=tiff
874
956
# decode all the camera-specific MakerNote formats
958
# Note is the data that comprises this MakerNote. The MakerNote will
959
# likely have pointers in it that point to other parts of the file. We'll
960
# use self.offset as the starting point for most of those pointers, since
961
# they are relative to the beginning of the file.
963
# If the MakerNote is in a newer format, it may use relative addressing
964
# within the MakerNote. In that case we'll use relative addresses for the
967
# As an aside: it's not just to be annoying that the manufacturers use
968
# relative offsets. It's so that if the makernote has to be moved by the
969
# picture software all of the offsets don't have to be adjusted. Overall,
970
# this is probably the right strategy for makernotes, though the spec is
971
# ambiguous. (The spec does not appear to imagine that makernotes would
972
# follow EXIF format internally. Once they did, it's ambiguous whether
973
# the offsets should be from the header at the start of all the EXIF info,
974
# or from the header at the start of the makernote.)
875
975
def decode_maker_note(self):
876
976
note=self.tags['EXIF MakerNote']
877
977
make=self.tags['Image Make'].printable
878
978
model=self.tags['Image Model'].printable
882
if note.values[0:5] == [78, 105, 107, 111, 110]: # "Nikon"
981
# The maker note usually starts with the word Nikon, followed by the
982
# type of the makernote (1 or 2, as a short). If the word Nikon is
983
# not at the start of the makernote, it's probably type 2, since some
984
# cameras work that way.
985
if make in ('NIKON', 'NIKON CORPORATION'):
986
if note.values[0:7] == [78, 105, 107, 111, 110, 00, 01]:
988
print "Looks like a type 1 Nikon MakerNote."
884
989
self.dump_IFD(note.field_offset+8, 'MakerNote',
885
990
dict=MAKERNOTE_NIKON_OLDER_TAGS)
991
elif note.values[0:7] == [78, 105, 107, 111, 110, 00, 02]:
993
print "Looks like a labeled type 2 Nikon MakerNote"
994
if note.values[12:14] != [0, 42] and note.values[12:14] != [42L, 0L]:
995
raise ValueError, "Missing marker tag '42' in MakerNote."
996
# skip the Makernote label and the TIFF header
997
self.dump_IFD(note.field_offset+10+8, 'MakerNote',
998
dict=MAKERNOTE_NIKON_NEWER_TAGS, relative=1)
887
# newer model (E99x or D1)
1002
print "Looks like an unlabeled type 2 Nikon MakerNote"
888
1003
self.dump_IFD(note.field_offset, 'MakerNote',
889
1004
dict=MAKERNOTE_NIKON_NEWER_TAGS)