diff --git a/Tests/images/zero_bb_eof_before_boundingbox.eps b/Tests/images/zero_bb_eof_before_boundingbox.eps new file mode 100644 index 000000000..c268bffd1 Binary files /dev/null and b/Tests/images/zero_bb_eof_before_boundingbox.eps differ diff --git a/Tests/images/zero_bb_trailer.eps b/Tests/images/zero_bb_trailer.eps index 84ee7829c..964889965 100644 Binary files a/Tests/images/zero_bb_trailer.eps and b/Tests/images/zero_bb_trailer.eps differ diff --git a/Tests/test_file_eps.py b/Tests/test_file_eps.py index 21c1fd778..4f4d26fb1 100644 --- a/Tests/test_file_eps.py +++ b/Tests/test_file_eps.py @@ -406,10 +406,16 @@ def test_timeout(test_file): pass -def test_boundary_box_in_trailer(): - # Check whether boundary boxes are parsed in the same way - # when specified in the header or the trailer +def test_bounding_box_in_trailer(): + # Check bounding boxes are parsed in the same way + # when specified in the header and the trailer with Image.open("Tests/images/zero_bb_trailer.eps") as trailer_image, Image.open( FILE1 ) as header_image: assert trailer_image.size == header_image.size + + +def test_eof_before_bounding_box(): + with pytest.raises(OSError): + with Image.open("Tests/images/zero_bb_eof_before_boundingbox.eps"): + pass diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 16cfe2ab2..95af62540 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -245,6 +245,34 @@ class EpsImageFile(ImageFile.ImageFile): msg = 'EPS header missing "%%BoundingBox" comment' raise SyntaxError(msg) + def _read_comment(s): + nonlocal reading_trailer_comments + try: + m = split.match(s) + except re.error as e: + msg = "not an EPS file" + raise SyntaxError(msg) from e + + if m: + k, v = m.group(1, 2) + self.info[k] = v + if k == "BoundingBox": + if v == "(atend)": + reading_trailer_comments = True + elif not self._size or reading_trailer_comments: + try: + # Note: The DSC spec says that BoundingBox + # fields should be integers, but some drivers + # put floating point values there anyway. + box = [int(float(i)) for i in v.split()] + self._size = box[2] - box[0], box[3] - box[1] + self.tile = [ + ("eps", (0, 0) + self.size, offset, (length, box)) + ] + except Exception: + pass + return True + while True: byte = self.fp.read(1) if byte == b"": @@ -289,22 +317,7 @@ class EpsImageFile(ImageFile.ImageFile): continue s = str(bytes_mv[:bytes_read], "latin-1") - - try: - m = split.match(s) - except re.error as e: - msg = "not an EPS file" - raise SyntaxError(msg) from e - - if m: - k, v = m.group(1, 2) - self.info[k] = v - if k == "BoundingBox": - if v == "(atend)": - reading_trailer_comments = True - else: - self._read_boundary_box(v, offset, length) - else: + if not _read_comment(s): m = field.match(s) if m: k = m.group(1) @@ -354,27 +367,13 @@ class EpsImageFile(ImageFile.ImageFile): # Load EPS trailer # if this line starts with "%%EOF", - # then we've reached the end of the trailer + # then we've reached the end of the file if bytes_mv[:5] == b"%%EOF": - reading_trailer_comments = False - continue + break s = str(bytes_mv[:bytes_read], "latin-1") - - try: - m = split.match(s) - except re.error as e: - msg = "not an EPS file" - raise SyntaxError(msg) from e - - if m: - k, v = m.group(1, 2) - self.info[k] = v - if k == "BoundingBox": - if not self._size: - self._read_boundary_box(v, offset, length) - - if bytes_mv[:9] == b"%%Trailer": + _read_comment(s) + elif bytes_mv[:9] == b"%%Trailer": trailer_reached = True bytes_read = 0 @@ -407,17 +406,6 @@ class EpsImageFile(ImageFile.ImageFile): return length, offset - def _read_boundary_box(self, v, offset, length): - try: - # Note: The DSC spec says that BoundingBox - # fields should be integers, but some drivers - # put floating point values there anyway. - box = [int(float(i)) for i in v.split()] - self._size = box[2] - box[0], box[3] - box[1] - self.tile = [("eps", (0, 0) + self.size, offset, (length, box))] - except Exception: - pass - def load(self, scale=1, transparency=False): # Load EPS via Ghostscript if self.tile: