From 8093cf3704773cf96aee492cd43e1eb982cb06de Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 10 Jun 2025 19:14:30 +1000 Subject: [PATCH 1/3] Fixed type hints --- src/PIL/QoiImagePlugin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index 6f2c9c5c6..b8c631ed3 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -113,7 +113,7 @@ class QoiDecoder(ImageFile.PyDecoder): return -1, 0 -def _save(im: Image.image, fp: IO[bytes], filename: str | bytes) -> None: +def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if im.mode == "RGB": channels = 3 elif im.mode == "RGBA": @@ -138,8 +138,8 @@ def _save(im: Image.image, fp: IO[bytes], filename: str | bytes) -> None: class QoiEncoder(ImageFile.PyEncoder): _pushes_fd = True - _previous_pixel: tuple[int] | None = None - _previously_seen_pixels: dict[int, tuple[int]] = {} + _previous_pixel: tuple[int, int, int, int] | None = None + _previously_seen_pixels: dict[int, tuple[int, int, int, int]] = {} def _write_run(self, run): return o8(0xC0 | (run - 1)) # QOI_OP_RUN @@ -181,7 +181,7 @@ class QoiEncoder(ImageFile.PyEncoder): hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64 if self._previously_seen_pixels.get(hash_value) == pixel: data += o8(hash_value) # QOI_OP_INDEX - else: + elif self._previous_pixel: self._previously_seen_pixels[hash_value] = pixel pr, pg, pb, pa = self._previous_pixel From 7ebfb871d0101c494b41957fb449db85f807a82a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 10 Jun 2025 19:18:34 +1000 Subject: [PATCH 2/3] Simplified code --- Tests/test_file_qoi.py | 12 +++--------- src/PIL/QoiImagePlugin.py | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Tests/test_file_qoi.py b/Tests/test_file_qoi.py index 5efe7aa90..25cd20748 100644 --- a/Tests/test_file_qoi.py +++ b/Tests/test_file_qoi.py @@ -6,11 +6,7 @@ import pytest from PIL import Image, QoiImagePlugin -from .helper import ( - assert_image_equal, - assert_image_equal_tofile, - hopper, -) +from .helper import assert_image_equal_tofile, hopper def test_sanity() -> None: @@ -42,15 +38,13 @@ def test_save(tmp_path: Path) -> None: im = hopper("RGB") im.save(f, qoi_colorspace="sRGB") - with Image.open(f) as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, f) for image in ["Tests/images/default_font.png", "Tests/images/pil123rgba.png"]: with Image.open(image) as im: im.save(f) - with Image.open(f) as reloaded: - assert_image_equal(im, reloaded) + assert_image_equal_tofile(im, f) im = hopper("P") with pytest.raises(ValueError): diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index b8c631ed3..903f8b365 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -133,7 +133,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, 0, im.mode)]) + ImageFile._save(im, fp, [ImageFile._Tile("qoi", (0, 0) + im.size)]) class QoiEncoder(ImageFile.PyEncoder): From 79b753c87ecd37c1ab97009a20869e263306e9ed Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 10 Jun 2025 19:25:27 +1000 Subject: [PATCH 3/3] Added type hints --- src/PIL/QoiImagePlugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/QoiImagePlugin.py b/src/PIL/QoiImagePlugin.py index 903f8b365..c123249ea 100644 --- a/src/PIL/QoiImagePlugin.py +++ b/src/PIL/QoiImagePlugin.py @@ -141,10 +141,10 @@ class QoiEncoder(ImageFile.PyEncoder): _previous_pixel: tuple[int, int, int, int] | None = None _previously_seen_pixels: dict[int, tuple[int, int, int, int]] = {} - def _write_run(self, run): + def _write_run(self, run: int) -> bytes: return o8(0xC0 | (run - 1)) # QOI_OP_RUN - def _delta(self, left, right): + def _delta(self, left: int, right: int) -> int: result = (left - right) & 0xFF if result >= 0x80: result -= 0x100