mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-25 17:36:18 +03:00
Updated type hints
This commit is contained in:
parent
4b258be3bb
commit
cc83cc8ec8
|
@ -18,7 +18,7 @@ from typing import Any, Callable, Sequence
|
||||||
import pytest
|
import pytest
|
||||||
from packaging.version import parse as parse_version
|
from packaging.version import parse as parse_version
|
||||||
|
|
||||||
from PIL import Image, ImageMath, features
|
from PIL import Image, ImageFile, ImageMath, features
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -240,7 +240,7 @@ class PillowLeakTestCase:
|
||||||
# helpers
|
# helpers
|
||||||
|
|
||||||
|
|
||||||
def fromstring(data: bytes) -> Image.Image:
|
def fromstring(data: bytes) -> ImageFile.ImageFile:
|
||||||
return Image.open(BytesIO(data))
|
return Image.open(BytesIO(data))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1033,8 +1033,10 @@ class TestFileJpeg:
|
||||||
|
|
||||||
def test_repr_jpeg(self) -> None:
|
def test_repr_jpeg(self) -> None:
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
b = im._repr_jpeg_()
|
||||||
|
assert b is not None
|
||||||
|
|
||||||
with Image.open(BytesIO(im._repr_jpeg_())) as repr_jpeg:
|
with Image.open(BytesIO(b)) as repr_jpeg:
|
||||||
assert repr_jpeg.format == "JPEG"
|
assert repr_jpeg.format == "JPEG"
|
||||||
assert_image_similar(im, repr_jpeg, 17)
|
assert_image_similar(im, repr_jpeg, 17)
|
||||||
|
|
||||||
|
|
|
@ -535,8 +535,10 @@ class TestFilePng:
|
||||||
|
|
||||||
def test_repr_png(self) -> None:
|
def test_repr_png(self) -> None:
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
b = im._repr_png_()
|
||||||
|
assert b is not None
|
||||||
|
|
||||||
with Image.open(BytesIO(im._repr_png_())) as repr_png:
|
with Image.open(BytesIO(b)) as repr_png:
|
||||||
assert repr_png.format == "PNG"
|
assert repr_png.format == "PNG"
|
||||||
assert_image_equal(im, repr_png)
|
assert_image_equal(im, repr_png)
|
||||||
|
|
||||||
|
@ -768,14 +770,10 @@ class TestFilePng:
|
||||||
def test_save_stdout(self, buffer: bool) -> None:
|
def test_save_stdout(self, buffer: bool) -> None:
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
|
|
||||||
if buffer:
|
|
||||||
|
|
||||||
class MyStdOut:
|
class MyStdOut:
|
||||||
buffer = BytesIO()
|
buffer = BytesIO()
|
||||||
|
|
||||||
mystdout = MyStdOut()
|
mystdout: MyStdOut | BytesIO = MyStdOut() if buffer else BytesIO()
|
||||||
else:
|
|
||||||
mystdout = BytesIO()
|
|
||||||
|
|
||||||
sys.stdout = mystdout
|
sys.stdout = mystdout
|
||||||
|
|
||||||
|
@ -785,7 +783,7 @@ class TestFilePng:
|
||||||
# Reset stdout
|
# Reset stdout
|
||||||
sys.stdout = old_stdout
|
sys.stdout = old_stdout
|
||||||
|
|
||||||
if buffer:
|
if isinstance(mystdout, MyStdOut):
|
||||||
mystdout = mystdout.buffer
|
mystdout = mystdout.buffer
|
||||||
with Image.open(mystdout) as reloaded:
|
with Image.open(mystdout) as reloaded:
|
||||||
assert_image_equal_tofile(reloaded, TEST_PNG_FILE)
|
assert_image_equal_tofile(reloaded, TEST_PNG_FILE)
|
||||||
|
|
|
@ -368,14 +368,10 @@ def test_mimetypes(tmp_path: Path) -> None:
|
||||||
def test_save_stdout(buffer: bool) -> None:
|
def test_save_stdout(buffer: bool) -> None:
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
|
|
||||||
if buffer:
|
|
||||||
|
|
||||||
class MyStdOut:
|
class MyStdOut:
|
||||||
buffer = BytesIO()
|
buffer = BytesIO()
|
||||||
|
|
||||||
mystdout = MyStdOut()
|
mystdout: MyStdOut | BytesIO = MyStdOut() if buffer else BytesIO()
|
||||||
else:
|
|
||||||
mystdout = BytesIO()
|
|
||||||
|
|
||||||
sys.stdout = mystdout
|
sys.stdout = mystdout
|
||||||
|
|
||||||
|
@ -385,7 +381,7 @@ def test_save_stdout(buffer: bool) -> None:
|
||||||
# Reset stdout
|
# Reset stdout
|
||||||
sys.stdout = old_stdout
|
sys.stdout = old_stdout
|
||||||
|
|
||||||
if buffer:
|
if isinstance(mystdout, MyStdOut):
|
||||||
mystdout = mystdout.buffer
|
mystdout = mystdout.buffer
|
||||||
with Image.open(mystdout) as reloaded:
|
with Image.open(mystdout) as reloaded:
|
||||||
assert_image_equal_tofile(reloaded, TEST_FILE)
|
assert_image_equal_tofile(reloaded, TEST_FILE)
|
||||||
|
|
|
@ -120,7 +120,7 @@ class TestFileTiff:
|
||||||
def test_set_legacy_api(self) -> None:
|
def test_set_legacy_api(self) -> None:
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
with pytest.raises(Exception) as e:
|
with pytest.raises(Exception) as e:
|
||||||
ifd.legacy_api = None
|
ifd.legacy_api = False
|
||||||
assert str(e.value) == "Not allowing setting of legacy api"
|
assert str(e.value) == "Not allowing setting of legacy api"
|
||||||
|
|
||||||
def test_xyres_tiff(self) -> None:
|
def test_xyres_tiff(self) -> None:
|
||||||
|
|
|
@ -34,7 +34,7 @@ class TestDefaultFontLeak(TestTTypeFontLeak):
|
||||||
|
|
||||||
def test_leak(self) -> None:
|
def test_leak(self) -> None:
|
||||||
if features.check_module("freetype2"):
|
if features.check_module("freetype2"):
|
||||||
ImageFont.core = _util.DeferredError(ImportError)
|
ImageFont.core = _util.DeferredError(ImportError("Disabled for testing"))
|
||||||
try:
|
try:
|
||||||
default_font = ImageFont.load_default()
|
default_font = ImageFont.load_default()
|
||||||
finally:
|
finally:
|
||||||
|
|
|
@ -393,13 +393,13 @@ class TestImage:
|
||||||
|
|
||||||
# errors
|
# errors
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
source.alpha_composite(over, "invalid source")
|
source.alpha_composite(over, "invalid destination") # type: ignore[arg-type]
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
source.alpha_composite(over, (0, 0), "invalid destination")
|
source.alpha_composite(over, (0, 0), "invalid source") # type: ignore[arg-type]
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
source.alpha_composite(over, 0)
|
source.alpha_composite(over, 0) # type: ignore[arg-type]
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
source.alpha_composite(over, (0, 0), 0)
|
source.alpha_composite(over, (0, 0), 0) # type: ignore[arg-type]
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
source.alpha_composite(over, (0, 0), (0, -1))
|
source.alpha_composite(over, (0, 0), (0, -1))
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,9 @@ def draft_roundtrip(
|
||||||
im = Image.new(in_mode, in_size)
|
im = Image.new(in_mode, in_size)
|
||||||
data = tostring(im, "JPEG")
|
data = tostring(im, "JPEG")
|
||||||
im = fromstring(data)
|
im = fromstring(data)
|
||||||
mode, box = im.draft(req_mode, req_size)
|
result = im.draft(req_mode, req_size)
|
||||||
|
assert result is not None
|
||||||
|
box = result[1]
|
||||||
scale, _ = im.decoderconfig
|
scale, _ = im.decoderconfig
|
||||||
assert box[:2] == (0, 0)
|
assert box[:2] == (0, 0)
|
||||||
assert (im.width - scale) < box[2] <= im.width
|
assert (im.width - scale) < box[2] <= im.width
|
||||||
|
|
|
@ -338,3 +338,8 @@ class TestImagingPaste:
|
||||||
|
|
||||||
im.copy().paste(im2)
|
im.copy().paste(im2)
|
||||||
im.copy().paste(im2, (0, 0))
|
im.copy().paste(im2, (0, 0))
|
||||||
|
|
||||||
|
def test_incorrect_abbreviated_form(self) -> None:
|
||||||
|
im = Image.new("L", (1, 1))
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
im.paste(im, im, im)
|
||||||
|
|
|
@ -61,4 +61,4 @@ def test_f_lut() -> None:
|
||||||
def test_f_mode() -> None:
|
def test_f_mode() -> None:
|
||||||
im = hopper("F")
|
im = hopper("F")
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
im.point(None)
|
im.point([])
|
||||||
|
|
|
@ -113,13 +113,13 @@ def test_array_F() -> None:
|
||||||
def test_not_flattened() -> None:
|
def test_not_flattened() -> None:
|
||||||
im = Image.new("L", (1, 1))
|
im = Image.new("L", (1, 1))
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
im.putdata([[0]]) # type: ignore[list-item]
|
im.putdata([[0]])
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
im.putdata([[0]], 2) # type: ignore[list-item]
|
im.putdata([[0]], 2)
|
||||||
|
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
im = Image.new("I", (1, 1))
|
im = Image.new("I", (1, 1))
|
||||||
im.putdata([[0]]) # type: ignore[list-item]
|
im.putdata([[0]])
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
im = Image.new("F", (1, 1))
|
im = Image.new("F", (1, 1))
|
||||||
im.putdata([[0]]) # type: ignore[list-item]
|
im.putdata([[0]])
|
||||||
|
|
|
@ -445,7 +445,7 @@ class TestCoreResampleBox:
|
||||||
im.resize((32, 32), resample, (20, 20, 100, 20))
|
im.resize((32, 32), resample, (20, 20, 100, 20))
|
||||||
|
|
||||||
with pytest.raises(TypeError, match="must be sequence of length 4"):
|
with pytest.raises(TypeError, match="must be sequence of length 4"):
|
||||||
im.resize((32, 32), resample, (im.width, im.height))
|
im.resize((32, 32), resample, (im.width, im.height)) # type: ignore[arg-type]
|
||||||
|
|
||||||
with pytest.raises(ValueError, match="can't be negative"):
|
with pytest.raises(ValueError, match="can't be negative"):
|
||||||
im.resize((32, 32), resample, (-20, 20, 100, 100))
|
im.resize((32, 32), resample, (-20, 20, 100, 100))
|
||||||
|
|
|
@ -103,7 +103,7 @@ def test_sanity() -> None:
|
||||||
|
|
||||||
|
|
||||||
def test_flags() -> None:
|
def test_flags() -> None:
|
||||||
assert ImageCms.Flags.NONE == 0
|
assert ImageCms.Flags.NONE.value == 0
|
||||||
assert ImageCms.Flags.GRIDPOINTS(0) == ImageCms.Flags.NONE
|
assert ImageCms.Flags.GRIDPOINTS(0) == ImageCms.Flags.NONE
|
||||||
assert ImageCms.Flags.GRIDPOINTS(256) == ImageCms.Flags.NONE
|
assert ImageCms.Flags.GRIDPOINTS(256) == ImageCms.Flags.NONE
|
||||||
|
|
||||||
|
@ -569,9 +569,9 @@ def assert_aux_channel_preserved(
|
||||||
for delta in nine_grid_deltas:
|
for delta in nine_grid_deltas:
|
||||||
channel_data.paste(
|
channel_data.paste(
|
||||||
channel_pattern,
|
channel_pattern,
|
||||||
tuple(
|
(
|
||||||
paste_offset[c] + delta[c] * channel_pattern.size[c]
|
paste_offset[0] + delta[0] * channel_pattern.size[0],
|
||||||
for c in range(2)
|
paste_offset[1] + delta[1] * channel_pattern.size[1],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
chans.append(channel_data)
|
chans.append(channel_data)
|
||||||
|
@ -642,7 +642,8 @@ def test_auxiliary_channels_isolated() -> None:
|
||||||
# convert with and without AUX data, test colors are equal
|
# convert with and without AUX data, test colors are equal
|
||||||
src_colorSpace = cast(Literal["LAB", "XYZ", "sRGB"], src_format[1])
|
src_colorSpace = cast(Literal["LAB", "XYZ", "sRGB"], src_format[1])
|
||||||
source_profile = ImageCms.createProfile(src_colorSpace)
|
source_profile = ImageCms.createProfile(src_colorSpace)
|
||||||
destination_profile = ImageCms.createProfile(dst_format[1])
|
dst_colorSpace = cast(Literal["LAB", "XYZ", "sRGB"], dst_format[1])
|
||||||
|
destination_profile = ImageCms.createProfile(dst_colorSpace)
|
||||||
source_image = src_format[3]
|
source_image = src_format[3]
|
||||||
test_transform = ImageCms.buildTransform(
|
test_transform = ImageCms.buildTransform(
|
||||||
source_profile,
|
source_profile,
|
||||||
|
|
|
@ -1581,7 +1581,7 @@ def test_compute_regular_polygon_vertices_input_error_handling(
|
||||||
error_message: str,
|
error_message: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
with pytest.raises(expected_error) as e:
|
with pytest.raises(expected_error) as e:
|
||||||
ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation)
|
ImageDraw._compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) # type: ignore[arg-type]
|
||||||
assert str(e.value) == error_message
|
assert str(e.value) == error_message
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,9 +51,10 @@ def test_sanity() -> None:
|
||||||
pen = ImageDraw2.Pen("blue", width=7)
|
pen = ImageDraw2.Pen("blue", width=7)
|
||||||
draw.line(list(range(10)), pen)
|
draw.line(list(range(10)), pen)
|
||||||
|
|
||||||
draw, handler = ImageDraw.getdraw(im)
|
draw2, handler = ImageDraw.getdraw(im)
|
||||||
|
assert draw2 is not None
|
||||||
pen = ImageDraw2.Pen("blue", width=7)
|
pen = ImageDraw2.Pen("blue", width=7)
|
||||||
draw.line(list(range(10)), pen)
|
draw2.line(list(range(10)), pen)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("bbox", BBOX)
|
@pytest.mark.parametrize("bbox", BBOX)
|
||||||
|
|
|
@ -381,7 +381,7 @@ class TestPyEncoder(CodecsTest):
|
||||||
def test_encode(self) -> None:
|
def test_encode(self) -> None:
|
||||||
encoder = ImageFile.PyEncoder(None)
|
encoder = ImageFile.PyEncoder(None)
|
||||||
with pytest.raises(NotImplementedError):
|
with pytest.raises(NotImplementedError):
|
||||||
encoder.encode(None)
|
encoder.encode(0)
|
||||||
|
|
||||||
bytes_consumed, errcode = encoder.encode_to_pyfd()
|
bytes_consumed, errcode = encoder.encode_to_pyfd()
|
||||||
assert bytes_consumed == 0
|
assert bytes_consumed == 0
|
||||||
|
|
|
@ -209,7 +209,7 @@ def test_getlength(
|
||||||
assert length == length_raqm
|
assert length == length_raqm
|
||||||
|
|
||||||
|
|
||||||
def test_float_size() -> None:
|
def test_float_size(layout_engine: ImageFont.Layout) -> None:
|
||||||
lengths = []
|
lengths = []
|
||||||
for size in (48, 48.5, 49):
|
for size in (48, 48.5, 49):
|
||||||
f = ImageFont.truetype(
|
f = ImageFont.truetype(
|
||||||
|
@ -494,8 +494,8 @@ def test_default_font() -> None:
|
||||||
assert_image_equal_tofile(im, "Tests/images/default_font_freetype.png")
|
assert_image_equal_tofile(im, "Tests/images/default_font_freetype.png")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("mode", (None, "1", "RGBA"))
|
@pytest.mark.parametrize("mode", ("", "1", "RGBA"))
|
||||||
def test_getbbox(font: ImageFont.FreeTypeFont, mode: str | None) -> None:
|
def test_getbbox(font: ImageFont.FreeTypeFont, mode: str) -> None:
|
||||||
assert (0, 4, 12, 16) == font.getbbox("A", mode)
|
assert (0, 4, 12, 16) == font.getbbox("A", mode)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ original_core = ImageFont.core
|
||||||
|
|
||||||
def setup_module() -> None:
|
def setup_module() -> None:
|
||||||
if features.check_module("freetype2"):
|
if features.check_module("freetype2"):
|
||||||
ImageFont.core = _util.DeferredError(ImportError)
|
ImageFont.core = _util.DeferredError(ImportError("Disabled for testing"))
|
||||||
|
|
||||||
|
|
||||||
def teardown_module() -> None:
|
def teardown_module() -> None:
|
||||||
|
@ -76,3 +76,8 @@ def test_oom() -> None:
|
||||||
font = ImageFont.ImageFont()
|
font = ImageFont.ImageFont()
|
||||||
font._load_pilfont_data(fp, Image.new("L", (1, 1)))
|
font._load_pilfont_data(fp, Image.new("L", (1, 1)))
|
||||||
font.getmask("A" * 1_000_000)
|
font.getmask("A" * 1_000_000)
|
||||||
|
|
||||||
|
|
||||||
|
def test_freetypefont_without_freetype() -> None:
|
||||||
|
with pytest.raises(ImportError):
|
||||||
|
ImageFont.truetype("Tests/fonts/FreeMono.ttf")
|
||||||
|
|
|
@ -45,7 +45,7 @@ def test_getcolor() -> None:
|
||||||
|
|
||||||
# Test unknown color specifier
|
# Test unknown color specifier
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
palette.getcolor("unknown")
|
palette.getcolor("unknown") # type: ignore[arg-type]
|
||||||
|
|
||||||
|
|
||||||
def test_getcolor_rgba_color_rgb_palette() -> None:
|
def test_getcolor_rgba_color_rgb_palette() -> None:
|
||||||
|
|
|
@ -54,14 +54,10 @@ def test_stdout(buffer: bool) -> None:
|
||||||
# Temporarily redirect stdout
|
# Temporarily redirect stdout
|
||||||
old_stdout = sys.stdout
|
old_stdout = sys.stdout
|
||||||
|
|
||||||
if buffer:
|
|
||||||
|
|
||||||
class MyStdOut:
|
class MyStdOut:
|
||||||
buffer = BytesIO()
|
buffer = BytesIO()
|
||||||
|
|
||||||
mystdout = MyStdOut()
|
mystdout: MyStdOut | BytesIO = MyStdOut() if buffer else BytesIO()
|
||||||
else:
|
|
||||||
mystdout = BytesIO()
|
|
||||||
|
|
||||||
sys.stdout = mystdout
|
sys.stdout = mystdout
|
||||||
|
|
||||||
|
@ -71,6 +67,6 @@ def test_stdout(buffer: bool) -> None:
|
||||||
# Reset stdout
|
# Reset stdout
|
||||||
sys.stdout = old_stdout
|
sys.stdout = old_stdout
|
||||||
|
|
||||||
if buffer:
|
if isinstance(mystdout, MyStdOut):
|
||||||
mystdout = mystdout.buffer
|
mystdout = mystdout.buffer
|
||||||
assert mystdout.getvalue() != b""
|
assert mystdout.getvalue() != b""
|
||||||
|
|
|
@ -1168,7 +1168,7 @@ class Image:
|
||||||
def quantize(
|
def quantize(
|
||||||
self,
|
self,
|
||||||
colors: int = 256,
|
colors: int = 256,
|
||||||
method: Quantize | None = None,
|
method: int | None = None,
|
||||||
kmeans: int = 0,
|
kmeans: int = 0,
|
||||||
palette=None,
|
palette=None,
|
||||||
dither: Dither = Dither.FLOYDSTEINBERG,
|
dither: Dither = Dither.FLOYDSTEINBERG,
|
||||||
|
@ -1309,7 +1309,7 @@ class Image:
|
||||||
return im.crop((x0, y0, x1, y1))
|
return im.crop((x0, y0, x1, y1))
|
||||||
|
|
||||||
def draft(
|
def draft(
|
||||||
self, mode: str | None, size: tuple[int, int]
|
self, mode: str | None, size: tuple[int, int] | None
|
||||||
) -> tuple[str, tuple[int, int, float, float]] | None:
|
) -> tuple[str, tuple[int, int, float, float]] | None:
|
||||||
"""
|
"""
|
||||||
Configures the image file loader so it returns a version of the
|
Configures the image file loader so it returns a version of the
|
||||||
|
@ -1744,7 +1744,7 @@ class Image:
|
||||||
def paste(
|
def paste(
|
||||||
self,
|
self,
|
||||||
im: Image | str | float | tuple[float, ...],
|
im: Image | str | float | tuple[float, ...],
|
||||||
box: tuple[int, int, int, int] | tuple[int, int] | None = None,
|
box: Image | tuple[int, int, int, int] | tuple[int, int] | None = None,
|
||||||
mask: Image | None = None,
|
mask: Image | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -1786,10 +1786,14 @@ class Image:
|
||||||
:param mask: An optional mask image.
|
:param mask: An optional mask image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if isImageType(box) and mask is None:
|
if isImageType(box):
|
||||||
|
if mask is not None:
|
||||||
|
msg = "If using second argument as mask, third argument must be None"
|
||||||
|
raise ValueError(msg)
|
||||||
# abbreviated paste(im, mask) syntax
|
# abbreviated paste(im, mask) syntax
|
||||||
mask = box
|
mask = box
|
||||||
box = None
|
box = None
|
||||||
|
assert not isinstance(box, Image)
|
||||||
|
|
||||||
if box is None:
|
if box is None:
|
||||||
box = (0, 0)
|
box = (0, 0)
|
||||||
|
@ -1995,7 +1999,10 @@ class Image:
|
||||||
self.im.putband(alpha.im, band)
|
self.im.putband(alpha.im, band)
|
||||||
|
|
||||||
def putdata(
|
def putdata(
|
||||||
self, data: Sequence[float], scale: float = 1.0, offset: float = 0.0
|
self,
|
||||||
|
data: Sequence[float] | Sequence[Sequence[int]],
|
||||||
|
scale: float = 1.0,
|
||||||
|
offset: float = 0.0,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Copies pixel data from a flattened sequence object into the image. The
|
Copies pixel data from a flattened sequence object into the image. The
|
||||||
|
@ -2656,7 +2663,7 @@ class Image:
|
||||||
self,
|
self,
|
||||||
size: tuple[float, float],
|
size: tuple[float, float],
|
||||||
resample: Resampling = Resampling.BICUBIC,
|
resample: Resampling = Resampling.BICUBIC,
|
||||||
reducing_gap: float = 2.0,
|
reducing_gap: float | None = 2.0,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Make this image into a thumbnail. This method modifies the
|
Make this image into a thumbnail. This method modifies the
|
||||||
|
@ -2717,11 +2724,12 @@ class Image:
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
box = None
|
box = None
|
||||||
|
final_size: tuple[int, int]
|
||||||
if reducing_gap is not None:
|
if reducing_gap is not None:
|
||||||
preserved_size = preserve_aspect_ratio()
|
preserved_size = preserve_aspect_ratio()
|
||||||
if preserved_size is None:
|
if preserved_size is None:
|
||||||
return
|
return
|
||||||
size = preserved_size
|
final_size = preserved_size
|
||||||
|
|
||||||
res = self.draft(
|
res = self.draft(
|
||||||
None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
|
None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap))
|
||||||
|
@ -2735,13 +2743,13 @@ class Image:
|
||||||
preserved_size = preserve_aspect_ratio()
|
preserved_size = preserve_aspect_ratio()
|
||||||
if preserved_size is None:
|
if preserved_size is None:
|
||||||
return
|
return
|
||||||
size = preserved_size
|
final_size = preserved_size
|
||||||
|
|
||||||
if self.size != size:
|
if self.size != final_size:
|
||||||
im = self.resize(size, resample, box=box, reducing_gap=reducing_gap)
|
im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap)
|
||||||
|
|
||||||
self.im = im.im
|
self.im = im.im
|
||||||
self._size = size
|
self._size = final_size
|
||||||
self._mode = self.im.mode
|
self._mode = self.im.mode
|
||||||
|
|
||||||
self.readonly = 0
|
self.readonly = 0
|
||||||
|
|
|
@ -62,7 +62,9 @@ directly.
|
||||||
|
|
||||||
|
|
||||||
class ImageDraw:
|
class ImageDraw:
|
||||||
font = None
|
font: (
|
||||||
|
ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont | None
|
||||||
|
) = None
|
||||||
|
|
||||||
def __init__(self, im: Image.Image, mode: str | None = None) -> None:
|
def __init__(self, im: Image.Image, mode: str | None = None) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -33,11 +33,12 @@ import sys
|
||||||
import warnings
|
import warnings
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
from types import ModuleType
|
||||||
from typing import IO, TYPE_CHECKING, Any, BinaryIO
|
from typing import IO, TYPE_CHECKING, Any, BinaryIO
|
||||||
|
|
||||||
from . import Image
|
from . import Image
|
||||||
from ._typing import StrOrBytesPath
|
from ._typing import StrOrBytesPath
|
||||||
from ._util import is_path
|
from ._util import DeferredError, is_path
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import ImageFile
|
from . import ImageFile
|
||||||
|
@ -53,11 +54,10 @@ class Layout(IntEnum):
|
||||||
MAX_STRING_LENGTH = 1_000_000
|
MAX_STRING_LENGTH = 1_000_000
|
||||||
|
|
||||||
|
|
||||||
|
core: ModuleType | DeferredError
|
||||||
try:
|
try:
|
||||||
from . import _imagingft as core
|
from . import _imagingft as core
|
||||||
except ImportError as ex:
|
except ImportError as ex:
|
||||||
from ._util import DeferredError
|
|
||||||
|
|
||||||
core = DeferredError.new(ex)
|
core = DeferredError.new(ex)
|
||||||
|
|
||||||
|
|
||||||
|
@ -199,6 +199,7 @@ class FreeTypeFont:
|
||||||
"""FreeType font wrapper (requires _imagingft service)"""
|
"""FreeType font wrapper (requires _imagingft service)"""
|
||||||
|
|
||||||
font: Font
|
font: Font
|
||||||
|
font_bytes: bytes
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -210,6 +211,9 @@ class FreeTypeFont:
|
||||||
) -> None:
|
) -> None:
|
||||||
# FIXME: use service provider instead
|
# FIXME: use service provider instead
|
||||||
|
|
||||||
|
if isinstance(core, DeferredError):
|
||||||
|
raise core.ex
|
||||||
|
|
||||||
if size <= 0:
|
if size <= 0:
|
||||||
msg = "font size must be greater than 0"
|
msg = "font size must be greater than 0"
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
@ -903,7 +907,7 @@ def load_default(size: float | None = None) -> FreeTypeFont | ImageFont:
|
||||||
:return: A font object.
|
:return: A font object.
|
||||||
"""
|
"""
|
||||||
f: FreeTypeFont | ImageFont
|
f: FreeTypeFont | ImageFont
|
||||||
if core.__class__.__name__ == "module" or size is not None:
|
if isinstance(core, ModuleType) or size is not None:
|
||||||
f = truetype(
|
f = truetype(
|
||||||
BytesIO(
|
BytesIO(
|
||||||
base64.b64decode(
|
base64.b64decode(
|
||||||
|
|
|
@ -196,7 +196,7 @@ if qt_is_installed:
|
||||||
self.setColorTable(im_data["colortable"])
|
self.setColorTable(im_data["colortable"])
|
||||||
|
|
||||||
|
|
||||||
def toqimage(im):
|
def toqimage(im) -> ImageQt:
|
||||||
return ImageQt(im)
|
return ImageQt(im)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Transform(Image.ImageTransformHandler):
|
||||||
|
|
||||||
method: Image.Transform
|
method: Image.Transform
|
||||||
|
|
||||||
def __init__(self, data: Sequence[int]) -> None:
|
def __init__(self, data: Sequence[Any]) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def getdata(self) -> tuple[Image.Transform, Sequence[int]]:
|
def getdata(self) -> tuple[Image.Transform, Sequence[int]]:
|
||||||
|
|
|
@ -428,7 +428,7 @@ class JpegImageFile(ImageFile.ImageFile):
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def draft(
|
def draft(
|
||||||
self, mode: str | None, size: tuple[int, int]
|
self, mode: str | None, size: tuple[int, int] | None
|
||||||
) -> tuple[str, tuple[int, int, float, float]] | None:
|
) -> tuple[str, tuple[int, int, float, float]] | None:
|
||||||
if len(self.tile) != 1:
|
if len(self.tile) != 1:
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -89,7 +89,7 @@ DOUBLE = 12
|
||||||
IFD = 13
|
IFD = 13
|
||||||
LONG8 = 16
|
LONG8 = 16
|
||||||
|
|
||||||
TAGS_V2 = {
|
_tags_v2 = {
|
||||||
254: ("NewSubfileType", LONG, 1),
|
254: ("NewSubfileType", LONG, 1),
|
||||||
255: ("SubfileType", SHORT, 1),
|
255: ("SubfileType", SHORT, 1),
|
||||||
256: ("ImageWidth", LONG, 1),
|
256: ("ImageWidth", LONG, 1),
|
||||||
|
@ -425,9 +425,11 @@ TAGS = {
|
||||||
50784: "Alias Layer Metadata",
|
50784: "Alias Layer Metadata",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAGS_V2: dict[int, TagInfo] = {}
|
||||||
|
|
||||||
|
|
||||||
def _populate():
|
def _populate():
|
||||||
for k, v in TAGS_V2.items():
|
for k, v in _tags_v2.items():
|
||||||
# Populate legacy structure.
|
# Populate legacy structure.
|
||||||
TAGS[k] = v[0]
|
TAGS[k] = v[0]
|
||||||
if len(v) == 4:
|
if len(v) == 4:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user