mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Added type hints
This commit is contained in:
parent
8f62fbdf44
commit
c85eb0cae5
|
@ -424,8 +424,10 @@ class TestFilePng:
|
||||||
im = roundtrip(im, pnginfo=info)
|
im = roundtrip(im, pnginfo=info)
|
||||||
assert im.info == {"spam": "Eggs", "eggs": "Spam"}
|
assert im.info == {"spam": "Eggs", "eggs": "Spam"}
|
||||||
assert im.text == {"spam": "Eggs", "eggs": "Spam"}
|
assert im.text == {"spam": "Eggs", "eggs": "Spam"}
|
||||||
|
assert isinstance(im.text["spam"], PngImagePlugin.iTXt)
|
||||||
assert im.text["spam"].lang == "en"
|
assert im.text["spam"].lang == "en"
|
||||||
assert im.text["spam"].tkey == "Spam"
|
assert im.text["spam"].tkey == "Spam"
|
||||||
|
assert isinstance(im.text["eggs"], PngImagePlugin.iTXt)
|
||||||
assert im.text["eggs"].lang == "en"
|
assert im.text["eggs"].lang == "en"
|
||||||
assert im.text["eggs"].tkey == "Eggs"
|
assert im.text["eggs"].tkey == "Eggs"
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import struct
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import warnings
|
import warnings
|
||||||
from collections.abc import Callable, MutableMapping, Sequence
|
from collections.abc import Callable, Iterator, MutableMapping, Sequence
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
from typing import (
|
from typing import (
|
||||||
|
@ -744,11 +744,11 @@ class Image:
|
||||||
new["shape"], new["typestr"] = _conv_type_shape(self)
|
new["shape"], new["typestr"] = _conv_type_shape(self)
|
||||||
return new
|
return new
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self) -> list[Any]:
|
||||||
im_data = self.tobytes() # load image first
|
im_data = self.tobytes() # load image first
|
||||||
return [self.info, self.mode, self.size, self.getpalette(), im_data]
|
return [self.info, self.mode, self.size, self.getpalette(), im_data]
|
||||||
|
|
||||||
def __setstate__(self, state) -> None:
|
def __setstate__(self, state: list[Any]) -> None:
|
||||||
Image.__init__(self)
|
Image.__init__(self)
|
||||||
info, mode, size, palette, data = state
|
info, mode, size, palette, data = state
|
||||||
self.info = info
|
self.info = info
|
||||||
|
@ -1683,7 +1683,9 @@ class Image:
|
||||||
x, y = self.im.getprojection()
|
x, y = self.im.getprojection()
|
||||||
return list(x), list(y)
|
return list(x), list(y)
|
||||||
|
|
||||||
def histogram(self, mask: Image | None = None, extrema=None) -> list[int]:
|
def histogram(
|
||||||
|
self, mask: Image | None = None, extrema: tuple[float, float] | None = None
|
||||||
|
) -> list[int]:
|
||||||
"""
|
"""
|
||||||
Returns a histogram for the image. The histogram is returned as a
|
Returns a histogram for the image. The histogram is returned as a
|
||||||
list of pixel counts, one for each pixel value in the source
|
list of pixel counts, one for each pixel value in the source
|
||||||
|
@ -1709,12 +1711,14 @@ class Image:
|
||||||
mask.load()
|
mask.load()
|
||||||
return self.im.histogram((0, 0), mask.im)
|
return self.im.histogram((0, 0), mask.im)
|
||||||
if self.mode in ("I", "F"):
|
if self.mode in ("I", "F"):
|
||||||
if extrema is None:
|
return self.im.histogram(
|
||||||
extrema = self.getextrema()
|
extrema if extrema is not None else self.getextrema()
|
||||||
return self.im.histogram(extrema)
|
)
|
||||||
return self.im.histogram()
|
return self.im.histogram()
|
||||||
|
|
||||||
def entropy(self, mask: Image | None = None, extrema=None):
|
def entropy(
|
||||||
|
self, mask: Image | None = None, extrema: tuple[float, float] | None = None
|
||||||
|
) -> float:
|
||||||
"""
|
"""
|
||||||
Calculates and returns the entropy for the image.
|
Calculates and returns the entropy for the image.
|
||||||
|
|
||||||
|
@ -1735,9 +1739,9 @@ class Image:
|
||||||
mask.load()
|
mask.load()
|
||||||
return self.im.entropy((0, 0), mask.im)
|
return self.im.entropy((0, 0), mask.im)
|
||||||
if self.mode in ("I", "F"):
|
if self.mode in ("I", "F"):
|
||||||
if extrema is None:
|
return self.im.entropy(
|
||||||
extrema = self.getextrema()
|
extrema if extrema is not None else self.getextrema()
|
||||||
return self.im.entropy(extrema)
|
)
|
||||||
return self.im.entropy()
|
return self.im.entropy()
|
||||||
|
|
||||||
def paste(
|
def paste(
|
||||||
|
@ -3881,7 +3885,7 @@ class Exif(_ExifBase):
|
||||||
# returns a dict with any single item tuples/lists as individual values
|
# returns a dict with any single item tuples/lists as individual values
|
||||||
return {k: self._fixup(v) for k, v in src_dict.items()}
|
return {k: self._fixup(v) for k, v in src_dict.items()}
|
||||||
|
|
||||||
def _get_ifd_dict(self, offset: int, group=None):
|
def _get_ifd_dict(self, offset: int, group: int | None = None):
|
||||||
try:
|
try:
|
||||||
# an offset pointer to the location of the nested embedded IFD.
|
# an offset pointer to the location of the nested embedded IFD.
|
||||||
# It should be a long, but may be corrupted.
|
# It should be a long, but may be corrupted.
|
||||||
|
@ -4136,7 +4140,7 @@ class Exif(_ExifBase):
|
||||||
else:
|
else:
|
||||||
del self._data[tag]
|
del self._data[tag]
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self) -> Iterator[int]:
|
||||||
keys = set(self._data)
|
keys = set(self._data)
|
||||||
if self._info is not None:
|
if self._info is not None:
|
||||||
keys.update(self._info)
|
keys.update(self._info)
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import AnyStr, BinaryIO
|
from typing import Any, AnyStr, BinaryIO
|
||||||
|
|
||||||
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
|
||||||
from ._typing import Coords, StrOrBytesPath
|
from ._typing import Coords, StrOrBytesPath
|
||||||
|
@ -111,7 +111,7 @@ class Draw:
|
||||||
(xoffset, yoffset) = offset
|
(xoffset, yoffset) = offset
|
||||||
self.transform = (1, 0, xoffset, 0, 1, yoffset)
|
self.transform = (1, 0, xoffset, 0, 1, yoffset)
|
||||||
|
|
||||||
def arc(self, xy: Coords, start, end, *options) -> None:
|
def arc(self, xy: Coords, start, end, *options: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Draws an arc (a portion of a circle outline) between the start and end
|
Draws an arc (a portion of a circle outline) between the start and end
|
||||||
angles, inside the given bounding box.
|
angles, inside the given bounding box.
|
||||||
|
@ -120,7 +120,7 @@ class Draw:
|
||||||
"""
|
"""
|
||||||
self.render("arc", xy, start, end, *options)
|
self.render("arc", xy, start, end, *options)
|
||||||
|
|
||||||
def chord(self, xy: Coords, start, end, *options) -> None:
|
def chord(self, xy: Coords, start, end, *options: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points
|
Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points
|
||||||
with a straight line.
|
with a straight line.
|
||||||
|
@ -129,7 +129,7 @@ class Draw:
|
||||||
"""
|
"""
|
||||||
self.render("chord", xy, start, end, *options)
|
self.render("chord", xy, start, end, *options)
|
||||||
|
|
||||||
def ellipse(self, xy: Coords, *options) -> None:
|
def ellipse(self, xy: Coords, *options: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Draws an ellipse inside the given bounding box.
|
Draws an ellipse inside the given bounding box.
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ class Draw:
|
||||||
"""
|
"""
|
||||||
self.render("ellipse", xy, *options)
|
self.render("ellipse", xy, *options)
|
||||||
|
|
||||||
def line(self, xy: Coords, *options) -> None:
|
def line(self, xy: Coords, *options: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Draws a line between the coordinates in the ``xy`` list.
|
Draws a line between the coordinates in the ``xy`` list.
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ class Draw:
|
||||||
"""
|
"""
|
||||||
self.render("line", xy, *options)
|
self.render("line", xy, *options)
|
||||||
|
|
||||||
def pieslice(self, xy: Coords, start, end, *options) -> None:
|
def pieslice(self, xy: Coords, start, end, *options: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Same as arc, but also draws straight lines between the end points and the
|
Same as arc, but also draws straight lines between the end points and the
|
||||||
center of the bounding box.
|
center of the bounding box.
|
||||||
|
@ -154,7 +154,7 @@ class Draw:
|
||||||
"""
|
"""
|
||||||
self.render("pieslice", xy, start, end, *options)
|
self.render("pieslice", xy, start, end, *options)
|
||||||
|
|
||||||
def polygon(self, xy: Coords, *options) -> None:
|
def polygon(self, xy: Coords, *options: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Draws a polygon.
|
Draws a polygon.
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import re
|
||||||
import struct
|
import struct
|
||||||
import warnings
|
import warnings
|
||||||
import zlib
|
import zlib
|
||||||
|
from collections.abc import Callable
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import IO, TYPE_CHECKING, Any, NamedTuple, NoReturn
|
from typing import IO, TYPE_CHECKING, Any, NamedTuple, NoReturn
|
||||||
|
|
||||||
|
@ -135,7 +136,7 @@ class Blend(IntEnum):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _safe_zlib_decompress(s):
|
def _safe_zlib_decompress(s: bytes) -> bytes:
|
||||||
dobj = zlib.decompressobj()
|
dobj = zlib.decompressobj()
|
||||||
plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
|
plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
|
||||||
if dobj.unconsumed_tail:
|
if dobj.unconsumed_tail:
|
||||||
|
@ -783,7 +784,7 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
self._mode = self.png.im_mode
|
self._mode = self.png.im_mode
|
||||||
self._size = self.png.im_size
|
self._size = self.png.im_size
|
||||||
self.info = self.png.im_info
|
self.info = self.png.im_info
|
||||||
self._text = None
|
self._text: dict[str, str | iTXt] | None = None
|
||||||
self.tile = self.png.im_tile
|
self.tile = self.png.im_tile
|
||||||
self.custom_mimetype = self.png.im_custom_mimetype
|
self.custom_mimetype = self.png.im_custom_mimetype
|
||||||
self.n_frames = self.png.im_n_frames or 1
|
self.n_frames = self.png.im_n_frames or 1
|
||||||
|
@ -810,7 +811,7 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
self.is_animated = self.n_frames > 1
|
self.is_animated = self.n_frames > 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def text(self) -> dict[str, str | iTXt]:
|
||||||
# experimental
|
# experimental
|
||||||
if self._text is None:
|
if self._text is None:
|
||||||
# iTxt, tEXt and zTXt chunks may appear at the end of the file
|
# iTxt, tEXt and zTXt chunks may appear at the end of the file
|
||||||
|
@ -822,6 +823,7 @@ class PngImageFile(ImageFile.ImageFile):
|
||||||
self.load()
|
self.load()
|
||||||
if self.is_animated:
|
if self.is_animated:
|
||||||
self.seek(frame)
|
self.seek(frame)
|
||||||
|
assert self._text is not None
|
||||||
return self._text
|
return self._text
|
||||||
|
|
||||||
def verify(self) -> None:
|
def verify(self) -> None:
|
||||||
|
@ -1105,7 +1107,7 @@ def putchunk(fp: IO[bytes], cid: bytes, *data: bytes) -> None:
|
||||||
class _idat:
|
class _idat:
|
||||||
# wrap output from the encoder in IDAT chunks
|
# wrap output from the encoder in IDAT chunks
|
||||||
|
|
||||||
def __init__(self, fp, chunk) -> None:
|
def __init__(self, fp: IO[bytes], chunk: Callable[..., None]) -> None:
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
self.chunk = chunk
|
self.chunk = chunk
|
||||||
|
|
||||||
|
@ -1116,7 +1118,7 @@ class _idat:
|
||||||
class _fdat:
|
class _fdat:
|
||||||
# wrap encoder output in fdAT chunks
|
# wrap encoder output in fdAT chunks
|
||||||
|
|
||||||
def __init__(self, fp: IO[bytes], chunk, seq_num: int) -> None:
|
def __init__(self, fp: IO[bytes], chunk: Callable[..., None], seq_num: int) -> None:
|
||||||
self.fp = fp
|
self.fp = fp
|
||||||
self.chunk = chunk
|
self.chunk = chunk
|
||||||
self.seq_num = seq_num
|
self.seq_num = seq_num
|
||||||
|
@ -1135,7 +1137,7 @@ class _Frame(NamedTuple):
|
||||||
def _write_multiple_frames(
|
def _write_multiple_frames(
|
||||||
im: Image.Image,
|
im: Image.Image,
|
||||||
fp: IO[bytes],
|
fp: IO[bytes],
|
||||||
chunk,
|
chunk: Callable[..., None],
|
||||||
mode: str,
|
mode: str,
|
||||||
rawmode: str,
|
rawmode: str,
|
||||||
default_image: Image.Image | None,
|
default_image: Image.Image | None,
|
||||||
|
@ -1275,7 +1277,11 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||||
|
|
||||||
|
|
||||||
def _save(
|
def _save(
|
||||||
im: Image.Image, fp, filename: str | bytes, chunk=putchunk, save_all: bool = False
|
im: Image.Image,
|
||||||
|
fp: IO[bytes],
|
||||||
|
filename: str | bytes,
|
||||||
|
chunk: Callable[..., None] = putchunk,
|
||||||
|
save_all: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
# save an image to disk (called by the save method)
|
# save an image to disk (called by the save method)
|
||||||
|
|
||||||
|
@ -1483,22 +1489,16 @@ def _save(
|
||||||
|
|
||||||
def getchunks(im: Image.Image, **params: Any) -> list[tuple[bytes, bytes, bytes]]:
|
def getchunks(im: Image.Image, **params: Any) -> list[tuple[bytes, bytes, bytes]]:
|
||||||
"""Return a list of PNG chunks representing this image."""
|
"""Return a list of PNG chunks representing this image."""
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
class collector:
|
chunks = []
|
||||||
data = []
|
|
||||||
|
|
||||||
def write(self, data: bytes) -> None:
|
def append(fp: IO[bytes], cid: bytes, *data: bytes) -> None:
|
||||||
pass
|
|
||||||
|
|
||||||
def append(self, chunk: tuple[bytes, bytes, bytes]) -> None:
|
|
||||||
self.data.append(chunk)
|
|
||||||
|
|
||||||
def append(fp: collector, cid: bytes, *data: bytes) -> None:
|
|
||||||
byte_data = b"".join(data)
|
byte_data = b"".join(data)
|
||||||
crc = o32(_crc32(byte_data, _crc32(cid)))
|
crc = o32(_crc32(byte_data, _crc32(cid)))
|
||||||
fp.append((cid, byte_data, crc))
|
chunks.append((cid, byte_data, crc))
|
||||||
|
|
||||||
fp = collector()
|
fp = BytesIO()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
im.encoderinfo = params
|
im.encoderinfo = params
|
||||||
|
@ -1506,7 +1506,7 @@ def getchunks(im: Image.Image, **params: Any) -> list[tuple[bytes, bytes, bytes]
|
||||||
finally:
|
finally:
|
||||||
del im.encoderinfo
|
del im.encoderinfo
|
||||||
|
|
||||||
return fp.data
|
return chunks
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
|
@ -1020,7 +1020,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
||||||
.. deprecated:: 3.0.0
|
.. deprecated:: 3.0.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._legacy_api = True
|
self._legacy_api = True
|
||||||
|
|
||||||
|
@ -1142,13 +1142,15 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self._seek(0)
|
self._seek(0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def n_frames(self):
|
def n_frames(self) -> int:
|
||||||
if self._n_frames is None:
|
current_n_frames = self._n_frames
|
||||||
|
if current_n_frames is None:
|
||||||
current = self.tell()
|
current = self.tell()
|
||||||
self._seek(len(self._frame_pos))
|
self._seek(len(self._frame_pos))
|
||||||
while self._n_frames is None:
|
while self._n_frames is None:
|
||||||
self._seek(self.tell() + 1)
|
self._seek(self.tell() + 1)
|
||||||
self.seek(current)
|
self.seek(current)
|
||||||
|
assert self._n_frames is not None
|
||||||
return self._n_frames
|
return self._n_frames
|
||||||
|
|
||||||
def seek(self, frame: int) -> None:
|
def seek(self, frame: int) -> None:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user