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
reads complete exif header
-- ReimarBauer 2006-12-13 19:28:00
Toggle line numbers
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