~toolpart/+junk/pythoncard

« back to all changes in this revision

Viewing changes to EXIF.py

  • Committer: Bazaar Package Importer
  • Author(s): Sandro Tosi
  • Date: 2010-03-04 23:55:10 UTC
  • mfrom: (3.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20100304235510-3v6lbhzwrgm0pcca
Tags: 0.8.2-1
* QA upload.
* New upstream release
* debian/control
  - set maintainer to QA group
  - set Homepage field, removing the URL from packages description
  - bump versioned b-d-i on python-support, to properly support Python module
  - replace b-d on python-all-dev with python-all, since building only
    arch:all packages
  - replace Source-Version substvar with source:Version
  - add ${misc:Depends} to binary packages Depends
* debian/watch
  - updated to use the SourceForge redirector; thanks to Raphael Geissert for
    the report and to Dario Minnucci for the patch; Closes: #449904
* debian/{pythoncard-doc, python-pythoncard}.install
  - use wildcards instead of site-packages to fix build with python 2.6;
    thanks to Ilya Barygin for the report and patch; Closes: #572332
* debian/pythoncard-doc.doc-base
  - set section to Programmin/Python
* debian/pythoncard-tools.menu
  - set menu main section to Applications
* debian/pythoncard-tools.postinst
  - removed, needed only to update the menu, but it's now created by debhelper

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Library to extract EXIF information in digital camera image files
2
2
#
 
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',
 
11
#                        'EXIF MakerNote'):
 
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.)
 
15
#
 
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.
 
19
#
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.
5
22
#
6
23
# Updated and turned into general-purpose library by Gene Cash
7
 
# <email gcash cfl.rr.com>
8
 
#
9
 
# This copyright license is intended to be similar to the FreeBSD license. 
10
 
#
11
 
# Copyright 2002 Gene Cash All rights reserved. 
 
24
# <email gcash at cfl.rr.com>
 
25
#
 
26
# This copyright license is intended to be similar to the FreeBSD license.
 
27
#
 
28
# Copyright 2002 Gene Cash All rights reserved.
12
29
#
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.
38
55
#
 
56
# Patch Contributors:
 
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.
 
65
#
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.
 
88
#               IFD_Tag() object.
 
89
# 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L.
62
90
#
63
 
# To do:
64
 
# * Better printing of ratios
65
91
 
66
92
# field type descriptions as (length, abbreviation, full name) tuples
67
93
FIELD_TYPES=(
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',
 
127
              3: 'Rotated 180',
 
128
              4: 'Mirrored vertical',
 
129
              5: 'Mirrored horizontal then rotated 90 CCW',
 
130
              6: 'Rotated 90 CW',
 
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', ),
219
253
             {3: 'Digital Camera'}),
220
254
    0xA301: ('SceneType',
221
255
             {1: 'Directly Photographed'}),
 
256
    0xA302: ('CVAPattern',),
222
257
    }
223
258
 
224
259
# interoperability tags
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',
283
329
              0x0300: 'Left',
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',
286
346
             {-3: 'B&W',
287
347
              -2: '-2',
290
350
              1:  '1',
291
351
              2:  '2'}),
292
352
    0x0095: ('NoiseReduction', ),
 
353
    0x00A7: ('TotalShutterReleases', ),
 
354
    0x00A9: ('ImageOptimization', ),
 
355
    0x00AA: ('Saturation', ),
 
356
    0x00AB: ('DigitalVariProgram', ),
293
357
    0x0010: ('DataDump', )
294
358
    }
295
359
 
356
420
    0x0207: ('SoftwareRelease',  ),
357
421
    0x0208: ('PictureInfo',  ),
358
422
    # print as string
359
 
    0x0209: ('CameraID', lambda x: ''.join(map(chr, x))), 
 
423
    0x0209: ('CameraID', lambda x: ''.join(map(chr, x))),
360
424
    0x0F00: ('DataDump',  )
361
425
    }
362
426
 
624
688
         0X002C: '1.33 EV',
625
689
         0X0030: '1.50 EV',
626
690
         0X0034: '1.67 EV',
627
 
         0X0040: '2 EV'}), 
 
691
         0X0040: '2 EV'}),
628
692
    19: ('SubjectDistance', )
629
693
    }
630
694
 
638
702
# extract multibyte integer in Intel format (big endian)
639
703
def s2n_intel(str):
640
704
    x=0
641
 
    y=0
 
705
    y=0L
642
706
    for c in str:
643
707
        x=x | (ord(c) << y)
644
708
        y=y+8
697
761
 
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):
701
765
        self.file=file
702
766
        self.endian=endian
703
767
        self.offset=offset
 
768
        self.fake_exif=fake_exif
704
769
        self.debug=debug
705
770
        self.tags={}
706
771
        
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)
714
782
            val=s2n_motorola(slice)
715
783
        # Sign extension ?
716
784
        if signed:
717
 
            #msb=1 << (8*length-1)
718
 
            #if val & msb:
719
 
            #    val=val-(msb << 1)
720
 
            pass
 
785
            msb=1L << (8*length-1)
 
786
            if val & msb:
 
787
                val=val-(msb << 1)
721
788
        return val
722
789
 
723
790
    # convert offset to string
750
817
        return a
751
818
 
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
756
824
            entry=ifd+2+12*i
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)
 
828
            if tag_entry:
 
829
                tag_name=tag_entry[0]
 
830
            else:
 
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)
765
839
            offset=entry+8
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.
 
847
                if relative:
 
848
                    tmp_offset=self.s2n(offset, 4)
 
849
                    offset=tmp_offset+ifd-self.offset+4
 
850
                    if self.fake_exif:
 
851
                        offset=offset+18
 
852
                else:
 
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
772
857
                if count != 0:
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','')
775
861
                else:
776
862
                    values=''
777
863
            else:
791
877
                printable=str(values[0])
792
878
            else:
793
879
                printable=str(values)
794
 
            # figure out tag name
795
 
            tag_entry=dict.get(tag)
 
880
            # compute printable version of values
796
881
            if tag_entry:
797
 
                tag_name=tag_entry[0]
798
882
                if len(tag_entry) != 1:
799
883
                    # optional 2nd tag element is present
800
884
                    if callable(tag_entry[1]):
803
887
                    else:
804
888
                        printable=''
805
889
                        for i in values:
806
 
                            # use LUT for this tag
 
890
                            # use lookup table for this tag
807
891
                            printable+=tag_entry[1].get(i, repr(i))
808
 
            else:
809
 
                tag_name='Tag 0x%04X' % tag
810
892
            self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag,
811
893
                                                     field_type,
812
894
                                                     values, field_offset,
813
895
                                                     count*typelen)
814
896
            if self.debug:
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]))
817
899
 
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
873
955
        
874
956
    # decode all the camera-specific MakerNote formats
 
957
 
 
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.
 
962
    #
 
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
 
965
    # pointers.
 
966
    #
 
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
879
979
 
880
980
        # Nikon
881
 
        if make == 'NIKON':
882
 
            if note.values[0:5] == [78, 105, 107, 111, 110]: # "Nikon"
883
 
                # older model
 
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]:
 
987
                if self.debug:
 
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]:
 
992
                if self.debug:
 
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)
886
999
            else:
887
 
                # newer model (E99x or D1)
 
1000
                # E99x or D1
 
1001
                if self.debug:
 
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)
890
1005
            return
904
1019
        # Fujifilm
905
1020
        if make == 'FUJIFILM':
906
1021
            # bug: everything else is "Motorola" endian, but the MakerNote
907
 
            # is "Intel" endian 
 
1022
            # is "Intel" endian
908
1023
            endian=self.endian
909
1024
            self.endian='I'
910
1025
            # bug: IFD offsets are from beginning of MakerNote, not
959
1074
    elif data[0:2] == '\xFF\xD8':
960
1075
        # it's a JPEG file
961
1076
        # skip JFIF style header(s)
 
1077
        fake_exif=0
962
1078
        while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX', 'OLYM'):
963
1079
            length=ord(data[4])*256+ord(data[5])
964
1080
            file.read(length-8)
965
1081
            # fake an EXIF beginning of file
966
1082
            data='\xFF\x00'+file.read(10)
 
1083
            fake_exif=1
967
1084
        if data[2] == '\xFF' and data[6:10] == 'Exif':
968
1085
            # detected EXIF header
969
1086
            offset=file.tell()
978
1095
    # deal with the EXIF info we found
979
1096
    if debug:
980
1097
        print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format'
981
 
    hdr=EXIF_header(file, endian, offset, debug)
 
1098
    hdr=EXIF_header(file, endian, offset, fake_exif, debug)
982
1099
    ifd_list=hdr.list_IFDs()
983
1100
    ctr=0
984
1101
    for i in ifd_list: