mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-13 01:50:48 +03:00
Basic MPO reading works, seek is partially there.
This commit is contained in:
parent
098e4c36d6
commit
d5909e4946
|
@ -2231,7 +2231,6 @@ def open(fp, mode="r"):
|
|||
|
||||
for i in ID:
|
||||
try:
|
||||
print(ID)
|
||||
factory, accept = OPEN[i]
|
||||
if not accept or accept(prefix):
|
||||
fp.seek(0)
|
||||
|
|
|
@ -37,6 +37,7 @@ __version__ = "0.6"
|
|||
import array
|
||||
import struct
|
||||
import io
|
||||
from struct import unpack
|
||||
from PIL import Image, ImageFile, TiffImagePlugin, _binary
|
||||
from PIL.JpegPresets import presets
|
||||
from PIL._util import isStringType
|
||||
|
@ -114,6 +115,7 @@ def APP(self, marker):
|
|||
elif marker == 0xFFE2 and s[:4] == b"MPF\0":
|
||||
# extract MPO information
|
||||
self.info["mp"] = s[4:]
|
||||
self.info["mpoffset"] = self.fp.tell()
|
||||
|
||||
|
||||
def COM(self, marker):
|
||||
|
@ -451,12 +453,30 @@ def _getmp(self):
|
|||
return None
|
||||
file = io.BytesIO(data)
|
||||
head = file.read(8)
|
||||
endianness = '>' if head[:4] == b'\x4d\x4d\x00\x2a' else '<'
|
||||
mp = {}
|
||||
# process dictionary
|
||||
info = TiffImagePlugin.ImageFileDirectory(head)
|
||||
info.load(file)
|
||||
for key, value in info.items():
|
||||
mp[key] = _fixup(value)
|
||||
# it's an error not to have a number of images
|
||||
try:
|
||||
quant = mp[0xB001]
|
||||
except KeyError:
|
||||
raise SyntaxError("malformed MP Index (no number of images)")
|
||||
# get MP entries
|
||||
try:
|
||||
mpentries = []
|
||||
for entrynum in range(0, quant):
|
||||
rawmpentry = mp[0xB002][entrynum * 16:(entrynum + 1) * 16]
|
||||
unpackedentry = unpack('{0}LLLHH'.format(endianness), rawmpentry)
|
||||
labels = ('Attribute', 'Size', 'DataOffset', 'EntryNo1', 'EntryNo2')
|
||||
mpentry = dict(zip(labels, unpackedentry))
|
||||
mpentries.append(mpentry)
|
||||
mp[0xB002] = mpentries
|
||||
except KeyError:
|
||||
raise SyntaxError("malformed MP Index (bad MP Entry)")
|
||||
return mp
|
||||
|
||||
|
||||
|
|
|
@ -38,21 +38,28 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile):
|
|||
|
||||
def _open(self):
|
||||
JpegImagePlugin.JpegImageFile._open(self)
|
||||
self.mpinfo = self._getmp()
|
||||
self.__framecount = self.mpinfo[0xB001]
|
||||
self.__mpoffsets = [mpent['DataOffset'] + self.info['mpoffset'] \
|
||||
for mpent in self.mpinfo[0xB002]]
|
||||
assert self.__framecount == len(self.__mpoffsets)
|
||||
del self.info['mpoffset'] # no longer needed
|
||||
self.__fp = self.fp # FIXME: hack
|
||||
self.__rewind = self.fp.tell()
|
||||
self.seek(0) # get ready to read first frame
|
||||
self.__fp.seek(self.__mpoffsets[0]) # get ready to read first frame
|
||||
self.__frame = 0
|
||||
self.offset = 0
|
||||
|
||||
def seek(self, frame):
|
||||
|
||||
if frame == 0:
|
||||
# rewind
|
||||
self.__offset = 0
|
||||
self.dispose = None
|
||||
self.__frame = -1
|
||||
self.__fp.seek(self.__rewind)
|
||||
|
||||
if frame != self.__frame + 1:
|
||||
raise ValueError("cannot seek to frame %d" % frame)
|
||||
if frame < 0 or frame >= self.__framecount:
|
||||
raise EOFError("no more images in MPO file")
|
||||
else:
|
||||
self.fp = self.__fp
|
||||
self.fp.seek(self.__mpoffsets[frame])
|
||||
self.offset = self.__mpoffsets[frame]
|
||||
rawmode = self.mode
|
||||
if self.mode == "CMYK":
|
||||
rawmode = "CMYK;I" # assume adobe conventions
|
||||
self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))]
|
||||
self.__frame = frame
|
||||
|
||||
def tell(self):
|
||||
|
|
|
@ -54,6 +54,26 @@ class TestFileMpo(PillowTestCase):
|
|||
info = im._getmp()
|
||||
self.assertEqual(info[45056], '0100')
|
||||
self.assertEqual(info[45057], 2)
|
||||
|
||||
def test_seek(self):
|
||||
for test_file in test_files:
|
||||
im = Image.open(test_file)
|
||||
self.assertEqual(im.tell(), 0)
|
||||
# prior to first image raises an error, both blatant and borderline
|
||||
self.assertRaises(EOFError, im.seek, -1)
|
||||
self.assertRaises(EOFError, im.seek, -523)
|
||||
# after the final image raises an error, both blatant and borderline
|
||||
self.assertRaises(EOFError, im.seek, 2)
|
||||
self.assertRaises(EOFError, im.seek, 523)
|
||||
# bad calls shouldn't change the frame
|
||||
self.assertEqual(im.tell(), 0)
|
||||
# this one will work
|
||||
im.seek(1)
|
||||
self.assertEqual(im.tell(), 1)
|
||||
# and this one, too
|
||||
im.seek(0)
|
||||
self.assertEqual(im.tell(), 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue
Block a user