mirror of
https://github.com/python-pillow/Pillow.git
synced 2026-02-03 22:15:52 +03:00
Merge c7b6c4ff81 into 62aa42f9da
This commit is contained in:
commit
93469770eb
|
|
@ -19,6 +19,7 @@ from PIL import (
|
|||
UnidentifiedImageError,
|
||||
features,
|
||||
)
|
||||
from PIL._typing import Buffer
|
||||
|
||||
from .helper import (
|
||||
assert_image,
|
||||
|
|
@ -40,6 +41,7 @@ try:
|
|||
except ImportError:
|
||||
ElementTree = None
|
||||
|
||||
|
||||
TEST_FILE = "Tests/images/hopper.jpg"
|
||||
|
||||
|
||||
|
|
@ -1054,7 +1056,7 @@ class TestFileJpeg:
|
|||
# the image should still end when there is no new data
|
||||
class InfiniteMockPyDecoder(ImageFile.PyDecoder):
|
||||
def decode(
|
||||
self, buffer: bytes | Image.SupportsArrayInterface
|
||||
self, buffer: Buffer | Image.SupportsArrayInterface
|
||||
) -> tuple[int, int]:
|
||||
return 0, 0
|
||||
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ def test_reduce() -> None:
|
|||
assert callable(im.reduce)
|
||||
|
||||
im.reduce = 2 # type: ignore[assignment, method-assign]
|
||||
assert im.reduce == 2
|
||||
assert im.reduce == 2 # type: ignore[comparison-overlap]
|
||||
|
||||
im.load()
|
||||
assert im.size == (160, 120)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from .helper import assert_image_equal, hopper
|
|||
def test_sanity(data_type: str) -> None:
|
||||
im1 = hopper()
|
||||
|
||||
data = im1.tobytes()
|
||||
data: bytes | memoryview[int] = im1.tobytes()
|
||||
if data_type == "memoryview":
|
||||
data = memoryview(data)
|
||||
im2 = Image.frombytes(im1.mode, im1.size, data)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from PIL import (
|
|||
_binary,
|
||||
features,
|
||||
)
|
||||
from PIL._typing import Buffer
|
||||
|
||||
from .helper import (
|
||||
assert_image,
|
||||
|
|
@ -232,7 +233,7 @@ class MockPyDecoder(ImageFile.PyDecoder):
|
|||
|
||||
super().__init__(mode, *args)
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
# eof
|
||||
return -1, 0
|
||||
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ class TestImageWinDib:
|
|||
|
||||
# Act
|
||||
# Make one the same as the using tobytes()/frombytes()
|
||||
test_buffer = dib1.tobytes()
|
||||
test_buffer: bytes | memoryview[int] = dib1.tobytes()
|
||||
for datatype in ("bytes", "memoryview"):
|
||||
if datatype == "memoryview":
|
||||
test_buffer = memoryview(test_buffer)
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ TYPE_CHECKING = False
|
|||
if TYPE_CHECKING:
|
||||
from pathlib import Path
|
||||
|
||||
QImage = type
|
||||
else:
|
||||
if ImageQt.qt_is_installed:
|
||||
from PIL.ImageQt import QImage
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not ImageQt.qt_is_installed, reason="Qt bindings are not installed"
|
||||
)
|
||||
|
||||
if ImageQt.qt_is_installed:
|
||||
from PIL.ImageQt import QImage
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "L", "P", "1"))
|
||||
def test_sanity(mode: str, tmp_path: Path) -> None:
|
||||
|
|
|
|||
|
|
@ -14,10 +14,16 @@ from __future__ import annotations
|
|||
|
||||
import struct
|
||||
from io import BytesIO
|
||||
from typing import IO
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
|
||||
TYPE_CHECKING = False
|
||||
if TYPE_CHECKING:
|
||||
from typing import IO
|
||||
|
||||
from typing_extensions import Buffer
|
||||
|
||||
|
||||
# Magic ("DDS ")
|
||||
DDS_MAGIC = 0x20534444
|
||||
|
||||
|
|
@ -258,7 +264,7 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
class DXT1Decoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
try:
|
||||
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
||||
|
|
@ -271,7 +277,7 @@ class DXT1Decoder(ImageFile.PyDecoder):
|
|||
class DXT5Decoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
try:
|
||||
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
||||
|
|
|
|||
|
|
@ -216,11 +216,10 @@ testpaths = [
|
|||
[tool.mypy]
|
||||
python_version = "3.10"
|
||||
pretty = true
|
||||
disallow_any_generics = true
|
||||
disallow_untyped_defs = true
|
||||
strict = true
|
||||
disallow_subclassing_any = false
|
||||
disallow_untyped_calls = false
|
||||
enable_error_code = "ignore-without-code"
|
||||
extra_checks = true
|
||||
follow_imports = "silent"
|
||||
warn_redundant_casts = true
|
||||
no_implicit_reexport = false
|
||||
warn_return_any = false
|
||||
warn_unreachable = true
|
||||
warn_unused_ignores = true
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ from io import BytesIO
|
|||
from typing import IO
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._typing import Buffer
|
||||
|
||||
|
||||
class Format(IntEnum):
|
||||
|
|
@ -295,7 +296,7 @@ class BlpImageFile(ImageFile.ImageFile):
|
|||
class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
try:
|
||||
self._read_header()
|
||||
self._load()
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from ._binary import i32le as i32
|
|||
from ._binary import o8
|
||||
from ._binary import o16le as o16
|
||||
from ._binary import o32le as o32
|
||||
from ._typing import Buffer
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
|
@ -327,7 +328,7 @@ class BmpImageFile(ImageFile.ImageFile):
|
|||
class BmpRleDecoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
rle4 = self.args[1]
|
||||
data = bytearray()
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ from . import Image, ImageFile, ImagePalette
|
|||
from ._binary import i32le as i32
|
||||
from ._binary import o8
|
||||
from ._binary import o32le as o32
|
||||
from ._typing import Buffer
|
||||
|
||||
# Magic ("DDS ")
|
||||
DDS_MAGIC = 0x20534444
|
||||
|
|
@ -488,7 +489,7 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
class DdsRgbDecoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
bitcount, masks = self.args
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,9 @@ class EpsImageFile(ImageFile.ImageFile):
|
|||
imagedata_size: tuple[int, int] | None = None
|
||||
|
||||
byte_arr = bytearray(255)
|
||||
bytes_mv = memoryview(byte_arr)
|
||||
# the extra `bytes` annotation here works around several false positive
|
||||
# `comparison-overlap` mypy errors
|
||||
bytes_mv: bytes | memoryview = memoryview(byte_arr)
|
||||
bytes_read = 0
|
||||
reading_header_comments = True
|
||||
reading_trailer_comments = False
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import gzip
|
|||
import math
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._typing import Buffer
|
||||
|
||||
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
|
|
@ -126,7 +127,7 @@ class FitsImageFile(ImageFile.ImageFile):
|
|||
class FitsGzipDecoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
value = gzip.decompress(self.fd.read())
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ if TYPE_CHECKING:
|
|||
from typing import IO, Literal
|
||||
|
||||
from . import _imaging
|
||||
from ._typing import Buffer
|
||||
|
||||
|
||||
class LoadingStrategy(IntEnum):
|
||||
|
|
@ -1188,7 +1187,7 @@ def getdata(
|
|||
class Collector(BytesIO):
|
||||
data = []
|
||||
|
||||
def write(self, data: Buffer) -> int:
|
||||
def write(self, data: bytes) -> int: # type: ignore[override]
|
||||
self.data.append(data)
|
||||
return len(data)
|
||||
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@ if TYPE_CHECKING:
|
|||
from types import ModuleType
|
||||
from typing import Any, Literal
|
||||
|
||||
from ._typing import Buffer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -86,37 +88,45 @@ WARN_POSSIBLE_FORMATS: bool = False
|
|||
MAX_IMAGE_PIXELS: int | None = int(1024 * 1024 * 1024 // 4 // 3)
|
||||
|
||||
|
||||
try:
|
||||
# If the _imaging C module is not present, Pillow will not load.
|
||||
# Note that other modules should not refer to _imaging directly;
|
||||
# import Image and use the Image.core variable instead.
|
||||
# Also note that Image.core is not a publicly documented interface,
|
||||
# and should be considered private and subject to change.
|
||||
from . import _imaging as core
|
||||
if TYPE_CHECKING:
|
||||
from . import _imaging
|
||||
|
||||
if __version__ != getattr(core, "PILLOW_VERSION", None):
|
||||
msg = (
|
||||
"The _imaging extension was built for another version of Pillow or PIL:\n"
|
||||
f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n"
|
||||
f"Pillow version: {__version__}"
|
||||
)
|
||||
raise ImportError(msg)
|
||||
# mypy will not recognize `core` as a public symbol when imported as
|
||||
# `from . import _imaging as core`
|
||||
core = _imaging
|
||||
else:
|
||||
try:
|
||||
# If the _imaging C module is not present, Pillow will not load.
|
||||
# Note that other modules should not refer to _imaging directly;
|
||||
# import Image and use the Image.core variable instead.
|
||||
# Also note that Image.core is not a publicly documented interface,
|
||||
# and should be considered private and subject to change.
|
||||
from . import _imaging as core
|
||||
|
||||
except ImportError as v:
|
||||
# Explanations for ways that we know we might have an import error
|
||||
if str(v).startswith("Module use of python"):
|
||||
# The _imaging C module is present, but not compiled for
|
||||
# the right version (windows only). Print a warning, if
|
||||
# possible.
|
||||
warnings.warn(
|
||||
"The _imaging extension was built for another version of Python.",
|
||||
RuntimeWarning,
|
||||
)
|
||||
elif str(v).startswith("The _imaging extension"):
|
||||
warnings.warn(str(v), RuntimeWarning)
|
||||
# Fail here anyway. Don't let people run with a mostly broken Pillow.
|
||||
# see docs/porting.rst
|
||||
raise
|
||||
if __version__ != getattr(core, "PILLOW_VERSION", None):
|
||||
msg = (
|
||||
f"The _imaging extension was built for another version of Pillow or "
|
||||
f"PIL:\n "
|
||||
f"Core version: {getattr(core, 'PILLOW_VERSION', None)}\n"
|
||||
f"Pillow version: {__version__}"
|
||||
)
|
||||
raise ImportError(msg)
|
||||
|
||||
except ImportError as v:
|
||||
# Explanations for ways that we know we might have an import error
|
||||
if str(v).startswith("Module use of python"):
|
||||
# The _imaging C module is present, but not compiled for
|
||||
# the right version (windows only). Print a warning, if
|
||||
# possible.
|
||||
warnings.warn(
|
||||
"The _imaging extension was built for another version of Python.",
|
||||
RuntimeWarning,
|
||||
)
|
||||
elif str(v).startswith("The _imaging extension"):
|
||||
warnings.warn(str(v), RuntimeWarning)
|
||||
# Fail here anyway. Don't let people run with a mostly broken Pillow.
|
||||
# see docs/porting.rst
|
||||
raise
|
||||
|
||||
|
||||
#
|
||||
|
|
@ -931,7 +941,7 @@ class Image:
|
|||
|
||||
def frombytes(
|
||||
self,
|
||||
data: bytes | bytearray | SupportsArrayInterface,
|
||||
data: Buffer | SupportsArrayInterface,
|
||||
decoder_name: str = "raw",
|
||||
*args: Any,
|
||||
) -> None:
|
||||
|
|
@ -3232,7 +3242,7 @@ def new(
|
|||
def frombytes(
|
||||
mode: str,
|
||||
size: tuple[int, int],
|
||||
data: bytes | bytearray | SupportsArrayInterface,
|
||||
data: Buffer | SupportsArrayInterface,
|
||||
decoder_name: str = "raw",
|
||||
*args: Any,
|
||||
) -> Image:
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ from ._util import DeferredError, is_path
|
|||
|
||||
TYPE_CHECKING = False
|
||||
if TYPE_CHECKING:
|
||||
from ._typing import StrOrBytesPath
|
||||
from ._typing import Buffer, StrOrBytesPath
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -839,7 +839,7 @@ class PyDecoder(PyCodec):
|
|||
def pulls_fd(self) -> bool:
|
||||
return self._pulls_fd
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
"""
|
||||
Override to perform the decoding process.
|
||||
|
||||
|
|
@ -852,7 +852,10 @@ class PyDecoder(PyCodec):
|
|||
raise NotImplementedError(msg)
|
||||
|
||||
def set_as_raw(
|
||||
self, data: bytes, rawmode: str | None = None, extra: tuple[Any, ...] = ()
|
||||
self,
|
||||
data: bytes | bytearray,
|
||||
rawmode: str | None = None,
|
||||
extra: tuple[Any, ...] = (),
|
||||
) -> None:
|
||||
"""
|
||||
Convenience method to set the internal image from a stream of raw data
|
||||
|
|
@ -893,7 +896,7 @@ class PyEncoder(PyCodec):
|
|||
def pushes_fd(self) -> bool:
|
||||
return self._pushes_fd
|
||||
|
||||
def encode(self, bufsize: int) -> tuple[int, int, bytes]:
|
||||
def encode(self, bufsize: int) -> tuple[int, int, bytes | bytearray]:
|
||||
"""
|
||||
Override to perform the encoding process.
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from . import Image
|
||||
from ._typing import Buffer
|
||||
|
||||
|
||||
class HDC:
|
||||
|
|
@ -183,7 +184,7 @@ class Dib:
|
|||
else:
|
||||
self.image.paste(im.im)
|
||||
|
||||
def frombytes(self, buffer: bytes) -> None:
|
||||
def frombytes(self, buffer: Buffer) -> None:
|
||||
"""
|
||||
Load display memory contents from byte data.
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ from typing import IO
|
|||
from . import Image, ImageFile
|
||||
from ._binary import i16le as i16
|
||||
from ._binary import o16le as o16
|
||||
from ._typing import Buffer
|
||||
|
||||
#
|
||||
# read MSP files
|
||||
|
|
@ -112,7 +113,7 @@ class MspDecoder(ImageFile.PyDecoder):
|
|||
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
|
||||
img = io.BytesIO()
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ TYPE_CHECKING = False
|
|||
if TYPE_CHECKING:
|
||||
from typing import IO
|
||||
|
||||
from ._typing import Buffer
|
||||
|
||||
_DictBase = collections.UserDict[str | bytes, Any]
|
||||
else:
|
||||
_DictBase = collections.UserDict
|
||||
|
|
@ -316,11 +318,11 @@ class PdfBinary:
|
|||
|
||||
|
||||
class PdfStream:
|
||||
def __init__(self, dictionary: PdfDict, buf: bytes) -> None:
|
||||
def __init__(self, dictionary: PdfDict, buf: Buffer) -> None:
|
||||
self.dictionary = dictionary
|
||||
self.buf = buf
|
||||
|
||||
def decode(self) -> bytes:
|
||||
def decode(self) -> Buffer:
|
||||
try:
|
||||
filter = self.dictionary[b"Filter"]
|
||||
except KeyError:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ from . import Image, ImageFile
|
|||
from ._binary import i16be as i16
|
||||
from ._binary import o8
|
||||
from ._binary import o32le as o32
|
||||
from ._typing import Buffer
|
||||
|
||||
#
|
||||
# --------------------------------------------------------------------
|
||||
|
|
@ -169,12 +170,12 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
|
|||
|
||||
return self.fd.read(ImageFile.SAFEBLOCK)
|
||||
|
||||
def _find_comment_end(self, block: bytes, start: int = 0) -> int:
|
||||
def _find_comment_end(self, block: bytes | bytearray, start: int = 0) -> int:
|
||||
a = block.find(b"\n", start)
|
||||
b = block.find(b"\r", start)
|
||||
return min(a, b) if a * b > 0 else max(a, b) # lowest nonnegative index (or -1)
|
||||
|
||||
def _ignore_comments(self, block: bytes) -> bytes:
|
||||
def _ignore_comments(self, block: bytes | bytearray) -> bytes | bytearray:
|
||||
if self._comment_spans:
|
||||
# Finish current comment
|
||||
while block:
|
||||
|
|
@ -216,6 +217,7 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
|
|||
data = bytearray()
|
||||
total_bytes = self.state.xsize * self.state.ysize
|
||||
|
||||
block: bytes | bytearray
|
||||
while len(data) != total_bytes:
|
||||
block = self._read_block() # read next block
|
||||
if not block:
|
||||
|
|
@ -241,9 +243,9 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
|
|||
bands = Image.getmodebands(self.mode)
|
||||
total_bytes = self.state.xsize * self.state.ysize * bands * out_byte_count
|
||||
|
||||
half_token = b""
|
||||
half_token: bytes | bytearray = b""
|
||||
while len(data) != total_bytes:
|
||||
block = self._read_block() # read next block
|
||||
block: bytes | bytearray = self._read_block() # read next block
|
||||
if not block:
|
||||
if half_token:
|
||||
block = bytearray(b" ") # flush half_token
|
||||
|
|
@ -284,7 +286,7 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
|
|||
break
|
||||
return data
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
self._comment_spans = False
|
||||
if self.mode == "1":
|
||||
data = self._decode_bitonal()
|
||||
|
|
@ -300,7 +302,7 @@ class PpmPlainDecoder(ImageFile.PyDecoder):
|
|||
class PpmDecoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
|
||||
data = bytearray()
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from . import Image, ImageFile
|
|||
from ._binary import i32be as i32
|
||||
from ._binary import o8
|
||||
from ._binary import o32be as o32
|
||||
from ._typing import Buffer
|
||||
|
||||
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
|
|
@ -51,7 +52,7 @@ class QoiDecoder(ImageFile.PyDecoder):
|
|||
hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64
|
||||
self._previously_seen_pixels[hash_value] = value
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
|
||||
self._previously_seen_pixels = {}
|
||||
|
|
@ -151,7 +152,7 @@ class QoiEncoder(ImageFile.PyEncoder):
|
|||
result -= 256
|
||||
return result
|
||||
|
||||
def encode(self, bufsize: int) -> tuple[int, int, bytes]:
|
||||
def encode(self, bufsize: int) -> tuple[int, int, bytearray]:
|
||||
assert self.im is not None
|
||||
|
||||
self._previously_seen_pixels = {0: (0, 0, 0, 0)}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from typing import IO
|
|||
from . import Image, ImageFile
|
||||
from ._binary import i16be as i16
|
||||
from ._binary import o8
|
||||
from ._typing import Buffer
|
||||
|
||||
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
|
|
@ -198,7 +199,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
class SGI16Decoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
assert self.im is not None
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import re
|
|||
|
||||
from . import Image, ImageFile, ImagePalette
|
||||
from ._binary import o8
|
||||
from ._typing import Buffer
|
||||
|
||||
# XPM header
|
||||
xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)')
|
||||
|
|
@ -118,7 +119,7 @@ class XpmImageFile(ImageFile.ImageFile):
|
|||
class XpmDecoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
def decode(self, buffer: Buffer | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
|
||||
data = bytearray()
|
||||
|
|
|
|||
|
|
@ -21,10 +21,13 @@ if sys.version_info >= (3, 13):
|
|||
else:
|
||||
CapsuleType = object
|
||||
|
||||
if sys.version_info >= (3, 12):
|
||||
from collections.abc import Buffer
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Buffer
|
||||
else:
|
||||
Buffer = Any
|
||||
if sys.version_info >= (3, 12):
|
||||
from collections.abc import Buffer
|
||||
else:
|
||||
Buffer = Any
|
||||
|
||||
|
||||
_Ink = float | tuple[int, ...] | str
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user