mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-10 19:56:47 +03:00
Merge pull request #8285 from radarhere/type_hint
This commit is contained in:
commit
0633257be3
|
@ -5,6 +5,7 @@ ipython
|
|||
numpy
|
||||
packaging
|
||||
pytest
|
||||
sphinx
|
||||
types-defusedxml
|
||||
types-olefile
|
||||
types-setuptools
|
||||
|
|
|
@ -317,7 +317,13 @@ class TestPyEncoder(CodecsTest):
|
|||
|
||||
fp = BytesIO()
|
||||
ImageFile._save(
|
||||
im, fp, [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 0, "RGB")]
|
||||
im,
|
||||
fp,
|
||||
[
|
||||
ImageFile._Tile(
|
||||
"MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 0, "RGB"
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
assert MockPyEncoder.last
|
||||
|
@ -333,7 +339,7 @@ class TestPyEncoder(CodecsTest):
|
|||
im.tile = [("MOCK", None, 32, None)]
|
||||
|
||||
fp = BytesIO()
|
||||
ImageFile._save(im, fp, [("MOCK", None, 0, "RGB")])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("MOCK", None, 0, "RGB")])
|
||||
|
||||
assert MockPyEncoder.last
|
||||
assert MockPyEncoder.last.state.xoff == 0
|
||||
|
@ -350,7 +356,9 @@ class TestPyEncoder(CodecsTest):
|
|||
MockPyEncoder.last = None
|
||||
with pytest.raises(ValueError):
|
||||
ImageFile._save(
|
||||
im, fp, [("MOCK", (xoff, yoff, -10, yoff + ysize), 0, "RGB")]
|
||||
im,
|
||||
fp,
|
||||
[ImageFile._Tile("MOCK", (xoff, yoff, -10, yoff + ysize), 0, "RGB")],
|
||||
)
|
||||
last: MockPyEncoder | None = MockPyEncoder.last
|
||||
assert last
|
||||
|
@ -358,7 +366,9 @@ class TestPyEncoder(CodecsTest):
|
|||
|
||||
with pytest.raises(ValueError):
|
||||
ImageFile._save(
|
||||
im, fp, [("MOCK", (xoff, yoff, xoff + xsize, -10), 0, "RGB")]
|
||||
im,
|
||||
fp,
|
||||
[ImageFile._Tile("MOCK", (xoff, yoff, xoff + xsize, -10), 0, "RGB")],
|
||||
)
|
||||
|
||||
def test_oversize(self) -> None:
|
||||
|
@ -371,14 +381,22 @@ class TestPyEncoder(CodecsTest):
|
|||
ImageFile._save(
|
||||
im,
|
||||
fp,
|
||||
[("MOCK", (xoff, yoff, xoff + xsize + 100, yoff + ysize), 0, "RGB")],
|
||||
[
|
||||
ImageFile._Tile(
|
||||
"MOCK", (xoff, yoff, xoff + xsize + 100, yoff + ysize), 0, "RGB"
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
ImageFile._save(
|
||||
im,
|
||||
fp,
|
||||
[("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize + 100), 0, "RGB")],
|
||||
[
|
||||
ImageFile._Tile(
|
||||
"MOCK", (xoff, yoff, xoff + xsize, yoff + ysize + 100), 0, "RGB"
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def test_encode(self) -> None:
|
||||
|
|
|
@ -14,6 +14,7 @@ from __future__ import annotations
|
|||
|
||||
import struct
|
||||
from io import BytesIO
|
||||
from typing import IO
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
|
||||
|
@ -94,26 +95,26 @@ DXT3_FOURCC = 0x33545844
|
|||
DXT5_FOURCC = 0x35545844
|
||||
|
||||
|
||||
def _decode565(bits):
|
||||
def _decode565(bits: int) -> tuple[int, int, int]:
|
||||
a = ((bits >> 11) & 0x1F) << 3
|
||||
b = ((bits >> 5) & 0x3F) << 2
|
||||
c = (bits & 0x1F) << 3
|
||||
return a, b, c
|
||||
|
||||
|
||||
def _c2a(a, b):
|
||||
def _c2a(a: int, b: int) -> int:
|
||||
return (2 * a + b) // 3
|
||||
|
||||
|
||||
def _c2b(a, b):
|
||||
def _c2b(a: int, b: int) -> int:
|
||||
return (a + b) // 2
|
||||
|
||||
|
||||
def _c3(a, b):
|
||||
def _c3(a: int, b: int) -> int:
|
||||
return (2 * b + a) // 3
|
||||
|
||||
|
||||
def _dxt1(data, width, height):
|
||||
def _dxt1(data: IO[bytes], width: int, height: int) -> bytes:
|
||||
# TODO implement this function as pixel format in decode.c
|
||||
ret = bytearray(4 * width * height)
|
||||
|
||||
|
@ -151,7 +152,7 @@ def _dxt1(data, width, height):
|
|||
return bytes(ret)
|
||||
|
||||
|
||||
def _dxtc_alpha(a0, a1, ac0, ac1, ai):
|
||||
def _dxtc_alpha(a0: int, a1: int, ac0: int, ac1: int, ai: int) -> int:
|
||||
if ai <= 12:
|
||||
ac = (ac0 >> ai) & 7
|
||||
elif ai == 15:
|
||||
|
@ -175,7 +176,7 @@ def _dxtc_alpha(a0, a1, ac0, ac1, ai):
|
|||
return alpha
|
||||
|
||||
|
||||
def _dxt5(data, width, height):
|
||||
def _dxt5(data: IO[bytes], width: int, height: int) -> bytes:
|
||||
# TODO implement this function as pixel format in decode.c
|
||||
ret = bytearray(4 * width * height)
|
||||
|
||||
|
@ -211,7 +212,7 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
format = "DDS"
|
||||
format_description = "DirectDraw Surface"
|
||||
|
||||
def _open(self):
|
||||
def _open(self) -> None:
|
||||
if not _accept(self.fp.read(4)):
|
||||
msg = "not a DDS file"
|
||||
raise SyntaxError(msg)
|
||||
|
@ -242,19 +243,20 @@ class DdsImageFile(ImageFile.ImageFile):
|
|||
elif fourcc == b"DXT5":
|
||||
self.decoder = "DXT5"
|
||||
else:
|
||||
msg = f"Unimplemented pixel format {fourcc}"
|
||||
msg = f"Unimplemented pixel format {repr(fourcc)}"
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
self.tile = [(self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]
|
||||
|
||||
def load_seek(self, pos):
|
||||
def load_seek(self, pos: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class DXT1Decoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer):
|
||||
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
try:
|
||||
self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize))
|
||||
except struct.error as e:
|
||||
|
@ -266,7 +268,8 @@ class DXT1Decoder(ImageFile.PyDecoder):
|
|||
class DXT5Decoder(ImageFile.PyDecoder):
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer):
|
||||
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||
assert self.fd is not None
|
||||
try:
|
||||
self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize))
|
||||
except struct.error as e:
|
||||
|
@ -279,7 +282,7 @@ Image.register_decoder("DXT1", DXT1Decoder)
|
|||
Image.register_decoder("DXT5", DXT5Decoder)
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
return prefix[:4] == b"DDS "
|
||||
|
||||
|
||||
|
|
|
@ -1517,19 +1517,21 @@ To add other read or write support, use
|
|||
:py:func:`PIL.WmfImagePlugin.register_handler` to register a WMF and EMF
|
||||
handler. ::
|
||||
|
||||
from PIL import Image
|
||||
from typing import IO
|
||||
|
||||
from PIL import Image, ImageFile
|
||||
from PIL import WmfImagePlugin
|
||||
|
||||
|
||||
class WmfHandler:
|
||||
def open(self, im):
|
||||
class WmfHandler(ImageFile.StubHandler):
|
||||
def open(self, im: ImageFile.StubImageFile) -> None:
|
||||
...
|
||||
|
||||
def load(self, im):
|
||||
def load(self, im: ImageFile.StubImageFile) -> Image.Image:
|
||||
...
|
||||
return image
|
||||
|
||||
def save(self, im, fp, filename):
|
||||
def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
|
||||
...
|
||||
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ Rolling an image
|
|||
|
||||
::
|
||||
|
||||
def roll(im, delta):
|
||||
def roll(im: Image.Image, delta: int) -> Image.Image:
|
||||
"""Roll an image sideways."""
|
||||
xsize, ysize = im.size
|
||||
|
||||
|
@ -211,7 +211,7 @@ Merging images
|
|||
|
||||
::
|
||||
|
||||
def merge(im1, im2):
|
||||
def merge(im1: Image.Image, im2: Image.Image) -> Image.Image:
|
||||
w = im1.size[0] + im2.size[0]
|
||||
h = max(im1.size[1], im2.size[1])
|
||||
im = Image.new("RGBA", (w, h))
|
||||
|
@ -704,7 +704,7 @@ in the current directory can be saved as JPEGs at reduced quality.
|
|||
import glob
|
||||
from PIL import Image
|
||||
|
||||
def compress_image(source_path, dest_path):
|
||||
def compress_image(source_path: str, dest_path: str) -> None:
|
||||
with Image.open(source_path) as img:
|
||||
if img.mode != "RGB":
|
||||
img = img.convert("RGB")
|
||||
|
|
|
@ -53,7 +53,7 @@ true color.
|
|||
from PIL import Image, ImageFile
|
||||
|
||||
|
||||
def _accept(prefix):
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
return prefix[:4] == b"SPAM"
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ true color.
|
|||
format = "SPAM"
|
||||
format_description = "Spam raster image"
|
||||
|
||||
def _open(self):
|
||||
def _open(self) -> None:
|
||||
|
||||
header = self.fp.read(128).split()
|
||||
|
||||
|
@ -82,7 +82,7 @@ true color.
|
|||
raise SyntaxError(msg)
|
||||
|
||||
# data descriptor
|
||||
self.tile = [("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))]
|
||||
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))]
|
||||
|
||||
|
||||
Image.register_open(SpamImageFile.format, SpamImageFile, _accept)
|
||||
|
|
|
@ -477,7 +477,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
fp.write(struct.pack("<i", 5))
|
||||
fp.write(struct.pack("<i", 0))
|
||||
|
||||
ImageFile._save(im, fp, [("BLP", (0, 0) + im.size, 0, im.mode)])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("BLP", (0, 0) + im.size, 0, im.mode)])
|
||||
|
||||
|
||||
Image.register_open(BlpImageFile.format, BlpImageFile, _accept)
|
||||
|
|
|
@ -482,7 +482,9 @@ def _save(
|
|||
if palette:
|
||||
fp.write(palette)
|
||||
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))])
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -434,7 +434,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes, eps: int = 1) -
|
|||
if hasattr(fp, "flush"):
|
||||
fp.flush()
|
||||
|
||||
ImageFile._save(im, fp, [("eps", (0, 0) + im.size, 0, None)])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("eps", (0, 0) + im.size, 0, None)])
|
||||
|
||||
fp.write(b"\n%%%%EndBinary\n")
|
||||
fp.write(b"grestore end\n")
|
||||
|
|
|
@ -591,7 +591,9 @@ def _write_single_frame(
|
|||
_write_local_header(fp, im, (0, 0), flags)
|
||||
|
||||
im_out.encoderconfig = (8, get_interlace(im))
|
||||
ImageFile._save(im_out, fp, [("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])])
|
||||
ImageFile._save(
|
||||
im_out, fp, [ImageFile._Tile("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])]
|
||||
)
|
||||
|
||||
fp.write(b"\0") # end of image data
|
||||
|
||||
|
@ -1054,7 +1056,9 @@ def _write_frame_data(
|
|||
_write_local_header(fp, im_frame, offset, 0)
|
||||
|
||||
ImageFile._save(
|
||||
im_frame, fp, [("gif", (0, 0) + im_frame.size, 0, RAWMODE[im_frame.mode])]
|
||||
im_frame,
|
||||
fp,
|
||||
[ImageFile._Tile("gif", (0, 0) + im_frame.size, 0, RAWMODE[im_frame.mode])],
|
||||
)
|
||||
|
||||
fp.write(b"\0") # end of image data
|
||||
|
|
|
@ -97,7 +97,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
if bits != 32:
|
||||
and_mask = Image.new("1", size)
|
||||
ImageFile._save(
|
||||
and_mask, image_io, [("raw", (0, 0) + size, 0, ("1", 0, -1))]
|
||||
and_mask,
|
||||
image_io,
|
||||
[ImageFile._Tile("raw", (0, 0) + size, 0, ("1", 0, -1))],
|
||||
)
|
||||
else:
|
||||
frame.save(image_io, "png")
|
||||
|
|
|
@ -360,7 +360,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
palette += im_palette[colors * i : colors * (i + 1)]
|
||||
palette += b"\x00" * (256 - colors)
|
||||
fp.write(palette) # 768 bytes
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))])
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -218,9 +218,10 @@ if hasattr(core, "DEFAULT_STRATEGY"):
|
|||
# Registries
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import mmap
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from . import ImageFile, ImagePalette, TiffImagePlugin
|
||||
from . import ImageFile, ImageFilter, ImagePalette, TiffImagePlugin
|
||||
from ._typing import NumpyArray, StrOrBytesPath, TypeGuard
|
||||
ID: list[str] = []
|
||||
OPEN: dict[
|
||||
|
@ -612,7 +613,7 @@ class Image:
|
|||
logger.debug("Error closing: %s", msg)
|
||||
|
||||
if getattr(self, "map", None):
|
||||
self.map = None
|
||||
self.map: mmap.mmap | None = None
|
||||
|
||||
# Instead of simply setting to None, we're setting up a
|
||||
# deferred error that will better explain that the core image
|
||||
|
@ -1336,9 +1337,6 @@ class Image:
|
|||
self.load()
|
||||
return self._new(self.im.expand(xmargin, ymargin))
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from . import ImageFilter
|
||||
|
||||
def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image:
|
||||
"""
|
||||
Filters this image using the given filter. For a list of
|
||||
|
|
|
@ -93,7 +93,7 @@ def _tilesort(t: _Tile) -> int:
|
|||
|
||||
class _Tile(NamedTuple):
|
||||
codec_name: str
|
||||
extents: tuple[int, int, int, int]
|
||||
extents: tuple[int, int, int, int] | None
|
||||
offset: int
|
||||
args: tuple[Any, ...] | str | None
|
||||
|
||||
|
@ -174,7 +174,7 @@ class ImageFile(Image.Image):
|
|||
self.fp.close()
|
||||
self.fp = None
|
||||
|
||||
def load(self):
|
||||
def load(self) -> Image.core.PixelAccess | None:
|
||||
"""Load image data based on tile list"""
|
||||
|
||||
if self.tile is None:
|
||||
|
@ -185,7 +185,7 @@ class ImageFile(Image.Image):
|
|||
if not self.tile:
|
||||
return pixel
|
||||
|
||||
self.map = None
|
||||
self.map: mmap.mmap | None = None
|
||||
use_mmap = self.filename and len(self.tile) == 1
|
||||
# As of pypy 2.1.0, memory mapping was failing here.
|
||||
use_mmap = use_mmap and not hasattr(sys, "pypy_version_info")
|
||||
|
@ -193,17 +193,17 @@ class ImageFile(Image.Image):
|
|||
readonly = 0
|
||||
|
||||
# look for read/seek overrides
|
||||
try:
|
||||
if hasattr(self, "load_read"):
|
||||
read = self.load_read
|
||||
# don't use mmap if there are custom read/seek functions
|
||||
use_mmap = False
|
||||
except AttributeError:
|
||||
else:
|
||||
read = self.fp.read
|
||||
|
||||
try:
|
||||
if hasattr(self, "load_seek"):
|
||||
seek = self.load_seek
|
||||
use_mmap = False
|
||||
except AttributeError:
|
||||
else:
|
||||
seek = self.fp.seek
|
||||
|
||||
if use_mmap:
|
||||
|
@ -243,11 +243,8 @@ class ImageFile(Image.Image):
|
|||
# sort tiles in file order
|
||||
self.tile.sort(key=_tilesort)
|
||||
|
||||
try:
|
||||
# FIXME: This is a hack to handle TIFF's JpegTables tag.
|
||||
prefix = self.tile_prefix
|
||||
except AttributeError:
|
||||
prefix = b""
|
||||
# FIXME: This is a hack to handle TIFF's JpegTables tag.
|
||||
prefix = getattr(self, "tile_prefix", b"")
|
||||
|
||||
# Remove consecutive duplicates that only differ by their offset
|
||||
self.tile = [
|
||||
|
@ -525,7 +522,7 @@ class Parser:
|
|||
# --------------------------------------------------------------------
|
||||
|
||||
|
||||
def _save(im: Image.Image, fp: IO[bytes], tile, bufsize: int = 0) -> None:
|
||||
def _save(im: Image.Image, fp: IO[bytes], tile: list[_Tile], bufsize: int = 0) -> None:
|
||||
"""Helper to save image based on tile list
|
||||
|
||||
:param im: Image object.
|
||||
|
|
|
@ -419,7 +419,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
plt,
|
||||
)
|
||||
|
||||
ImageFile._save(im, fp, [("jpeg2k", (0, 0) + im.size, 0, kind)])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("jpeg2k", (0, 0) + im.size, 0, kind)])
|
||||
|
||||
|
||||
# ------------------------------------------------------------
|
||||
|
|
|
@ -826,7 +826,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
# Ensure that our buffer is big enough. Same with the icc_profile block.
|
||||
bufsize = max(bufsize, len(exif) + 5, len(extra) + 1)
|
||||
|
||||
ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize
|
||||
)
|
||||
|
||||
|
||||
def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
|
|
|
@ -188,7 +188,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
fp.write(o16(h))
|
||||
|
||||
# image body
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 32, ("1", 0, 1))])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 32, ("1", 0, 1))])
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -213,7 +213,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
)
|
||||
|
||||
# now convert data to raw form
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))])
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))]
|
||||
)
|
||||
|
||||
if hasattr(fp, "flush"):
|
||||
fp.flush()
|
||||
|
|
|
@ -198,7 +198,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
|
||||
assert fp.tell() == 128
|
||||
|
||||
ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))])
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))]
|
||||
)
|
||||
|
||||
if im.mode == "P":
|
||||
# colour palette
|
||||
|
|
|
@ -138,7 +138,7 @@ def _write_image(
|
|||
op = io.BytesIO()
|
||||
|
||||
if decode_filter == "ASCIIHexDecode":
|
||||
ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
|
||||
ImageFile._save(im, op, [ImageFile._Tile("hex", (0, 0) + im.size, 0, im.mode)])
|
||||
elif decode_filter == "CCITTFaxDecode":
|
||||
im.save(
|
||||
op,
|
||||
|
|
|
@ -1226,7 +1226,7 @@ def _write_multiple_frames(
|
|||
ImageFile._save(
|
||||
im,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[("zip", (0, 0) + im.size, 0, rawmode)],
|
||||
[ImageFile._Tile("zip", (0, 0) + im.size, 0, rawmode)],
|
||||
)
|
||||
|
||||
seq_num = 0
|
||||
|
@ -1263,14 +1263,14 @@ def _write_multiple_frames(
|
|||
ImageFile._save(
|
||||
im_frame,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[("zip", (0, 0) + im_frame.size, 0, rawmode)],
|
||||
[ImageFile._Tile("zip", (0, 0) + im_frame.size, 0, rawmode)],
|
||||
)
|
||||
else:
|
||||
fdat_chunks = _fdat(fp, chunk, seq_num)
|
||||
ImageFile._save(
|
||||
im_frame,
|
||||
cast(IO[bytes], fdat_chunks),
|
||||
[("zip", (0, 0) + im_frame.size, 0, rawmode)],
|
||||
[ImageFile._Tile("zip", (0, 0) + im_frame.size, 0, rawmode)],
|
||||
)
|
||||
seq_num = fdat_chunks.seq_num
|
||||
return None
|
||||
|
@ -1471,7 +1471,7 @@ def _save(
|
|||
ImageFile._save(
|
||||
single_im,
|
||||
cast(IO[bytes], _idat(fp, chunk)),
|
||||
[("zip", (0, 0) + single_im.size, 0, rawmode)],
|
||||
[ImageFile._Tile("zip", (0, 0) + single_im.size, 0, rawmode)],
|
||||
)
|
||||
|
||||
if info:
|
||||
|
|
|
@ -353,7 +353,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
elif head == b"Pf":
|
||||
fp.write(b"-1.0\n")
|
||||
row_order = -1 if im.mode == "F" else 1
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, row_order))])
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, row_order))]
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -278,7 +278,9 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
fp.writelines(hdr)
|
||||
|
||||
rawmode = "F;32NF" # 32-bit native floating point
|
||||
ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
|
||||
ImageFile._save(
|
||||
im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))]
|
||||
)
|
||||
|
||||
|
||||
def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
|
|
|
@ -238,11 +238,15 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
|
||||
if rle:
|
||||
ImageFile._save(
|
||||
im, fp, [("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))]
|
||||
im,
|
||||
fp,
|
||||
[ImageFile._Tile("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))],
|
||||
)
|
||||
else:
|
||||
ImageFile._save(
|
||||
im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))]
|
||||
im,
|
||||
fp,
|
||||
[ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))],
|
||||
)
|
||||
|
||||
# write targa version 2 footer
|
||||
|
|
|
@ -456,8 +456,11 @@ class IFDRational(Rational):
|
|||
__int__ = _delegate("__int__")
|
||||
|
||||
|
||||
def _register_loader(idx: int, size: int):
|
||||
def decorator(func):
|
||||
_LoaderFunc = Callable[["ImageFileDirectory_v2", bytes, bool], Any]
|
||||
|
||||
|
||||
def _register_loader(idx: int, size: int) -> Callable[[_LoaderFunc], _LoaderFunc]:
|
||||
def decorator(func: _LoaderFunc) -> _LoaderFunc:
|
||||
from .TiffTags import TYPES
|
||||
|
||||
if func.__name__.startswith("load_"):
|
||||
|
@ -482,12 +485,13 @@ def _register_basic(idx_fmt_name: tuple[int, str, str]) -> None:
|
|||
idx, fmt, name = idx_fmt_name
|
||||
TYPES[idx] = name
|
||||
size = struct.calcsize(f"={fmt}")
|
||||
_load_dispatch[idx] = ( # noqa: F821
|
||||
size,
|
||||
lambda self, data, legacy_api=True: (
|
||||
self._unpack(f"{len(data) // size}{fmt}", data)
|
||||
),
|
||||
)
|
||||
|
||||
def basic_handler(
|
||||
self: ImageFileDirectory_v2, data: bytes, legacy_api: bool = True
|
||||
) -> tuple[Any, ...]:
|
||||
return self._unpack(f"{len(data) // size}{fmt}", data)
|
||||
|
||||
_load_dispatch[idx] = size, basic_handler # noqa: F821
|
||||
_write_dispatch[idx] = lambda self, *values: ( # noqa: F821
|
||||
b"".join(self._pack(fmt, value) for value in values)
|
||||
)
|
||||
|
@ -560,7 +564,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
|
||||
"""
|
||||
|
||||
_load_dispatch: dict[int, Callable[[ImageFileDirectory_v2, bytes, bool], Any]] = {}
|
||||
_load_dispatch: dict[int, tuple[int, _LoaderFunc]] = {}
|
||||
_write_dispatch: dict[int, Callable[..., Any]] = {}
|
||||
|
||||
def __init__(
|
||||
|
@ -653,10 +657,10 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
def __contains__(self, tag: object) -> bool:
|
||||
return tag in self._tags_v2 or tag in self._tagdata
|
||||
|
||||
def __setitem__(self, tag: int, value) -> None:
|
||||
def __setitem__(self, tag: int, value: Any) -> None:
|
||||
self._setitem(tag, value, self.legacy_api)
|
||||
|
||||
def _setitem(self, tag: int, value, legacy_api: bool) -> None:
|
||||
def _setitem(self, tag: int, value: Any, legacy_api: bool) -> None:
|
||||
basetypes = (Number, bytes, str)
|
||||
|
||||
info = TiffTags.lookup(tag, self.group)
|
||||
|
@ -744,10 +748,10 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
def __iter__(self) -> Iterator[int]:
|
||||
return iter(set(self._tagdata) | set(self._tags_v2))
|
||||
|
||||
def _unpack(self, fmt: str, data: bytes):
|
||||
def _unpack(self, fmt: str, data: bytes) -> tuple[Any, ...]:
|
||||
return struct.unpack(self._endian + fmt, data)
|
||||
|
||||
def _pack(self, fmt: str, *values) -> bytes:
|
||||
def _pack(self, fmt: str, *values: Any) -> bytes:
|
||||
return struct.pack(self._endian + fmt, *values)
|
||||
|
||||
list(
|
||||
|
@ -824,7 +828,9 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
|||
return value
|
||||
|
||||
@_register_loader(10, 8)
|
||||
def load_signed_rational(self, data: bytes, legacy_api: bool = True):
|
||||
def load_signed_rational(
|
||||
self, data: bytes, legacy_api: bool = True
|
||||
) -> tuple[tuple[int, int] | IFDRational, ...]:
|
||||
vals = self._unpack(f"{len(data) // 4}l", data)
|
||||
|
||||
def combine(a: int, b: int) -> tuple[int, int] | IFDRational:
|
||||
|
@ -1088,7 +1094,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
|||
def __iter__(self) -> Iterator[int]:
|
||||
return iter(set(self._tagdata) | set(self._tags_v1))
|
||||
|
||||
def __setitem__(self, tag: int, value) -> None:
|
||||
def __setitem__(self, tag: int, value: Any) -> None:
|
||||
for legacy_api in (False, True):
|
||||
self._setitem(tag, value, legacy_api)
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
|||
|
||||
fp.write(b"static char im_bits[] = {\n")
|
||||
|
||||
ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)])
|
||||
ImageFile._save(im, fp, [ImageFile._Tile("xbm", (0, 0) + im.size, 0, None)])
|
||||
|
||||
fp.write(b"};\n")
|
||||
|
||||
|
|
2
tox.ini
2
tox.ini
|
@ -36,4 +36,4 @@ deps =
|
|||
extras =
|
||||
typing
|
||||
commands =
|
||||
mypy src Tests {posargs}
|
||||
mypy docs src winbuild Tests {posargs}
|
||||
|
|
|
@ -7,6 +7,7 @@ import re
|
|||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
|
||||
def cmd_cd(path: str) -> str:
|
||||
|
@ -43,21 +44,19 @@ def cmd_nmake(
|
|||
target: str = "",
|
||||
params: list[str] | None = None,
|
||||
) -> str:
|
||||
params = "" if params is None else " ".join(params)
|
||||
|
||||
return " ".join(
|
||||
[
|
||||
"{nmake}",
|
||||
"-nologo",
|
||||
f'-f "{makefile}"' if makefile is not None else "",
|
||||
f"{params}",
|
||||
f'{" ".join(params)}' if params is not None else "",
|
||||
f'"{target}"',
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def cmds_cmake(
|
||||
target: str | tuple[str, ...] | list[str], *params, build_dir: str = "."
|
||||
target: str | tuple[str, ...] | list[str], *params: str, build_dir: str = "."
|
||||
) -> list[str]:
|
||||
if not isinstance(target, str):
|
||||
target = " ".join(target)
|
||||
|
@ -129,7 +128,7 @@ V["ZLIB_DOTLESS"] = V["ZLIB"].replace(".", "")
|
|||
|
||||
|
||||
# dependencies, listed in order of compilation
|
||||
DEPS = {
|
||||
DEPS: dict[str, dict[str, Any]] = {
|
||||
"libjpeg": {
|
||||
"url": f"{SF_PROJECTS}/libjpeg-turbo/files/{V['JPEGTURBO']}/"
|
||||
f"libjpeg-turbo-{V['JPEGTURBO']}.tar.gz/download",
|
||||
|
@ -538,7 +537,7 @@ def write_script(
|
|||
print(" " + line)
|
||||
|
||||
|
||||
def get_footer(dep: dict) -> list[str]:
|
||||
def get_footer(dep: dict[str, Any]) -> list[str]:
|
||||
lines = []
|
||||
for out in dep.get("headers", []):
|
||||
lines.append(cmd_copy(out, "{inc_dir}"))
|
||||
|
@ -583,6 +582,7 @@ def build_dep(name: str, prefs: dict[str, str], verbose: bool) -> str:
|
|||
license_text += f.read()
|
||||
if "license_pattern" in dep:
|
||||
match = re.search(dep["license_pattern"], license_text, re.DOTALL)
|
||||
assert match is not None
|
||||
license_text = "\n".join(match.groups())
|
||||
assert len(license_text) > 50
|
||||
with open(os.path.join(license_dir, f"{directory}.txt"), "w") as f:
|
||||
|
|
Loading…
Reference in New Issue
Block a user