1238 |
1238 |
1239 # class that handles an EXIF header |
1239 # class that handles an EXIF header |
1240 class EXIF_header: |
1240 class EXIF_header: |
1241 def __init__(self, file, endian, offset, fake_exif, strict, debug=0): |
1241 def __init__(self, file, endian, offset, fake_exif, strict, debug=0): |
1242 self.file = file |
1242 self.file = file |
|
1243 self.mmap = mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) |
1243 self.endian = endian |
1244 self.endian = endian |
1244 self.offset = offset |
1245 self.offset = offset |
1245 self.fake_exif = fake_exif |
1246 self.fake_exif = fake_exif |
1246 self.strict = strict |
1247 self.strict = strict |
1247 self.debug = debug |
1248 self.debug = debug |
1248 self.tags = {} |
1249 self.tags = {} |
|
1250 |
|
1251 def pread(self, reloffset, length): |
|
1252 """Read <length> bytes from self.file at relative offset <offset>""" |
|
1253 |
|
1254 offset = self.offset + reloffset |
|
1255 |
|
1256 return self.mmap[offset:offset + length] |
1249 |
1257 |
1250 # convert slice to integer, based on sign and endian flags |
1258 # convert slice to integer, based on sign and endian flags |
1251 # usually this offset is assumed to be relative to the beginning of the |
1259 # usually this offset is assumed to be relative to the beginning of the |
1252 # start of the EXIF information. For some cameras that use relative tags, |
1260 # start of the EXIF information. For some cameras that use relative tags, |
1253 # this offset may be relative to some other starting point. |
1261 # this offset may be relative to some other starting point. |
1254 def s2n(self, offset, length, signed=0): |
1262 def s2n(self, offset, length, signed=0): |
1255 self.file.seek(self.offset+offset) |
1263 slice=self.pread(offset, length) |
1256 slice=self.file.read(length) |
|
1257 if self.endian == 'I': |
1264 if self.endian == 'I': |
1258 val=s2n_intel(slice) |
1265 val=s2n_intel(slice) |
1259 else: |
1266 else: |
1260 val=s2n_motorola(slice) |
1267 val=s2n_motorola(slice) |
1261 # Sign extension ? |
1268 # Sign extension ? |
1347 if field_type == 2: |
1354 if field_type == 2: |
1348 # special case: null-terminated ASCII string |
1355 # special case: null-terminated ASCII string |
1349 # XXX investigate |
1356 # XXX investigate |
1350 # sometimes gets too big to fit in int value |
1357 # sometimes gets too big to fit in int value |
1351 if count != 0 and count < (2**31): |
1358 if count != 0 and count < (2**31): |
1352 self.file.seek(self.offset + offset) |
1359 values = self.pread(offset, count) |
1353 values = self.file.read(count) |
|
1354 #print values |
1360 #print values |
1355 # Drop any garbage after a null. |
1361 # Drop any garbage after a null. |
1356 values = values.split('\x00', 1)[0] |
1362 values = values.split('\x00', 1)[0] |
1357 else: |
1363 else: |
1358 values = '' |
1364 values = '' |
1424 if self.endian == 'M': |
1430 if self.endian == 'M': |
1425 tiff = 'MM\x00*\x00\x00\x00\x08' |
1431 tiff = 'MM\x00*\x00\x00\x00\x08' |
1426 else: |
1432 else: |
1427 tiff = 'II*\x00\x08\x00\x00\x00' |
1433 tiff = 'II*\x00\x08\x00\x00\x00' |
1428 # ... plus thumbnail IFD data plus a null "next IFD" pointer |
1434 # ... plus thumbnail IFD data plus a null "next IFD" pointer |
1429 self.file.seek(self.offset+thumb_ifd) |
1435 tiff += self.pread(thumb_ifd, entries*12+2)+'\x00\x00\x00\x00' |
1430 tiff += self.file.read(entries*12+2)+'\x00\x00\x00\x00' |
|
1431 |
1436 |
1432 # fix up large value offset pointers into data area |
1437 # fix up large value offset pointers into data area |
1433 for i in range(entries): |
1438 for i in range(entries): |
1434 entry = thumb_ifd + 2 + 12 * i |
1439 entry = thumb_ifd + 2 + 12 * i |
1435 tag = self.s2n(entry, 2) |
1440 tag = self.s2n(entry, 2) |
1452 # remember strip offsets location |
1457 # remember strip offsets location |
1453 if tag == 0x0111: |
1458 if tag == 0x0111: |
1454 strip_off = newoff |
1459 strip_off = newoff |
1455 strip_len = 4 |
1460 strip_len = 4 |
1456 # get original data and store it |
1461 # get original data and store it |
1457 self.file.seek(self.offset + oldoff) |
1462 tiff += self.pread(oldoff, count * typelen) |
1458 tiff += self.file.read(count * typelen) |
|
1459 |
1463 |
1460 # add pixel strips and update strip offset info |
1464 # add pixel strips and update strip offset info |
1461 old_offsets = self.tags['Thumbnail StripOffsets'].values |
1465 old_offsets = self.tags['Thumbnail StripOffsets'].values |
1462 old_counts = self.tags['Thumbnail StripByteCounts'].values |
1466 old_counts = self.tags['Thumbnail StripByteCounts'].values |
1463 for i in range(len(old_offsets)): |
1467 for i in range(len(old_offsets)): |
1464 # update offset pointer (more nasty "strings are immutable" crap) |
1468 # update offset pointer (more nasty "strings are immutable" crap) |
1465 offset = self.n2s(len(tiff), strip_len) |
1469 offset = self.n2s(len(tiff), strip_len) |
1466 tiff = tiff[:strip_off] + offset + tiff[strip_off + strip_len:] |
1470 tiff = tiff[:strip_off] + offset + tiff[strip_off + strip_len:] |
1467 strip_off += strip_len |
1471 strip_off += strip_len |
1468 # add pixel strip to end |
1472 # add pixel strip to end |
1469 self.file.seek(self.offset + old_offsets[i]) |
1473 tiff += self.pread(old_offsets[i], old_counts[i]) |
1470 tiff += self.file.read(old_counts[i]) |
|
1471 |
1474 |
1472 self.tags['TIFFThumbnail'] = tiff |
1475 self.tags['TIFFThumbnail'] = tiff |
1473 |
1476 |
1474 # decode all the camera-specific MakerNote formats |
1477 # decode all the camera-specific MakerNote formats |
1475 |
1478 |