mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Merge pull request #8270 from radarhere/type_hint
This commit is contained in:
commit
4df4df2a18
|
@ -154,7 +154,7 @@ class TestFileJpeg:
|
|||
assert k > 0.9
|
||||
|
||||
def test_rgb(self) -> None:
|
||||
def getchannels(im: JpegImagePlugin.JpegImageFile) -> tuple[int, int, int]:
|
||||
def getchannels(im: JpegImagePlugin.JpegImageFile) -> tuple[int, ...]:
|
||||
return tuple(v[0] for v in im.layer)
|
||||
|
||||
im = hopper()
|
||||
|
|
|
@ -99,7 +99,7 @@ class TestImage:
|
|||
im = Image.new("L", (100, 100))
|
||||
|
||||
p = Pretty()
|
||||
im._repr_pretty_(p, None)
|
||||
im._repr_pretty_(p, False)
|
||||
assert p.pretty_output == "<PIL.Image.Image image mode=L size=100x100>"
|
||||
|
||||
def test_open_formats(self) -> None:
|
||||
|
|
|
@ -185,6 +185,14 @@ Plugin reference
|
|||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`~PIL.MpoImagePlugin` Module
|
||||
----------------------------------
|
||||
|
||||
.. automodule:: PIL.MpoImagePlugin
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
:mod:`~PIL.MspImagePlugin` Module
|
||||
---------------------------------
|
||||
|
||||
|
|
|
@ -65,16 +65,24 @@ def has_ghostscript() -> bool:
|
|||
return gs_binary is not False
|
||||
|
||||
|
||||
def Ghostscript(tile, size, fp, scale=1, transparency: bool = False) -> Image.Image:
|
||||
def Ghostscript(
|
||||
tile: list[ImageFile._Tile],
|
||||
size: tuple[int, int],
|
||||
fp: IO[bytes],
|
||||
scale: int = 1,
|
||||
transparency: bool = False,
|
||||
) -> Image.Image:
|
||||
"""Render an image using Ghostscript"""
|
||||
global gs_binary
|
||||
if not has_ghostscript():
|
||||
msg = "Unable to locate Ghostscript on paths"
|
||||
raise OSError(msg)
|
||||
assert isinstance(gs_binary, str)
|
||||
|
||||
# Unpack decoder tile
|
||||
decoder, tile, offset, data = tile[0]
|
||||
length, bbox = data
|
||||
args = tile[0].args
|
||||
assert isinstance(args, tuple)
|
||||
length, bbox = args
|
||||
|
||||
# Hack to support hi-res rendering
|
||||
scale = int(scale) or 1
|
||||
|
@ -227,7 +235,11 @@ class EpsImageFile(ImageFile.ImageFile):
|
|||
# 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))]
|
||||
self.tile = [
|
||||
ImageFile._Tile(
|
||||
"eps", (0, 0) + self.size, offset, (length, box)
|
||||
)
|
||||
]
|
||||
except Exception:
|
||||
pass
|
||||
return True
|
||||
|
|
|
@ -220,7 +220,7 @@ if hasattr(core, "DEFAULT_STRATEGY"):
|
|||
if TYPE_CHECKING:
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from . import ImageFile, ImagePalette
|
||||
from . import ImageFile, ImagePalette, TiffImagePlugin
|
||||
from ._typing import NumpyArray, StrOrBytesPath, TypeGuard
|
||||
ID: list[str] = []
|
||||
OPEN: dict[
|
||||
|
@ -676,7 +676,7 @@ class Image:
|
|||
id(self),
|
||||
)
|
||||
|
||||
def _repr_pretty_(self, p, cycle) -> None:
|
||||
def _repr_pretty_(self, p, cycle: bool) -> None:
|
||||
"""IPython plain text display support"""
|
||||
|
||||
# Same as __repr__ but without unpredictable id(self),
|
||||
|
@ -1551,6 +1551,7 @@ class Image:
|
|||
ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset))
|
||||
ifd1 = exif.get_ifd(ExifTags.IFD.IFD1)
|
||||
if ifd1 and ifd1.get(513):
|
||||
assert exif._info is not None
|
||||
ifds.append((ifd1, exif._info.next))
|
||||
|
||||
offset = None
|
||||
|
@ -1560,12 +1561,13 @@ class Image:
|
|||
offset = current_offset
|
||||
|
||||
fp = self.fp
|
||||
thumbnail_offset = ifd.get(513)
|
||||
if thumbnail_offset is not None:
|
||||
thumbnail_offset += getattr(self, "_exif_offset", 0)
|
||||
self.fp.seek(thumbnail_offset)
|
||||
data = self.fp.read(ifd.get(514))
|
||||
fp = io.BytesIO(data)
|
||||
if ifd is not None:
|
||||
thumbnail_offset = ifd.get(513)
|
||||
if thumbnail_offset is not None:
|
||||
thumbnail_offset += getattr(self, "_exif_offset", 0)
|
||||
self.fp.seek(thumbnail_offset)
|
||||
data = self.fp.read(ifd.get(514))
|
||||
fp = io.BytesIO(data)
|
||||
|
||||
with open(fp) as im:
|
||||
from . import TiffImagePlugin
|
||||
|
@ -3869,14 +3871,14 @@ class Exif(_ExifBase):
|
|||
bigtiff = False
|
||||
_loaded = False
|
||||
|
||||
def __init__(self):
|
||||
self._data = {}
|
||||
self._hidden_data = {}
|
||||
self._ifds = {}
|
||||
self._info = None
|
||||
self._loaded_exif = None
|
||||
def __init__(self) -> None:
|
||||
self._data: dict[int, Any] = {}
|
||||
self._hidden_data: dict[int, Any] = {}
|
||||
self._ifds: dict[int, dict[int, Any]] = {}
|
||||
self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None
|
||||
self._loaded_exif: bytes | None = None
|
||||
|
||||
def _fixup(self, value):
|
||||
def _fixup(self, value: Any) -> Any:
|
||||
try:
|
||||
if len(value) == 1 and isinstance(value, tuple):
|
||||
return value[0]
|
||||
|
@ -3884,24 +3886,26 @@ class Exif(_ExifBase):
|
|||
pass
|
||||
return value
|
||||
|
||||
def _fixup_dict(self, src_dict):
|
||||
def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]:
|
||||
# Helper function
|
||||
# returns a dict with any single item tuples/lists as individual values
|
||||
return {k: self._fixup(v) for k, v in src_dict.items()}
|
||||
|
||||
def _get_ifd_dict(self, offset: int, group: int | None = None):
|
||||
def _get_ifd_dict(
|
||||
self, offset: int, group: int | None = None
|
||||
) -> dict[int, Any] | None:
|
||||
try:
|
||||
# an offset pointer to the location of the nested embedded IFD.
|
||||
# It should be a long, but may be corrupted.
|
||||
self.fp.seek(offset)
|
||||
except (KeyError, TypeError):
|
||||
pass
|
||||
return None
|
||||
else:
|
||||
from . import TiffImagePlugin
|
||||
|
||||
info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group)
|
||||
info.load(self.fp)
|
||||
return self._fixup_dict(info)
|
||||
return self._fixup_dict(dict(info))
|
||||
|
||||
def _get_head(self) -> bytes:
|
||||
version = b"\x2B" if self.bigtiff else b"\x2A"
|
||||
|
@ -3966,7 +3970,7 @@ class Exif(_ExifBase):
|
|||
self.fp.seek(offset)
|
||||
self._info.load(self.fp)
|
||||
|
||||
def _get_merged_dict(self):
|
||||
def _get_merged_dict(self) -> dict[int, Any]:
|
||||
merged_dict = dict(self)
|
||||
|
||||
# get EXIF extension
|
||||
|
@ -4124,7 +4128,7 @@ class Exif(_ExifBase):
|
|||
keys.update(self._info)
|
||||
return len(keys)
|
||||
|
||||
def __getitem__(self, tag: int):
|
||||
def __getitem__(self, tag: int) -> Any:
|
||||
if self._info is not None and tag not in self._data and tag in self._info:
|
||||
self._data[tag] = self._fixup(self._info[tag])
|
||||
del self._info[tag]
|
||||
|
@ -4133,7 +4137,7 @@ class Exif(_ExifBase):
|
|||
def __contains__(self, tag: object) -> bool:
|
||||
return tag in self._data or (self._info is not None and tag in self._info)
|
||||
|
||||
def __setitem__(self, tag: int, value) -> None:
|
||||
def __setitem__(self, tag: int, value: Any) -> None:
|
||||
if self._info is not None and tag in self._info:
|
||||
del self._info[tag]
|
||||
self._data[tag] = value
|
||||
|
|
|
@ -86,7 +86,7 @@ def raise_oserror(error: int) -> OSError:
|
|||
raise _get_oserror(error, encoder=False)
|
||||
|
||||
|
||||
def _tilesort(t) -> int:
|
||||
def _tilesort(t: _Tile) -> int:
|
||||
# sort on offset
|
||||
return t[2]
|
||||
|
||||
|
@ -161,7 +161,7 @@ class ImageFile(Image.Image):
|
|||
return Image.MIME.get(self.format.upper())
|
||||
return None
|
||||
|
||||
def __setstate__(self, state) -> None:
|
||||
def __setstate__(self, state: list[Any]) -> None:
|
||||
self.tile = []
|
||||
super().__setstate__(state)
|
||||
|
||||
|
@ -525,7 +525,7 @@ class Parser:
|
|||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
def _save(im, fp, tile, bufsize: int = 0) -> None:
|
||||
def _save(im: Image.Image, fp: IO[bytes], tile, bufsize: int = 0) -> None:
|
||||
"""Helper to save image based on tile list
|
||||
|
||||
:param im: Image object.
|
||||
|
@ -554,7 +554,12 @@ def _save(im, fp, tile, bufsize: int = 0) -> None:
|
|||
|
||||
|
||||
def _encode_tile(
|
||||
im, fp: IO[bytes], tile: list[_Tile], bufsize: int, fh, exc=None
|
||||
im: Image.Image,
|
||||
fp: IO[bytes],
|
||||
tile: list[_Tile],
|
||||
bufsize: int,
|
||||
fh,
|
||||
exc: BaseException | None = None,
|
||||
) -> None:
|
||||
for encoder_name, extents, offset, args in tile:
|
||||
if offset > 0:
|
||||
|
@ -664,7 +669,11 @@ class PyCodec:
|
|||
"""
|
||||
self.fd = fd
|
||||
|
||||
def setimage(self, im, extents=None):
|
||||
def setimage(
|
||||
self,
|
||||
im: Image.core.ImagingCore,
|
||||
extents: tuple[int, int, int, int] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Called from ImageFile to set the core output image for the codec
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ import subprocess
|
|||
import sys
|
||||
import tempfile
|
||||
import warnings
|
||||
from typing import IO, Any
|
||||
from typing import IO, TYPE_CHECKING, Any
|
||||
|
||||
from . import Image, ImageFile
|
||||
from ._binary import i16be as i16
|
||||
|
@ -51,6 +51,9 @@ from ._binary import o8
|
|||
from ._binary import o16be as o16
|
||||
from .JpegPresets import presets
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .MpoImagePlugin import MpoImageFile
|
||||
|
||||
#
|
||||
# Parser
|
||||
|
||||
|
@ -329,7 +332,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
format = "JPEG"
|
||||
format_description = "JPEG (ISO 10918)"
|
||||
|
||||
def _open(self):
|
||||
def _open(self) -> None:
|
||||
s = self.fp.read(3)
|
||||
|
||||
if not _accept(s):
|
||||
|
@ -342,13 +345,13 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
self._exif_offset = 0
|
||||
|
||||
# JPEG specifics (internal)
|
||||
self.layer = []
|
||||
self.huffman_dc = {}
|
||||
self.huffman_ac = {}
|
||||
self.quantization = {}
|
||||
self.app = {} # compatibility
|
||||
self.applist = []
|
||||
self.icclist = []
|
||||
self.layer: list[tuple[int, int, int, int]] = []
|
||||
self.huffman_dc: dict[Any, Any] = {}
|
||||
self.huffman_ac: dict[Any, Any] = {}
|
||||
self.quantization: dict[int, list[int]] = {}
|
||||
self.app: dict[str, bytes] = {} # compatibility
|
||||
self.applist: list[tuple[str, bytes]] = []
|
||||
self.icclist: list[bytes] = []
|
||||
|
||||
while True:
|
||||
i = s[0]
|
||||
|
@ -831,7 +834,9 @@ def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
|
||||
##
|
||||
# Factory for making JPEG and MPO instances
|
||||
def jpeg_factory(fp: IO[bytes] | None = None, filename: str | bytes | None = None):
|
||||
def jpeg_factory(
|
||||
fp: IO[bytes] | None = None, filename: str | bytes | None = None
|
||||
) -> JpegImageFile | MpoImageFile:
|
||||
im = JpegImageFile(fp, filename)
|
||||
try:
|
||||
mpheader = im._getmp()
|
||||
|
|
|
@ -40,7 +40,7 @@ import warnings
|
|||
import zlib
|
||||
from collections.abc import Callable
|
||||
from enum import IntEnum
|
||||
from typing import IO, TYPE_CHECKING, Any, NamedTuple, NoReturn
|
||||
from typing import IO, TYPE_CHECKING, Any, NamedTuple, NoReturn, cast
|
||||
|
||||
from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence
|
||||
from ._binary import i16be as i16
|
||||
|
@ -1223,7 +1223,11 @@ def _write_multiple_frames(
|
|||
if default_image:
|
||||
if im.mode != mode:
|
||||
im = im.convert(mode)
|
||||
ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
|
||||
ImageFile._save(
|
||||
im,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[("zip", (0, 0) + im.size, 0, rawmode)],
|
||||
)
|
||||
|
||||
seq_num = 0
|
||||
for frame, frame_data in enumerate(im_frames):
|
||||
|
@ -1258,14 +1262,14 @@ def _write_multiple_frames(
|
|||
# first frame must be in IDAT chunks for backwards compatibility
|
||||
ImageFile._save(
|
||||
im_frame,
|
||||
_idat(fp, chunk),
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[("zip", (0, 0) + im_frame.size, 0, rawmode)],
|
||||
)
|
||||
else:
|
||||
fdat_chunks = _fdat(fp, chunk, seq_num)
|
||||
ImageFile._save(
|
||||
im_frame,
|
||||
fdat_chunks,
|
||||
cast(IO[bytes], fdat_chunks),
|
||||
[("zip", (0, 0) + im_frame.size, 0, rawmode)],
|
||||
)
|
||||
seq_num = fdat_chunks.seq_num
|
||||
|
@ -1465,7 +1469,9 @@ def _save(
|
|||
)
|
||||
if single_im:
|
||||
ImageFile._save(
|
||||
single_im, _idat(fp, chunk), [("zip", (0, 0) + single_im.size, 0, rawmode)]
|
||||
single_im,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[("zip", (0, 0) + single_im.size, 0, rawmode)],
|
||||
)
|
||||
|
||||
if info:
|
||||
|
|
|
@ -288,8 +288,10 @@ def _accept(prefix: bytes) -> bool:
|
|||
return prefix[:4] in PREFIXES
|
||||
|
||||
|
||||
def _limit_rational(val, max_val):
|
||||
inv = abs(val) > 1
|
||||
def _limit_rational(
|
||||
val: float | Fraction | IFDRational, max_val: int
|
||||
) -> tuple[float, float]:
|
||||
inv = abs(float(val)) > 1
|
||||
n_d = IFDRational(1 / val if inv else val).limit_rational(max_val)
|
||||
return n_d[::-1] if inv else n_d
|
||||
|
||||
|
@ -792,7 +794,9 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
return value + b"\0"
|
||||
|
||||
@_register_loader(5, 8)
|
||||
def load_rational(self, data, legacy_api: bool = True):
|
||||
def load_rational(
|
||||
self, data: bytes, legacy_api: bool = True
|
||||
) -> tuple[tuple[int, int] | IFDRational, ...]:
|
||||
vals = self._unpack(f"{len(data) // 4}L", data)
|
||||
|
||||
def combine(a: int, b: int) -> tuple[int, int] | IFDRational:
|
||||
|
@ -801,7 +805,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
|
||||
|
||||
@_register_writer(5)
|
||||
def write_rational(self, *values) -> bytes:
|
||||
def write_rational(self, *values: IFDRational) -> bytes:
|
||||
return b"".join(
|
||||
self._pack("2L", *_limit_rational(frac, 2**32 - 1)) for frac in values
|
||||
)
|
||||
|
@ -828,7 +832,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
|
||||
|
||||
@_register_writer(10)
|
||||
def write_signed_rational(self, *values) -> bytes:
|
||||
def write_signed_rational(self, *values: IFDRational) -> bytes:
|
||||
return b"".join(
|
||||
self._pack("2l", *_limit_signed_rational(frac, 2**31 - 1, -(2**31)))
|
||||
for frac in values
|
||||
|
|
Loading…
Reference in New Issue
Block a user