diff --git a/.github/workflows/test-mingw.yml b/.github/workflows/test-mingw.yml
index b4e479f12..a07a27c46 100644
--- a/.github/workflows/test-mingw.yml
+++ b/.github/workflows/test-mingw.yml
@@ -67,10 +67,10 @@ jobs:
mingw-w64-x86_64-python3-cffi \
mingw-w64-x86_64-python3-numpy \
mingw-w64-x86_64-python3-olefile \
- mingw-w64-x86_64-python3-pip \
mingw-w64-x86_64-python3-setuptools \
mingw-w64-x86_64-python-pyqt6
+ python3 -m ensurepip
python3 -m pip install pyroma pytest pytest-cov pytest-timeout
pushd depends && ./install_extra_test_images.sh && popd
diff --git a/.github/workflows/wheels-dependencies.sh b/.github/workflows/wheels-dependencies.sh
index 26bf2f6d6..cc8d7e085 100755
--- a/.github/workflows/wheels-dependencies.sh
+++ b/.github/workflows/wheels-dependencies.sh
@@ -19,7 +19,7 @@ FREETYPE_VERSION=2.13.2
HARFBUZZ_VERSION=8.3.0
LIBPNG_VERSION=1.6.40
JPEGTURBO_VERSION=3.0.1
-OPENJPEG_VERSION=2.5.0
+OPENJPEG_VERSION=2.5.2
XZ_VERSION=5.4.5
TIFF_VERSION=4.6.0
LCMS2_VERSION=2.16
@@ -40,7 +40,7 @@ BROTLI_VERSION=1.1.0
if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "x86_64" ]]; then
function build_openjpeg {
- local out_dir=$(fetch_unpack https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz openjpeg-2.5.0.tar.gz)
+ local out_dir=$(fetch_unpack https://github.com/uclouvain/openjpeg/archive/v${OPENJPEG_VERSION}.tar.gz openjpeg-${OPENJPEG_VERSION}.tar.gz)
(cd $out_dir \
&& cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
&& make install)
@@ -93,6 +93,9 @@ function build {
done
fi
build_openjpeg
+ if [ -f /usr/local/lib64/libopenjp2.so ]; then
+ cp /usr/local/lib64/libopenjp2.so /usr/local/lib
+ fi
ORIGINAL_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -O3 -DNDEBUG"
diff --git a/CHANGES.rst b/CHANGES.rst
index 205ffa294..7adcf1b40 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,6 +5,12 @@ Changelog (Pillow)
10.3.0 (unreleased)
-------------------
+- Handle truncated chunks at the end of PNG images #7709
+ [lajiyuan, radarhere]
+
+- Match mask size to pasted image size in GifImagePlugin #7779
+ [radarhere]
+
- Release GIL while calling ``WebPAnimDecoderGetNext`` #7782
[evanmiller, radarhere]
diff --git a/README.md b/README.md
index 9776c40e2..f142ef563 100644
--- a/README.md
+++ b/README.md
@@ -82,9 +82,6 @@ As of 2019, Pillow development is
-
None:
assert reread.n_frames == 10
+def test_append_different_size_image(tmp_path: Path) -> None:
+ out = str(tmp_path / "temp.gif")
+
+ im = Image.new("RGB", (100, 100))
+ bigger_im = Image.new("RGB", (200, 200), "#f00")
+
+ im.save(out, save_all=True, append_images=[bigger_im])
+
+ with Image.open(out) as reread:
+ assert reread.size == (100, 100)
+
+ reread.seek(1)
+ assert reread.size == (100, 100)
+
+
def test_transparent_optimize(tmp_path: Path) -> None:
# From issue #2195, if the transparent color is incorrectly optimized out, GIF loses
# transparency.
diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py
index c51f56ce7..334839f5c 100644
--- a/Tests/test_file_png.py
+++ b/Tests/test_file_png.py
@@ -783,6 +783,18 @@ class TestFilePng:
with Image.open(mystdout) as reloaded:
assert_image_equal_tofile(reloaded, TEST_PNG_FILE)
+ def test_truncated_end_chunk(self) -> None:
+ with Image.open("Tests/images/truncated_end_chunk.png") as im:
+ with pytest.raises(OSError):
+ im.load()
+
+ ImageFile.LOAD_TRUNCATED_IMAGES = True
+ try:
+ with Image.open("Tests/images/truncated_end_chunk.png") as im:
+ assert_image_equal_tofile(im, "Tests/images/hopper.png")
+ finally:
+ ImageFile.LOAD_TRUNCATED_IMAGES = False
+
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
@skip_unless_feature("zlib")
diff --git a/Tests/test_image.py b/Tests/test_image.py
index 4c04e0da4..2a4d453e2 100644
--- a/Tests/test_image.py
+++ b/Tests/test_image.py
@@ -685,15 +685,18 @@ class TestImage:
_make_new(im, blank_p, ImagePalette.ImagePalette())
_make_new(im, blank_pa, ImagePalette.ImagePalette())
- def test_p_from_rgb_rgba(self) -> None:
- for mode, color in [
+ @pytest.mark.parametrize(
+ "mode, color",
+ (
("RGB", "#DDEEFF"),
("RGB", (221, 238, 255)),
("RGBA", (221, 238, 255, 255)),
- ]:
- im = Image.new("P", (100, 100), color)
- expected = Image.new(mode, (100, 100), color)
- assert_image_equal(im.convert(mode), expected)
+ ),
+ )
+ def test_p_from_rgb_rgba(self, mode: str, color: str | tuple[int, ...]) -> None:
+ im = Image.new("P", (100, 100), color)
+ expected = Image.new(mode, (100, 100), color)
+ assert_image_equal(im.convert(mode), expected)
def test_no_resource_warning_on_save(self, tmp_path: Path) -> None:
# https://github.com/python-pillow/Pillow/issues/835
diff --git a/depends/install_openjpeg.sh b/depends/install_openjpeg.sh
index 4f4b81a62..8c2967bc2 100755
--- a/depends/install_openjpeg.sh
+++ b/depends/install_openjpeg.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# install openjpeg
-archive=openjpeg-2.5.0
+archive=openjpeg-2.5.2
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
diff --git a/docs/deprecations.rst b/docs/deprecations.rst
index 205fcb9ab..8877ccdeb 100644
--- a/docs/deprecations.rst
+++ b/docs/deprecations.rst
@@ -504,3 +504,27 @@ PIL.OleFileIO
the upstream :pypi:`olefile` Python package, and replaced with an :py:exc:`ImportError` in 5.0.0
(2018-01). The deprecated file has now been removed from Pillow. If needed, install from
PyPI (eg. ``python3 -m pip install olefile``).
+
+import _imaging
+~~~~~~~~~~~~~~~
+
+.. versionremoved:: 2.1.0
+
+Pillow >= 2.1.0 no longer supports ``import _imaging``.
+Please use ``from PIL.Image import core as _imaging`` instead.
+
+Pillow and PIL
+~~~~~~~~~~~~~~
+
+.. versionremoved:: 1.0.0
+
+Pillow and PIL cannot co-exist in the same environment.
+Before installing Pillow, please uninstall PIL.
+
+import Image
+~~~~~~~~~~~~
+
+.. versionremoved:: 1.0.0
+
+Pillow >= 1.0 no longer supports ``import Image``.
+Please use ``from PIL import Image`` instead.
diff --git a/docs/index.rst b/docs/index.rst
index bf2feea9a..f4e81e45d 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -73,10 +73,6 @@ Pillow for enterprise is available via the Tidelift Subscription. `Learn more
-Warnings
---------
-
-.. warning:: Pillow and PIL cannot co-exist in the same environment. Before installing Pillow, please uninstall PIL.
-
-.. warning:: Pillow >= 1.0 no longer supports ``import Image``. Please use ``from PIL import Image`` instead.
-
-.. warning:: Pillow >= 2.1.0 no longer supports ``import _imaging``. Please use ``from PIL.Image import core as _imaging`` instead.
-
Python Support
--------------
@@ -186,7 +177,7 @@ Many of Pillow's features require external libraries:
* **openjpeg** provides JPEG 2000 functionality.
* Pillow has been tested with openjpeg **2.0.0**, **2.1.0**, **2.3.1**,
- **2.4.0** and **2.5.0**.
+ **2.4.0**, **2.5.0** and **2.5.2**.
* Pillow does **not** support the earlier **1.5** series which ships
with Debian Jessie.
diff --git a/docs/reference/ImageOps.rst b/docs/reference/ImageOps.rst
index 475253078..051fdcfc9 100644
--- a/docs/reference/ImageOps.rst
+++ b/docs/reference/ImageOps.rst
@@ -14,6 +14,8 @@ only work on L and RGB images.
.. autofunction:: colorize
.. autofunction:: crop
.. autofunction:: scale
+.. autoclass:: SupportsGetMesh
+ :show-inheritance:
.. autofunction:: deform
.. autofunction:: equalize
.. autofunction:: expand
diff --git a/pyproject.toml b/pyproject.toml
index 58c2464bc..518facc34 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -80,7 +80,6 @@ Homepage = "https://python-pillow.org"
Mastodon = "https://fosstodon.org/@pillow"
"Release notes" = "https://pillow.readthedocs.io/en/stable/releasenotes/index.html"
Source = "https://github.com/python-pillow/Pillow"
-Twitter = "https://twitter.com/PythonPillow"
[tool.setuptools]
packages = ["PIL"]
diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py
index dc842d7a3..b38b43013 100644
--- a/src/PIL/GifImagePlugin.py
+++ b/src/PIL/GifImagePlugin.py
@@ -649,9 +649,7 @@ def _write_multiple_frames(im, fp, palette):
if "transparency" in encoderinfo:
# When the delta is zero, fill the image with transparency
diff_frame = im_frame.copy()
- fill = Image.new(
- "P", diff_frame.size, encoderinfo["transparency"]
- )
+ fill = Image.new("P", delta.size, encoderinfo["transparency"])
if delta.mode == "RGBA":
r, g, b, a = delta.split()
mask = ImageMath.eval(
diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py
index 6218c723f..33db8fa50 100644
--- a/src/PIL/ImageOps.py
+++ b/src/PIL/ImageOps.py
@@ -411,7 +411,15 @@ def scale(
return image.resize(size, resample)
-class _SupportsGetMesh(Protocol):
+class SupportsGetMesh(Protocol):
+ """
+ An object that supports the ``getmesh`` method, taking an image as an
+ argument, and returning a list of tuples. Each tuple contains two tuples,
+ the source box as a tuple of 4 integers, and a tuple of 8 integers for the
+ final quadrilateral, in order of top left, bottom left, bottom right, top
+ right.
+ """
+
def getmesh(
self, image: Image.Image
) -> list[
@@ -421,7 +429,7 @@ class _SupportsGetMesh(Protocol):
def deform(
image: Image.Image,
- deformer: _SupportsGetMesh,
+ deformer: SupportsGetMesh,
resample: int = Image.Resampling.BILINEAR,
) -> Image.Image:
"""
diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py
index 823f12492..1248fb785 100644
--- a/src/PIL/PngImagePlugin.py
+++ b/src/PIL/PngImagePlugin.py
@@ -981,7 +981,13 @@ class PngImageFile(ImageFile.ImageFile):
except EOFError:
if cid == b"fdAT":
length -= 4
- ImageFile._safe_read(self.fp, length)
+ try:
+ ImageFile._safe_read(self.fp, length)
+ except OSError as e:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ break
+ else:
+ raise e
except AttributeError:
logger.debug("%r %s %s (unknown)", cid, pos, length)
s = ImageFile._safe_read(self.fp, length)
diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py
index df33ea493..2ee9872e6 100644
--- a/winbuild/build_prepare.py
+++ b/winbuild/build_prepare.py
@@ -308,21 +308,16 @@ DEPS = {
"libs": [r"Lib\MS\*.lib"],
},
"openjpeg": {
- "url": "https://github.com/uclouvain/openjpeg/archive/v2.5.0.tar.gz",
- "filename": "openjpeg-2.5.0.tar.gz",
- "dir": "openjpeg-2.5.0",
+ "url": "https://github.com/uclouvain/openjpeg/archive/v2.5.2.tar.gz",
+ "filename": "openjpeg-2.5.2.tar.gz",
+ "dir": "openjpeg-2.5.2",
"license": "LICENSE",
- "patch": {
- r"src\lib\openjp2\ht_dec.c": {
- "#ifdef OPJ_COMPILER_MSVC\n return (OPJ_UINT32)__popcnt(val);": "#if defined(OPJ_COMPILER_MSVC) && (defined(_M_IX86) || defined(_M_AMD64))\n return (OPJ_UINT32)__popcnt(val);", # noqa: E501
- }
- },
"build": [
*cmds_cmake(
"openjp2", "-DBUILD_CODEC:BOOL=OFF", "-DBUILD_SHARED_LIBS:BOOL=OFF"
),
- cmd_mkdir(r"{inc_dir}\openjpeg-2.5.0"),
- cmd_copy(r"src\lib\openjp2\*.h", r"{inc_dir}\openjpeg-2.5.0"),
+ cmd_mkdir(r"{inc_dir}\openjpeg-2.5.2"),
+ cmd_copy(r"src\lib\openjp2\*.h", r"{inc_dir}\openjpeg-2.5.2"),
],
"libs": [r"bin\*.lib"],
},