diff --git a/Tests/test_file_bufrstub.py b/Tests/test_file_bufrstub.py index 8c6bb1a69f7..48949ad2fe2 100644 --- a/Tests/test_file_bufrstub.py +++ b/Tests/test_file_bufrstub.py @@ -20,7 +20,7 @@ def test_open() -> None: # Dummy data from the stub assert im.mode == "F" - assert im.size == (1, 1) + assert im.size == (0, 0) def test_invalid_file() -> None: @@ -58,6 +58,7 @@ class TestHandler(ImageFile.StubHandler): def open(self, im: ImageFile.StubImageFile) -> None: self.opened = True + im._size = (1, 1) def load(self, im: ImageFile.StubImageFile) -> Image.Image: self.loaded = True diff --git a/Tests/test_file_gribstub.py b/Tests/test_file_gribstub.py index 05925d50202..45b5565e505 100644 --- a/Tests/test_file_gribstub.py +++ b/Tests/test_file_gribstub.py @@ -20,7 +20,7 @@ def test_open() -> None: # Dummy data from the stub assert im.mode == "F" - assert im.size == (1, 1) + assert im.size == (0, 0) def test_invalid_file() -> None: @@ -58,6 +58,7 @@ class TestHandler(ImageFile.StubHandler): def open(self, im: Image.Image) -> None: self.opened = True + im._size = (1, 1) def load(self, im: ImageFile.ImageFile) -> Image.Image: self.loaded = True diff --git a/Tests/test_file_hdf5stub.py b/Tests/test_file_hdf5stub.py index e1a56309b90..c22196bd640 100644 --- a/Tests/test_file_hdf5stub.py +++ b/Tests/test_file_hdf5stub.py @@ -19,7 +19,7 @@ def test_open() -> None: # Dummy data from the stub assert im.mode == "F" - assert im.size == (1, 1) + assert im.size == (0, 0) def test_invalid_file() -> None: @@ -60,6 +60,7 @@ class TestHandler(ImageFile.StubHandler): def open(self, im: Image.Image) -> None: self.opened = True + im._size = (1, 1) def load(self, im: ImageFile.ImageFile) -> Image.Image: self.loaded = True diff --git a/Tests/test_file_wmf.py b/Tests/test_file_wmf.py index 56901f46b07..451a726ae43 100644 --- a/Tests/test_file_wmf.py +++ b/Tests/test_file_wmf.py @@ -69,6 +69,9 @@ def test_register_handler(tmp_path: Path) -> None: class TestHandler(ImageFile.StubHandler): methodCalled = False + def open(self, im: ImageFile.StubImageFile) -> None: + im._size = (1, 1) + def load(self, im: ImageFile.StubImageFile) -> Image.Image: return Image.new("RGB", (1, 1)) @@ -76,7 +79,7 @@ def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None: self.methodCalled = True handler = TestHandler() - original_handler = WmfImagePlugin._handler + original_handler = WmfImagePlugin.WmfStubImageFile._handler WmfImagePlugin.register_handler(handler) im = hopper() diff --git a/src/PIL/BufrStubImagePlugin.py b/src/PIL/BufrStubImagePlugin.py index d82c4c746c3..ef7b2d74cb4 100644 --- a/src/PIL/BufrStubImagePlugin.py +++ b/src/PIL/BufrStubImagePlugin.py @@ -15,8 +15,6 @@ from . import Image, ImageFile -_handler = None - def register_handler(handler: ImageFile.StubHandler | None) -> None: """ @@ -24,8 +22,7 @@ def register_handler(handler: ImageFile.StubHandler | None) -> None: :param handler: Handler object. """ - global _handler - _handler = handler + BufrStubImageFile._handler = handler # -------------------------------------------------------------------- @@ -50,17 +47,15 @@ def _open(self) -> None: # make something up self._mode = "F" - self._size = 1, 1 - - def _load(self) -> ImageFile.StubHandler | None: - return _handler def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - if _handler is None or not hasattr(_handler, "save"): + if BufrStubImageFile._handler is None or not hasattr( + BufrStubImageFile._handler, "save" + ): msg = "BUFR save handler not installed" raise OSError(msg) - _handler.save(im, fp, filename) + BufrStubImageFile._handler.save(im, fp, filename) # -------------------------------------------------------------------- diff --git a/src/PIL/GribStubImagePlugin.py b/src/PIL/GribStubImagePlugin.py index 3784ef2f134..c24d1d04767 100644 --- a/src/PIL/GribStubImagePlugin.py +++ b/src/PIL/GribStubImagePlugin.py @@ -15,8 +15,6 @@ from . import Image, ImageFile -_handler = None - def register_handler(handler: ImageFile.StubHandler | None) -> None: """ @@ -24,8 +22,7 @@ def register_handler(handler: ImageFile.StubHandler | None) -> None: :param handler: Handler object. """ - global _handler - _handler = handler + GribStubImageFile._handler = handler # -------------------------------------------------------------------- @@ -50,17 +47,15 @@ def _open(self) -> None: # make something up self._mode = "F" - self._size = 1, 1 - - def _load(self) -> ImageFile.StubHandler | None: - return _handler def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - if _handler is None or not hasattr(_handler, "save"): + if GribStubImageFile._handler is None or not hasattr( + GribStubImageFile._handler, "save" + ): msg = "GRIB save handler not installed" raise OSError(msg) - _handler.save(im, fp, filename) + GribStubImageFile._handler.save(im, fp, filename) # -------------------------------------------------------------------- diff --git a/src/PIL/Hdf5StubImagePlugin.py b/src/PIL/Hdf5StubImagePlugin.py index 1a56660f7bd..0996afac822 100644 --- a/src/PIL/Hdf5StubImagePlugin.py +++ b/src/PIL/Hdf5StubImagePlugin.py @@ -15,8 +15,6 @@ from . import Image, ImageFile -_handler = None - def register_handler(handler: ImageFile.StubHandler | None) -> None: """ @@ -24,8 +22,7 @@ def register_handler(handler: ImageFile.StubHandler | None) -> None: :param handler: Handler object. """ - global _handler - _handler = handler + HDF5StubImageFile._handler = handler # -------------------------------------------------------------------- @@ -50,17 +47,15 @@ def _open(self) -> None: # make something up self._mode = "F" - self._size = 1, 1 - - def _load(self) -> ImageFile.StubHandler | None: - return _handler def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - if _handler is None or not hasattr(_handler, "save"): + if HDF5StubImageFile._handler is None or not hasattr( + HDF5StubImageFile._handler, "save" + ): msg = "HDF5 save handler not installed" raise OSError(msg) - _handler.save(im, fp, filename) + HDF5StubImageFile._handler.save(im, fp, filename) # -------------------------------------------------------------------- diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index eaa1e45812c..e087365f5cf 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -151,9 +151,8 @@ def __init__( try: self._open() - if isinstance(self, StubImageFile): - if loader := self._load(): - loader.open(self) + if isinstance(self, StubImageFile) and self._handler: + self._handler.open(self) except ( IndexError, # end of data TypeError, # end of data (ord) @@ -163,7 +162,11 @@ def __init__( ) as v: raise SyntaxError(v) from v - if not self.mode or self.size[0] <= 0 or self.size[1] <= 0: + if not self.mode or ( + min(self.size) < 0 + if isinstance(self, StubImageFile) and self._handler is None + else min(self.size) <= 0 + ): msg = "not identified by this driver" raise SyntaxError(msg) except BaseException: @@ -468,6 +471,7 @@ def _seek_check(self, frame: int) -> bool: class StubHandler(abc.ABC): + @abc.abstractmethod def open(self, im: StubImageFile) -> None: pass @@ -484,27 +488,23 @@ class StubImageFile(ImageFile, metaclass=abc.ABCMeta): certain format, but relies on external code to load the file. """ + _handler: StubHandler | None = None + @abc.abstractmethod def _open(self) -> None: pass def load(self) -> Image.core.PixelAccess | None: - loader = self._load() - if loader is None: + if self._handler is None: msg = f"cannot find loader for this {self.format} file" raise OSError(msg) - image = loader.load(self) + image = self._handler.load(self) assert image is not None # become the other object (!) self.__class__ = image.__class__ # type: ignore[assignment] self.__dict__ = image.__dict__ return image.load() - @abc.abstractmethod - def _load(self) -> StubHandler | None: - """(Hook) Find actual image loader.""" - pass - class Parser: """ diff --git a/src/PIL/WmfImagePlugin.py b/src/PIL/WmfImagePlugin.py index f5e244782fc..b3cf052feca 100644 --- a/src/PIL/WmfImagePlugin.py +++ b/src/PIL/WmfImagePlugin.py @@ -27,41 +27,6 @@ from ._binary import si16le as short from ._binary import si32le as _long -_handler = None - - -def register_handler(handler: ImageFile.StubHandler | None) -> None: - """ - Install application-specific WMF image handler. - - :param handler: Handler object. - """ - global _handler - _handler = handler - - -if hasattr(Image.core, "drawwmf"): - # install default handler (windows only) - - class WmfHandler(ImageFile.StubHandler): - def open(self, im: ImageFile.StubImageFile) -> None: - self.bbox = im.info["wmf_bbox"] - - def load(self, im: ImageFile.StubImageFile) -> Image.Image: - assert im.fp is not None - im.fp.seek(0) # rewind - return Image.frombytes( - "RGB", - im.size, - Image.core.drawwmf(im.fp.read(), im.size, self.bbox), - "raw", - "BGR", - (im.size[0] * 3 + 3) & -4, - -1, - ) - - register_handler(WmfHandler()) - # # -------------------------------------------------------------------- # Read WMF file @@ -147,9 +112,6 @@ def _open(self) -> None: self._mode = "RGB" self._size = size - def _load(self) -> ImageFile.StubHandler | None: - return _handler - def load( self, dpi: float | tuple[float, float] | None = None ) -> Image.core.PixelAccess | None: @@ -166,10 +128,44 @@ def load( def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - if _handler is None or not hasattr(_handler, "save"): + if WmfStubImageFile._handler is None or not hasattr( + WmfStubImageFile._handler, "save" + ): msg = "WMF save handler not installed" raise OSError(msg) - _handler.save(im, fp, filename) + WmfStubImageFile._handler.save(im, fp, filename) + + +def register_handler(handler: ImageFile.StubHandler | None) -> None: + """ + Install application-specific WMF image handler. + + :param handler: Handler object. + """ + WmfStubImageFile._handler = handler + + +if hasattr(Image.core, "drawwmf"): + # install default handler (windows only) + + class WmfHandler(ImageFile.StubHandler): + def open(self, im: ImageFile.StubImageFile) -> None: + self.bbox = im.info["wmf_bbox"] + + def load(self, im: ImageFile.StubImageFile) -> Image.Image: + assert im.fp is not None + im.fp.seek(0) # rewind + return Image.frombytes( + "RGB", + im.size, + Image.core.drawwmf(im.fp.read(), im.size, self.bbox), + "raw", + "BGR", + (im.size[0] * 3 + 3) & -4, + -1, + ) + + register_handler(WmfHandler()) #