mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 10:16:17 +03:00
Added type hints
This commit is contained in:
parent
6dd4b3c826
commit
726cdf5eed
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import AnyStr
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -92,7 +93,7 @@ def test_textsize(request: pytest.FixtureRequest, tmp_path: Path) -> None:
|
|||
|
||||
|
||||
def _test_high_characters(
|
||||
request: pytest.FixtureRequest, tmp_path: Path, message: str | bytes
|
||||
request: pytest.FixtureRequest, tmp_path: Path, message: AnyStr
|
||||
) -> None:
|
||||
tempname = save_font(request, tmp_path)
|
||||
font = ImageFont.load(tempname)
|
||||
|
|
|
@ -717,14 +717,14 @@ def test_variation_set_by_name(font: ImageFont.FreeTypeFont) -> None:
|
|||
|
||||
font = ImageFont.truetype("Tests/fonts/AdobeVFPrototype.ttf", 36)
|
||||
_check_text(font, "Tests/images/variation_adobe.png", 11)
|
||||
for name in ["Bold", b"Bold"]:
|
||||
for name in ("Bold", b"Bold"):
|
||||
font.set_variation_by_name(name)
|
||||
assert font.getname()[1] == "Bold"
|
||||
_check_text(font, "Tests/images/variation_adobe_name.png", 16)
|
||||
|
||||
font = ImageFont.truetype("Tests/fonts/TINY5x3GX.ttf", 36)
|
||||
_check_text(font, "Tests/images/variation_tiny.png", 40)
|
||||
for name in ["200", b"200"]:
|
||||
for name in ("200", b"200"):
|
||||
font.set_variation_by_name(name)
|
||||
assert font.getname()[1] == "200"
|
||||
_check_text(font, "Tests/images/variation_tiny_name.png", 40)
|
||||
|
|
|
@ -91,3 +91,11 @@ Constants
|
|||
Set to 1,000,000, to protect against potential DOS attacks. Pillow will
|
||||
raise a :py:exc:`ValueError` if the number of characters is over this limit. The
|
||||
check can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.
|
||||
|
||||
Dictionaries
|
||||
------------
|
||||
|
||||
.. autoclass:: Axis
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
|
@ -78,3 +78,7 @@ on some Python versions.
|
|||
|
||||
An internal interface module previously known as :mod:`~PIL._imaging`,
|
||||
implemented in :file:`_imaging.c`.
|
||||
|
||||
.. py:class:: ImagingCore
|
||||
|
||||
A representation of the image data.
|
||||
|
|
|
@ -159,6 +159,4 @@ exclude = [
|
|||
'^Tests/oss-fuzz/fuzz_font.py$',
|
||||
'^Tests/oss-fuzz/fuzz_pillow.py$',
|
||||
'^Tests/test_qt_image_qapplication.py$',
|
||||
'^Tests/test_font_pcf_charsets.py$',
|
||||
'^Tests/test_font_pcf.py$',
|
||||
]
|
||||
|
|
|
@ -218,6 +218,8 @@ if hasattr(core, "DEFAULT_STRATEGY"):
|
|||
# Registries
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from . import ImageFile, ImagePalette
|
||||
from ._typing import NumpyArray, StrOrBytesPath, TypeGuard
|
||||
ID: list[str] = []
|
||||
|
@ -241,9 +243,9 @@ ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {}
|
|||
_ENDIAN = "<" if sys.byteorder == "little" else ">"
|
||||
|
||||
|
||||
def _conv_type_shape(im):
|
||||
def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]:
|
||||
m = ImageMode.getmode(im.mode)
|
||||
shape = (im.height, im.width)
|
||||
shape: tuple[int, ...] = (im.height, im.width)
|
||||
extra = len(m.bands)
|
||||
if extra != 1:
|
||||
shape += (extra,)
|
||||
|
@ -470,10 +472,10 @@ class _E:
|
|||
self.scale = scale
|
||||
self.offset = offset
|
||||
|
||||
def __neg__(self):
|
||||
def __neg__(self) -> _E:
|
||||
return _E(-self.scale, -self.offset)
|
||||
|
||||
def __add__(self, other):
|
||||
def __add__(self, other) -> _E:
|
||||
if isinstance(other, _E):
|
||||
return _E(self.scale + other.scale, self.offset + other.offset)
|
||||
return _E(self.scale, self.offset + other)
|
||||
|
@ -486,14 +488,14 @@ class _E:
|
|||
def __rsub__(self, other):
|
||||
return other + -self
|
||||
|
||||
def __mul__(self, other):
|
||||
def __mul__(self, other) -> _E:
|
||||
if isinstance(other, _E):
|
||||
return NotImplemented
|
||||
return _E(self.scale * other, self.offset * other)
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
def __truediv__(self, other):
|
||||
def __truediv__(self, other) -> _E:
|
||||
if isinstance(other, _E):
|
||||
return NotImplemented
|
||||
return _E(self.scale / other, self.offset / other)
|
||||
|
@ -718,9 +720,9 @@ class Image:
|
|||
return self._repr_image("JPEG")
|
||||
|
||||
@property
|
||||
def __array_interface__(self):
|
||||
def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]:
|
||||
# numpy array interface support
|
||||
new = {"version": 3}
|
||||
new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3}
|
||||
try:
|
||||
if self.mode == "1":
|
||||
# Binary images need to be extended from bits to bytes
|
||||
|
@ -1418,7 +1420,7 @@ class Image:
|
|||
return out
|
||||
return self.im.getcolors(maxcolors)
|
||||
|
||||
def getdata(self, band: int | None = None):
|
||||
def getdata(self, band: int | None = None) -> core.ImagingCore:
|
||||
"""
|
||||
Returns the contents of this image as a sequence object
|
||||
containing pixel values. The sequence object is flattened, so
|
||||
|
@ -1467,8 +1469,8 @@ class Image:
|
|||
def get_name(tag: str) -> str:
|
||||
return re.sub("^{[^}]+}", "", tag)
|
||||
|
||||
def get_value(element):
|
||||
value = {get_name(k): v for k, v in element.attrib.items()}
|
||||
def get_value(element: Element) -> str | dict[str, Any] | None:
|
||||
value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()}
|
||||
children = list(element)
|
||||
if children:
|
||||
for child in children:
|
||||
|
@ -1712,7 +1714,7 @@ class Image:
|
|||
return self.im.histogram(extrema)
|
||||
return self.im.histogram()
|
||||
|
||||
def entropy(self, mask=None, extrema=None):
|
||||
def entropy(self, mask: Image | None = None, extrema=None):
|
||||
"""
|
||||
Calculates and returns the entropy for the image.
|
||||
|
||||
|
@ -1996,7 +1998,7 @@ class Image:
|
|||
|
||||
def putdata(
|
||||
self,
|
||||
data: Sequence[float] | Sequence[Sequence[int]] | NumpyArray,
|
||||
data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray,
|
||||
scale: float = 1.0,
|
||||
offset: float = 0.0,
|
||||
) -> None:
|
||||
|
@ -2184,7 +2186,12 @@ class Image:
|
|||
|
||||
return m_im
|
||||
|
||||
def _get_safe_box(self, size, resample, box):
|
||||
def _get_safe_box(
|
||||
self,
|
||||
size: tuple[int, int],
|
||||
resample: Resampling,
|
||||
box: tuple[float, float, float, float],
|
||||
) -> tuple[int, int, int, int]:
|
||||
"""Expands the box so it includes adjacent pixels
|
||||
that may be used by resampling with the given resampling filter.
|
||||
"""
|
||||
|
@ -2294,7 +2301,7 @@ class Image:
|
|||
factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1
|
||||
factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1
|
||||
if factor_x > 1 or factor_y > 1:
|
||||
reduce_box = self._get_safe_box(size, resample, box)
|
||||
reduce_box = self._get_safe_box(size, cast(Resampling, resample), box)
|
||||
factor = (factor_x, factor_y)
|
||||
self = (
|
||||
self.reduce(factor, box=reduce_box)
|
||||
|
@ -2430,7 +2437,7 @@ class Image:
|
|||
0.0,
|
||||
]
|
||||
|
||||
def transform(x, y, matrix):
|
||||
def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]:
|
||||
(a, b, c, d, e, f) = matrix
|
||||
return a * x + b * y + c, d * x + e * y + f
|
||||
|
||||
|
@ -2445,9 +2452,9 @@ class Image:
|
|||
xx = []
|
||||
yy = []
|
||||
for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
|
||||
x, y = transform(x, y, matrix)
|
||||
xx.append(x)
|
||||
yy.append(y)
|
||||
transformed_x, transformed_y = transform(x, y, matrix)
|
||||
xx.append(transformed_x)
|
||||
yy.append(transformed_y)
|
||||
nw = math.ceil(max(xx)) - math.floor(min(xx))
|
||||
nh = math.ceil(max(yy)) - math.floor(min(yy))
|
||||
|
||||
|
@ -2705,7 +2712,7 @@ class Image:
|
|||
provided_size = tuple(map(math.floor, size))
|
||||
|
||||
def preserve_aspect_ratio() -> tuple[int, int] | None:
|
||||
def round_aspect(number, key):
|
||||
def round_aspect(number: float, key: Callable[[int], float]) -> int:
|
||||
return max(min(math.floor(number), math.ceil(number), key=key), 1)
|
||||
|
||||
x, y = provided_size
|
||||
|
@ -2849,7 +2856,13 @@ class Image:
|
|||
return im
|
||||
|
||||
def __transformer(
|
||||
self, box, image, method, data, resample=Resampling.NEAREST, fill=1
|
||||
self,
|
||||
box: tuple[int, int, int, int],
|
||||
image: Image,
|
||||
method,
|
||||
data,
|
||||
resample: int = Resampling.NEAREST,
|
||||
fill: bool = True,
|
||||
):
|
||||
w = box[2] - box[0]
|
||||
h = box[3] - box[1]
|
||||
|
@ -2899,11 +2912,12 @@ class Image:
|
|||
Resampling.BICUBIC,
|
||||
):
|
||||
if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS):
|
||||
msg = {
|
||||
unusable: dict[int, str] = {
|
||||
Resampling.BOX: "Image.Resampling.BOX",
|
||||
Resampling.HAMMING: "Image.Resampling.HAMMING",
|
||||
Resampling.LANCZOS: "Image.Resampling.LANCZOS",
|
||||
}[resample] + f" ({resample}) cannot be used."
|
||||
}
|
||||
msg = unusable[resample] + f" ({resample}) cannot be used."
|
||||
else:
|
||||
msg = f"Unknown resampling filter ({resample})."
|
||||
|
||||
|
@ -3843,7 +3857,7 @@ class Exif(_ExifBase):
|
|||
print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99
|
||||
"""
|
||||
|
||||
endian = None
|
||||
endian: str | None = None
|
||||
bigtiff = False
|
||||
_loaded = False
|
||||
|
||||
|
@ -3892,7 +3906,7 @@ class Exif(_ExifBase):
|
|||
head += b"\x00\x00\x00\x00"
|
||||
return head
|
||||
|
||||
def load(self, data):
|
||||
def load(self, data: bytes) -> None:
|
||||
# Extract EXIF information. This is highly experimental,
|
||||
# and is likely to be replaced with something better in a future
|
||||
# version.
|
||||
|
@ -3911,7 +3925,7 @@ class Exif(_ExifBase):
|
|||
self._info = None
|
||||
return
|
||||
|
||||
self.fp = io.BytesIO(data)
|
||||
self.fp: IO[bytes] = io.BytesIO(data)
|
||||
self.head = self.fp.read(8)
|
||||
# process dictionary
|
||||
from . import TiffImagePlugin
|
||||
|
@ -3921,7 +3935,7 @@ class Exif(_ExifBase):
|
|||
self.fp.seek(self._info.next)
|
||||
self._info.load(self.fp)
|
||||
|
||||
def load_from_fp(self, fp, offset=None):
|
||||
def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None:
|
||||
self._loaded_exif = None
|
||||
self._data.clear()
|
||||
self._hidden_data.clear()
|
||||
|
|
|
@ -36,7 +36,7 @@ import numbers
|
|||
import struct
|
||||
from collections.abc import Sequence
|
||||
from types import ModuleType
|
||||
from typing import TYPE_CHECKING, AnyStr, Callable, Union, cast
|
||||
from typing import TYPE_CHECKING, Any, AnyStr, Callable, Union, cast
|
||||
|
||||
from . import Image, ImageColor
|
||||
from ._deprecate import deprecate
|
||||
|
@ -561,7 +561,12 @@ class ImageDraw:
|
|||
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):
|
||||
def _multiline_spacing(
|
||||
self,
|
||||
font: ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont,
|
||||
spacing: float,
|
||||
stroke_width: float,
|
||||
) -> float:
|
||||
return (
|
||||
self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3]
|
||||
+ stroke_width
|
||||
|
@ -571,25 +576,25 @@ class ImageDraw:
|
|||
def text(
|
||||
self,
|
||||
xy: tuple[float, float],
|
||||
text: str,
|
||||
fill=None,
|
||||
text: AnyStr,
|
||||
fill: _Ink | None = None,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
anchor=None,
|
||||
spacing=4,
|
||||
align="left",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
stroke_fill=None,
|
||||
embedded_color=False,
|
||||
*args,
|
||||
**kwargs,
|
||||
anchor: str | None = None,
|
||||
spacing: float = 4,
|
||||
align: str = "left",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
stroke_fill: _Ink | None = None,
|
||||
embedded_color: bool = False,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Draw text."""
|
||||
if embedded_color and self.mode not in ("RGB", "RGBA"):
|
||||
|
@ -623,15 +628,14 @@ class ImageDraw:
|
|||
return fill_ink
|
||||
return ink
|
||||
|
||||
def draw_text(ink, stroke_width=0) -> None:
|
||||
def draw_text(ink: int, stroke_width: float = 0) -> None:
|
||||
mode = self.fontmode
|
||||
if stroke_width == 0 and embedded_color:
|
||||
mode = "RGBA"
|
||||
coord = []
|
||||
start = []
|
||||
for i in range(2):
|
||||
coord.append(int(xy[i]))
|
||||
start.append(math.modf(xy[i])[0])
|
||||
start = (math.modf(xy[0])[0], math.modf(xy[1])[0])
|
||||
try:
|
||||
mask, offset = font.getmask2( # type: ignore[union-attr,misc]
|
||||
text,
|
||||
|
@ -697,25 +701,25 @@ class ImageDraw:
|
|||
def multiline_text(
|
||||
self,
|
||||
xy: tuple[float, float],
|
||||
text: str,
|
||||
fill=None,
|
||||
text: AnyStr,
|
||||
fill: _Ink | None = None,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
anchor=None,
|
||||
spacing=4,
|
||||
align="left",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
stroke_fill=None,
|
||||
embedded_color=False,
|
||||
anchor: str | None = None,
|
||||
spacing: float = 4,
|
||||
align: str = "left",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
stroke_fill: _Ink | None = None,
|
||||
embedded_color: bool = False,
|
||||
*,
|
||||
font_size=None,
|
||||
font_size: float | None = None,
|
||||
) -> None:
|
||||
if direction == "ttb":
|
||||
msg = "ttb direction is unsupported for multiline text"
|
||||
|
@ -788,19 +792,19 @@ class ImageDraw:
|
|||
|
||||
def textlength(
|
||||
self,
|
||||
text: str,
|
||||
text: AnyStr,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
embedded_color=False,
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
embedded_color: bool = False,
|
||||
*,
|
||||
font_size=None,
|
||||
font_size: float | None = None,
|
||||
) -> float:
|
||||
"""Get the length of a given string, in pixels with 1/64 precision."""
|
||||
if self._multiline_check(text):
|
||||
|
@ -817,20 +821,25 @@ class ImageDraw:
|
|||
|
||||
def textbbox(
|
||||
self,
|
||||
xy,
|
||||
text,
|
||||
font=None,
|
||||
anchor=None,
|
||||
spacing=4,
|
||||
align="left",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
embedded_color=False,
|
||||
xy: tuple[float, float],
|
||||
text: AnyStr,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
anchor: str | None = None,
|
||||
spacing: float = 4,
|
||||
align: str = "left",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
embedded_color: bool = False,
|
||||
*,
|
||||
font_size=None,
|
||||
) -> tuple[int, int, int, int]:
|
||||
font_size: float | None = None,
|
||||
) -> tuple[float, float, float, float]:
|
||||
"""Get the bounding box of a given string, in pixels."""
|
||||
if embedded_color and self.mode not in ("RGB", "RGBA"):
|
||||
msg = "Embedded color supported only in RGB and RGBA modes"
|
||||
|
@ -862,20 +871,25 @@ class ImageDraw:
|
|||
|
||||
def multiline_textbbox(
|
||||
self,
|
||||
xy,
|
||||
text,
|
||||
font=None,
|
||||
anchor=None,
|
||||
spacing=4,
|
||||
align="left",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
embedded_color=False,
|
||||
xy: tuple[float, float],
|
||||
text: AnyStr,
|
||||
font: (
|
||||
ImageFont.ImageFont
|
||||
| ImageFont.FreeTypeFont
|
||||
| ImageFont.TransposedFont
|
||||
| None
|
||||
) = None,
|
||||
anchor: str | None = None,
|
||||
spacing: float = 4,
|
||||
align: str = "left",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
embedded_color: bool = False,
|
||||
*,
|
||||
font_size=None,
|
||||
) -> tuple[int, int, int, int]:
|
||||
font_size: float | None = None,
|
||||
) -> tuple[float, float, float, float]:
|
||||
if direction == "ttb":
|
||||
msg = "ttb direction is unsupported for multiline text"
|
||||
raise ValueError(msg)
|
||||
|
@ -914,7 +928,7 @@ class ImageDraw:
|
|||
elif anchor[1] == "d":
|
||||
top -= (len(lines) - 1) * line_spacing
|
||||
|
||||
bbox: tuple[int, int, int, int] | None = None
|
||||
bbox: tuple[float, float, float, float] | None = None
|
||||
|
||||
for idx, line in enumerate(lines):
|
||||
left = xy[0]
|
||||
|
|
|
@ -34,7 +34,7 @@ import warnings
|
|||
from enum import IntEnum
|
||||
from io import BytesIO
|
||||
from types import ModuleType
|
||||
from typing import IO, TYPE_CHECKING, Any, BinaryIO
|
||||
from typing import IO, TYPE_CHECKING, Any, BinaryIO, TypedDict
|
||||
|
||||
from . import Image
|
||||
from ._typing import StrOrBytesPath
|
||||
|
@ -46,6 +46,13 @@ if TYPE_CHECKING:
|
|||
from ._imagingft import Font
|
||||
|
||||
|
||||
class Axis(TypedDict):
|
||||
minimum: int | None
|
||||
default: int | None
|
||||
maximum: int | None
|
||||
name: bytes | None
|
||||
|
||||
|
||||
class Layout(IntEnum):
|
||||
BASIC = 0
|
||||
RAQM = 1
|
||||
|
@ -138,7 +145,9 @@ class ImageFont:
|
|||
|
||||
self.font = Image.core.font(image.im, data)
|
||||
|
||||
def getmask(self, text, mode="", *args, **kwargs):
|
||||
def getmask(
|
||||
self, text: str | bytes, mode: str = "", *args: Any, **kwargs: Any
|
||||
) -> Image.core.ImagingCore:
|
||||
"""
|
||||
Create a bitmap for the text.
|
||||
|
||||
|
@ -236,7 +245,7 @@ class FreeTypeFont:
|
|||
|
||||
self.layout_engine = layout_engine
|
||||
|
||||
def load_from_bytes(f):
|
||||
def load_from_bytes(f) -> None:
|
||||
self.font_bytes = f.read()
|
||||
self.font = core.getfont(
|
||||
"", size, index, encoding, self.font_bytes, layout_engine
|
||||
|
@ -283,7 +292,12 @@ class FreeTypeFont:
|
|||
return self.font.ascent, self.font.descent
|
||||
|
||||
def getlength(
|
||||
self, text: str | bytes, mode="", direction=None, features=None, language=None
|
||||
self,
|
||||
text: str | bytes,
|
||||
mode: str = "",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
) -> float:
|
||||
"""
|
||||
Returns length (in pixels with 1/64 precision) of given text when rendered
|
||||
|
@ -424,16 +438,16 @@ class FreeTypeFont:
|
|||
|
||||
def getmask(
|
||||
self,
|
||||
text,
|
||||
mode="",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
anchor=None,
|
||||
ink=0,
|
||||
start=None,
|
||||
):
|
||||
text: str | bytes,
|
||||
mode: str = "",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
anchor: str | None = None,
|
||||
ink: int = 0,
|
||||
start: tuple[float, float] | None = None,
|
||||
) -> Image.core.ImagingCore:
|
||||
"""
|
||||
Create a bitmap for the text.
|
||||
|
||||
|
@ -516,17 +530,17 @@ class FreeTypeFont:
|
|||
def getmask2(
|
||||
self,
|
||||
text: str | bytes,
|
||||
mode="",
|
||||
direction=None,
|
||||
features=None,
|
||||
language=None,
|
||||
stroke_width=0,
|
||||
anchor=None,
|
||||
ink=0,
|
||||
start=None,
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
mode: str = "",
|
||||
direction: str | None = None,
|
||||
features: list[str] | None = None,
|
||||
language: str | None = None,
|
||||
stroke_width: float = 0,
|
||||
anchor: str | None = None,
|
||||
ink: int = 0,
|
||||
start: tuple[float, float] | None = None,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> tuple[Image.core.ImagingCore, tuple[int, int]]:
|
||||
"""
|
||||
Create a bitmap for the text.
|
||||
|
||||
|
@ -599,7 +613,7 @@ class FreeTypeFont:
|
|||
if start is None:
|
||||
start = (0, 0)
|
||||
|
||||
def fill(width, height):
|
||||
def fill(width: int, height: int) -> Image.core.ImagingCore:
|
||||
size = (width, height)
|
||||
Image._decompression_bomb_check(size)
|
||||
return Image.core.fill("RGBA" if mode == "RGBA" else "L", size)
|
||||
|
@ -619,8 +633,13 @@ class FreeTypeFont:
|
|||
)
|
||||
|
||||
def font_variant(
|
||||
self, font=None, size=None, index=None, encoding=None, layout_engine=None
|
||||
):
|
||||
self,
|
||||
font: StrOrBytesPath | BinaryIO | None = None,
|
||||
size: float | None = None,
|
||||
index: int | None = None,
|
||||
encoding: str | None = None,
|
||||
layout_engine: Layout | None = None,
|
||||
) -> FreeTypeFont:
|
||||
"""
|
||||
Create a copy of this FreeTypeFont object,
|
||||
using any specified arguments to override the settings.
|
||||
|
@ -655,7 +674,7 @@ class FreeTypeFont:
|
|||
raise NotImplementedError(msg) from e
|
||||
return [name.replace(b"\x00", b"") for name in names]
|
||||
|
||||
def set_variation_by_name(self, name):
|
||||
def set_variation_by_name(self, name: str | bytes) -> None:
|
||||
"""
|
||||
:param name: The name of the style.
|
||||
:exception OSError: If the font is not a variation font.
|
||||
|
@ -674,7 +693,7 @@ class FreeTypeFont:
|
|||
|
||||
self.font.setvarname(index)
|
||||
|
||||
def get_variation_axes(self):
|
||||
def get_variation_axes(self) -> list[Axis]:
|
||||
"""
|
||||
:returns: A list of the axes in a variation font.
|
||||
:exception OSError: If the font is not a variation font.
|
||||
|
@ -704,7 +723,9 @@ class FreeTypeFont:
|
|||
class TransposedFont:
|
||||
"""Wrapper for writing rotated or mirrored text"""
|
||||
|
||||
def __init__(self, font, orientation=None):
|
||||
def __init__(
|
||||
self, font: ImageFont | FreeTypeFont, orientation: Image.Transpose | None = None
|
||||
):
|
||||
"""
|
||||
Wrapper that creates a transposed font from any existing font
|
||||
object.
|
||||
|
@ -718,13 +739,17 @@ class TransposedFont:
|
|||
self.font = font
|
||||
self.orientation = orientation # any 'transpose' argument, or None
|
||||
|
||||
def getmask(self, text, mode="", *args, **kwargs):
|
||||
def getmask(
|
||||
self, text: str | bytes, mode: str = "", *args: Any, **kwargs: Any
|
||||
) -> Image.core.ImagingCore:
|
||||
im = self.font.getmask(text, mode, *args, **kwargs)
|
||||
if self.orientation is not None:
|
||||
return im.transpose(self.orientation)
|
||||
return im
|
||||
|
||||
def getbbox(self, text, *args, **kwargs):
|
||||
def getbbox(
|
||||
self, text: str | bytes, *args: Any, **kwargs: Any
|
||||
) -> tuple[int, int, float, float]:
|
||||
# TransposedFont doesn't support getmask2, move top-left point to (0, 0)
|
||||
# this has no effect on ImageFont and simulates anchor="lt" for FreeTypeFont
|
||||
left, top, right, bottom = self.font.getbbox(text, *args, **kwargs)
|
||||
|
@ -734,7 +759,7 @@ class TransposedFont:
|
|||
return 0, 0, height, width
|
||||
return 0, 0, width, height
|
||||
|
||||
def getlength(self, text: str | bytes, *args, **kwargs) -> float:
|
||||
def getlength(self, text: str | bytes, *args: Any, **kwargs: Any) -> 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)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from typing import Any
|
||||
|
||||
class ImagingCore:
|
||||
def __getitem__(self, index: int) -> float: ...
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
class ImagingFont:
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
from typing import Any, TypedDict
|
||||
from typing import Any, Callable
|
||||
|
||||
from . import _imaging
|
||||
|
||||
class _Axis(TypedDict):
|
||||
minimum: int | None
|
||||
default: int | None
|
||||
maximum: int | None
|
||||
name: bytes | None
|
||||
from . import ImageFont, _imaging
|
||||
|
||||
class Font:
|
||||
@property
|
||||
|
@ -28,42 +22,48 @@ class Font:
|
|||
def render(
|
||||
self,
|
||||
string: str | bytes,
|
||||
fill,
|
||||
mode=...,
|
||||
dir=...,
|
||||
features=...,
|
||||
lang=...,
|
||||
stroke_width=...,
|
||||
anchor=...,
|
||||
foreground_ink_long=...,
|
||||
x_start=...,
|
||||
y_start=...,
|
||||
fill: Callable[[int, int], _imaging.ImagingCore],
|
||||
mode: str,
|
||||
dir: str | None,
|
||||
features: list[str] | None,
|
||||
lang: str | None,
|
||||
stroke_width: float,
|
||||
anchor: str | None,
|
||||
foreground_ink_long: int,
|
||||
x_start: float,
|
||||
y_start: float,
|
||||
/,
|
||||
) -> tuple[_imaging.ImagingCore, tuple[int, int]]: ...
|
||||
def getsize(
|
||||
self,
|
||||
string: str | bytes | bytearray,
|
||||
mode=...,
|
||||
dir=...,
|
||||
features=...,
|
||||
lang=...,
|
||||
anchor=...,
|
||||
mode: str,
|
||||
dir: str | None,
|
||||
features: list[str] | None,
|
||||
lang: str | None,
|
||||
anchor: str | None,
|
||||
/,
|
||||
) -> tuple[tuple[int, int], tuple[int, int]]: ...
|
||||
def getlength(
|
||||
self, string: str | bytes, mode=..., dir=..., features=..., lang=..., /
|
||||
self,
|
||||
string: str | bytes,
|
||||
mode: str,
|
||||
dir: str | None,
|
||||
features: list[str] | None,
|
||||
lang: str | None,
|
||||
/,
|
||||
) -> float: ...
|
||||
def getvarnames(self) -> list[bytes]: ...
|
||||
def getvaraxes(self) -> list[_Axis] | None: ...
|
||||
def getvaraxes(self) -> list[ImageFont.Axis]: ...
|
||||
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=...,
|
||||
index: int,
|
||||
encoding: str,
|
||||
font_bytes: bytes,
|
||||
layout_engine: int,
|
||||
) -> Font: ...
|
||||
def __getattr__(name: str) -> Any: ...
|
||||
|
|
Loading…
Reference in New Issue
Block a user