mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Merge pull request #8046 from srittau/type-annotations
Add various type annotations
This commit is contained in:
commit
5bacce9dc2
|
@ -124,8 +124,8 @@ def test_fastpath_translate() -> None:
|
|||
def test_center() -> None:
|
||||
im = hopper()
|
||||
rotate(im, im.mode, 45, center=(0, 0))
|
||||
rotate(im, im.mode, 45, translate=(im.size[0] / 2, 0))
|
||||
rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] / 2, 0))
|
||||
rotate(im, im.mode, 45, translate=(im.size[0] // 2, 0))
|
||||
rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0] // 2, 0))
|
||||
|
||||
|
||||
def test_rotate_no_fill() -> None:
|
||||
|
|
|
@ -144,10 +144,12 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
.. py:currentmodule:: PIL.Image
|
||||
|
||||
.. data:: Resampling.NEAREST
|
||||
:noindex:
|
||||
|
||||
Pick one nearest pixel from the input image. Ignore all other input pixels.
|
||||
|
||||
.. data:: Resampling.BOX
|
||||
:noindex:
|
||||
|
||||
Each pixel of source image contributes to one pixel of the
|
||||
destination image with identical weights.
|
||||
|
@ -158,6 +160,7 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
.. versionadded:: 3.4.0
|
||||
|
||||
.. data:: Resampling.BILINEAR
|
||||
:noindex:
|
||||
|
||||
For resize calculate the output pixel value using linear interpolation
|
||||
on all pixels that may contribute to the output value.
|
||||
|
@ -165,6 +168,7 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
in the input image is used.
|
||||
|
||||
.. data:: Resampling.HAMMING
|
||||
:noindex:
|
||||
|
||||
Produces a sharper image than :data:`Resampling.BILINEAR`, doesn't have
|
||||
dislocations on local level like with :data:`Resampling.BOX`.
|
||||
|
@ -174,6 +178,7 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
.. versionadded:: 3.4.0
|
||||
|
||||
.. data:: Resampling.BICUBIC
|
||||
:noindex:
|
||||
|
||||
For resize calculate the output pixel value using cubic interpolation
|
||||
on all pixels that may contribute to the output value.
|
||||
|
@ -181,6 +186,7 @@ pixel, the Python Imaging Library provides different resampling *filters*.
|
|||
in the input image is used.
|
||||
|
||||
.. data:: Resampling.LANCZOS
|
||||
:noindex:
|
||||
|
||||
Calculate the output pixel value using a high-quality Lanczos filter (a
|
||||
truncated sinc) on all pixels that may contribute to the output value.
|
||||
|
|
|
@ -78,8 +78,6 @@ Constructing images
|
|||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. autofunction:: new
|
||||
.. autoclass:: SupportsArrayInterface
|
||||
:show-inheritance:
|
||||
.. autofunction:: fromarray
|
||||
.. autofunction:: frombytes
|
||||
.. autofunction:: frombuffer
|
||||
|
@ -365,6 +363,14 @@ Classes
|
|||
.. autoclass:: PIL.Image.ImagePointHandler
|
||||
.. autoclass:: PIL.Image.ImageTransformHandler
|
||||
|
||||
Protocols
|
||||
---------
|
||||
|
||||
.. autoclass:: SupportsArrayInterface
|
||||
:show-inheritance:
|
||||
.. autoclass:: SupportsGetData
|
||||
:show-inheritance:
|
||||
|
||||
Constants
|
||||
---------
|
||||
|
||||
|
@ -418,7 +424,6 @@ See :ref:`concept-filters` for details.
|
|||
.. autoclass:: Resampling
|
||||
:members:
|
||||
:undoc-members:
|
||||
:noindex:
|
||||
|
||||
Dither modes
|
||||
^^^^^^^^^^^^
|
||||
|
|
|
@ -503,6 +503,12 @@ def _getscaleoffset(expr):
|
|||
# Implementation wrapper
|
||||
|
||||
|
||||
class SupportsGetData(Protocol):
|
||||
def getdata(
|
||||
self,
|
||||
) -> tuple[Transform, Sequence[int]]: ...
|
||||
|
||||
|
||||
class Image:
|
||||
"""
|
||||
This class represents an image object. To create
|
||||
|
@ -1289,7 +1295,7 @@ class Image:
|
|||
return im.crop((x0, y0, x1, y1))
|
||||
|
||||
def draft(
|
||||
self, mode: str, size: tuple[int, int]
|
||||
self, mode: str | None, size: tuple[int, int]
|
||||
) -> tuple[str, tuple[int, int, float, float]] | None:
|
||||
"""
|
||||
Configures the image file loader so it returns a version of the
|
||||
|
@ -1709,7 +1715,12 @@ class Image:
|
|||
return self.im.entropy(extrema)
|
||||
return self.im.entropy()
|
||||
|
||||
def paste(self, im, box=None, mask=None) -> None:
|
||||
def paste(
|
||||
self,
|
||||
im: Image | str | float | tuple[float, ...],
|
||||
box: tuple[int, int, int, int] | tuple[int, int] | None = None,
|
||||
mask: Image | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
Pastes another image into this image. The box argument is either
|
||||
a 2-tuple giving the upper left corner, a 4-tuple defining the
|
||||
|
@ -1737,7 +1748,7 @@ class Image:
|
|||
See :py:meth:`~PIL.Image.Image.alpha_composite` if you want to
|
||||
combine images with respect to their alpha channels.
|
||||
|
||||
:param im: Source image or pixel value (integer or tuple).
|
||||
:param im: Source image or pixel value (integer, float or tuple).
|
||||
:param box: An optional 4-tuple giving the region to paste into.
|
||||
If a 2-tuple is used instead, it's treated as the upper left
|
||||
corner. If omitted or None, the source is pasted into the
|
||||
|
@ -2146,7 +2157,13 @@ class Image:
|
|||
min(self.size[1], math.ceil(box[3] + support_y)),
|
||||
)
|
||||
|
||||
def resize(self, size, resample=None, box=None, reducing_gap=None) -> Image:
|
||||
def resize(
|
||||
self,
|
||||
size: tuple[int, int],
|
||||
resample: int | None = None,
|
||||
box: tuple[float, float, float, float] | None = None,
|
||||
reducing_gap: float | None = None,
|
||||
) -> Image:
|
||||
"""
|
||||
Returns a resized copy of this image.
|
||||
|
||||
|
@ -2211,13 +2228,9 @@ class Image:
|
|||
msg = "reducing_gap must be 1.0 or greater"
|
||||
raise ValueError(msg)
|
||||
|
||||
size = tuple(size)
|
||||
|
||||
self.load()
|
||||
if box is None:
|
||||
box = (0, 0) + self.size
|
||||
else:
|
||||
box = tuple(box)
|
||||
|
||||
if self.size == size and box == (0, 0) + self.size:
|
||||
return self.copy()
|
||||
|
@ -2252,7 +2265,11 @@ class Image:
|
|||
|
||||
return self._new(self.im.resize(size, resample, box))
|
||||
|
||||
def reduce(self, factor, box=None):
|
||||
def reduce(
|
||||
self,
|
||||
factor: int | tuple[int, int],
|
||||
box: tuple[int, int, int, int] | None = None,
|
||||
) -> Image:
|
||||
"""
|
||||
Returns a copy of the image reduced ``factor`` times.
|
||||
If the size of the image is not dividable by ``factor``,
|
||||
|
@ -2270,8 +2287,6 @@ class Image:
|
|||
|
||||
if box is None:
|
||||
box = (0, 0) + self.size
|
||||
else:
|
||||
box = tuple(box)
|
||||
|
||||
if factor == (1, 1) and box == (0, 0) + self.size:
|
||||
return self.copy()
|
||||
|
@ -2287,13 +2302,13 @@ class Image:
|
|||
|
||||
def rotate(
|
||||
self,
|
||||
angle,
|
||||
resample=Resampling.NEAREST,
|
||||
expand=0,
|
||||
center=None,
|
||||
translate=None,
|
||||
fillcolor=None,
|
||||
):
|
||||
angle: float,
|
||||
resample: Resampling = Resampling.NEAREST,
|
||||
expand: int | bool = False,
|
||||
center: tuple[int, int] | None = None,
|
||||
translate: tuple[int, int] | None = None,
|
||||
fillcolor: float | tuple[float, ...] | str | None = None,
|
||||
) -> Image:
|
||||
"""
|
||||
Returns a rotated copy of this image. This method returns a
|
||||
copy of this image, rotated the given number of degrees counter
|
||||
|
@ -2600,7 +2615,12 @@ class Image:
|
|||
"""
|
||||
return 0
|
||||
|
||||
def thumbnail(self, size, resample=Resampling.BICUBIC, reducing_gap=2.0):
|
||||
def thumbnail(
|
||||
self,
|
||||
size: tuple[float, float],
|
||||
resample: Resampling = Resampling.BICUBIC,
|
||||
reducing_gap: float = 2.0,
|
||||
) -> None:
|
||||
"""
|
||||
Make this image into a thumbnail. This method modifies the
|
||||
image to contain a thumbnail version of itself, no larger than
|
||||
|
@ -2661,20 +2681,24 @@ class Image:
|
|||
|
||||
box = None
|
||||
if reducing_gap is not None:
|
||||
size = preserve_aspect_ratio()
|
||||
if size is None:
|
||||
preserved_size = preserve_aspect_ratio()
|
||||
if preserved_size is None:
|
||||
return
|
||||
size = preserved_size
|
||||
|
||||
res = self.draft(None, (size[0] * reducing_gap, size[1] * reducing_gap))
|
||||
res = self.draft(
|
||||
None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
|
||||
)
|
||||
if res is not None:
|
||||
box = res[1]
|
||||
if box is None:
|
||||
self.load()
|
||||
|
||||
# load() may have changed the size of the image
|
||||
size = preserve_aspect_ratio()
|
||||
if size is None:
|
||||
preserved_size = preserve_aspect_ratio()
|
||||
if preserved_size is None:
|
||||
return
|
||||
size = preserved_size
|
||||
|
||||
if self.size != size:
|
||||
im = self.resize(size, resample, box=box, reducing_gap=reducing_gap)
|
||||
|
@ -2690,12 +2714,12 @@ class Image:
|
|||
# instead of bloating the method docs, add a separate chapter.
|
||||
def transform(
|
||||
self,
|
||||
size,
|
||||
method,
|
||||
data=None,
|
||||
resample=Resampling.NEAREST,
|
||||
fill=1,
|
||||
fillcolor=None,
|
||||
size: tuple[int, int],
|
||||
method: Transform | ImageTransformHandler | SupportsGetData,
|
||||
data: Sequence[Any] | None = None,
|
||||
resample: int = Resampling.NEAREST,
|
||||
fill: int = 1,
|
||||
fillcolor: float | tuple[float, ...] | str | None = None,
|
||||
) -> Image:
|
||||
"""
|
||||
Transforms this image. This method creates a new image with the
|
||||
|
@ -2929,7 +2953,7 @@ class ImageTransformHandler:
|
|||
self,
|
||||
size: tuple[int, int],
|
||||
image: Image,
|
||||
**options: dict[str, str | int | tuple[int, ...] | list[int]],
|
||||
**options: Any,
|
||||
) -> Image:
|
||||
pass
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ from __future__ import annotations
|
|||
import math
|
||||
import numbers
|
||||
import struct
|
||||
from typing import TYPE_CHECKING, Sequence, cast
|
||||
from typing import TYPE_CHECKING, AnyStr, Sequence, cast
|
||||
|
||||
from . import Image, ImageColor
|
||||
from ._typing import Coords
|
||||
|
@ -95,7 +95,9 @@ class ImageDraw:
|
|||
if TYPE_CHECKING:
|
||||
from . import ImageFont
|
||||
|
||||
def getfont(self) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
|
||||
def getfont(
|
||||
self,
|
||||
) -> ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont:
|
||||
"""
|
||||
Get the current default font.
|
||||
|
||||
|
@ -120,14 +122,15 @@ class ImageDraw:
|
|||
self.font = ImageFont.load_default()
|
||||
return self.font
|
||||
|
||||
def _getfont(self, font_size: float | None):
|
||||
def _getfont(
|
||||
self, font_size: float | None
|
||||
) -> ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont:
|
||||
if font_size is not None:
|
||||
from . import ImageFont
|
||||
|
||||
font = ImageFont.load_default(font_size)
|
||||
return ImageFont.load_default(font_size)
|
||||
else:
|
||||
font = self.getfont()
|
||||
return font
|
||||
return self.getfont()
|
||||
|
||||
def _getink(self, ink, fill=None) -> tuple[int | None, int | None]:
|
||||
if ink is None and fill is None:
|
||||
|
@ -460,15 +463,13 @@ class ImageDraw:
|
|||
right[3] -= r + 1
|
||||
self.draw.draw_rectangle(right, ink, 1)
|
||||
|
||||
def _multiline_check(self, text) -> bool:
|
||||
def _multiline_check(self, text: AnyStr) -> bool:
|
||||
split_character = "\n" if isinstance(text, str) else b"\n"
|
||||
|
||||
return split_character in text
|
||||
|
||||
def _multiline_split(self, text) -> list[str | bytes]:
|
||||
split_character = "\n" if isinstance(text, str) else b"\n"
|
||||
|
||||
return text.split(split_character)
|
||||
def _multiline_split(self, text: AnyStr) -> list[AnyStr]:
|
||||
return text.split("\n" if isinstance(text, str) else b"\n")
|
||||
|
||||
def _multiline_spacing(self, font, spacing, stroke_width):
|
||||
return (
|
||||
|
@ -479,10 +480,15 @@ class ImageDraw:
|
|||
|
||||
def text(
|
||||
self,
|
||||
xy,
|
||||
text,
|
||||
xy: tuple[float, float],
|
||||
text: str,
|
||||
fill=None,
|
||||
font=None,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
anchor=None,
|
||||
spacing=4,
|
||||
align="left",
|
||||
|
@ -536,7 +542,7 @@ class ImageDraw:
|
|||
coord.append(int(xy[i]))
|
||||
start.append(math.modf(xy[i])[0])
|
||||
try:
|
||||
mask, offset = font.getmask2(
|
||||
mask, offset = font.getmask2( # type: ignore[union-attr,misc]
|
||||
text,
|
||||
mode,
|
||||
direction=direction,
|
||||
|
@ -552,7 +558,7 @@ class ImageDraw:
|
|||
coord = [coord[0] + offset[0], coord[1] + offset[1]]
|
||||
except AttributeError:
|
||||
try:
|
||||
mask = font.getmask(
|
||||
mask = font.getmask( # type: ignore[misc]
|
||||
text,
|
||||
mode,
|
||||
direction,
|
||||
|
@ -601,10 +607,15 @@ class ImageDraw:
|
|||
|
||||
def multiline_text(
|
||||
self,
|
||||
xy,
|
||||
text,
|
||||
xy: tuple[float, float],
|
||||
text: str,
|
||||
fill=None,
|
||||
font=None,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
anchor=None,
|
||||
spacing=4,
|
||||
align="left",
|
||||
|
@ -634,7 +645,7 @@ class ImageDraw:
|
|||
font = self._getfont(font_size)
|
||||
|
||||
widths = []
|
||||
max_width = 0
|
||||
max_width: float = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self._multiline_spacing(font, spacing, stroke_width)
|
||||
for line in lines:
|
||||
|
@ -688,15 +699,20 @@ class ImageDraw:
|
|||
|
||||
def textlength(
|
||||
self,
|
||||
text,
|
||||
font=None,
|
||||
text: str,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
embedded_color=False,
|
||||
*,
|
||||
font_size=None,
|
||||
):
|
||||
) -> float:
|
||||
"""Get the length of a given string, in pixels with 1/64 precision."""
|
||||
if self._multiline_check(text):
|
||||
msg = "can't measure length of multiline text"
|
||||
|
@ -788,7 +804,7 @@ class ImageDraw:
|
|||
font = self._getfont(font_size)
|
||||
|
||||
widths = []
|
||||
max_width = 0
|
||||
max_width: float = 0
|
||||
lines = self._multiline_split(text)
|
||||
line_spacing = self._multiline_spacing(font, spacing, stroke_width)
|
||||
for line in lines:
|
||||
|
|
|
@ -33,11 +33,16 @@ import sys
|
|||
import warnings
|
||||
from enum import IntEnum
|
||||
from io import BytesIO
|
||||
from typing import BinaryIO
|
||||
from typing import IO, TYPE_CHECKING, Any, BinaryIO
|
||||
|
||||
from . import Image
|
||||
from ._typing import StrOrBytesPath
|
||||
from ._util import is_directory, is_path
|
||||
from ._util import is_path
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import ImageFile
|
||||
from ._imaging import ImagingFont
|
||||
from ._imagingft import Font
|
||||
|
||||
|
||||
class Layout(IntEnum):
|
||||
|
@ -56,7 +61,7 @@ except ImportError as ex:
|
|||
core = DeferredError.new(ex)
|
||||
|
||||
|
||||
def _string_length_check(text):
|
||||
def _string_length_check(text: str | bytes | bytearray) -> None:
|
||||
if MAX_STRING_LENGTH is not None and len(text) > MAX_STRING_LENGTH:
|
||||
msg = "too many characters in string"
|
||||
raise ValueError(msg)
|
||||
|
@ -81,9 +86,11 @@ def _string_length_check(text):
|
|||
class ImageFont:
|
||||
"""PIL font wrapper"""
|
||||
|
||||
def _load_pilfont(self, filename):
|
||||
font: ImagingFont
|
||||
|
||||
def _load_pilfont(self, filename: str) -> None:
|
||||
with open(filename, "rb") as fp:
|
||||
image = None
|
||||
image: ImageFile.ImageFile | None = None
|
||||
for ext in (".png", ".gif", ".pbm"):
|
||||
if image:
|
||||
image.close()
|
||||
|
@ -106,7 +113,7 @@ class ImageFont:
|
|||
self._load_pilfont_data(fp, image)
|
||||
image.close()
|
||||
|
||||
def _load_pilfont_data(self, file, image):
|
||||
def _load_pilfont_data(self, file: IO[bytes], image: Image.Image) -> None:
|
||||
# read PILfont header
|
||||
if file.readline() != b"PILfont\n":
|
||||
msg = "Not a PILfont file"
|
||||
|
@ -153,7 +160,9 @@ class ImageFont:
|
|||
Image._decompression_bomb_check(self.font.getsize(text))
|
||||
return self.font.getmask(text, mode)
|
||||
|
||||
def getbbox(self, text, *args, **kwargs):
|
||||
def getbbox(
|
||||
self, text: str | bytes | bytearray, *args: Any, **kwargs: Any
|
||||
) -> tuple[int, int, int, int]:
|
||||
"""
|
||||
Returns bounding box (in pixels) of given text.
|
||||
|
||||
|
@ -167,7 +176,9 @@ class ImageFont:
|
|||
width, height = self.font.getsize(text)
|
||||
return 0, 0, width, height
|
||||
|
||||
def getlength(self, text, *args, **kwargs):
|
||||
def getlength(
|
||||
self, text: str | bytes | bytearray, *args: Any, **kwargs: Any
|
||||
) -> int:
|
||||
"""
|
||||
Returns length (in pixels) of given text.
|
||||
This is the amount by which following text should be offset.
|
||||
|
@ -187,6 +198,8 @@ class ImageFont:
|
|||
class FreeTypeFont:
|
||||
"""FreeType font wrapper (requires _imagingft service)"""
|
||||
|
||||
font: Font
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
font: StrOrBytesPath | BinaryIO | None = None,
|
||||
|
@ -250,7 +263,7 @@ class FreeTypeFont:
|
|||
path, size, index, encoding, layout_engine = state
|
||||
self.__init__(path, size, index, encoding, layout_engine)
|
||||
|
||||
def getname(self):
|
||||
def getname(self) -> tuple[str | None, str | None]:
|
||||
"""
|
||||
:return: A tuple of the font family (e.g. Helvetica) and the font style
|
||||
(e.g. Bold)
|
||||
|
@ -265,7 +278,9 @@ class FreeTypeFont:
|
|||
"""
|
||||
return self.font.ascent, self.font.descent
|
||||
|
||||
def getlength(self, text, mode="", direction=None, features=None, language=None):
|
||||
def getlength(
|
||||
self, text: str, mode="", direction=None, features=None, language=None
|
||||
) -> float:
|
||||
"""
|
||||
Returns length (in pixels with 1/64 precision) of given text when rendered
|
||||
in font with provided direction, features, and language.
|
||||
|
@ -339,14 +354,14 @@ class FreeTypeFont:
|
|||
|
||||
def getbbox(
|
||||
self,
|
||||
text,
|
||||
mode="",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
anchor=None,
|
||||
):
|
||||
text: str,
|
||||
mode: str = "",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
anchor: str | None = None,
|
||||
) -> tuple[float, float, float, float]:
|
||||
"""
|
||||
Returns bounding box (in pixels) of given text relative to given anchor
|
||||
when rendered in font with provided direction, features, and language.
|
||||
|
@ -496,7 +511,7 @@ class FreeTypeFont:
|
|||
|
||||
def getmask2(
|
||||
self,
|
||||
text,
|
||||
text: str,
|
||||
mode="",
|
||||
direction=None,
|
||||
features=None,
|
||||
|
@ -666,10 +681,11 @@ class FreeTypeFont:
|
|||
msg = "FreeType 2.9.1 or greater is required"
|
||||
raise NotImplementedError(msg) from e
|
||||
for axis in axes:
|
||||
axis["name"] = axis["name"].replace(b"\x00", b"")
|
||||
if axis["name"]:
|
||||
axis["name"] = axis["name"].replace(b"\x00", b"")
|
||||
return axes
|
||||
|
||||
def set_variation_by_axes(self, axes):
|
||||
def set_variation_by_axes(self, axes: list[float]) -> None:
|
||||
"""
|
||||
:param axes: A list of values for each axis.
|
||||
:exception OSError: If the font is not a variation font.
|
||||
|
@ -714,14 +730,14 @@ class TransposedFont:
|
|||
return 0, 0, height, width
|
||||
return 0, 0, width, height
|
||||
|
||||
def getlength(self, text, *args, **kwargs):
|
||||
def getlength(self, text: str, *args, **kwargs) -> float:
|
||||
if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270):
|
||||
msg = "text length is undefined for text rotated by 90 or 270 degrees"
|
||||
raise ValueError(msg)
|
||||
return self.font.getlength(text, *args, **kwargs)
|
||||
|
||||
|
||||
def load(filename):
|
||||
def load(filename: str) -> ImageFont:
|
||||
"""
|
||||
Load a font file. This function loads a font object from the given
|
||||
bitmap font file, and returns the corresponding font object.
|
||||
|
@ -735,7 +751,13 @@ def load(filename):
|
|||
return f
|
||||
|
||||
|
||||
def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
||||
def truetype(
|
||||
font: StrOrBytesPath | BinaryIO | None = None,
|
||||
size: float = 10,
|
||||
index: int = 0,
|
||||
encoding: str = "",
|
||||
layout_engine: Layout | None = None,
|
||||
) -> FreeTypeFont:
|
||||
"""
|
||||
Load a TrueType or OpenType font from a file or file-like object,
|
||||
and create a font object.
|
||||
|
@ -796,7 +818,7 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
|||
:exception ValueError: If the font size is not greater than zero.
|
||||
"""
|
||||
|
||||
def freetype(font):
|
||||
def freetype(font: StrOrBytesPath | BinaryIO | None) -> FreeTypeFont:
|
||||
return FreeTypeFont(font, size, index, encoding, layout_engine)
|
||||
|
||||
try:
|
||||
|
@ -846,7 +868,7 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
|
|||
raise
|
||||
|
||||
|
||||
def load_path(filename):
|
||||
def load_path(filename: str | bytes) -> ImageFont:
|
||||
"""
|
||||
Load font file. Same as :py:func:`~PIL.ImageFont.load`, but searches for a
|
||||
bitmap font along the Python path.
|
||||
|
@ -855,14 +877,13 @@ def load_path(filename):
|
|||
:return: A font object.
|
||||
:exception OSError: If the file could not be read.
|
||||
"""
|
||||
if not isinstance(filename, str):
|
||||
filename = filename.decode("utf-8")
|
||||
for directory in sys.path:
|
||||
if is_directory(directory):
|
||||
if not isinstance(filename, str):
|
||||
filename = filename.decode("utf-8")
|
||||
try:
|
||||
return load(os.path.join(directory, filename))
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
return load(os.path.join(directory, filename))
|
||||
except OSError:
|
||||
pass
|
||||
msg = "cannot find font file"
|
||||
raise OSError(msg)
|
||||
|
||||
|
@ -881,6 +902,7 @@ def load_default(size: float | None = None) -> FreeTypeFont | ImageFont:
|
|||
|
||||
:return: A font object.
|
||||
"""
|
||||
f: FreeTypeFont | ImageFont
|
||||
if core.__class__.__name__ == "module" or size is not None:
|
||||
f = truetype(
|
||||
BytesIO(
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Sequence
|
||||
from typing import Any, Sequence
|
||||
|
||||
from . import Image
|
||||
|
||||
|
@ -34,7 +34,7 @@ class Transform(Image.ImageTransformHandler):
|
|||
self,
|
||||
size: tuple[int, int],
|
||||
image: Image.Image,
|
||||
**options: dict[str, str | int | tuple[int, ...] | list[int]],
|
||||
**options: Any,
|
||||
) -> Image.Image:
|
||||
"""Perform the transform. Called from :py:meth:`.Image.transform`."""
|
||||
# can be overridden
|
||||
|
|
|
@ -426,7 +426,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
|||
return s
|
||||
|
||||
def draft(
|
||||
self, mode: str, size: tuple[int, int]
|
||||
self, mode: str | None, size: tuple[int, int]
|
||||
) -> tuple[str, tuple[int, int, float, float]] | None:
|
||||
if len(self.tile) != 1:
|
||||
return None
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
from typing import Any
|
||||
|
||||
class ImagingCore:
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
class ImagingFont:
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
class ImagingDraw:
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
class PixelAccess:
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
def font(image, glyphdata: bytes) -> ImagingFont: ...
|
||||
def __getattr__(name: str) -> Any: ...
|
||||
|
|
|
@ -1,3 +1,69 @@
|
|||
from typing import Any
|
||||
from typing import Any, TypedDict
|
||||
|
||||
from . import _imaging
|
||||
|
||||
class _Axis(TypedDict):
|
||||
minimum: int | None
|
||||
default: int | None
|
||||
maximum: int | None
|
||||
name: bytes | None
|
||||
|
||||
class Font:
|
||||
@property
|
||||
def family(self) -> str | None: ...
|
||||
@property
|
||||
def style(self) -> str | None: ...
|
||||
@property
|
||||
def ascent(self) -> int: ...
|
||||
@property
|
||||
def descent(self) -> int: ...
|
||||
@property
|
||||
def height(self) -> int: ...
|
||||
@property
|
||||
def x_ppem(self) -> int: ...
|
||||
@property
|
||||
def y_ppem(self) -> int: ...
|
||||
@property
|
||||
def glyphs(self) -> int: ...
|
||||
def render(
|
||||
self,
|
||||
string: str,
|
||||
fill,
|
||||
mode=...,
|
||||
dir=...,
|
||||
features=...,
|
||||
lang=...,
|
||||
stroke_width=...,
|
||||
anchor=...,
|
||||
foreground_ink_long=...,
|
||||
x_start=...,
|
||||
y_start=...,
|
||||
/,
|
||||
) -> tuple[_imaging.ImagingCore, tuple[int, int]]: ...
|
||||
def getsize(
|
||||
self,
|
||||
string: str | bytes | bytearray,
|
||||
mode=...,
|
||||
dir=...,
|
||||
features=...,
|
||||
lang=...,
|
||||
anchor=...,
|
||||
/,
|
||||
) -> tuple[tuple[int, int], tuple[int, int]]: ...
|
||||
def getlength(
|
||||
self, string: str, mode=..., dir=..., features=..., lang=..., /
|
||||
) -> float: ...
|
||||
def getvarnames(self) -> list[bytes]: ...
|
||||
def getvaraxes(self) -> list[_Axis] | None: ...
|
||||
def setvarname(self, instance_index: int, /) -> None: ...
|
||||
def setvaraxes(self, axes: list[float], /) -> None: ...
|
||||
|
||||
def getfont(
|
||||
filename: str | bytes,
|
||||
size: float,
|
||||
index=...,
|
||||
encoding=...,
|
||||
font_bytes=...,
|
||||
layout_engine=...,
|
||||
) -> Font: ...
|
||||
def __getattr__(name: str) -> Any: ...
|
||||
|
|
Loading…
Reference in New Issue
Block a user