diff --git a/PIL/Image.py b/PIL/Image.py index b4aa11e20..eb08fab9e 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -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) diff --git a/PIL/JpegImagePlugin.py b/PIL/JpegImagePlugin.py index 7dfdfa308..ce225ddc1 100644 --- a/PIL/JpegImagePlugin.py +++ b/PIL/JpegImagePlugin.py @@ -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 diff --git a/PIL/MpoImagePlugin.py b/PIL/MpoImagePlugin.py index 18f32bd48..6accf5110 100644 --- a/PIL/MpoImagePlugin.py +++ b/PIL/MpoImagePlugin.py @@ -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): diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 17f9a66fb..a0bcf6f40 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -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()