From b76d4ee3603fb2d6bf760cf6302a113b86586bea Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 17 Oct 2026 20:14:43 +1100 Subject: [PATCH 1/4] Use NamedTuple field name --- src/PIL/Jpeg2KImagePlugin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index 97f3282af8c..1a116193612 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -374,9 +374,9 @@ def load(self) -> Image.core.PixelAccess | None: # Update the reduce and layers settings t = self.tile[0] - assert isinstance(t[3], tuple) - t3 = (t[3][0], self._reduce, self.layers, t[3][3], t[3][4]) - self.tile = [ImageFile._Tile(t[0], (0, 0, *self.size), t[2], t3)] + assert isinstance(t.args, tuple) + args = (t.args[0], self._reduce, self.layers, t.args[3], t.args[4]) + self.tile = [t._replace(extents=(0, 0, *self.size), args=args)] return ImageFile.ImageFile.load(self) From d3b3cc334930e4c3c5f3506d471aca39ad4d3669 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 17 Oct 2026 21:14:13 +1100 Subject: [PATCH 2/4] Simplify tiles by using None extents --- Tests/test_file_iptc.py | 2 +- Tests/test_file_pcx.py | 1 - src/PIL/AvifImagePlugin.py | 2 +- src/PIL/BlpImagePlugin.py | 4 ++-- src/PIL/BmpImagePlugin.py | 4 +--- src/PIL/CurImagePlugin.py | 2 +- src/PIL/DdsImagePlugin.py | 11 ++++------- src/PIL/EpsImagePlugin.py | 6 ++---- src/PIL/FitsImagePlugin.py | 2 +- src/PIL/FliImagePlugin.py | 2 +- src/PIL/FtexImagePlugin.py | 4 ++-- src/PIL/GdImageFile.py | 2 +- src/PIL/GifImagePlugin.py | 4 +--- src/PIL/IcoImagePlugin.py | 7 +++---- src/PIL/ImImagePlugin.py | 24 +++++++----------------- src/PIL/ImtImagePlugin.py | 2 +- src/PIL/IptcImagePlugin.py | 4 +--- src/PIL/Jpeg2KImagePlugin.py | 6 +++--- src/PIL/JpegImagePlugin.py | 17 ++++++----------- src/PIL/McIdasImagePlugin.py | 4 +--- src/PIL/MpoImagePlugin.py | 4 +--- src/PIL/MspImagePlugin.py | 6 +++--- src/PIL/PalmImagePlugin.py | 4 +--- src/PIL/PcxImagePlugin.py | 7 ++----- src/PIL/PdfImagePlugin.py | 2 +- src/PIL/PixarImagePlugin.py | 2 +- src/PIL/PngImagePlugin.py | 2 +- src/PIL/PpmImagePlugin.py | 8 ++------ src/PIL/QoiImagePlugin.py | 2 +- src/PIL/SgiImagePlugin.py | 10 +++------- src/PIL/SpiderImagePlugin.py | 4 ++-- src/PIL/SunImagePlugin.py | 8 ++------ src/PIL/TgaImagePlugin.py | 8 ++++---- src/PIL/TiffImagePlugin.py | 2 +- src/PIL/WebPImagePlugin.py | 2 +- src/PIL/XVThumbImagePlugin.py | 4 +--- src/PIL/XbmImagePlugin.py | 4 ++-- src/PIL/XpmImagePlugin.py | 2 +- 38 files changed, 70 insertions(+), 121 deletions(-) diff --git a/Tests/test_file_iptc.py b/Tests/test_file_iptc.py index 3eb5cde8e50..b7185fed385 100644 --- a/Tests/test_file_iptc.py +++ b/Tests/test_file_iptc.py @@ -34,7 +34,7 @@ def test_open() -> None: f = create_iptc_image() with Image.open(f) as im: - assert im.tile == [("iptc", (0, 0, 1, 1), 25, ("raw", None))] + assert im.tile == [("iptc", None, 25, ("raw", None))] assert_image_equal(im, expected) with Image.open(f) as im: diff --git a/Tests/test_file_pcx.py b/Tests/test_file_pcx.py index 2541efda7b1..1f2d8e18d67 100644 --- a/Tests/test_file_pcx.py +++ b/Tests/test_file_pcx.py @@ -107,7 +107,6 @@ def test_pil184() -> None: test_file = "Tests/images/pil184.pcx" with Image.open(test_file) as im: assert im.size == (447, 144) - assert im.tile[0][1] == (0, 0, 447, 144) # Make sure all pixels are either 0 or 255. assert im.histogram()[0] + im.histogram()[255] == 447 * 144 diff --git a/src/PIL/AvifImagePlugin.py b/src/PIL/AvifImagePlugin.py index 6a124214a08..72ee30305e1 100644 --- a/src/PIL/AvifImagePlugin.py +++ b/src/PIL/AvifImagePlugin.py @@ -120,7 +120,7 @@ def seek(self, frame: int) -> None: # Set tile self.__frame = frame - self.tile = [ImageFile._Tile("raw", (0, 0, *self.size), 0, self.mode)] + self.tile = [ImageFile._Tile("raw", None, 0, self.mode)] def load(self) -> Image.core.PixelAccess | None: if self.tile: diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index d59fff52295..f236a9bfec1 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -294,7 +294,7 @@ def _open(self) -> None: decoder = self.magic.decode() self._mode = "RGBA" if alpha else "RGB" - self.tile = [ImageFile._Tile(decoder, (0, 0, *self.size), offset, args)] + self.tile = [ImageFile._Tile(decoder, None, offset, args)] class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder): @@ -491,7 +491,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(struct.pack(" None: # patch up the bitmap height self._size = self.width, self.height // 2 if not self._masked: - self.tile = [self.tile[0]._replace(extents=(0, 0, *self.size))] + self.tile = [self.tile[0]._replace(extents=None)] def load_prepare(self) -> None: if self._masked: diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index febe0c70afc..7da9edfbba3 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -352,7 +352,6 @@ def _open(self) -> None: flags, height, width = struct.unpack("<3I", header[:12]) self._size = (width, height) - extents = (0, 0, *self.size) pitch, depth, mipmaps = struct.unpack("<3I", header[12:24]) struct.unpack("<11I", header[24:68]) # reserved @@ -371,7 +370,7 @@ def _open(self) -> None: mask_count = 3 masks = struct.unpack(f"<{mask_count}I", header[84 : 84 + mask_count * 4]) - self.tile = [ImageFile._Tile("dds_rgb", extents, 0, (bitcount, masks))] + self.tile = [ImageFile._Tile("dds_rgb", None, 0, (bitcount, masks))] return elif pfflags & DDPF.LUMINANCE: if bitcount == 8: @@ -480,11 +479,9 @@ def _open(self) -> None: raise NotImplementedError(msg) if n: - self.tile = [ - ImageFile._Tile("bcn", extents, offset, (n, self.pixel_format)) - ] + self.tile = [ImageFile._Tile("bcn", None, offset, (n, self.pixel_format))] else: - self.tile = [ImageFile._Tile("raw", extents, 0, rawmode or self.mode)] + self.tile = [ImageFile._Tile("raw", None, 0, rawmode or self.mode)] def load_seek(self, pos: int) -> None: pass @@ -624,7 +621,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # dxgi_format, 2D resource, misc, array size, straight alpha struct.pack("<5I", dxgi_format, 3, 0, 0, 1) ) - ImageFile._save(im, fp, [ImageFile._Tile(codec_name, (0, 0, *im.size), 0, args)]) + ImageFile._save(im, fp, [ImageFile._Tile(codec_name, None, 0, args)]) def _accept(prefix: bytes) -> bool: diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index e60ce197f33..da4c64c6966 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -385,9 +385,7 @@ def read_comment(s: str) -> bool: bounding_box[3] - bounding_box[1], ) - self.tile = [ - ImageFile._Tile("eps", (0, 0, *self.size), offset, (length, bounding_box)) - ] + self.tile = [ImageFile._Tile("eps", None, offset, (length, bounding_box))] def _find_offset(self, fp: IO[bytes]) -> tuple[int, int]: s = fp.read(4) @@ -474,7 +472,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, [ImageFile._Tile("eps", (0, 0, *im.size))]) + ImageFile._save(im, fp, [ImageFile._Tile("eps", None)]) fp.write(b"\n%%%%EndBinary\n") fp.write(b"grestore end\n") diff --git a/src/PIL/FitsImagePlugin.py b/src/PIL/FitsImagePlugin.py index 4ac47b595e0..ee8f2f8a517 100644 --- a/src/PIL/FitsImagePlugin.py +++ b/src/PIL/FitsImagePlugin.py @@ -70,7 +70,7 @@ def _open(self) -> None: raise ValueError(msg) offset += self.fp.tell() - 80 - self.tile = [ImageFile._Tile(decoder_name, (0, 0, *self.size), offset, args)] + self.tile = [ImageFile._Tile(decoder_name, None, offset, args)] def _get_size( self, headers: dict[bytes, bytes], prefix: bytes diff --git a/src/PIL/FliImagePlugin.py b/src/PIL/FliImagePlugin.py index 571cb60bc8e..cdbd0ffee35 100644 --- a/src/PIL/FliImagePlugin.py +++ b/src/PIL/FliImagePlugin.py @@ -172,7 +172,7 @@ def _seek(self, frame: int) -> None: framesize = i32(s) self.decodermaxblock = framesize - self.tile = [ImageFile._Tile("fli", (0, 0, *self.size), self.__offset)] + self.tile = [ImageFile._Tile("fli", None, self.__offset)] self.__offset += framesize diff --git a/src/PIL/FtexImagePlugin.py b/src/PIL/FtexImagePlugin.py index 232e0f8e7b1..5d92938efde 100644 --- a/src/PIL/FtexImagePlugin.py +++ b/src/PIL/FtexImagePlugin.py @@ -96,10 +96,10 @@ def _open(self) -> None: if format == Format.DXT1: self._mode = "RGBA" - self.tile = [ImageFile._Tile("bcn", (0, 0, *self.size), 0, (1,))] + self.tile = [ImageFile._Tile("bcn", None, 0, (1,))] elif format == Format.UNCOMPRESSED: self._mode = "RGB" - self.tile = [ImageFile._Tile("raw", (0, 0, *self.size), 0, "RGB")] + self.tile = [ImageFile._Tile("raw", None, 0, "RGB")] else: msg = f"Invalid texture compression format: {repr(format)}" raise ValueError(msg) diff --git a/src/PIL/GdImageFile.py b/src/PIL/GdImageFile.py index b94ab2f5e69..843bb8ebcd4 100644 --- a/src/PIL/GdImageFile.py +++ b/src/PIL/GdImageFile.py @@ -81,7 +81,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "raw", - (0, 0, *self.size), + None, 7 + true_color_offset + 6 + 256 * 4, "L", ) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 06aeeb8485d..b3c4d46c326 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -634,9 +634,7 @@ def _write_single_frame( _write_local_header(fp, im, (0, 0), flags) im_out.encoderconfig = (8, get_interlace(im)) - ImageFile._save( - im_out, fp, [ImageFile._Tile("gif", (0, 0, *im.size), 0, RAWMODE[im_out.mode])] - ) + ImageFile._save(im_out, fp, [ImageFile._Tile("gif", None, 0, RAWMODE[im_out.mode])]) fp.write(b"\0") # end of image data diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py index 3d2c687888e..85740e9d7d8 100644 --- a/src/PIL/IcoImagePlugin.py +++ b/src/PIL/IcoImagePlugin.py @@ -135,7 +135,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ImageFile._save( and_mask, image_io, - [ImageFile._Tile("raw", (0, 0, *size), 0, ("1", 0, -1))], + [ImageFile._Tile("raw", None, 0, ("1", 0, -1))], ) else: frame.save(image_io, "png") @@ -263,8 +263,7 @@ def frame(self, idx: int) -> Image.Image: # change tile dimension to only encompass XOR image im._size = (im.size[0], int(im.size[1] / 2)) - d, e, o, a = im.tile[0] - im.tile[0] = ImageFile._Tile(d, (0, 0, *im.size), o, a) + im.tile = [im.tile[0]._replace(extents=None)] # figure out where AND mask image starts if header.bpp == 32: @@ -274,7 +273,7 @@ def frame(self, idx: int) -> Image.Image: # channel. # Back up to start of bmp data - self.buf.seek(o) + self.buf.seek(im.tile[0].offset) # extract every 4th byte (eg. 3,7,11,15,...) alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4] diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index 5cf934fee6d..7eb5b269776 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -266,9 +266,7 @@ def _open(self) -> None: bits = int(self.rawmode[2:]) if bits not in [8, 16, 32]: self.tile = [ - ImageFile._Tile( - "bit", (0, 0, *self.size), offs, (bits, 8, 3, 0, -1) - ) + ImageFile._Tile("bit", None, offs, (bits, 8, 3, 0, -1)) ] return except ValueError: @@ -279,17 +277,13 @@ def _open(self) -> None: # ever stumbled upon such a file ;-) size = self.size[0] * self.size[1] self.tile = [ - ImageFile._Tile("raw", (0, 0, *self.size), offs, ("G", 0, -1)), - ImageFile._Tile("raw", (0, 0, *self.size), offs + size, ("R", 0, -1)), - ImageFile._Tile( - "raw", (0, 0, *self.size), offs + 2 * size, ("B", 0, -1) - ), + ImageFile._Tile("raw", None, offs, ("G", 0, -1)), + ImageFile._Tile("raw", None, offs + size, ("R", 0, -1)), + ImageFile._Tile("raw", None, offs + 2 * size, ("B", 0, -1)), ] else: # LabEye/IFUNC files - self.tile = [ - ImageFile._Tile("raw", (0, 0, *self.size), offs, (self.rawmode, 0, -1)) - ] + self.tile = [ImageFile._Tile("raw", None, offs, (self.rawmode, 0, -1))] @property def n_frames(self) -> int: @@ -317,9 +311,7 @@ def seek(self, frame: int) -> None: self.fp = self._fp - self.tile = [ - ImageFile._Tile("raw", (0, 0, *self.size), offs, (self.rawmode, 0, -1)) - ] + self.tile = [ImageFile._Tile("raw", None, offs, (self.rawmode, 0, -1))] def tell(self) -> int: return self.frame @@ -385,9 +377,7 @@ 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, [ImageFile._Tile("raw", (0, 0, *im.size), 0, (rawmode, 0, -1))] - ) + ImageFile._save(im, fp, [ImageFile._Tile("raw", None, 0, (rawmode, 0, -1))]) # diff --git a/src/PIL/ImtImagePlugin.py b/src/PIL/ImtImagePlugin.py index 2127b890dde..cf76ac8aef6 100644 --- a/src/PIL/ImtImagePlugin.py +++ b/src/PIL/ImtImagePlugin.py @@ -60,7 +60,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "raw", - (0, 0, *self.size), + None, self.fp.tell() - len(buffer), self.mode, ) diff --git a/src/PIL/IptcImagePlugin.py b/src/PIL/IptcImagePlugin.py index 2b91b5b842b..ae12dbfdc0a 100644 --- a/src/PIL/IptcImagePlugin.py +++ b/src/PIL/IptcImagePlugin.py @@ -125,9 +125,7 @@ def _open(self) -> None: # tile if tag == (8, 10): - self.tile = [ - ImageFile._Tile("iptc", (0, 0, *self.size), offset, (compression, band)) - ] + self.tile = [ImageFile._Tile("iptc", None, offset, (compression, band))] def load(self) -> Image.core.PixelAccess | None: if self.tile: diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index 1a116193612..7a41a90ca3c 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -319,7 +319,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "jpeg2k", - (0, 0, *self.size), + None, 0, (self.codec, self._reduce, self.layers, fd, length), ) @@ -376,7 +376,7 @@ def load(self) -> Image.core.PixelAccess | None: t = self.tile[0] assert isinstance(t.args, tuple) args = (t.args[0], self._reduce, self.layers, t.args[3], t.args[4]) - self.tile = [t._replace(extents=(0, 0, *self.size), args=args)] + self.tile = [t._replace(args=args)] return ImageFile.ImageFile.load(self) @@ -455,7 +455,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: plt, ) - ImageFile._save(im, fp, [ImageFile._Tile("jpeg2k", (0, 0, *im.size), 0, kind)]) + ImageFile._save(im, fp, [ImageFile._Tile("jpeg2k", None, 0, kind)]) # ------------------------------------------------------------ diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index f4b26932a14..cd57bc6270f 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -395,9 +395,7 @@ def _open(self) -> None: rawmode = self.mode if self.mode == "CMYK": rawmode = "CMYK;I" # assume adobe conventions - self.tile = [ - ImageFile._Tile("jpeg", (0, 0, *self.size), 0, (rawmode, "")) - ] + self.tile = [ImageFile._Tile("jpeg", None, 0, (rawmode, ""))] # self.__offset = self.fp.tell() break s = self.fp.read(1) @@ -460,12 +458,11 @@ def draft( for s in [8, 4, 2, 1]: if scale >= s: break - assert e is not None e = ( - e[0], - e[1], - (e[2] - e[0] + s - 1) // s + e[0], - (e[3] - e[1] + s - 1) // s + e[1], + 0, + 0, + (self.size[0] + s - 1) // s, + (self.size[1] + s - 1) // s, ) self._size = ((self.size[0] + s - 1) // s, (self.size[1] + s - 1) // s) scale = s @@ -868,9 +865,7 @@ def validate_qtables( # and the comment (COM marker). bufsize = max(len(exif) + 5, len(extra), len(comment or b"") + 5) - ImageFile._save( - im, fp, [ImageFile._Tile("jpeg", (0, 0, *im.size), 0, rawmode)], bufsize - ) + ImageFile._save(im, fp, [ImageFile._Tile("jpeg", None, 0, rawmode)], bufsize) ## diff --git a/src/PIL/McIdasImagePlugin.py b/src/PIL/McIdasImagePlugin.py index e2f03146563..03ab2d1da2b 100644 --- a/src/PIL/McIdasImagePlugin.py +++ b/src/PIL/McIdasImagePlugin.py @@ -67,9 +67,7 @@ def _open(self) -> None: offset = w[34] + w[15] stride = w[15] + w[10] * w[11] * w[14] - self.tile = [ - ImageFile._Tile("raw", (0, 0, *self.size), offset, (rawmode, stride, 1)) - ] + self.tile = [ImageFile._Tile("raw", None, offset, (rawmode, stride, 1))] # -------------------------------------------------------------------- diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index 2c78b3e451e..a2c89d9df1e 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -166,9 +166,7 @@ def seek(self, frame: int) -> None: if self.info.get("exif") != original_exif: self._reload_exif() - self.tile = [ - ImageFile._Tile("jpeg", (0, 0, *self.size), self.offset, self.tile[0][-1]) - ] + self.tile = [ImageFile._Tile("jpeg", None, self.offset, self.tile[0][-1])] self.__frame = frame Image.Image.seek(self, frame) diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index 186e38f8887..d8fc86b1d12 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -73,9 +73,9 @@ def _open(self) -> None: self._size = i16(s, 4), i16(s, 6) if s.startswith(b"DanM"): - self.tile = [ImageFile._Tile("raw", (0, 0, *self.size), 32, "1")] + self.tile = [ImageFile._Tile("raw", None, 32, "1")] else: - self.tile = [ImageFile._Tile("MSP", (0, 0, *self.size), 32)] + self.tile = [ImageFile._Tile("MSP", None, 32)] class MspDecoder(ImageFile.PyDecoder): @@ -194,7 +194,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(o16(h)) # image body - ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0, *im.size), 32, "1")]) + ImageFile._save(im, fp, [ImageFile._Tile("raw", None, 32, "1")]) # diff --git a/src/PIL/PalmImagePlugin.py b/src/PIL/PalmImagePlugin.py index d5a0116783a..97f8dfadfd4 100644 --- a/src/PIL/PalmImagePlugin.py +++ b/src/PIL/PalmImagePlugin.py @@ -202,9 +202,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(colormap[3 * i : 3 * i + 3]) # now convert data to raw form - ImageFile._save( - im, fp, [ImageFile._Tile("raw", (0, 0, *im.size), 0, (rawmode, rowbytes, 1))] - ) + ImageFile._save(im, fp, [ImageFile._Tile("raw", None, 0, (rawmode, rowbytes, 1))]) if hasattr(fp, "flush"): fp.flush() diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index b5a3afcb20a..7e36360cffd 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -131,10 +131,9 @@ def _open(self) -> None: if provided_stride != stride: stride += stride % 2 - bbox = (0, 0, *self.size) logger.debug("size: %sx%s", *self.size) - self.tile = [ImageFile._Tile("pcx", bbox, offset, (rawmode, planes * stride))] + self.tile = [ImageFile._Tile("pcx", None, offset, (rawmode, planes * stride))] # -------------------------------------------------------------------- @@ -208,9 +207,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: assert fp.tell() == 128 - ImageFile._save( - im, fp, [ImageFile._Tile("pcx", (0, 0, *im.size), 0, (rawmode, bits * planes))] - ) + ImageFile._save(im, fp, [ImageFile._Tile("pcx", None, 0, (rawmode, bits * planes))]) if im.mode == "P": # colour palette diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index cbd82cb8d2b..e66b46ba3a5 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -142,7 +142,7 @@ def _write_image( op = io.BytesIO() if decode_filter == "ASCIIHexDecode": - ImageFile._save(im, op, [ImageFile._Tile("hex", (0, 0, *im.size), 0, im.mode)]) + ImageFile._save(im, op, [ImageFile._Tile("hex", None, 0, im.mode)]) elif decode_filter == "CCITTFaxDecode": im.save( op, diff --git a/src/PIL/PixarImagePlugin.py b/src/PIL/PixarImagePlugin.py index 2f0a25b4ef0..1063a9db35a 100644 --- a/src/PIL/PixarImagePlugin.py +++ b/src/PIL/PixarImagePlugin.py @@ -63,7 +63,7 @@ def _open(self) -> None: # FIXME: to be continued... # create tile descriptor (assuming "dumped") - self.tile = [ImageFile._Tile("raw", (0, 0, *self.size), 1024, self.mode)] + self.tile = [ImageFile._Tile("raw", None, 1024, self.mode)] # diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index f61a0bb37d7..4ae7dacd895 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -1290,7 +1290,7 @@ def _write_multiple_frames( ImageFile._save( default_im, cast("IO[bytes]", _idat(fp, chunk)), - [ImageFile._Tile("zip", (0, 0, *im.size), 0, rawmode)], + [ImageFile._Tile("zip", None, 0, rawmode)], ) seq_num = 0 diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index edd81ec3f41..dfe07f77f6d 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -156,9 +156,7 @@ def _open(self) -> None: decoder_name = "ppm" args = rawmode if decoder_name == "raw" else (rawmode, maxval) - self.tile = [ - ImageFile._Tile(decoder_name, (0, 0, *self.size), self.fp.tell(), args) - ] + self.tile = [ImageFile._Tile(decoder_name, None, self.fp.tell(), args)] # @@ -360,9 +358,7 @@ 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, [ImageFile._Tile("raw", (0, 0, *im.size), 0, (rawmode, 0, row_order))] - ) + ImageFile._save(im, fp, [ImageFile._Tile("raw", None, 0, (rawmode, 0, row_order))]) # diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index 20354db1914..8b4df74b3b8 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -144,7 +144,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(o8(channels)) fp.write(o8(colorspace)) - ImageFile._save(im, fp, [ImageFile._Tile("qoi", (0, 0, *im.size))]) + ImageFile._save(im, fp, [ImageFile._Tile("qoi", None)]) class QoiEncoder(ImageFile.PyEncoder): diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index f4093cf74c2..0c219f96f30 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -109,7 +109,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "SGI16", - (0, 0, *self.size), + None, headlen, (self.mode, 0, orientation), ) @@ -119,16 +119,12 @@ def _open(self) -> None: offset = headlen for layer in self.mode: self.tile.append( - ImageFile._Tile( - "raw", (0, 0, *self.size), offset, (layer, 0, orientation) - ) + ImageFile._Tile("raw", None, offset, (layer, 0, orientation)) ) offset += pagesize elif compression == 1: self.tile = [ - ImageFile._Tile( - "sgi_rle", (0, 0, *self.size), headlen, (rawmode, orientation, bpc) - ) + ImageFile._Tile("sgi_rle", None, headlen, (rawmode, orientation, bpc)) ] diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index 9321688cbb0..5d35cb99769 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -162,7 +162,7 @@ def _open(self) -> None: self.rawmode = "F;32F" self._mode = "F" - self.tile = [ImageFile._Tile("raw", (0, 0, *self.size), offset, self.rawmode)] + self.tile = [ImageFile._Tile("raw", None, offset, self.rawmode)] self._fp = self.fp # FIXME: hack # 1st image index is zero (although SPIDER imgnumber starts at 1) @@ -282,7 +282,7 @@ 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, [ImageFile._Tile("raw", (0, 0, *im.size), 0, rawmode)]) + ImageFile._save(im, fp, [ImageFile._Tile("raw", None, 0, rawmode)]) def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: diff --git a/src/PIL/SunImagePlugin.py b/src/PIL/SunImagePlugin.py index 73547d54d07..ad621d3db8d 100644 --- a/src/PIL/SunImagePlugin.py +++ b/src/PIL/SunImagePlugin.py @@ -126,13 +126,9 @@ def _open(self) -> None: # (https://www.fileformat.info/format/sunraster/egff.htm) if file_type in (0, 1, 3, 4, 5): - self.tile = [ - ImageFile._Tile("raw", (0, 0, *self.size), offset, (rawmode, stride)) - ] + self.tile = [ImageFile._Tile("raw", None, offset, (rawmode, stride))] elif file_type == 2: - self.tile = [ - ImageFile._Tile("sun_rle", (0, 0, *self.size), offset, rawmode) - ] + self.tile = [ImageFile._Tile("sun_rle", None, offset, rawmode)] else: msg = "Unsupported Sun Raster file type" raise SyntaxError(msg) diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index 8a112d50558..cbdf647e972 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -147,7 +147,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "tga_rle", - (0, 0, *self.size), + None, self.fp.tell(), (rawmode, orientation, depth), ) @@ -156,7 +156,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "raw", - (0, 0, *self.size), + None, self.fp.tell(), (rawmode, 0, orientation), ) @@ -269,13 +269,13 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ImageFile._save( im, fp, - [ImageFile._Tile("tga_rle", (0, 0, *im.size), 0, (rawmode, orientation))], + [ImageFile._Tile("tga_rle", None, 0, (rawmode, orientation))], ) else: ImageFile._save( im, fp, - [ImageFile._Tile("raw", (0, 0, *im.size), 0, (rawmode, 0, orientation))], + [ImageFile._Tile("raw", None, 0, (rawmode, 0, orientation))], ) # write targa version 2 footer diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 6305b42e3f2..efe9ebffc5b 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -2064,7 +2064,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ImageFile._save( im, fp, - [ImageFile._Tile("raw", (0, 0, *im.size), offset, (rawmode, stride, 1))], + [ImageFile._Tile("raw", None, offset, (rawmode, stride, 1))], ) # -- helper for multi-page save -- diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index 9e0b1cb76df..f412ad31b6e 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -168,7 +168,7 @@ def load(self) -> Image.core.PixelAccess | None: if self.fp and self._exclusive_fp: self.fp.close() self.fp = BytesIO(data) - self.tile = [ImageFile._Tile("raw", (0, 0, *self.size), 0, self.rawmode)] + self.tile = [ImageFile._Tile("raw", None, 0, self.rawmode)] return super().load() diff --git a/src/PIL/XVThumbImagePlugin.py b/src/PIL/XVThumbImagePlugin.py index 0fdccf246f7..1d270cd1b6c 100644 --- a/src/PIL/XVThumbImagePlugin.py +++ b/src/PIL/XVThumbImagePlugin.py @@ -73,9 +73,7 @@ def _open(self) -> None: self.palette = ImagePalette.raw("RGB", PALETTE) - self.tile = [ - ImageFile._Tile("raw", (0, 0, *self.size), self.fp.tell(), self.mode) - ] + self.tile = [ImageFile._Tile("raw", None, self.fp.tell(), self.mode)] # -------------------------------------------------------------------- diff --git a/src/PIL/XbmImagePlugin.py b/src/PIL/XbmImagePlugin.py index 6a4ad7b76c8..24bc52dc6fe 100644 --- a/src/PIL/XbmImagePlugin.py +++ b/src/PIL/XbmImagePlugin.py @@ -97,7 +97,7 @@ def _open(self) -> None: self._mode = "1" self._size = width, height - self.tile = [ImageFile._Tile("xbm", (0, 0, *self.size), offset)] + self.tile = [ImageFile._Tile("xbm", None, offset)] def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: @@ -115,7 +115,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, [ImageFile._Tile("xbm", (0, 0, *im.size))]) + ImageFile._save(im, fp, [ImageFile._Tile("xbm", None)]) fp.write(b"};\n") diff --git a/src/PIL/XpmImagePlugin.py b/src/PIL/XpmImagePlugin.py index d3e3bd1b91c..ed277478066 100644 --- a/src/PIL/XpmImagePlugin.py +++ b/src/PIL/XpmImagePlugin.py @@ -115,7 +115,7 @@ def _open(self) -> None: if transparent_key is not None: self.info["transparency"] = palette_keys.index(transparent_key) - self.tile = [ImageFile._Tile("xpm", (0, 0, *self.size), self.fp.tell(), args)] + self.tile = [ImageFile._Tile("xpm", None, self.fp.tell(), args)] def load_read(self, read_bytes: int) -> bytes: # From 2c8bd8e3893d32799e23e62bded62627058a230c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 17 Oct 2026 21:14:47 +1100 Subject: [PATCH 3/4] Set tile extents to None as default --- src/PIL/AvifImagePlugin.py | 2 +- src/PIL/BlpImagePlugin.py | 2 +- src/PIL/BmpImagePlugin.py | 2 +- src/PIL/DdsImagePlugin.py | 6 +++--- src/PIL/EpsImagePlugin.py | 2 +- src/PIL/FtexImagePlugin.py | 4 ++-- src/PIL/GifImagePlugin.py | 2 +- src/PIL/IcoImagePlugin.py | 2 +- src/PIL/ImImagePlugin.py | 2 +- src/PIL/ImageFile.py | 2 +- src/PIL/Jpeg2KImagePlugin.py | 6 ++---- src/PIL/JpegImagePlugin.py | 4 ++-- src/PIL/PalmImagePlugin.py | 2 +- src/PIL/PcxImagePlugin.py | 2 +- src/PIL/PdfImagePlugin.py | 2 +- src/PIL/PngImagePlugin.py | 2 +- src/PIL/PpmImagePlugin.py | 2 +- src/PIL/QoiImagePlugin.py | 2 +- src/PIL/SpiderImagePlugin.py | 2 +- src/PIL/TgaImagePlugin.py | 4 ++-- src/PIL/WebPImagePlugin.py | 2 +- src/PIL/XbmImagePlugin.py | 2 +- 22 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/PIL/AvifImagePlugin.py b/src/PIL/AvifImagePlugin.py index 72ee30305e1..dd87a508313 100644 --- a/src/PIL/AvifImagePlugin.py +++ b/src/PIL/AvifImagePlugin.py @@ -120,7 +120,7 @@ def seek(self, frame: int) -> None: # Set tile self.__frame = frame - self.tile = [ImageFile._Tile("raw", None, 0, self.mode)] + self.tile = [ImageFile._Tile("raw", args=self.mode)] def load(self) -> Image.core.PixelAccess | None: if self.tile: diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index f236a9bfec1..8cc7f7d5cff 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -491,7 +491,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(struct.pack(" None: mask_count = 3 masks = struct.unpack(f"<{mask_count}I", header[84 : 84 + mask_count * 4]) - self.tile = [ImageFile._Tile("dds_rgb", None, 0, (bitcount, masks))] + self.tile = [ImageFile._Tile("dds_rgb", args=(bitcount, masks))] return elif pfflags & DDPF.LUMINANCE: if bitcount == 8: @@ -481,7 +481,7 @@ def _open(self) -> None: if n: self.tile = [ImageFile._Tile("bcn", None, offset, (n, self.pixel_format))] else: - self.tile = [ImageFile._Tile("raw", None, 0, rawmode or self.mode)] + self.tile = [ImageFile._Tile("raw", args=rawmode or self.mode)] def load_seek(self, pos: int) -> None: pass @@ -621,7 +621,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # dxgi_format, 2D resource, misc, array size, straight alpha struct.pack("<5I", dxgi_format, 3, 0, 0, 1) ) - ImageFile._save(im, fp, [ImageFile._Tile(codec_name, None, 0, args)]) + ImageFile._save(im, fp, [ImageFile._Tile(codec_name, args=args)]) def _accept(prefix: bytes) -> bool: diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index da4c64c6966..ac3fc34028b 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -472,7 +472,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, [ImageFile._Tile("eps", None)]) + ImageFile._save(im, fp, [ImageFile._Tile("eps")]) fp.write(b"\n%%%%EndBinary\n") fp.write(b"grestore end\n") diff --git a/src/PIL/FtexImagePlugin.py b/src/PIL/FtexImagePlugin.py index 5d92938efde..d3877f94b92 100644 --- a/src/PIL/FtexImagePlugin.py +++ b/src/PIL/FtexImagePlugin.py @@ -96,10 +96,10 @@ def _open(self) -> None: if format == Format.DXT1: self._mode = "RGBA" - self.tile = [ImageFile._Tile("bcn", None, 0, (1,))] + self.tile = [ImageFile._Tile("bcn", args=(1,))] elif format == Format.UNCOMPRESSED: self._mode = "RGB" - self.tile = [ImageFile._Tile("raw", None, 0, "RGB")] + self.tile = [ImageFile._Tile("raw", args="RGB")] else: msg = f"Invalid texture compression format: {repr(format)}" raise ValueError(msg) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index b3c4d46c326..6e37a8139a6 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -634,7 +634,7 @@ def _write_single_frame( _write_local_header(fp, im, (0, 0), flags) im_out.encoderconfig = (8, get_interlace(im)) - ImageFile._save(im_out, fp, [ImageFile._Tile("gif", None, 0, RAWMODE[im_out.mode])]) + ImageFile._save(im_out, fp, [ImageFile._Tile("gif", args=RAWMODE[im_out.mode])]) fp.write(b"\0") # end of image data diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py index 85740e9d7d8..a39028fac8e 100644 --- a/src/PIL/IcoImagePlugin.py +++ b/src/PIL/IcoImagePlugin.py @@ -135,7 +135,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ImageFile._save( and_mask, image_io, - [ImageFile._Tile("raw", None, 0, ("1", 0, -1))], + [ImageFile._Tile("raw", args=("1", 0, -1))], ) else: frame.save(image_io, "png") diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index 7eb5b269776..49f199c4b4e 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -377,7 +377,7 @@ 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, [ImageFile._Tile("raw", None, 0, (rawmode, 0, -1))]) + ImageFile._save(im, fp, [ImageFile._Tile("raw", args=(rawmode, 0, -1))]) # diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 188b4130b92..2cac8953372 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -105,7 +105,7 @@ def _tilesort(t: _Tile) -> int: class _Tile(NamedTuple): codec_name: str - extents: tuple[int, int, int, int] | None + extents: tuple[int, int, int, int] | None = None offset: int = 0 args: tuple[Any, ...] | str | None = None diff --git a/src/PIL/Jpeg2KImagePlugin.py b/src/PIL/Jpeg2KImagePlugin.py index 7a41a90ca3c..ee578b771b2 100644 --- a/src/PIL/Jpeg2KImagePlugin.py +++ b/src/PIL/Jpeg2KImagePlugin.py @@ -319,9 +319,7 @@ def _open(self) -> None: self.tile = [ ImageFile._Tile( "jpeg2k", - None, - 0, - (self.codec, self._reduce, self.layers, fd, length), + args=(self.codec, self._reduce, self.layers, fd, length), ) ] @@ -455,7 +453,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: plt, ) - ImageFile._save(im, fp, [ImageFile._Tile("jpeg2k", None, 0, kind)]) + ImageFile._save(im, fp, [ImageFile._Tile("jpeg2k", args=kind)]) # ------------------------------------------------------------ diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index cd57bc6270f..dd0a470a736 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -395,7 +395,7 @@ def _open(self) -> None: rawmode = self.mode if self.mode == "CMYK": rawmode = "CMYK;I" # assume adobe conventions - self.tile = [ImageFile._Tile("jpeg", None, 0, (rawmode, ""))] + self.tile = [ImageFile._Tile("jpeg", args=(rawmode, ""))] # self.__offset = self.fp.tell() break s = self.fp.read(1) @@ -865,7 +865,7 @@ def validate_qtables( # and the comment (COM marker). bufsize = max(len(exif) + 5, len(extra), len(comment or b"") + 5) - ImageFile._save(im, fp, [ImageFile._Tile("jpeg", None, 0, rawmode)], bufsize) + ImageFile._save(im, fp, [ImageFile._Tile("jpeg", args=rawmode)], bufsize) ## diff --git a/src/PIL/PalmImagePlugin.py b/src/PIL/PalmImagePlugin.py index 97f8dfadfd4..bf8e81a5f5e 100644 --- a/src/PIL/PalmImagePlugin.py +++ b/src/PIL/PalmImagePlugin.py @@ -202,7 +202,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(colormap[3 * i : 3 * i + 3]) # now convert data to raw form - ImageFile._save(im, fp, [ImageFile._Tile("raw", None, 0, (rawmode, rowbytes, 1))]) + ImageFile._save(im, fp, [ImageFile._Tile("raw", args=(rawmode, rowbytes, 1))]) if hasattr(fp, "flush"): fp.flush() diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index 7e36360cffd..a696b2cd96b 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -207,7 +207,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: assert fp.tell() == 128 - ImageFile._save(im, fp, [ImageFile._Tile("pcx", None, 0, (rawmode, bits * planes))]) + ImageFile._save(im, fp, [ImageFile._Tile("pcx", args=(rawmode, bits * planes))]) if im.mode == "P": # colour palette diff --git a/src/PIL/PdfImagePlugin.py b/src/PIL/PdfImagePlugin.py index e66b46ba3a5..4e2321f89eb 100644 --- a/src/PIL/PdfImagePlugin.py +++ b/src/PIL/PdfImagePlugin.py @@ -142,7 +142,7 @@ def _write_image( op = io.BytesIO() if decode_filter == "ASCIIHexDecode": - ImageFile._save(im, op, [ImageFile._Tile("hex", None, 0, im.mode)]) + ImageFile._save(im, op, [ImageFile._Tile("hex", args=im.mode)]) elif decode_filter == "CCITTFaxDecode": im.save( op, diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 4ae7dacd895..4919fbb196c 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -1290,7 +1290,7 @@ def _write_multiple_frames( ImageFile._save( default_im, cast("IO[bytes]", _idat(fp, chunk)), - [ImageFile._Tile("zip", None, 0, rawmode)], + [ImageFile._Tile("zip", args=rawmode)], ) seq_num = 0 diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index dfe07f77f6d..16161f525ee 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -358,7 +358,7 @@ 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, [ImageFile._Tile("raw", None, 0, (rawmode, 0, row_order))]) + ImageFile._save(im, fp, [ImageFile._Tile("raw", args=(rawmode, 0, row_order))]) # diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index 8b4df74b3b8..d94de27b620 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -144,7 +144,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(o8(channels)) fp.write(o8(colorspace)) - ImageFile._save(im, fp, [ImageFile._Tile("qoi", None)]) + ImageFile._save(im, fp, [ImageFile._Tile("qoi")]) class QoiEncoder(ImageFile.PyEncoder): diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index 5d35cb99769..3b828b8b86e 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -282,7 +282,7 @@ 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, [ImageFile._Tile("raw", None, 0, rawmode)]) + ImageFile._save(im, fp, [ImageFile._Tile("raw", args=rawmode)]) def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index cbdf647e972..036068b26c2 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -269,13 +269,13 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ImageFile._save( im, fp, - [ImageFile._Tile("tga_rle", None, 0, (rawmode, orientation))], + [ImageFile._Tile("tga_rle", args=(rawmode, orientation))], ) else: ImageFile._save( im, fp, - [ImageFile._Tile("raw", None, 0, (rawmode, 0, orientation))], + [ImageFile._Tile("raw", args=(rawmode, 0, orientation))], ) # write targa version 2 footer diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index f412ad31b6e..923fb9faaa3 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -168,7 +168,7 @@ def load(self) -> Image.core.PixelAccess | None: if self.fp and self._exclusive_fp: self.fp.close() self.fp = BytesIO(data) - self.tile = [ImageFile._Tile("raw", None, 0, self.rawmode)] + self.tile = [ImageFile._Tile("raw", args=self.rawmode)] return super().load() diff --git a/src/PIL/XbmImagePlugin.py b/src/PIL/XbmImagePlugin.py index 24bc52dc6fe..69ce54ebf19 100644 --- a/src/PIL/XbmImagePlugin.py +++ b/src/PIL/XbmImagePlugin.py @@ -115,7 +115,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, [ImageFile._Tile("xbm", None)]) + ImageFile._save(im, fp, [ImageFile._Tile("xbm")]) fp.write(b"};\n") From 48bd00328baaebcc4c442f7142122c1a07013866 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 17 Oct 2026 21:17:41 +1100 Subject: [PATCH 4/4] Allow None as default in C setimage --- src/PIL/Image.py | 4 ++-- src/PIL/TiffImagePlugin.py | 2 +- src/decode.c | 4 ++-- src/encode.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 40720c5d438..cefe6f1fc96 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -884,7 +884,7 @@ def tobytes(self, encoder_name: str = "raw", *args: Any) -> bytes: # unpack data e = _getencoder(self.mode, encoder_name, encoder_args) try: - e.setimage(self.im, (0, 0, *self.size)) + e.setimage(self.im) from . import ImageFile @@ -957,7 +957,7 @@ def frombytes( # unpack data d = _getdecoder(self.mode, decoder_name, decoder_args) - d.setimage(self.im, (0, 0, *self.size)) + d.setimage(self.im) s = d.decode(data) if s[0] >= 0: diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index efe9ebffc5b..9c92bc466f1 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -2042,7 +2042,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: a = (rawmode, _fp, filename, tags, types) encoder = Image._getencoder(im.mode, "libtiff", a, encoderconfig) try: - encoder.setimage(im.im, (0, 0, *im.size)) + encoder.setimage(im.im) while True: errcode, data = encoder.encode(ImageFile.MAXBLOCK)[1:] if not _fp: diff --git a/src/decode.c b/src/decode.c index 43f4302de76..279e98f18e7 100644 --- a/src/decode.c +++ b/src/decode.c @@ -157,13 +157,13 @@ PyImaging_AsImaging(PyObject *op); static PyObject * _setimage(ImagingDecoderObject *decoder, PyObject *args) { - PyObject *op, *extents; + PyObject *op, *extents = Py_None; Imaging im; ImagingCodecState state; int x0, y0, x1, y1; /* FIXME: should publish the ImagingType descriptor */ - if (!PyArg_ParseTuple(args, "OO", &op, &extents)) { + if (!PyArg_ParseTuple(args, "O|O", &op, &extents)) { return NULL; } im = PyImaging_AsImaging(op); diff --git a/src/encode.c b/src/encode.c index 28b6762d51e..2182c41db50 100644 --- a/src/encode.c +++ b/src/encode.c @@ -224,13 +224,13 @@ PyImaging_AsImaging(PyObject *op); static PyObject * _setimage(ImagingEncoderObject *encoder, PyObject *args) { - PyObject *op, *extents; + PyObject *op, *extents = Py_None; Imaging im; ImagingCodecState state; Py_ssize_t x0, y0, x1, y1; /* FIXME: should publish the ImagingType descriptor */ - if (!PyArg_ParseTuple(args, "OO", &op, &extents)) { + if (!PyArg_ParseTuple(args, "O|O", &op, &extents)) { return NULL; } im = PyImaging_AsImaging(op);