changeset 1703:0803e5da055d

EXIF.py: optional parameter 'name' for process_file and dump_IFD. If used the reading of EXIF data ends after that name. some PEP8 changes
author Reimar Bauer <rb.proj AT googlemail DOT com>
date Sat, 06 Jan 2007 12:01:25 +0100
parents 790c1e655a5b
children fe19c9ac4b82
files MoinMoin/filter/EXIF.py
diffstat 1 files changed, 192 insertions(+), 180 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/filter/EXIF.py	Fri Jan 05 23:21:35 2007 +0100
+++ b/MoinMoin/filter/EXIF.py	Sat Jan 06 12:01:25 2007 +0100
@@ -87,17 +87,26 @@
 #               IFD_Tag() object.
 # 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L.
 #
+#############
+# 2006-08-04 ReimarBauer added an optional parameter name to process_file and dump_IFD. Using this parameter the 
+#            loop is breaked after that tag_name is processed.
+#            Example:
+#                    f = open(infile, 'rb')
+#                    tags = EXIF.process_file(f,'DateTimeOriginal')
+#                    f.close()
+#            some PEP8 changes
+#############
 
 # field type descriptions as (length, abbreviation, full name) tuples
-FIELD_TYPES=(
-    (0, 'X',  'Proprietary'), # no such type
-    (1, 'B',  'Byte'),
-    (1, 'A',  'ASCII'),
-    (2, 'S',  'Short'),
-    (4, 'L',  'Long'),
-    (8, 'R',  'Ratio'),
+FIELD_TYPES = (
+    (0, 'X', 'Proprietary'), # no such type
+    (1, 'B', 'Byte'),
+    (1, 'A', 'ASCII'),
+    (2, 'S', 'Short'),
+    (4, 'L', 'Long'),
+    (8, 'R', 'Ratio'),
     (1, 'SB', 'Signed Byte'),
-    (1, 'U',  'Undefined'),
+    (1, 'U', 'Undefined'),
     (2, 'SS', 'Signed Short'),
     (4, 'SL', 'Signed Long'),
     (8, 'SR', 'Signed Ratio')
@@ -106,7 +115,7 @@
 # dictionary of main EXIF tag names
 # first element of tuple is tag name, optional second element is
 # another dictionary giving names to values
-EXIF_TAGS={
+EXIF_TAGS = {
     0x0100: ('ImageWidth', ),
     0x0101: ('ImageLength', ),
     0x0102: ('BitsPerSample', ),
@@ -256,7 +265,7 @@
     }
 
 # interoperability tags
-INTR_TAGS={
+INTR_TAGS = {
     0x0001: ('InteroperabilityIndex', ),
     0x0002: ('InteroperabilityVersion', ),
     0x1000: ('RelatedImageFileFormat', ),
@@ -265,7 +274,7 @@
     }
 
 # GPS tags (not used yet, haven't seen camera with GPS)
-GPS_TAGS={
+GPS_TAGS = {
     0x0000: ('GPSVersionID', ),
     0x0001: ('GPSLatitudeRef', ),
     0x0002: ('GPSLatitude', ),
@@ -297,7 +306,7 @@
 
 # Nikon E99x MakerNote Tags
 # http://members.tripod.com/~tawba/990exif.htm
-MAKERNOTE_NIKON_NEWER_TAGS={
+MAKERNOTE_NIKON_NEWER_TAGS = {
     0x0002: ('ISOSetting', ),
     0x0003: ('ColorMode', ),
     0x0004: ('Quality', ),
@@ -356,7 +365,7 @@
     0x0010: ('DataDump', )
     }
 
-MAKERNOTE_NIKON_OLDER_TAGS={
+MAKERNOTE_NIKON_OLDER_TAGS = {
     0x0003: ('Quality',
              {1: 'VGA Basic',
               2: 'VGA Normal',
@@ -390,20 +399,20 @@
 
 # decode Olympus SpecialMode tag in MakerNote
 def olympus_special_mode(v):
-    a={
+    a = {
         0: 'Normal',
         1: 'Unknown',
         2: 'Fast',
         3: 'Panorama'}
-    b={
+    b = {
         0: 'Non-panoramic',
         1: 'Left to right',
         2: 'Right to left',
         3: 'Bottom to top',
         4: 'Top to bottom'}
     return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
-        
-MAKERNOTE_OLYMPUS_TAGS={
+
+MAKERNOTE_OLYMPUS_TAGS = {
     # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
     # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
     0x0100: ('JPEGThumbnail', ),
@@ -416,14 +425,14 @@
              {0: 'Normal',
               1: 'Macro'}),
     0x0204: ('DigitalZoom', ),
-    0x0207: ('SoftwareRelease',  ),
-    0x0208: ('PictureInfo',  ),
+    0x0207: ('SoftwareRelease', ),
+    0x0208: ('PictureInfo', ),
     # print as string
     0x0209: ('CameraID', lambda x: ''.join(map(chr, x))),
-    0x0F00: ('DataDump',  )
+    0x0F00: ('DataDump', )
     }
 
-MAKERNOTE_CASIO_TAGS={
+MAKERNOTE_CASIO_TAGS = {
     0x0001: ('RecordingMode',
              {1: 'Single Shutter',
               2: 'Panorama',
@@ -474,10 +483,10 @@
               100: 'High',
               125: '+1.0',
               244: '+3.0',
-              250: '+2.0',})
+              250: '+2.0', })
     }
 
-MAKERNOTE_FUJIFILM_TAGS={
+MAKERNOTE_FUJIFILM_TAGS = {
     0x0000: ('NoteVersion', lambda x: ''.join(map(chr, x))),
     0x1000: ('Quality', ),
     0x1001: ('Sharpness',
@@ -542,7 +551,7 @@
               1: 'On'})
     }
 
-MAKERNOTE_CANON_TAGS={
+MAKERNOTE_CANON_TAGS = {
     0x0006: ('ImageType', ),
     0x0007: ('FirmwareVersion', ),
     0x0008: ('ImageNumber', ),
@@ -551,7 +560,7 @@
 
 # see http://www.burren.cx/david/canon.html by David Burren
 # this is in element offset, name, optional value dictionary format
-MAKERNOTE_CANON_TAG_0x001={
+MAKERNOTE_CANON_TAG_0x001 = {
     1: ('Macromode',
         {1: 'Macro',
          2: 'Normal'}),
@@ -659,7 +668,7 @@
           1: 'Continuous'})
     }
 
-MAKERNOTE_CANON_TAG_0x004={
+MAKERNOTE_CANON_TAG_0x004 = {
     7: ('WhiteBalance',
         {0: 'Auto',
          1: 'Sunny',
@@ -693,18 +702,18 @@
 
 # extract multibyte integer in Motorola format (little endian)
 def s2n_motorola(str):
-    x=0
+    x = 0
     for c in str:
-        x=(x << 8) | ord(c)
+        x = (x << 8) | ord(c)
     return x
 
 # extract multibyte integer in Intel format (big endian)
 def s2n_intel(str):
-    x=0
-    y=0L
+    x = 0
+    y = 0L
     for c in str:
-        x=x | (ord(c) << y)
-        y=y+8
+        x = x | (ord(c) << y)
+        y = y + 8
     return x
 
 # ratio object that eventually will be able to reduce itself to lowest
@@ -717,8 +726,8 @@
 
 class Ratio:
     def __init__(self, num, den):
-        self.num=num
-        self.den=den
+        self.num = num
+        self.den = den
 
     def __repr__(self):
         self.reduce()
@@ -727,31 +736,31 @@
         return '%d/%d' % (self.num, self.den)
 
     def reduce(self):
-        div=gcd(self.num, self.den)
+        div = gcd(self.num, self.den)
         if div > 1:
-            self.num=self.num/div
-            self.den=self.den/div
+            self.num = self.num/div
+            self.den = self.den/div
 
 # for ease of dealing with tags
 class IFD_Tag:
     def __init__(self, printable, tag, field_type, values, field_offset,
                  field_length):
         # printable version of data
-        self.printable=printable
+        self.printable = printable
         # tag ID number
-        self.tag=tag
+        self.tag = tag
         # field type as index into FIELD_TYPES
-        self.field_type=field_type
+        self.field_type = field_type
         # offset of start of field in bytes from beginning of IFD
-        self.field_offset=field_offset
+        self.field_offset = field_offset
         # length of data field in bytes
-        self.field_length=field_length
+        self.field_length = field_length
         # either a string or array of data items
-        self.values=values
-        
+        self.values = values
+
     def __str__(self):
         return self.printable
-    
+
     def __repr__(self):
         return '(0x%04X) %s=%s @ %d' % (self.tag,
                                         FIELD_TYPES[self.field_type][2],
@@ -761,81 +770,81 @@
 # class that handles an EXIF header
 class EXIF_header:
     def __init__(self, file, endian, offset, fake_exif, debug=0):
-        self.file=file
-        self.endian=endian
-        self.offset=offset
-        self.fake_exif=fake_exif
-        self.debug=debug
-        self.tags={}
-        
+        self.file = file
+        self.endian = endian
+        self.offset = offset
+        self.fake_exif = fake_exif
+        self.debug = debug
+        self.tags = {}
+
     # convert slice to integer, based on sign and endian flags
     # usually this offset is assumed to be relative to the beginning of the
     # start of the EXIF information.  For some cameras that use relative tags,
     # this offset may be relative to some other starting point.
     def s2n(self, offset, length, signed=0):
         self.file.seek(self.offset+offset)
-        slice=self.file.read(length)
+        slice = self.file.read(length)
         if self.endian == 'I':
-            val=s2n_intel(slice)
+            val = s2n_intel(slice)
         else:
-            val=s2n_motorola(slice)
+            val = s2n_motorola(slice)
         # Sign extension ?
         if signed:
-            msb=1L << (8*length-1)
+            msb = 1L << (8*length-1)
             if val & msb:
-                val=val-(msb << 1)
+                val = val-(msb << 1)
         return val
 
     # convert offset to string
     def n2s(self, offset, length):
-        s=''
+        s = ''
         for i in range(length):
             if self.endian == 'I':
-                s=s+chr(offset & 0xFF)
+                s = s + chr(offset & 0xFF)
             else:
-                s=chr(offset & 0xFF)+s
-            offset=offset >> 8
+                s = chr(offset & 0xFF)+s
+            offset = offset >> 8
         return s
-    
+
     # return first IFD
     def first_IFD(self):
         return self.s2n(4, 4)
 
     # return pointer to next IFD
     def next_IFD(self, ifd):
-        entries=self.s2n(ifd, 2)
+        entries = self.s2n(ifd, 2)
         return self.s2n(ifd+2+12*entries, 4)
 
     # return list of IFDs in header
     def list_IFDs(self):
-        i=self.first_IFD()
-        a=[]
+        i = self.first_IFD()
+        a = []
         while i:
             a.append(i)
-            i=self.next_IFD(i)
+            i = self.next_IFD(i)
         return a
 
     # return list of entries in this IFD
-    def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0):
-        entries=self.s2n(ifd, 2)
+    def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0, name='UNDEF'):
+        entries = self.s2n(ifd, 2)
         for i in range(entries):
             # entry is index of start of this IFD in the file
-            entry=ifd+2+12*i
-            tag=self.s2n(entry, 2)
+            entry = ifd + 2 + 12 * i
+            tag = self.s2n(entry, 2)
             # get tag name.  We do it early to make debugging easier
-            tag_entry=dict.get(tag)
+            tag_entry = dict.get(tag)
             if tag_entry:
-                tag_name=tag_entry[0]
+                tag_name = tag_entry[0]
             else:
-                tag_name='Tag 0x%04X' % tag
-            field_type=self.s2n(entry+2, 2)
+                tag_name = 'Tag 0x%04X' % tag
+            field_type = self.s2n(entry+2, 2)
             if not 0 < field_type < len(FIELD_TYPES):
                 # unknown field type
                 raise ValueError, \
                       'unknown type %d in tag 0x%04X' % (field_type, tag)
-            typelen=FIELD_TYPES[field_type][0]
-            count=self.s2n(entry+4, 4)
-            offset=entry+8
+            typelen = FIELD_TYPES[field_type][0]
+            count = self.s2n(entry+4, 4)
+            offset = entry+8
             if count*typelen > 4:
                 # offset is not the value; it's a pointer to the value
                 # if relative we set things up so s2n will seek to the right
@@ -844,51 +853,51 @@
                 # other relative offsets, which would have to be computed here
                 # slightly differently.
                 if relative:
-                    tmp_offset=self.s2n(offset, 4)
-                    offset=tmp_offset+ifd-self.offset+4
+                    tmp_offset = self.s2n(offset, 4)
+                    offset = tmp_offset + ifd - self.offset + 4
                     if self.fake_exif:
-                        offset=offset+18
+                        offset = offset + 18
                 else:
-                    offset=self.s2n(offset, 4)
-            field_offset=offset
+                    offset = self.s2n(offset, 4)
+            field_offset = offset
             if field_type == 2:
                 # special case: null-terminated ASCII string
                 if count != 0:
                     self.file.seek(self.offset+offset)
-                    values=self.file.read(count)
-                    values=values.strip().replace('\x00','')
+                    values = self.file.read(count)
+                    values = values.strip().replace('\x00', '')
                 else:
-                    values=''
+                    values = ''
             else:
-                values=[]
-                signed=(field_type in [6, 8, 9, 10])
+                values = []
+                signed = (field_type in [6, 8, 9, 10])
                 for j in range(count):
                     if field_type in (5, 10):
                         # a ratio
-                        value_j=Ratio(self.s2n(offset,   4, signed),
+                        value_j = Ratio(self.s2n(offset, 4, signed),
                                       self.s2n(offset+4, 4, signed))
                     else:
-                        value_j=self.s2n(offset, typelen, signed)
+                        value_j = self.s2n(offset, typelen, signed)
                     values.append(value_j)
-                    offset=offset+typelen
+                    offset = offset+typelen
             # now "values" is either a string or an array
             if count == 1 and field_type != 2:
-                printable=str(values[0])
+                printable = str(values[0])
             else:
-                printable=str(values)
+                printable = str(values)
             # compute printable version of values
             if tag_entry:
                 if len(tag_entry) != 1:
                     # optional 2nd tag element is present
                     if callable(tag_entry[1]):
                         # call mapping function
-                        printable=tag_entry[1](values)
+                        printable = tag_entry[1](values)
                     else:
-                        printable=''
+                        printable = ''
                         for i in values:
                             # use lookup table for this tag
-                            printable+=tag_entry[1].get(i, repr(i))
-            self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag,
+                            printable += tag_entry[1].get(i, repr(i))
+            self.tags[ifd_name+' '+tag_name] = IFD_Tag(printable, tag,
                                                      field_type,
                                                      values, field_offset,
                                                      count*typelen)
@@ -896,62 +905,65 @@
                 print ' debug:   %s: %s' % (tag_name,
                                             repr(self.tags[ifd_name+' '+tag_name]))
 
+            if tag_name == name:
+                break
+
     # extract uncompressed TIFF thumbnail (like pulling teeth)
     # we take advantage of the pre-existing layout in the thumbnail IFD as
     # much as possible
     def extract_TIFF_thumbnail(self, thumb_ifd):
-        entries=self.s2n(thumb_ifd, 2)
+        entries = self.s2n(thumb_ifd, 2)
         # this is header plus offset to IFD ...
         if self.endian == 'M':
-            tiff='MM\x00*\x00\x00\x00\x08'
+            tiff = 'MM\x00*\x00\x00\x00\x08'
         else:
-            tiff='II*\x00\x08\x00\x00\x00'
+            tiff = 'II*\x00\x08\x00\x00\x00'
         # ... plus thumbnail IFD data plus a null "next IFD" pointer
         self.file.seek(self.offset+thumb_ifd)
-        tiff+=self.file.read(entries*12+2)+'\x00\x00\x00\x00'
-        
+        tiff += self.file.read(entries*12+2)+'\x00\x00\x00\x00'
+
         # fix up large value offset pointers into data area
         for i in range(entries):
-            entry=thumb_ifd+2+12*i
-            tag=self.s2n(entry, 2)
-            field_type=self.s2n(entry+2, 2)
-            typelen=FIELD_TYPES[field_type][0]
-            count=self.s2n(entry+4, 4)
-            oldoff=self.s2n(entry+8, 4)
+            entry = thumb_ifd+2+12*i
+            tag = self.s2n(entry, 2)
+            field_type = self.s2n(entry+2, 2)
+            typelen = FIELD_TYPES[field_type][0]
+            count = self.s2n(entry+4, 4)
+            oldoff = self.s2n(entry+8, 4)
             # start of the 4-byte pointer area in entry
-            ptr=i*12+18
+            ptr = i*12+18
             # remember strip offsets location
             if tag == 0x0111:
-                strip_off=ptr
-                strip_len=count*typelen
+                strip_off = ptr
+                strip_len = count*typelen
             # is it in the data area?
             if count*typelen > 4:
                 # update offset pointer (nasty "strings are immutable" crap)
                 # should be able to say "tiff[ptr:ptr+4]=newoff"
-                newoff=len(tiff)
-                tiff=tiff[:ptr]+self.n2s(newoff, 4)+tiff[ptr+4:]
+                newoff = len(tiff)
+                tiff = tiff[:ptr]+self.n2s(newoff, 4)+tiff[ptr+4:]
                 # remember strip offsets location
                 if tag == 0x0111:
-                    strip_off=newoff
-                    strip_len=4
+                    strip_off = newoff
+                    strip_len = 4
                 # get original data and store it
                 self.file.seek(self.offset+oldoff)
-                tiff+=self.file.read(count*typelen)
-                
+                tiff += self.file.read(count*typelen)
+
         # add pixel strips and update strip offset info
-        old_offsets=self.tags['Thumbnail StripOffsets'].values
-        old_counts=self.tags['Thumbnail StripByteCounts'].values
+        old_offsets = self.tags['Thumbnail StripOffsets'].values
+        old_counts = self.tags['Thumbnail StripByteCounts'].values
         for i in range(len(old_offsets)):
             # update offset pointer (more nasty "strings are immutable" crap)
-            offset=self.n2s(len(tiff), strip_len)
-            tiff=tiff[:strip_off]+offset+tiff[strip_off+strip_len:]
-            strip_off+=strip_len
+            offset = self.n2s(len(tiff), strip_len)
+            tiff = tiff[:strip_off]+offset+tiff[strip_off+strip_len:]
+            strip_off += strip_len
             # add pixel strip to end
             self.file.seek(self.offset+old_offsets[i])
-            tiff+=self.file.read(old_counts[i])
-            
-        self.tags['TIFFThumbnail']=tiff
-        
+            tiff += self.file.read(old_counts[i])
+
+        self.tags['TIFFThumbnail'] = tiff
+
     # decode all the camera-specific MakerNote formats
 
     # Note is the data that comprises this MakerNote.  The MakerNote will
@@ -972,9 +984,9 @@
     # the offsets should be from the header at the start of all the EXIF info,
     # or from the header at the start of the makernote.)
     def decode_maker_note(self):
-        note=self.tags['EXIF MakerNote']
-        make=self.tags['Image Make'].printable
-        model=self.tags['Image Model'].printable
+        note = self.tags['EXIF MakerNote']
+        make = self.tags['Image Make'].printable
+        model = self.tags['Image Model'].printable
 
         # Nikon
         # The maker note usually starts with the word Nikon, followed by the
@@ -1014,24 +1026,24 @@
             self.dump_IFD(note.field_offset, 'MakerNote',
                           dict=MAKERNOTE_CASIO_TAGS)
             return
-        
+
         # Fujifilm
         if make == 'FUJIFILM':
             # bug: everything else is "Motorola" endian, but the MakerNote
             # is "Intel" endian
-            endian=self.endian
-            self.endian='I'
+            endian = self.endian
+            self.endian = 'I'
             # bug: IFD offsets are from beginning of MakerNote, not
             # beginning of file header
-            offset=self.offset
-            self.offset+=note.field_offset
+            offset = self.offset
+            self.offset += note.field_offset
             # process note with bogus values (note is actually at offset 12)
             self.dump_IFD(12, 'MakerNote', dict=MAKERNOTE_FUJIFILM_TAGS)
             # reset to correct values
-            self.endian=endian
-            self.offset=offset
+            self.endian = endian
+            self.offset = offset
             return
-        
+
         # Canon
         if make == 'Canon':
             self.dump_IFD(note.field_offset, 'MakerNote',
@@ -1045,45 +1057,45 @@
     # see http://www.burren.cx/david/canon.html by David Burren
     def canon_decode_tag(self, value, dict):
         for i in range(1, len(value)):
-            x=dict.get(i, ('Unknown', ))
+            x = dict.get(i, ('Unknown', ))
             if self.debug:
                 print i, x
-            name=x[0]
+            name = x[0]
             if len(x) > 1:
-                val=x[1].get(value[i], 'Unknown')
+                val = x[1].get(value[i], 'Unknown')
             else:
-                val=value[i]
+                val = value[i]
             # it's not a real IFD Tag but we fake one to make everybody
             # happy. this will have a "proprietary" type
-            self.tags['MakerNote '+name]=IFD_Tag(str(val), None, 0, None,
+            self.tags['MakerNote '+name] = IFD_Tag(str(val), None, 0, None,
                                                  None, None)
 
 # process an image file (expects an open file object)
 # this is the function that has to deal with all the arbitrary nasty bits
 # of the EXIF standard
-def process_file(file, debug=0):
+def process_file(file, name='UNDEF', debug=0):
     # determine whether it's a JPEG or TIFF
-    data=file.read(12)
+    data = file.read(12)
     if data[0:4] in ['II*\x00', 'MM\x00*']:
         # it's a TIFF file
         file.seek(0)
-        endian=file.read(1)
+        endian = file.read(1)
         file.read(1)
-        offset=0
+        offset = 0
     elif data[0:2] == '\xFF\xD8':
         # it's a JPEG file
         # skip JFIF style header(s)
-        fake_exif=0
+        fake_exif = 0
         while data[2] == '\xFF' and data[6:10] in ('JFIF', 'JFXX', 'OLYM'):
-            length=ord(data[4])*256+ord(data[5])
+            length = ord(data[4])*256+ord(data[5])
             file.read(length-8)
             # fake an EXIF beginning of file
-            data='\xFF\x00'+file.read(10)
-            fake_exif=1
+            data = '\xFF\x00'+file.read(10)
+            fake_exif = 1
         if data[2] == '\xFF' and data[6:10] == 'Exif':
             # detected EXIF header
-            offset=file.tell()
-            endian=file.read(1)
+            offset = file.tell()
+            endian = file.read(1)
         else:
             # no EXIF information
             return {}
@@ -1094,54 +1106,54 @@
     # deal with the EXIF info we found
     if debug:
         print {'I': 'Intel', 'M': 'Motorola'}[endian], 'format'
-    hdr=EXIF_header(file, endian, offset, fake_exif, debug)
-    ifd_list=hdr.list_IFDs()
-    ctr=0
+    hdr = EXIF_header(file, endian, offset, fake_exif, debug)
+    ifd_list = hdr.list_IFDs()
+    ctr = 0
     for i in ifd_list:
         if ctr == 0:
-            IFD_name='Image'
+            IFD_name = 'Image'
         elif ctr == 1:
-            IFD_name='Thumbnail'
-            thumb_ifd=i
+            IFD_name = 'Thumbnail'
+            thumb_ifd = i
         else:
-            IFD_name='IFD %d' % ctr
+            IFD_name = 'IFD %d' % ctr
         if debug:
             print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
-        hdr.dump_IFD(i, IFD_name)
+        hdr.dump_IFD(i, IFD_name, name=name)
         # EXIF IFD
-        exif_off=hdr.tags.get(IFD_name+' ExifOffset')
+        exif_off = hdr.tags.get(IFD_name+' ExifOffset')
         if exif_off:
             if debug:
                 print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
-            hdr.dump_IFD(exif_off.values[0], 'EXIF')
+            hdr.dump_IFD(exif_off.values[0], 'EXIF', name=name)
             # Interoperability IFD contained in EXIF IFD
-            intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
+            intr_off = hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
             if intr_off:
                 if debug:
                     print ' EXIF Interoperability SubSubIFD at offset %d:' \
                           % intr_off.values[0]
                 hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability',
-                             dict=INTR_TAGS)
+                             dict=INTR_TAGSi, name=name)
         # GPS IFD
-        gps_off=hdr.tags.get(IFD_name+' GPSInfo')
+        gps_off = hdr.tags.get(IFD_name+' GPSInfo')
         if gps_off:
             if debug:
                 print ' GPS SubIFD at offset %d:' % gps_off.values[0]
-            hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS)
-        ctr+=1
+            hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS, name=name)
+        ctr += 1
 
     # extract uncompressed TIFF thumbnail
-    thumb=hdr.tags.get('Thumbnail Compression')
+    thumb = hdr.tags.get('Thumbnail Compression')
     if thumb and thumb.printable == 'Uncompressed TIFF':
         hdr.extract_TIFF_thumbnail(thumb_ifd)
-        
+
     # JPEG thumbnail (thankfully the JPEG data is stored as a unit)
-    thumb_off=hdr.tags.get('Thumbnail JPEGInterchangeFormat')
+    thumb_off = hdr.tags.get('Thumbnail JPEGInterchangeFormat')
     if thumb_off:
         file.seek(offset+thumb_off.values[0])
-        size=hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
-        hdr.tags['JPEGThumbnail']=file.read(size)
-        
+        size = hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
+        hdr.tags['JPEGThumbnail'] = file.read(size)
+
     # deal with MakerNote contained in EXIF IFD
     if hdr.tags.has_key('EXIF MakerNote'):
         hdr.decode_maker_note()
@@ -1149,36 +1161,36 @@
     # Sometimes in a TIFF file, a JPEG thumbnail is hidden in the MakerNote
     # since it's not allowed in a uncompressed TIFF IFD
     if not hdr.tags.has_key('JPEGThumbnail'):
-        thumb_off=hdr.tags.get('MakerNote JPEGThumbnail')
+        thumb_off = hdr.tags.get('MakerNote JPEGThumbnail')
         if thumb_off:
             file.seek(offset+thumb_off.values[0])
-            hdr.tags['JPEGThumbnail']=file.read(thumb_off.field_length)
-            
+            hdr.tags['JPEGThumbnail'] = file.read(thumb_off.field_length)
+
     return hdr.tags
 
 # library test/debug function (dump given files)
 if __name__ == '__main__':
     import sys
-    
+
     if len(sys.argv) < 2:
         print 'Usage: %s files...\n' % sys.argv[0]
         sys.exit(0)
-        
+
     for filename in sys.argv[1:]:
         try:
-            file=open(filename, 'rb')
+            file = open(filename, 'rb')
         except:
             print filename, 'unreadable'
             print
             continue
         print filename+':'
         # data=process_file(file, 1) # with debug info
-        data=process_file(file)
+        data = process_file(file, name, 0)
         if not data:
             print 'No EXIF information found'
             continue
 
-        x=data.keys()
+        x = data.keys()
         x.sort()
         for i in x:
             if i in ('JPEGThumbnail', 'TIFFThumbnail'):