Short description To avoid having two versions of EXIF.py installed if Gallery2 is used I have patched the current 1.6dev version.

The change is about breaking the for loop after the tag_name is processed if this name is submitted.

Some PEP8 changes added too.

reads exif header until 'DateTimeOriginal' is reached

   1 from MoinMoin.filter import EXIF
   2 f = open(infile, 'rb')
   3 tags = EXIF.process_file(f,'DateTimeOriginal')
   4 f.close()
   5 if tags.has_key('EXIF DateTimeOriginal'):
   6     print str(tags['EXIF DateTimeOriginal'])

reads complete exif header

   1 from MoinMoin.filter import EXIF
   2 f = open(infile, 'rb')
   3 tags = EXIF.process_file(f)
   4 f.close()
   5 if tags.has_key('EXIF DateTimeOriginal'):
   6     print str(tags['EXIF DateTimeOriginal'])

-- ReimarBauer 2006-12-13 19:28:00

   1 # HG changeset patch
   2 # User ReimarBauer <R.Bauer@fz-juelich.de>
   3 # Date 1166038936 -3600
   4 # Node ID bb4ad9653be273b196eea25d89471a3a96fa13ae
   5 # Parent  7c58e8af1a97b7711f9eae67fdebf08e103cb3e2
   6 speedup for access from Gallery2 which only reads the 'DateTimeOriginal' time of the image exif. An optional keyword name was added for breaking the for loop after its resolving.
   7 
   8 diff -r 7c58e8af1a97 -r bb4ad9653be2 MoinMoin/filter/EXIF.py
   9 --- a/MoinMoin/filter/EXIF.py	Thu Dec 07 21:35:43 2006 +0100
  10 +++ b/MoinMoin/filter/EXIF.py	Wed Dec 13 20:42:16 2006 +0100
  11 @@ -87,6 +87,14 @@
  12  #               IFD_Tag() object.
  13  # 15-FEB-04 CEC Finally fixed bit shift warning by converting Y to 0L.
  14  #
  15 +#############
  16 +# 2006-08-04 ReimarBauer because to speed up this routine for the Gallery2 parser of the http://moinmoin.wikiwikiweb.de/ project.
  17 +# I have added the parameter 'name' to process_file and dump_IFD.
  18 +# Using this the for loop is breaked after that tag_name is processed.
  19 +#       f = open(infile, 'rb')
  20 +#       tags = EXIF.process_file(f,'DateTimeOriginal')
  21 +#       f.close()
  22 +#############
  23  
  24  # field type descriptions as (length, abbreviation, full name) tuples
  25  FIELD_TYPES=(
  26 @@ -402,7 +410,7 @@ def olympus_special_mode(v):
  27          3: 'Bottom to top',
  28          4: 'Top to bottom'}
  29      return '%s - sequence %d - %s' % (a[v[0]], v[1], b[v[2]])
  30 -        
  31 +
  32  MAKERNOTE_OLYMPUS_TAGS={
  33      # ah HAH! those sneeeeeaky bastids! this is how they get past the fact
  34      # that a JPEG thumbnail is not allowed in an uncompressed TIFF file
  35 @@ -416,11 +424,11 @@ MAKERNOTE_OLYMPUS_TAGS={
  36               {0: 'Normal',
  37                1: 'Macro'}),
  38      0x0204: ('DigitalZoom', ),
  39 -    0x0207: ('SoftwareRelease',  ),
  40 -    0x0208: ('PictureInfo',  ),
  41 +    0x0207: ('SoftwareRelease', ),
  42 +    0x0208: ('PictureInfo', ),
  43      # print as string
  44      0x0209: ('CameraID', lambda x: ''.join(map(chr, x))),
  45 -    0x0F00: ('DataDump',  )
  46 +    0x0F00: ('DataDump', )
  47      }
  48  
  49  MAKERNOTE_CASIO_TAGS={
  50 @@ -748,10 +756,10 @@ class IFD_Tag:
  51          self.field_length=field_length
  52          # either a string or array of data items
  53          self.values=values
  54 -        
  55 +
  56      def __str__(self):
  57          return self.printable
  58 -    
  59 +
  60      def __repr__(self):
  61          return '(0x%04X) %s=%s @ %d' % (self.tag,
  62                                          FIELD_TYPES[self.field_type][2],
  63 @@ -767,7 +775,7 @@ class EXIF_header:
  64          self.fake_exif=fake_exif
  65          self.debug=debug
  66          self.tags={}
  67 -        
  68 +
  69      # convert slice to integer, based on sign and endian flags
  70      # usually this offset is assumed to be relative to the beginning of the
  71      # start of the EXIF information.  For some cameras that use relative tags,
  72 @@ -796,7 +804,7 @@ class EXIF_header:
  73                  s=chr(offset & 0xFF)+s
  74              offset=offset >> 8
  75          return s
  76 -    
  77 +
  78      # return first IFD
  79      def first_IFD(self):
  80          return self.s2n(4, 4)
  81 @@ -816,7 +824,7 @@ class EXIF_header:
  82          return a
  83  
  84      # return list of entries in this IFD
  85 -    def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0):
  86 +    def dump_IFD(self, ifd, ifd_name, dict=EXIF_TAGS, relative=0, name='UNDEF'):
  87          entries=self.s2n(ifd, 2)
  88          for i in range(entries):
  89              # entry is index of start of this IFD in the file
  90 @@ -856,7 +864,7 @@ class EXIF_header:
  91                  if count != 0:
  92                      self.file.seek(self.offset+offset)
  93                      values=self.file.read(count)
  94 -                    values=values.strip().replace('\x00','')
  95 +                    values=values.strip().replace('\x00', '')
  96                  else:
  97                      values=''
  98              else:
  99 @@ -865,7 +873,7 @@ class EXIF_header:
 100                  for j in range(count):
 101                      if field_type in (5, 10):
 102                          # a ratio
 103 -                        value_j=Ratio(self.s2n(offset,   4, signed),
 104 +                        value_j=Ratio(self.s2n(offset, 4, signed),
 105                                        self.s2n(offset+4, 4, signed))
 106                      else:
 107                          value_j=self.s2n(offset, typelen, signed)
 108 @@ -887,7 +895,7 @@ class EXIF_header:
 109                          printable=''
 110                          for i in values:
 111                              # use lookup table for this tag
 112 -                            printable+=tag_entry[1].get(i, repr(i))
 113 +                            printable += tag_entry[1].get(i, repr(i))
 114              self.tags[ifd_name+' '+tag_name]=IFD_Tag(printable, tag,
 115                                                       field_type,
 116                                                       values, field_offset,
 117 @@ -895,6 +903,9 @@ class EXIF_header:
 118              if self.debug:
 119                  print ' debug:   %s: %s' % (tag_name,
 120                                              repr(self.tags[ifd_name+' '+tag_name]))
 121 +
 122 +            if tag_name == name:
 123 +                break
 124  
 125      # extract uncompressed TIFF thumbnail (like pulling teeth)
 126      # we take advantage of the pre-existing layout in the thumbnail IFD as
 127 @@ -908,8 +919,8 @@ class EXIF_header:
 128              tiff='II*\x00\x08\x00\x00\x00'
 129          # ... plus thumbnail IFD data plus a null "next IFD" pointer
 130          self.file.seek(self.offset+thumb_ifd)
 131 -        tiff+=self.file.read(entries*12+2)+'\x00\x00\x00\x00'
 132 -        
 133 +        tiff += self.file.read(entries*12+2)+'\x00\x00\x00\x00'
 134 +
 135          # fix up large value offset pointers into data area
 136          for i in range(entries):
 137              entry=thumb_ifd+2+12*i
 138 @@ -936,8 +947,8 @@ class EXIF_header:
 139                      strip_len=4
 140                  # get original data and store it
 141                  self.file.seek(self.offset+oldoff)
 142 -                tiff+=self.file.read(count*typelen)
 143 -                
 144 +                tiff += self.file.read(count*typelen)
 145 +
 146          # add pixel strips and update strip offset info
 147          old_offsets=self.tags['Thumbnail StripOffsets'].values
 148          old_counts=self.tags['Thumbnail StripByteCounts'].values
 149 @@ -945,13 +956,13 @@ class EXIF_header:
 150              # update offset pointer (more nasty "strings are immutable" crap)
 151              offset=self.n2s(len(tiff), strip_len)
 152              tiff=tiff[:strip_off]+offset+tiff[strip_off+strip_len:]
 153 -            strip_off+=strip_len
 154 +            strip_off += strip_len
 155              # add pixel strip to end
 156              self.file.seek(self.offset+old_offsets[i])
 157 -            tiff+=self.file.read(old_counts[i])
 158 -            
 159 +            tiff += self.file.read(old_counts[i])
 160 +
 161          self.tags['TIFFThumbnail']=tiff
 162 -        
 163 +
 164      # decode all the camera-specific MakerNote formats
 165  
 166      # Note is the data that comprises this MakerNote.  The MakerNote will
 167 @@ -1014,7 +1025,7 @@ class EXIF_header:
 168              self.dump_IFD(note.field_offset, 'MakerNote',
 169                            dict=MAKERNOTE_CASIO_TAGS)
 170              return
 171 -        
 172 +
 173          # Fujifilm
 174          if make == 'FUJIFILM':
 175              # bug: everything else is "Motorola" endian, but the MakerNote
 176 @@ -1024,14 +1035,14 @@ class EXIF_header:
 177              # bug: IFD offsets are from beginning of MakerNote, not
 178              # beginning of file header
 179              offset=self.offset
 180 -            self.offset+=note.field_offset
 181 +            self.offset += note.field_offset
 182              # process note with bogus values (note is actually at offset 12)
 183              self.dump_IFD(12, 'MakerNote', dict=MAKERNOTE_FUJIFILM_TAGS)
 184              # reset to correct values
 185              self.endian=endian
 186              self.offset=offset
 187              return
 188 -        
 189 +
 190          # Canon
 191          if make == 'Canon':
 192              self.dump_IFD(note.field_offset, 'MakerNote',
 193 @@ -1061,7 +1072,7 @@ class EXIF_header:
 194  # process an image file (expects an open file object)
 195  # this is the function that has to deal with all the arbitrary nasty bits
 196  # of the EXIF standard
 197 -def process_file(file, debug=0):
 198 +def process_file(file, name='UNDEF', debug=0):
 199      # determine whether it's a JPEG or TIFF
 200      data=file.read(12)
 201      if data[0:4] in ['II*\x00', 'MM\x00*']:
 202 @@ -1107,13 +1118,13 @@ def process_file(file, debug=0):
 203              IFD_name='IFD %d' % ctr
 204          if debug:
 205              print ' IFD %d (%s) at offset %d:' % (ctr, IFD_name, i)
 206 -        hdr.dump_IFD(i, IFD_name)
 207 +        hdr.dump_IFD(i, IFD_name, name=name)
 208          # EXIF IFD
 209          exif_off=hdr.tags.get(IFD_name+' ExifOffset')
 210          if exif_off:
 211              if debug:
 212                  print ' EXIF SubIFD at offset %d:' % exif_off.values[0]
 213 -            hdr.dump_IFD(exif_off.values[0], 'EXIF')
 214 +            hdr.dump_IFD(exif_off.values[0], 'EXIF', name=name)
 215              # Interoperability IFD contained in EXIF IFD
 216              intr_off=hdr.tags.get('EXIF SubIFD InteroperabilityOffset')
 217              if intr_off:
 218 @@ -1121,27 +1132,27 @@ def process_file(file, debug=0):
 219                      print ' EXIF Interoperability SubSubIFD at offset %d:' \
 220                            % intr_off.values[0]
 221                  hdr.dump_IFD(intr_off.values[0], 'EXIF Interoperability',
 222 -                             dict=INTR_TAGS)
 223 +                             dict=INTR_TAGSi, name=name)
 224          # GPS IFD
 225          gps_off=hdr.tags.get(IFD_name+' GPSInfo')
 226          if gps_off:
 227              if debug:
 228                  print ' GPS SubIFD at offset %d:' % gps_off.values[0]
 229 -            hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS)
 230 -        ctr+=1
 231 +            hdr.dump_IFD(gps_off.values[0], 'GPS', dict=GPS_TAGS, name=name)
 232 +        ctr += 1
 233  
 234      # extract uncompressed TIFF thumbnail
 235      thumb=hdr.tags.get('Thumbnail Compression')
 236      if thumb and thumb.printable == 'Uncompressed TIFF':
 237          hdr.extract_TIFF_thumbnail(thumb_ifd)
 238 -        
 239 +
 240      # JPEG thumbnail (thankfully the JPEG data is stored as a unit)
 241      thumb_off=hdr.tags.get('Thumbnail JPEGInterchangeFormat')
 242      if thumb_off:
 243          file.seek(offset+thumb_off.values[0])
 244          size=hdr.tags['Thumbnail JPEGInterchangeFormatLength'].values[0]
 245          hdr.tags['JPEGThumbnail']=file.read(size)
 246 -        
 247 +
 248      # deal with MakerNote contained in EXIF IFD
 249      if hdr.tags.has_key('EXIF MakerNote'):
 250          hdr.decode_maker_note()
 251 @@ -1153,17 +1164,17 @@ def process_file(file, debug=0):
 252          if thumb_off:
 253              file.seek(offset+thumb_off.values[0])
 254              hdr.tags['JPEGThumbnail']=file.read(thumb_off.field_length)
 255 -            
 256 +
 257      return hdr.tags
 258  
 259  # library test/debug function (dump given files)
 260  if __name__ == '__main__':
 261      import sys
 262 -    
 263 +
 264      if len(sys.argv) < 2:
 265          print 'Usage: %s files...\n' % sys.argv[0]
 266          sys.exit(0)
 267 -        
 268 +
 269      for filename in sys.argv[1:]:
 270          try:
 271              file=open(filename, 'rb')
 272 @@ -1173,7 +1184,7 @@ if __name__ == '__main__':
 273              continue
 274          print filename+':'
 275          # data=process_file(file, 1) # with debug info
 276 -        data=process_file(file)
 277 +        data=process_file(file, name, 0)
 278          if not data:
 279              print 'No EXIF information found'
 280              continue
EXIF_20061213_patch.txt


CategoryFeatureImplemented

MoinMoin: FeatureRequests/EXIFFilterExtendedForGallery2 (last edited 2007-10-29 19:09:02 by localhost)