Skip to content

Commit c02c869

Browse files
authored
Merge branch 'main' into main
2 parents 9fad9d9 + d80cf0e commit c02c869

19 files changed

+98
-131
lines changed

.ci/requirements-cibw.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
cibuildwheel==3.0.0
1+
cibuildwheel==3.0.1

.github/workflows/wheels-dependencies.sh

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ if [[ "$CIBW_PLATFORM" == "ios" ]]; then
6060
# on using the Xcode builder, which isn't very helpful for most of Pillow's
6161
# dependencies. Therefore, we lean on the OSX configurations, plus CC, CFLAGS
6262
# etc. to ensure the right sysroot is selected.
63-
HOST_CMAKE_FLAGS="-DCMAKE_SYSTEM_NAME=$CMAKE_SYSTEM_NAME -DCMAKE_SYSTEM_PROCESSOR=$GNU_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET -DCMAKE_OSX_SYSROOT=$IOS_SDK_PATH -DBUILD_SHARED_LIBS=NO"
63+
HOST_CMAKE_FLAGS="-DCMAKE_SYSTEM_NAME=$CMAKE_SYSTEM_NAME -DCMAKE_SYSTEM_PROCESSOR=$GNU_ARCH -DCMAKE_OSX_DEPLOYMENT_TARGET=$IPHONEOS_DEPLOYMENT_TARGET -DCMAKE_OSX_SYSROOT=$IOS_SDK_PATH -DBUILD_SHARED_LIBS=NO -DENABLE_SHARED=NO"
6464

6565
# Meson needs to be pointed at a cross-platform configuration file
6666
# This will be generated once CC etc. have been evaluated.
@@ -103,7 +103,7 @@ TIFF_VERSION=4.7.0
103103
LCMS2_VERSION=2.17
104104
ZLIB_VERSION=1.3.1
105105
ZLIB_NG_VERSION=2.2.4
106-
LIBWEBP_VERSION=1.5.0 # Patched; next release won't need patching. See patch file.
106+
LIBWEBP_VERSION=1.6.0
107107
BZIP2_VERSION=1.0.8
108108
LIBXCB_VERSION=1.17.0
109109
BROTLI_VERSION=1.1.0 # Patched; next release won't need patching. See patch file.
@@ -280,7 +280,11 @@ function build {
280280
if [[ -n "$IS_MACOS" ]]; then
281281
webp_cflags="$webp_cflags -Wl,-headerpad_max_install_names"
282282
fi
283-
CFLAGS="$CFLAGS $webp_cflags" build_simple libwebp $LIBWEBP_VERSION \
283+
webp_ldflags=""
284+
if [[ -n "$IOS_SDK" ]]; then
285+
webp_ldflags="$webp_ldflags -llzma -lz"
286+
fi
287+
CFLAGS="$CFLAGS $webp_cflags" LDFLAGS="$LDFLAGS $webp_ldflags" build_simple libwebp $LIBWEBP_VERSION \
284288
https://storage.googleapis.com/downloads.webmproject.org/releases/webp tar.gz \
285289
--enable-libwebpmux --enable-libwebpdemux
286290

@@ -380,6 +384,15 @@ fi
380384

381385
wrap_wheel_builder build
382386

387+
# A safety catch for iOS. iOS can't use dynamic libraries, but clang will prefer
388+
# to link dynamic libraries to static libraries. The only way to reliably
389+
# prevent this is to not have dynamic libraries available in the first place.
390+
# The build process *shouldn't* generate any dylibs... but just in case, purge
391+
# any dylibs that *have* been installed into the build prefix directory.
392+
if [[ -n "$IOS_SDK" ]]; then
393+
find "$BUILD_PREFIX" -name "*.dylib" -exec rm -rf {} \;
394+
fi
395+
383396
# Return to the project root to finish the build
384397
popd > /dev/null
385398

.github/workflows/wheels.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,22 +77,22 @@ jobs:
7777
platform: linux
7878
os: ubuntu-latest
7979
cibw_arch: x86_64
80+
manylinux: "manylinux2014"
8081
- name: "manylinux_2_28 x86_64"
8182
platform: linux
8283
os: ubuntu-latest
8384
cibw_arch: x86_64
8485
build: "*manylinux*"
85-
manylinux: "manylinux_2_28"
8686
- name: "manylinux2014 and musllinux aarch64"
8787
platform: linux
8888
os: ubuntu-24.04-arm
8989
cibw_arch: aarch64
90+
manylinux: "manylinux2014"
9091
- name: "manylinux_2_28 aarch64"
9192
platform: linux
9293
os: ubuntu-24.04-arm
9394
cibw_arch: aarch64
9495
build: "*manylinux*"
95-
manylinux: "manylinux_2_28"
9696
- name: "iOS arm64 device"
9797
platform: ios
9898
os: macos-latest

Tests/helper.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -291,16 +291,6 @@ def djpeg_available() -> bool:
291291
return False
292292

293293

294-
def cjpeg_available() -> bool:
295-
if shutil.which("cjpeg"):
296-
try:
297-
subprocess.check_call(["cjpeg", "-version"])
298-
return True
299-
except subprocess.CalledProcessError: # pragma: no cover
300-
return False
301-
return False
302-
303-
304294
def netpbm_available() -> bool:
305295
return bool(shutil.which("ppmquant") and shutil.which("ppmtogif"))
306296

Tests/test_file_jpeg.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
assert_image_equal_tofile,
2727
assert_image_similar,
2828
assert_image_similar_tofile,
29-
cjpeg_available,
3029
djpeg_available,
3130
hopper,
3231
is_win32,
@@ -731,14 +730,6 @@ def test_load_djpeg(self) -> None:
731730
img.load_djpeg()
732731
assert_image_similar_tofile(img, TEST_FILE, 5)
733732

734-
@pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
735-
def test_save_cjpeg(self, tmp_path: Path) -> None:
736-
with Image.open(TEST_FILE) as img:
737-
tempfile = str(tmp_path / "temp.jpg")
738-
JpegImagePlugin._save_cjpeg(img, BytesIO(), tempfile)
739-
# Default save quality is 75%, so a tiny bit of difference is alright
740-
assert_image_similar_tofile(img, tempfile, 17)
741-
742733
def test_no_duplicate_0x1001_tag(self) -> None:
743734
# Arrange
744735
tag_ids = {v: k for k, v in ExifTags.TAGS.items()}

Tests/test_file_libtiff.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -873,8 +873,8 @@ def test_lzma(self, capfd: pytest.CaptureFixture[str]) -> None:
873873
assert im.mode == "RGB"
874874
assert im.size == (128, 128)
875875
assert im.format == "TIFF"
876-
im2 = hopper()
877-
assert_image_similar(im, im2, 5)
876+
with hopper() as im2:
877+
assert_image_similar(im, im2, 5)
878878
except OSError:
879879
captured = capfd.readouterr()
880880
if "LZMA compression support is not configured" in captured.err:

Tests/test_imagemath_lambda_eval.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from typing import Any
44

5-
from PIL import Image, ImageMath
5+
import pytest
6+
7+
from PIL import Image, ImageMath, _imagingmath
68

79

810
def pixel(im: Image.Image | int) -> str | int:
@@ -498,3 +500,31 @@ def test_logical_not_equal() -> None:
498500
)
499501
== "I 1"
500502
)
503+
504+
505+
def test_reflected_operands() -> None:
506+
assert pixel(ImageMath.lambda_eval(lambda args: 1 + args["A"], **images)) == "I 2"
507+
assert pixel(ImageMath.lambda_eval(lambda args: 1 - args["A"], **images)) == "I 0"
508+
assert pixel(ImageMath.lambda_eval(lambda args: 1 * args["A"], **images)) == "I 1"
509+
assert pixel(ImageMath.lambda_eval(lambda args: 1 / args["A"], **images)) == "I 1"
510+
assert pixel(ImageMath.lambda_eval(lambda args: 1 % args["A"], **images)) == "I 0"
511+
assert pixel(ImageMath.lambda_eval(lambda args: 1 ** args["A"], **images)) == "I 1"
512+
assert pixel(ImageMath.lambda_eval(lambda args: 1 & args["A"], **images)) == "I 1"
513+
assert pixel(ImageMath.lambda_eval(lambda args: 1 | args["A"], **images)) == "I 1"
514+
assert pixel(ImageMath.lambda_eval(lambda args: 1 ^ args["A"], **images)) == "I 0"
515+
516+
517+
def test_unsupported_mode() -> None:
518+
im = Image.new("RGB", (1, 1))
519+
with pytest.raises(ValueError, match="unsupported mode: RGB"):
520+
ImageMath.lambda_eval(lambda args: args["im"] + 1, im=im)
521+
522+
523+
def test_bad_operand_type(monkeypatch: pytest.MonkeyPatch) -> None:
524+
monkeypatch.delattr(_imagingmath, "abs_I")
525+
with pytest.raises(TypeError, match="bad operand type for 'abs'"):
526+
ImageMath.lambda_eval(lambda args: abs(args["I"]), I=I)
527+
528+
monkeypatch.delattr(_imagingmath, "max_F")
529+
with pytest.raises(TypeError, match="bad operand type for 'max'"):
530+
ImageMath.lambda_eval(lambda args: args["max"](args["I"], args["F"]), I=I, F=F)

Tests/test_shell_injection.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
from PIL import GifImagePlugin, Image, JpegImagePlugin
1111

12-
from .helper import cjpeg_available, djpeg_available, is_win32, netpbm_available
12+
from .helper import djpeg_available, is_win32, netpbm_available
1313

1414
TEST_JPG = "Tests/images/hopper.jpg"
1515
TEST_GIF = "Tests/images/hopper.gif"
@@ -42,11 +42,6 @@ def test_load_djpeg_filename(self, tmp_path: Path) -> None:
4242
assert isinstance(im, JpegImagePlugin.JpegImageFile)
4343
im.load_djpeg()
4444

45-
@pytest.mark.skipif(not cjpeg_available(), reason="cjpeg not available")
46-
def test_save_cjpeg_filename(self, tmp_path: Path) -> None:
47-
with Image.open(TEST_JPG) as im:
48-
self.assert_save_filename_check(tmp_path, im, JpegImagePlugin._save_cjpeg)
49-
5045
@pytest.mark.skipif(not netpbm_available(), reason="Netpbm not available")
5146
def test_save_netpbm_filename_bmp_mode(self, tmp_path: Path) -> None:
5247
with Image.open(TEST_GIF) as im:

depends/install_webp.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22
# install webp
33

4-
archive=libwebp-1.5.0
4+
archive=libwebp-1.6.0
55

66
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
77

docs/deprecations.rst

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ Deprecated features
1212
Below are features which are considered deprecated. Where appropriate,
1313
a :py:exc:`DeprecationWarning` is issued.
1414

15-
ImageDraw.getdraw hints parameter
16-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17-
18-
.. deprecated:: 10.4.0
19-
20-
The ``hints`` parameter in :py:meth:`~PIL.ImageDraw.getdraw()` has been deprecated.
21-
2215
ExifTags.IFD.Makernote
2316
^^^^^^^^^^^^^^^^^^^^^^
2417

@@ -186,6 +179,7 @@ ICNS (width, height, scale) sizes
186179
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
187180

188181
.. deprecated:: 11.0.0
182+
.. versionremoved:: 12.0.0
189183

190184
Setting an ICNS image size to ``(width, height, scale)`` before loading has been
191185
removed. Instead, ``load(scale)`` can be used.

0 commit comments

Comments
 (0)