mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Merge pull request #7801 from radarhere/codecs
This commit is contained in:
commit
3cdd49f31f
|
@ -993,13 +993,7 @@ class TestFileJpeg:
|
|||
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||
return 0, 0
|
||||
|
||||
decoder = InfiniteMockPyDecoder(None)
|
||||
|
||||
def closure(mode: str, *args) -> InfiniteMockPyDecoder:
|
||||
decoder.__init__(mode, *args)
|
||||
return decoder
|
||||
|
||||
Image.register_decoder("INFINITE", closure)
|
||||
Image.register_decoder("INFINITE", InfiniteMockPyDecoder)
|
||||
|
||||
with Image.open(TEST_FILE) as im:
|
||||
im.tile = [
|
||||
|
|
|
@ -16,6 +16,7 @@ from PIL import (
|
|||
ExifTags,
|
||||
Image,
|
||||
ImageDraw,
|
||||
ImageFile,
|
||||
ImagePalette,
|
||||
UnidentifiedImageError,
|
||||
features,
|
||||
|
@ -1041,25 +1042,20 @@ class TestImage:
|
|||
assert im.fp is None
|
||||
|
||||
|
||||
class MockEncoder:
|
||||
args: tuple[str, ...]
|
||||
|
||||
|
||||
def mock_encode(*args: str) -> MockEncoder:
|
||||
encoder = MockEncoder()
|
||||
encoder.args = args
|
||||
return encoder
|
||||
class MockEncoder(ImageFile.PyEncoder):
|
||||
pass
|
||||
|
||||
|
||||
class TestRegistry:
|
||||
def test_encode_registry(self) -> None:
|
||||
Image.register_encoder("MOCK", mock_encode)
|
||||
Image.register_encoder("MOCK", MockEncoder)
|
||||
assert "MOCK" in Image.ENCODERS
|
||||
|
||||
enc = Image._getencoder("RGB", "MOCK", ("args",), extra=("extra",))
|
||||
|
||||
assert isinstance(enc, MockEncoder)
|
||||
assert enc.args == ("RGB", "args", "extra")
|
||||
assert enc.mode == "RGB"
|
||||
assert enc.args == ("args", "extra")
|
||||
|
||||
def test_encode_registry_fail(self) -> None:
|
||||
with pytest.raises(OSError):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -201,12 +202,22 @@ class TestImageFile:
|
|||
|
||||
|
||||
class MockPyDecoder(ImageFile.PyDecoder):
|
||||
def __init__(self, mode: str, *args: Any) -> None:
|
||||
MockPyDecoder.last = self
|
||||
|
||||
super().__init__(mode, *args)
|
||||
|
||||
def decode(self, buffer):
|
||||
# eof
|
||||
return -1, 0
|
||||
|
||||
|
||||
class MockPyEncoder(ImageFile.PyEncoder):
|
||||
def __init__(self, mode: str, *args: Any) -> None:
|
||||
MockPyEncoder.last = self
|
||||
|
||||
super().__init__(mode, *args)
|
||||
|
||||
def encode(self, buffer):
|
||||
return 1, 1, b""
|
||||
|
||||
|
@ -228,19 +239,8 @@ class MockImageFile(ImageFile.ImageFile):
|
|||
class CodecsTest:
|
||||
@classmethod
|
||||
def setup_class(cls) -> None:
|
||||
cls.decoder = MockPyDecoder(None)
|
||||
cls.encoder = MockPyEncoder(None)
|
||||
|
||||
def decoder_closure(mode, *args):
|
||||
cls.decoder.__init__(mode, *args)
|
||||
return cls.decoder
|
||||
|
||||
def encoder_closure(mode, *args):
|
||||
cls.encoder.__init__(mode, *args)
|
||||
return cls.encoder
|
||||
|
||||
Image.register_decoder("MOCK", decoder_closure)
|
||||
Image.register_encoder("MOCK", encoder_closure)
|
||||
Image.register_decoder("MOCK", MockPyDecoder)
|
||||
Image.register_encoder("MOCK", MockPyEncoder)
|
||||
|
||||
|
||||
class TestPyDecoder(CodecsTest):
|
||||
|
@ -251,13 +251,13 @@ class TestPyDecoder(CodecsTest):
|
|||
|
||||
im.load()
|
||||
|
||||
assert self.decoder.state.xoff == xoff
|
||||
assert self.decoder.state.yoff == yoff
|
||||
assert self.decoder.state.xsize == xsize
|
||||
assert self.decoder.state.ysize == ysize
|
||||
assert MockPyDecoder.last.state.xoff == xoff
|
||||
assert MockPyDecoder.last.state.yoff == yoff
|
||||
assert MockPyDecoder.last.state.xsize == xsize
|
||||
assert MockPyDecoder.last.state.ysize == ysize
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
self.decoder.set_as_raw(b"\x00")
|
||||
MockPyDecoder.last.set_as_raw(b"\x00")
|
||||
|
||||
def test_extents_none(self) -> None:
|
||||
buf = BytesIO(b"\x00" * 255)
|
||||
|
@ -267,10 +267,10 @@ class TestPyDecoder(CodecsTest):
|
|||
|
||||
im.load()
|
||||
|
||||
assert self.decoder.state.xoff == 0
|
||||
assert self.decoder.state.yoff == 0
|
||||
assert self.decoder.state.xsize == 200
|
||||
assert self.decoder.state.ysize == 200
|
||||
assert MockPyDecoder.last.state.xoff == 0
|
||||
assert MockPyDecoder.last.state.yoff == 0
|
||||
assert MockPyDecoder.last.state.xsize == 200
|
||||
assert MockPyDecoder.last.state.ysize == 200
|
||||
|
||||
def test_negsize(self) -> None:
|
||||
buf = BytesIO(b"\x00" * 255)
|
||||
|
@ -315,10 +315,10 @@ class TestPyEncoder(CodecsTest):
|
|||
im, fp, [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 0, "RGB")]
|
||||
)
|
||||
|
||||
assert self.encoder.state.xoff == xoff
|
||||
assert self.encoder.state.yoff == yoff
|
||||
assert self.encoder.state.xsize == xsize
|
||||
assert self.encoder.state.ysize == ysize
|
||||
assert MockPyEncoder.last.state.xoff == xoff
|
||||
assert MockPyEncoder.last.state.yoff == yoff
|
||||
assert MockPyEncoder.last.state.xsize == xsize
|
||||
assert MockPyEncoder.last.state.ysize == ysize
|
||||
|
||||
def test_extents_none(self) -> None:
|
||||
buf = BytesIO(b"\x00" * 255)
|
||||
|
@ -329,10 +329,10 @@ class TestPyEncoder(CodecsTest):
|
|||
fp = BytesIO()
|
||||
ImageFile._save(im, fp, [("MOCK", None, 0, "RGB")])
|
||||
|
||||
assert self.encoder.state.xoff == 0
|
||||
assert self.encoder.state.yoff == 0
|
||||
assert self.encoder.state.xsize == 200
|
||||
assert self.encoder.state.ysize == 200
|
||||
assert MockPyEncoder.last.state.xoff == 0
|
||||
assert MockPyEncoder.last.state.yoff == 0
|
||||
assert MockPyEncoder.last.state.xsize == 200
|
||||
assert MockPyEncoder.last.state.ysize == 200
|
||||
|
||||
def test_negsize(self) -> None:
|
||||
buf = BytesIO(b"\x00" * 255)
|
||||
|
@ -340,12 +340,12 @@ class TestPyEncoder(CodecsTest):
|
|||
im = MockImageFile(buf)
|
||||
|
||||
fp = BytesIO()
|
||||
self.encoder.cleanup_called = False
|
||||
MockPyEncoder.last = None
|
||||
with pytest.raises(ValueError):
|
||||
ImageFile._save(
|
||||
im, fp, [("MOCK", (xoff, yoff, -10, yoff + ysize), 0, "RGB")]
|
||||
)
|
||||
assert self.encoder.cleanup_called
|
||||
assert MockPyEncoder.last.cleanup_called
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
ImageFile._save(
|
||||
|
|
|
@ -229,8 +229,8 @@ MIME: dict[str, str] = {}
|
|||
SAVE: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
|
||||
SAVE_ALL: dict[str, Callable[[Image, IO[bytes], str | bytes], None]] = {}
|
||||
EXTENSION: dict[str, str] = {}
|
||||
DECODERS: dict[str, object] = {}
|
||||
ENCODERS: dict[str, object] = {}
|
||||
DECODERS: dict[str, type[ImageFile.PyDecoder]] = {}
|
||||
ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {}
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Modes
|
||||
|
@ -3526,28 +3526,26 @@ def registered_extensions():
|
|||
return EXTENSION
|
||||
|
||||
|
||||
def register_decoder(name: str, decoder) -> None:
|
||||
def register_decoder(name: str, decoder: type[ImageFile.PyDecoder]) -> None:
|
||||
"""
|
||||
Registers an image decoder. This function should not be
|
||||
used in application code.
|
||||
|
||||
:param name: The name of the decoder
|
||||
:param decoder: A callable(mode, args) that returns an
|
||||
ImageFile.PyDecoder object
|
||||
:param decoder: An ImageFile.PyDecoder object
|
||||
|
||||
.. versionadded:: 4.1.0
|
||||
"""
|
||||
DECODERS[name] = decoder
|
||||
|
||||
|
||||
def register_encoder(name, encoder):
|
||||
def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None:
|
||||
"""
|
||||
Registers an image encoder. This function should not be
|
||||
used in application code.
|
||||
|
||||
:param name: The name of the encoder
|
||||
:param encoder: A callable(mode, args) that returns an
|
||||
ImageFile.PyEncoder object
|
||||
:param encoder: An ImageFile.PyEncoder object
|
||||
|
||||
.. versionadded:: 4.1.0
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue
Block a user