@@ -193,7 +193,11 @@ def _open(self) -> None:
193193 self .fp .seek (offset )
194194
195195 self ._mode = "RGB"
196- self ._size = None
196+
197+ # When reading header comments, the first comment is used.
198+ # When reading trailer comments, the last comment is used.
199+ bounding_box : list [int ] | None = None
200+ imagedata_size : tuple [int , int ] | None = None
197201
198202 byte_arr = bytearray (255 )
199203 bytes_mv = memoryview (byte_arr )
@@ -215,8 +219,8 @@ def check_required_header_comments() -> None:
215219 msg = 'EPS header missing "%%BoundingBox" comment'
216220 raise SyntaxError (msg )
217221
218- def _read_comment (s : str ) -> bool :
219- nonlocal reading_trailer_comments
222+ def read_comment (s : str ) -> bool :
223+ nonlocal bounding_box , reading_trailer_comments
220224 try :
221225 m = split .match (s )
222226 except re .error as e :
@@ -231,18 +235,12 @@ def _read_comment(s: str) -> bool:
231235 if k == "BoundingBox" :
232236 if v == "(atend)" :
233237 reading_trailer_comments = True
234- elif not self . _size or (trailer_reached and reading_trailer_comments ):
238+ elif not bounding_box or (trailer_reached and reading_trailer_comments ):
235239 try :
236240 # Note: The DSC spec says that BoundingBox
237241 # fields should be integers, but some drivers
238242 # put floating point values there anyway.
239- box = [int (float (i )) for i in v .split ()]
240- self ._size = box [2 ] - box [0 ], box [3 ] - box [1 ]
241- self .tile = [
242- ImageFile ._Tile (
243- "eps" , (0 , 0 ) + self .size , offset , (length , box )
244- )
245- ]
243+ bounding_box = [int (float (i )) for i in v .split ()]
246244 except Exception :
247245 pass
248246 return True
@@ -293,7 +291,7 @@ def _read_comment(s: str) -> bool:
293291 continue
294292
295293 s = str (bytes_mv [:bytes_read ], "latin-1" )
296- if not _read_comment (s ):
294+ if not read_comment (s ):
297295 m = field .match (s )
298296 if m :
299297 k = m .group (1 )
@@ -327,32 +325,50 @@ def _read_comment(s: str) -> bool:
327325 int (value ) for value in image_data_values [:4 ]
328326 )
329327
330- if bit_depth == 1 :
331- self ._mode = "1"
332- elif bit_depth == 8 :
333- try :
334- self ._mode = self .mode_map [mode_id ]
335- except ValueError :
336- break
337- else :
338- break
328+ if not imagedata_size :
329+ imagedata_size = columns , rows
339330
340- self ._size = columns , rows
341- return
331+ if bit_depth == 1 :
332+ self ._mode = "1"
333+ elif bit_depth == 8 :
334+ try :
335+ self ._mode = self .mode_map [mode_id ]
336+ except ValueError :
337+ pass
342338 elif bytes_mv [:5 ] == b"%%EOF" :
343339 break
344340 elif trailer_reached and reading_trailer_comments :
345341 # Load EPS trailer
346342 s = str (bytes_mv [:bytes_read ], "latin-1" )
347- _read_comment (s )
343+ read_comment (s )
348344 elif bytes_mv [:9 ] == b"%%Trailer" :
349345 trailer_reached = True
350346 bytes_read = 0
351347
352- if not self ._size :
348+ # A "BoundingBox" is always required,
349+ # even if an "ImageData" descriptor size exists.
350+ if not bounding_box :
353351 msg = "cannot determine EPS bounding box"
354352 raise OSError (msg )
355353
354+ # An "ImageData" size takes precedence over the "BoundingBox".
355+ if imagedata_size :
356+ self ._size = imagedata_size
357+ else :
358+ self ._size = (
359+ bounding_box [2 ] - bounding_box [0 ],
360+ bounding_box [3 ] - bounding_box [1 ],
361+ )
362+
363+ self .tile = [
364+ ImageFile ._Tile (
365+ codec_name = "eps" ,
366+ extents = (0 , 0 ) + self ._size ,
367+ offset = offset ,
368+ args = (length , bounding_box ),
369+ )
370+ ]
371+
356372 def _find_offset (self , fp : IO [bytes ]) -> tuple [int , int ]:
357373 s = fp .read (4 )
358374
0 commit comments