Skip to content

Commit

Permalink
Merge branch 'main' into libavif-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere authored Jan 3, 2025
2 parents 9328932 + 9ae8cb8 commit be02830
Show file tree
Hide file tree
Showing 70 changed files with 541 additions and 398 deletions.
2 changes: 1 addition & 1 deletion .ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ set -e

if [[ $(uname) != CYGWIN* ]]; then
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libjpeg-turbo-progs libopenjp2-7-dev\
ghostscript libjpeg-turbo8-dev libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev nasm
fi
Expand Down
2 changes: 1 addition & 1 deletion .ci/requirements-mypy.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mypy==1.13.0
mypy==1.14.1
IceSpringPySideStubs-PyQt6
IceSpringPySideStubs-PySide6
ipython
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
amazon-2023-amd64,
arch,
centos-stream-9-amd64,
centos-stream-10-amd64,
debian-12-bookworm-x86,
debian-12-bookworm-amd64,
fedora-40-amd64,
Expand Down
20 changes: 12 additions & 8 deletions .github/workflows/wheels-dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,17 @@ fi
ARCHIVE_SDIR=pillow-depends-main

# Package versions for fresh source builds
FREETYPE_VERSION=2.13.2
FREETYPE_VERSION=2.13.3
HARFBUZZ_VERSION=10.1.0
LIBPNG_VERSION=1.6.44
JPEGTURBO_VERSION=3.1.0
OPENJPEG_VERSION=2.5.3
XZ_VERSION=5.6.3
TIFF_VERSION=4.6.0
LCMS2_VERSION=2.16
if [[ -n "$IS_MACOS" ]]; then
GIFLIB_VERSION=5.2.2
else
GIFLIB_VERSION=5.2.1
fi
ZLIB_NG_VERSION=2.2.2
LIBWEBP_VERSION=1.4.0
GIFLIB_VERSION=5.2.2
ZLIB_NG_VERSION=2.2.3
LIBWEBP_VERSION=1.5.0
BZIP2_VERSION=1.0.8
LIBXCB_VERSION=1.17.0
BROTLI_VERSION=1.1.0
Expand Down Expand Up @@ -210,6 +206,14 @@ function build {
CFLAGS="$CFLAGS -O3 -DNDEBUG"
if [[ -n "$IS_MACOS" ]]; then
CFLAGS="$CFLAGS -Wl,-headerpad_max_install_names"
# For giflib 5.2.2
elif [ -n "$IS_ALPINE" ]; then
apk add imagemagick
else
if [[ "$MB_ML_VER" == "_2_28" ]]; then
yum install -y epel-release
fi
yum install -y ImageMagick
fi
build_libwebp
CFLAGS=$ORIGINAL_CFLAGS
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,6 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: pip
cache-dependency-path: "Makefile"

- run: make sdist

Expand Down
9 changes: 7 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
rev: v0.8.4
hooks:
- id: ruff
args: [--exit-non-zero-on-fix]
Expand All @@ -24,7 +24,7 @@ repos:
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.4
rev: v19.1.5
hooks:
- id: clang-format
types: [c]
Expand Down Expand Up @@ -56,6 +56,11 @@ repos:
- id: check-readthedocs
- id: check-renovate

- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v0.10.0
hooks:
- id: zizmor

- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.0
hooks:
Expand Down
Binary file modified Tests/images/imagedraw/discontiguous_corners_polygon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/jfif_unit_cm.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions Tests/test_color_lut.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,12 @@ def test_numpy_sources(self) -> None:

table = numpy.ones((7 * 6 * 5, 3), dtype=numpy.float16)
lut = ImageFilter.Color3DLUT((5, 6, 7), table)
assert isinstance(lut.table, numpy.ndarray)
assert lut.table.shape == (table.size,)

table = numpy.ones((7 * 6 * 5 * 3), dtype=numpy.float16)
lut = ImageFilter.Color3DLUT((5, 6, 7), table)
assert isinstance(lut.table, numpy.ndarray)
assert lut.table.shape == (table.size,)

# Check application
Expand Down
10 changes: 9 additions & 1 deletion Tests/test_file_blp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest

from PIL import Image
from PIL import BlpImagePlugin, Image

from .helper import (
assert_image_equal,
Expand All @@ -19,6 +19,7 @@ def test_load_blp1() -> None:
assert_image_equal_tofile(im, "Tests/images/blp/blp1_jpeg.png")

with Image.open("Tests/images/blp/blp1_jpeg2.blp") as im:
assert im.mode == "RGBA"
im.load()


Expand All @@ -37,6 +38,13 @@ def test_load_blp2_dxt1a() -> None:
assert_image_equal_tofile(im, "Tests/images/blp/blp2_dxt1a.png")


def test_invalid_file() -> None:
invalid_file = "Tests/images/flower.jpg"

with pytest.raises(BlpImagePlugin.BLPFormatError):
BlpImagePlugin.BlpImageFile(invalid_file)


def test_save(tmp_path: Path) -> None:
f = str(tmp_path / "temp.blp")

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_bufrstub.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
im.save(temp_file)
assert handler.saved

BufrStubImagePlugin._handler = None
BufrStubImagePlugin.register_handler(None)
10 changes: 4 additions & 6 deletions Tests/test_file_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

from PIL import ContainerIO, Image

from .helper import hopper

TEST_FILE = "Tests/images/dummy.container"


Expand All @@ -15,15 +13,15 @@ def test_sanity() -> None:


def test_isatty() -> None:
with hopper() as im:
container = ContainerIO.ContainerIO(im, 0, 0)
with open(TEST_FILE, "rb") as fh:
container = ContainerIO.ContainerIO(fh, 0, 0)

assert container.isatty() is False


def test_seekable() -> None:
with hopper() as im:
container = ContainerIO.ContainerIO(im, 0, 0)
with open(TEST_FILE, "rb") as fh:
container = ContainerIO.ContainerIO(fh, 0, 0)

assert container.seekable() is True

Expand Down
2 changes: 1 addition & 1 deletion Tests/test_file_gribstub.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
im.save(temp_file)
assert handler.saved

GribStubImagePlugin._handler = None
GribStubImagePlugin.register_handler(None)
2 changes: 1 addition & 1 deletion Tests/test_file_hdf5stub.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,4 @@ def save(self, im: Image.Image, fp: IO[bytes], filename: str) -> None:
im.save(temp_file)
assert handler.saved

Hdf5StubImagePlugin._handler = None
Hdf5StubImagePlugin.register_handler(None)
14 changes: 11 additions & 3 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ def test(xdpi: int, ydpi: int | None = None) -> tuple[int, int] | None:
assert test(100, 200) == (100, 200)
assert test(0) is None # square pixels

def test_dpi_jfif_cm(self):
with Image.open("Tests/images/jfif_unit_cm.jpg") as im:
assert im.info["dpi"] == (2.54, 5.08)

@mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
)
Expand Down Expand Up @@ -349,7 +353,6 @@ def test_empty_exif_gps(self) -> None:
assert exif.get_ifd(0x8825) == {}

transposed = ImageOps.exif_transpose(im)
assert transposed is not None
exif = transposed.getexif()
assert exif.get_ifd(0x8825) == {}

Expand Down Expand Up @@ -1000,8 +1003,13 @@ def test_save_xmp(self, tmp_path: Path) -> None:
with Image.open(f) as reloaded:
assert reloaded.info["xmp"] == b"XMP test"

im.info["xmp"] = b"1" * 65504
im.save(f)
# Check that XMP is not saved from image info
reloaded.save(f)

with Image.open(f) as reloaded:
assert "xmp" not in reloaded.info

im.save(f, xmp=b"1" * 65504)
with Image.open(f) as reloaded:
assert reloaded.info["xmp"] == b"1" * 65504

Expand Down
17 changes: 15 additions & 2 deletions Tests/test_file_jpeg2k.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,18 @@ def test_cmyk() -> None:
assert im.getpixel((0, 0)) == (185, 134, 0, 0)


@pytest.mark.skipif(
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
)
@skip_unless_feature_version("jpg_2000", "2.5.3")
def test_cmyk_save() -> None:
with Image.open(f"{EXTRA_DIR}/issue205.jp2") as jp2:
assert jp2.mode == "CMYK"

im = roundtrip(jp2)
assert_image_equal(im, jp2)


@pytest.mark.parametrize("ext", (".j2k", ".jp2"))
def test_16bit_monochrome_has_correct_mode(ext: str) -> None:
with Image.open("Tests/images/16bit.cropped" + ext) as im:
Expand Down Expand Up @@ -424,8 +436,9 @@ def test_pclr() -> None:


def test_comment() -> None:
with Image.open("Tests/images/comment.jp2") as im:
assert im.info["comment"] == b"Created by OpenJPEG version 2.5.0"
for path in ("Tests/images/9bit.j2k", "Tests/images/comment.jp2"):
with Image.open(path) as im:
assert im.info["comment"] == b"Created by OpenJPEG version 2.5.0"

# Test an image that is truncated partway through a codestream
with open("Tests/images/comment.jp2", "rb") as fp:
Expand Down
12 changes: 12 additions & 0 deletions Tests/test_file_mpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,15 @@ def test_save_all() -> None:
# Test that a single frame image will not be saved as an MPO
jpg = roundtrip(im, save_all=True)
assert "mp" not in jpg.info


def test_save_xmp() -> None:
im = Image.new("RGB", (1, 1))
im2 = Image.new("RGB", (1, 1), "#f00")
im2.encoderinfo = {"xmp": b"Second frame"}
im_reloaded = roundtrip(im, xmp=b"First frame", save_all=True, append_images=[im2])

assert im_reloaded.info["xmp"] == b"First frame"

im_reloaded.seek(1)
assert im_reloaded.info["xmp"] == b"Second frame"
8 changes: 2 additions & 6 deletions Tests/test_file_png.py
Original file line number Diff line number Diff line change
Expand Up @@ -772,22 +772,18 @@ def test_seek(self) -> None:
im.seek(1)

@pytest.mark.parametrize("buffer", (True, False))
def test_save_stdout(self, buffer: bool) -> None:
old_stdout = sys.stdout
def test_save_stdout(self, buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None:

class MyStdOut:
buffer = BytesIO()

mystdout: MyStdOut | BytesIO = MyStdOut() if buffer else BytesIO()

sys.stdout = mystdout
monkeypatch.setattr(sys, "stdout", mystdout)

with Image.open(TEST_PNG_FILE) as im:
im.save(sys.stdout, "PNG")

# Reset stdout
sys.stdout = old_stdout

if isinstance(mystdout, MyStdOut):
mystdout = mystdout.buffer
with Image.open(mystdout) as reloaded:
Expand Down
8 changes: 2 additions & 6 deletions Tests/test_file_ppm.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,22 +367,18 @@ def test_mimetypes(tmp_path: Path) -> None:


@pytest.mark.parametrize("buffer", (True, False))
def test_save_stdout(buffer: bool) -> None:
old_stdout = sys.stdout
def test_save_stdout(buffer: bool, monkeypatch: pytest.MonkeyPatch) -> None:

class MyStdOut:
buffer = BytesIO()

mystdout: MyStdOut | BytesIO = MyStdOut() if buffer else BytesIO()

sys.stdout = mystdout
monkeypatch.setattr(sys, "stdout", mystdout)

with Image.open(TEST_FILE) as im:
im.save(sys.stdout, "PPM")

# Reset stdout
sys.stdout = old_stdout

if isinstance(mystdout, MyStdOut):
mystdout = mystdout.buffer
with Image.open(mystdout) as reloaded:
Expand Down
7 changes: 7 additions & 0 deletions Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ def test_bigtiff(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif")
im.save(outfile, save_all=True, append_images=[im], tiffinfo=im.tag_v2)

def test_bigtiff_save(self, tmp_path: Path) -> None:
outfile = str(tmp_path / "temp.tif")
hopper().save(outfile, big_tiff=True)

with Image.open(outfile) as im:
assert im.tag_v2._bigtiff is True

def test_seek_too_large(self) -> None:
with pytest.raises(ValueError, match="Unable to seek to frame"):
Image.open("Tests/images/seek_too_large.tif")
Expand Down
7 changes: 7 additions & 0 deletions Tests/test_file_wmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ def test_load() -> None:
assert im.load()[0, 0] == (255, 255, 255)


def test_load_zero_inch() -> None:
b = BytesIO(b"\xd7\xcd\xc6\x9a\x00\x00" + b"\x00" * 10)
with pytest.raises(ValueError):
with Image.open(b):
pass


def test_register_handler(tmp_path: Path) -> None:
class TestHandler(ImageFile.StubHandler):
methodCalled = False
Expand Down
4 changes: 4 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,10 @@ def test_empty_get_ifd(self) -> None:
ifd[36864] = b"0220"
assert exif.get_ifd(0x8769) == {36864: b"0220"}

reloaded_exif = Image.Exif()
reloaded_exif.load(exif.tobytes())
assert reloaded_exif.get_ifd(0x8769) == {36864: b"0220"}

@mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
)
Expand Down
10 changes: 5 additions & 5 deletions Tests/test_image_thumbnail.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,20 +104,20 @@ def test_transposed() -> None:
assert im.size == (590, 88)


def test_load_first_unless_jpeg() -> None:
def test_load_first_unless_jpeg(monkeypatch: pytest.MonkeyPatch) -> None:
# Test that thumbnail() still uses draft() for JPEG
with Image.open("Tests/images/hopper.jpg") as im:
draft = im.draft
original_draft = im.draft

def im_draft(
mode: str, size: tuple[int, int]
mode: str | None, size: tuple[int, int] | None
) -> tuple[str, tuple[int, int, float, float]] | None:
result = draft(mode, size)
result = original_draft(mode, size)
assert result is not None

return result

im.draft = im_draft
monkeypatch.setattr(im, "draft", im_draft)

im.thumbnail((64, 64))

Expand Down
3 changes: 3 additions & 0 deletions Tests/test_imagedraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -1674,6 +1674,9 @@ def test_continuous_horizontal_edges_polygon() -> None:
def test_discontiguous_corners_polygon() -> None:
img, draw = create_base_image_draw((84, 68))
draw.polygon(((1, 21), (34, 4), (71, 1), (38, 18)), BLACK)
draw.polygon(
((82, 29), (82, 26), (82, 24), (67, 22), (52, 29), (52, 15), (67, 22)), BLACK
)
draw.polygon(((71, 44), (38, 27), (1, 24)), BLACK)
draw.polygon(
((38, 66), (5, 49), (77, 49), (47, 66), (82, 63), (82, 47), (1, 47), (1, 63)),
Expand Down
Loading

0 comments on commit be02830

Please sign in to comment.