mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-11 16:52:29 +03:00
Merge branch 'main' into main
This commit is contained in:
commit
54c3c93987
|
@ -66,7 +66,7 @@ if [[ $(uname) != CYGWIN* ]]; then
|
|||
pushd depends && ./install_raqm.sh && popd
|
||||
|
||||
# libavif
|
||||
pushd depends && CMAKE_POLICY_VERSION_MINIMUM=3.5 ./install_libavif.sh && popd
|
||||
pushd depends && ./install_libavif.sh && popd
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
||||
|
|
|
@ -1 +1 @@
|
|||
cibuildwheel==2.23.2
|
||||
cibuildwheel==2.23.3
|
||||
|
|
46
.github/ISSUE_TEMPLATE/RELEASE.md
vendored
Normal file
46
.github/ISSUE_TEMPLATE/RELEASE.md
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
name: "Maintainers only: Release"
|
||||
about: For maintainers to schedule a quarterly release
|
||||
labels: Release
|
||||
---
|
||||
|
||||
## Main release
|
||||
|
||||
Released quarterly on January 2nd, April 1st, July 1st and October 15th.
|
||||
|
||||
* [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/3154
|
||||
* [ ] Develop and prepare release in `main` branch.
|
||||
* [ ] Add release notes e.g. https://github.com/python-pillow/Pillow/pull/8885
|
||||
* [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions) to confirm passing tests in `main` branch.
|
||||
* [ ] Check that all the wheel builds pass the tests in the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml) jobs by manually triggering them.
|
||||
* [ ] In compliance with [PEP 440](https://peps.python.org/pep-0440/), update version identifier in `src/PIL/_version.py`
|
||||
* [ ] Run pre-release check via `make release-test` in a freshly cloned repo.
|
||||
* [ ] Create branch and tag for release e.g.:
|
||||
```bash
|
||||
git branch [[MAJOR.MINOR]].x
|
||||
git tag [[MAJOR.MINOR]].0
|
||||
git push --tags
|
||||
```
|
||||
* [ ] Check the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml) has passed, including the "Upload release to PyPI" job. This will have been triggered by the new tag.
|
||||
* [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases).
|
||||
* [ ] In compliance with [PEP 440](https://peps.python.org/pep-0440/), increment and append `.dev0` to version identifier in `src/PIL/_version.py` and then:
|
||||
```bash
|
||||
git push --all
|
||||
```
|
||||
|
||||
## Publicize release
|
||||
|
||||
* [ ] Announce release availability via [Mastodon](https://fosstodon.org/@pillow) e.g. https://fosstodon.org/@pillow/110639450470725321
|
||||
|
||||
## Documentation
|
||||
|
||||
* [ ] Make sure the [default version for Read the Docs](https://pillow.readthedocs.io/en/stable/) is up-to-date with the release changes
|
||||
|
||||
## Docker images
|
||||
|
||||
* [ ] Update Pillow in the Docker Images repository
|
||||
```bash
|
||||
git clone https://github.com/python-pillow/docker-images
|
||||
cd docker-images
|
||||
./update-pillow-tag.sh [[release tag]]
|
||||
```
|
6
.github/workflows/test-windows.yml
vendored
6
.github/workflows/test-windows.yml
vendored
|
@ -84,7 +84,7 @@ jobs:
|
|||
python3 -m pip install --upgrade pip
|
||||
|
||||
- name: Install CPython dependencies
|
||||
if: "!contains(matrix.python-version, 'pypy') && matrix.architecture != 'x86'"
|
||||
if: "!contains(matrix.python-version, 'pypy') && !contains(matrix.python-version, '3.14') && matrix.architecture != 'x86'"
|
||||
run: |
|
||||
python3 -m pip install PyQt6
|
||||
|
||||
|
@ -98,8 +98,8 @@ jobs:
|
|||
choco install nasm --no-progress
|
||||
echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
|
||||
|
||||
choco install ghostscript --version=10.5.0 --no-progress
|
||||
echo "C:\Program Files\gs\gs10.05.0\bin" >> $env:GITHUB_PATH
|
||||
choco install ghostscript --version=10.5.1 --no-progress
|
||||
echo "C:\Program Files\gs\gs10.05.1\bin" >> $env:GITHUB_PATH
|
||||
|
||||
# Install extra test images
|
||||
xcopy /S /Y Tests\test-images\* Tests\images
|
||||
|
|
4
.github/workflows/wheels-dependencies.sh
vendored
4
.github/workflows/wheels-dependencies.sh
vendored
|
@ -38,8 +38,8 @@ ARCHIVE_SDIR=pillow-depends-main
|
|||
|
||||
# Package versions for fresh source builds
|
||||
FREETYPE_VERSION=2.13.3
|
||||
HARFBUZZ_VERSION=11.1.0
|
||||
LIBPNG_VERSION=1.6.47
|
||||
HARFBUZZ_VERSION=11.2.1
|
||||
LIBPNG_VERSION=1.6.48
|
||||
JPEGTURBO_VERSION=3.1.0
|
||||
OPENJPEG_VERSION=2.5.3
|
||||
XZ_VERSION=5.8.1
|
||||
|
|
7
.github/zizmor.yml
vendored
Normal file
7
.github/zizmor.yml
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Configuration for the zizmor static analysis tool, run via pre-commit in CI
|
||||
# https://woodruffw.github.io/zizmor/configuration/
|
||||
rules:
|
||||
unpinned-uses:
|
||||
config:
|
||||
policies:
|
||||
"*": ref-pin
|
|
@ -1,6 +1,6 @@
|
|||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.11.4
|
||||
rev: v0.11.8
|
||||
hooks:
|
||||
- id: ruff
|
||||
args: [--exit-non-zero-on-fix]
|
||||
|
@ -24,7 +24,7 @@ repos:
|
|||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v20.1.0
|
||||
rev: v20.1.3
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types: [c]
|
||||
|
@ -51,14 +51,14 @@ repos:
|
|||
exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.32.1
|
||||
rev: 0.33.0
|
||||
hooks:
|
||||
- id: check-github-workflows
|
||||
- id: check-readthedocs
|
||||
- id: check-renovate
|
||||
|
||||
- repo: https://github.com/woodruffw/zizmor-pre-commit
|
||||
rev: v1.5.2
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
- id: zizmor
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ This library provides extensive file format support, an efficient internal repre
|
|||
|
||||
The core image library is designed for fast access to data stored in a few basic pixel formats. It should provide a solid foundation for a general image processing tool.
|
||||
|
||||
## More Information
|
||||
## More information
|
||||
|
||||
- [Documentation](https://pillow.readthedocs.io/)
|
||||
- [Installation](https://pillow.readthedocs.io/en/latest/installation/basic-installation.html)
|
||||
|
@ -107,6 +107,6 @@ The core image library is designed for fast access to data stored in a few basic
|
|||
- [Changelog](https://github.com/python-pillow/Pillow/releases)
|
||||
- [Pre-fork](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst#pre-fork)
|
||||
|
||||
## Report a Vulnerability
|
||||
## Report a vulnerability
|
||||
|
||||
To report a security vulnerability, please follow the procedure described in the [Tidelift security policy](https://tidelift.com/docs/security).
|
||||
|
|
35
RELEASING.md
35
RELEASING.md
|
@ -1,34 +1,15 @@
|
|||
# Release Checklist
|
||||
# Release checklist
|
||||
|
||||
See https://pillow.readthedocs.io/en/stable/releasenotes/versioning.html for
|
||||
information about how the version numbers line up with releases.
|
||||
|
||||
## Main Release
|
||||
## Main release
|
||||
|
||||
Released quarterly on January 2nd, April 1st, July 1st and October 15th.
|
||||
|
||||
* [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/3154
|
||||
* [ ] Develop and prepare release in `main` branch.
|
||||
* [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions) to confirm passing tests in `main` branch.
|
||||
* [ ] Check that all the wheel builds pass the tests in the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml) jobs by manually triggering them.
|
||||
* [ ] In compliance with [PEP 440](https://peps.python.org/pep-0440/), update version identifier in `src/PIL/_version.py`
|
||||
* [ ] Run pre-release check via `make release-test` in a freshly cloned repo.
|
||||
* [ ] Create branch and tag for release e.g.:
|
||||
```bash
|
||||
git branch 5.2.x
|
||||
git tag 5.2.0
|
||||
git push --tags
|
||||
```
|
||||
* [ ] Check the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml)
|
||||
has passed, including the "Upload release to PyPI" job. This will have been triggered
|
||||
by the new tag.
|
||||
* [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases).
|
||||
* [ ] In compliance with [PEP 440](https://peps.python.org/pep-0440/),
|
||||
increment and append `.dev0` to version identifier in `src/PIL/_version.py` and then:
|
||||
```bash
|
||||
git push --all
|
||||
```
|
||||
## Point Release
|
||||
* [ ] Create a new issue and select the "Maintainers only: Release" template.
|
||||
|
||||
## Point release
|
||||
|
||||
Released as needed for security, installation or critical bug fixes.
|
||||
|
||||
|
@ -58,7 +39,7 @@ Released as needed for security, installation or critical bug fixes.
|
|||
git push
|
||||
```
|
||||
|
||||
## Embargoed Release
|
||||
## Embargoed release
|
||||
|
||||
Released as needed privately to individual vendors for critical security-related bug fixes.
|
||||
|
||||
|
@ -82,7 +63,7 @@ Released as needed privately to individual vendors for critical security-related
|
|||
git push origin 2.5.x
|
||||
```
|
||||
|
||||
## Publicize Release
|
||||
## Publicize release
|
||||
|
||||
* [ ] Announce release availability via [Mastodon](https://fosstodon.org/@pillow) e.g. https://fosstodon.org/@pillow/110639450470725321
|
||||
|
||||
|
@ -90,7 +71,7 @@ Released as needed privately to individual vendors for critical security-related
|
|||
|
||||
* [ ] Make sure the [default version for Read the Docs](https://pillow.readthedocs.io/en/stable/) is up-to-date with the release changes
|
||||
|
||||
## Docker Images
|
||||
## Docker images
|
||||
|
||||
* [ ] Update Pillow in the Docker Images repository
|
||||
```bash
|
||||
|
|
|
@ -161,6 +161,12 @@ def assert_tuple_approx_equal(
|
|||
pytest.fail(msg + ": " + repr(actuals) + " != " + repr(targets))
|
||||
|
||||
|
||||
def timeout_unless_slower_valgrind(timeout: float) -> pytest.MarkDecorator:
|
||||
if "PILLOW_VALGRIND_TEST" in os.environ:
|
||||
return pytest.mark.pil_noop_mark()
|
||||
return pytest.mark.timeout(timeout)
|
||||
|
||||
|
||||
def skip_unless_feature(feature: str) -> pytest.MarkDecorator:
|
||||
reason = f"{feature} not available"
|
||||
return pytest.mark.skipif(not features.check(feature), reason=reason)
|
||||
|
|
|
@ -233,7 +233,7 @@ class TestFileAvif:
|
|||
with Image.open(out_gif) as reread:
|
||||
reread_value = reread.convert("RGB").getpixel((1, 1))
|
||||
difference = sum([abs(original_value[i] - reread_value[i]) for i in range(3)])
|
||||
assert difference <= 3
|
||||
assert difference <= 6
|
||||
|
||||
def test_save_single_frame(self, tmp_path: Path) -> None:
|
||||
temp_file = tmp_path / "temp.avif"
|
||||
|
|
|
@ -15,6 +15,7 @@ from .helper import (
|
|||
is_win32,
|
||||
mark_if_feature_version,
|
||||
skip_unless_feature,
|
||||
timeout_unless_slower_valgrind,
|
||||
)
|
||||
|
||||
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
|
||||
|
@ -398,7 +399,7 @@ def test_emptyline() -> None:
|
|||
assert image.format == "EPS"
|
||||
|
||||
|
||||
@pytest.mark.timeout(timeout=5)
|
||||
@timeout_unless_slower_valgrind(5)
|
||||
@pytest.mark.parametrize(
|
||||
"test_file",
|
||||
["Tests/images/eps/timeout-d675703545fee17acab56e5fec644c19979175de.eps"],
|
||||
|
|
|
@ -7,7 +7,12 @@ import pytest
|
|||
|
||||
from PIL import FliImagePlugin, Image, ImageFile
|
||||
|
||||
from .helper import assert_image_equal, assert_image_equal_tofile, is_pypy
|
||||
from .helper import (
|
||||
assert_image_equal,
|
||||
assert_image_equal_tofile,
|
||||
is_pypy,
|
||||
timeout_unless_slower_valgrind,
|
||||
)
|
||||
|
||||
# created as an export of a palette image from Gimp2.6
|
||||
# save as...-> hopper.fli, default options.
|
||||
|
@ -189,7 +194,7 @@ def test_seek() -> None:
|
|||
"Tests/images/timeout-bff0a9dc7243a8e6ede2408d2ffa6a9964698b87.fli",
|
||||
],
|
||||
)
|
||||
@pytest.mark.timeout(timeout=3)
|
||||
@timeout_unless_slower_valgrind(3)
|
||||
def test_timeouts(test_file: str) -> None:
|
||||
with open(test_file, "rb") as f:
|
||||
with Image.open(f) as im:
|
||||
|
|
|
@ -32,6 +32,7 @@ from .helper import (
|
|||
is_win32,
|
||||
mark_if_feature_version,
|
||||
skip_unless_feature,
|
||||
timeout_unless_slower_valgrind,
|
||||
)
|
||||
|
||||
ElementTree: ModuleType | None
|
||||
|
@ -1033,7 +1034,7 @@ class TestFileJpeg:
|
|||
with pytest.raises(ValueError):
|
||||
im.save(f, xmp=b"1" * 65505)
|
||||
|
||||
@pytest.mark.timeout(timeout=1)
|
||||
@timeout_unless_slower_valgrind(1)
|
||||
def test_eof(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
# Even though this decoder never says that it is finished
|
||||
# the image should still end when there is no new data
|
||||
|
|
|
@ -13,7 +13,12 @@ import pytest
|
|||
|
||||
from PIL import Image, PdfParser, features
|
||||
|
||||
from .helper import hopper, mark_if_feature_version, skip_unless_feature
|
||||
from .helper import (
|
||||
hopper,
|
||||
mark_if_feature_version,
|
||||
skip_unless_feature,
|
||||
timeout_unless_slower_valgrind,
|
||||
)
|
||||
|
||||
|
||||
def helper_save_as_pdf(tmp_path: Path, mode: str, **kwargs: Any) -> str:
|
||||
|
@ -339,8 +344,7 @@ def test_pdf_append_to_bytesio() -> None:
|
|||
assert len(f.getvalue()) > initial_size
|
||||
|
||||
|
||||
@pytest.mark.timeout(1)
|
||||
@pytest.mark.skipif("PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower")
|
||||
@timeout_unless_slower_valgrind(1)
|
||||
@pytest.mark.parametrize("newline", (b"\r", b"\n"))
|
||||
def test_redos(newline: bytes) -> None:
|
||||
malicious = b" trailer<<>>" + newline * 3456
|
||||
|
|
|
@ -26,6 +26,7 @@ from .helper import (
|
|||
hopper,
|
||||
is_pypy,
|
||||
is_win32,
|
||||
timeout_unless_slower_valgrind,
|
||||
)
|
||||
|
||||
ElementTree: ModuleType | None
|
||||
|
@ -988,7 +989,7 @@ class TestFileTiff:
|
|||
with pytest.raises(OSError):
|
||||
im.load()
|
||||
|
||||
@pytest.mark.timeout(6)
|
||||
@timeout_unless_slower_valgrind(6)
|
||||
@pytest.mark.filterwarnings("ignore:Truncated File Read")
|
||||
def test_timeout(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
with Image.open("Tests/images/timeout-6646305047838720") as im:
|
||||
|
@ -1001,7 +1002,7 @@ class TestFileTiff:
|
|||
"Tests/images/oom-225817ca0f8c663be7ab4b9e717b02c661e66834.tif",
|
||||
],
|
||||
)
|
||||
@pytest.mark.timeout(2)
|
||||
@timeout_unless_slower_valgrind(2)
|
||||
def test_oom(self, test_file: str) -> None:
|
||||
with pytest.raises(UnidentifiedImageError):
|
||||
with pytest.warns(UserWarning):
|
||||
|
|
|
@ -34,6 +34,7 @@ from .helper import (
|
|||
is_win32,
|
||||
mark_if_feature_version,
|
||||
skip_unless_feature,
|
||||
timeout_unless_slower_valgrind,
|
||||
)
|
||||
|
||||
ElementTree: ModuleType | None
|
||||
|
@ -572,10 +573,7 @@ class TestImage:
|
|||
i = Image.new("RGB", [1, 1])
|
||||
assert isinstance(i.size, tuple)
|
||||
|
||||
@pytest.mark.timeout(0.75)
|
||||
@pytest.mark.skipif(
|
||||
"PILLOW_VALGRIND_TEST" in os.environ, reason="Valgrind is slower"
|
||||
)
|
||||
@timeout_unless_slower_valgrind(0.75)
|
||||
@pytest.mark.parametrize("size", ((0, 100000000), (100000000, 0)))
|
||||
def test_empty_image(self, size: tuple[int, int]) -> None:
|
||||
Image.new("RGB", size)
|
||||
|
|
|
@ -462,7 +462,7 @@ class TestCoreResampleBox:
|
|||
im.resize((32, 32), resample, (20, 20, 20, 100))
|
||||
im.resize((32, 32), resample, (20, 20, 100, 20))
|
||||
|
||||
with pytest.raises(TypeError, match="must be sequence of length 4"):
|
||||
with pytest.raises(TypeError, match="must be (sequence|tuple) of length 4"):
|
||||
im.resize((32, 32), resample, (im.width, im.height)) # type: ignore[arg-type]
|
||||
|
||||
with pytest.raises(ValueError, match="can't be negative"):
|
||||
|
|
|
@ -7,7 +7,7 @@ import pytest
|
|||
|
||||
from PIL import Image, ImageDraw, ImageFont, _util, features
|
||||
|
||||
from .helper import assert_image_equal_tofile
|
||||
from .helper import assert_image_equal_tofile, timeout_unless_slower_valgrind
|
||||
|
||||
fonts = [ImageFont.load_default_imagefont()]
|
||||
if not features.check_module("freetype2"):
|
||||
|
@ -72,7 +72,7 @@ def test_decompression_bomb() -> None:
|
|||
font.getmask("A" * 1_000_000)
|
||||
|
||||
|
||||
@pytest.mark.timeout(4)
|
||||
@timeout_unless_slower_valgrind(4)
|
||||
def test_oom() -> None:
|
||||
glyph = struct.pack(
|
||||
">hhhhhhhhhh", 1, 0, -32767, -32767, 32767, 32767, -32767, -32767, 32767, 32767
|
||||
|
|
|
@ -162,3 +162,13 @@ def test_pickle_font_file(tmp_path: Path, protocol: int) -> None:
|
|||
|
||||
# Assert
|
||||
helper_assert_pickled_font_images(font, unpickled_font)
|
||||
|
||||
|
||||
def test_load_earlier_data() -> None:
|
||||
im = pickle.loads(
|
||||
b"\x80\x04\x95@\x00\x00\x00\x00\x00\x00\x00\x8c\x12PIL.PngImagePlugin"
|
||||
b"\x94\x8c\x0cPngImageFile\x94\x93\x94)\x81\x94]\x94(}\x94\x8c\x01L\x94K\x01"
|
||||
b"K\x01\x86\x94NC\x01\x00\x94eb."
|
||||
)
|
||||
assert im.mode == "L"
|
||||
assert im.size == (1, 1)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
version=1.2.1
|
||||
version=1.3.0
|
||||
|
||||
./download-and-extract.sh libavif-$version https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$version.tar.gz
|
||||
|
||||
|
|
|
@ -3,17 +3,23 @@
|
|||
|
||||
# You can set these variables from the command line.
|
||||
PYTHON = python3
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = $(PYTHON) -m sphinx.cmd.build
|
||||
PAPER =
|
||||
SPHINXOPTS = --fail-on-warning
|
||||
BUILDDIR = _build
|
||||
BUILDER = html
|
||||
JOBS = auto
|
||||
PAPER =
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = --define latex_paper_size=a4
|
||||
PAPEROPT_letter = --define latex_paper_size=letter
|
||||
ALLSPHINXOPTS = --doctree-dir $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
ALLSPHINXOPTS = --builder $(BUILDER) \
|
||||
--doctree-dir $(BUILDDIR)/doctrees \
|
||||
--jobs $(JOBS) \
|
||||
$(PAPEROPT_$(PAPER)) \
|
||||
$(SPHINXOPTS) \
|
||||
. $(BUILDDIR)/$(BUILDER)
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
|
@ -36,31 +42,19 @@ install-sphinx:
|
|||
.PHONY: html
|
||||
html:
|
||||
$(MAKE) install-sphinx
|
||||
$(SPHINXBUILD) --builder html --fail-on-warning --keep-going $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
$(SPHINXBUILD) $(ALLSPHINXOPTS)
|
||||
|
||||
.PHONY: dirhtml
|
||||
dirhtml:
|
||||
$(MAKE) install-sphinx
|
||||
$(SPHINXBUILD) --builder dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
dirhtml: BUILDER = dirhtml
|
||||
dirhtml: html
|
||||
|
||||
.PHONY: singlehtml
|
||||
singlehtml:
|
||||
$(MAKE) install-sphinx
|
||||
$(SPHINXBUILD) --builder singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
singlehtml: BUILDER = singlehtml
|
||||
singlehtml: html
|
||||
|
||||
.PHONY: linkcheck
|
||||
linkcheck:
|
||||
$(MAKE) install-sphinx
|
||||
$(SPHINXBUILD) --builder linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck -j auto
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
linkcheck: BUILDER = linkcheck
|
||||
linkcheck: html
|
||||
|
||||
.PHONY: htmlview
|
||||
htmlview: html
|
||||
|
|
|
@ -7,10 +7,8 @@ if "%SPHINXBUILD%" == "" (
|
|||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
|
21
setup.py
21
setup.py
|
@ -46,7 +46,7 @@ WEBP_ROOT = None
|
|||
ZLIB_ROOT = None
|
||||
FUZZING_BUILD = "LIB_FUZZING_ENGINE" in os.environ
|
||||
|
||||
if sys.platform == "win32" and sys.version_info >= (3, 14):
|
||||
if sys.platform == "win32" and sys.version_info >= (3, 15):
|
||||
import atexit
|
||||
|
||||
atexit.register(
|
||||
|
@ -224,13 +224,14 @@ def _add_directory(
|
|||
path.insert(where, subdir)
|
||||
|
||||
|
||||
def _find_include_file(self: pil_build_ext, include: str) -> int:
|
||||
def _find_include_file(self: pil_build_ext, include: str) -> str | None:
|
||||
for directory in self.compiler.include_dirs:
|
||||
_dbg("Checking for include file %s in %s", (include, directory))
|
||||
if os.path.isfile(os.path.join(directory, include)):
|
||||
path = os.path.join(directory, include)
|
||||
if os.path.isfile(path):
|
||||
_dbg("Found %s", include)
|
||||
return 1
|
||||
return 0
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
def _find_library_file(self: pil_build_ext, library: str) -> str | None:
|
||||
|
@ -852,9 +853,13 @@ class pil_build_ext(build_ext):
|
|||
|
||||
if feature.want("avif"):
|
||||
_dbg("Looking for avif")
|
||||
if _find_include_file(self, "avif/avif.h"):
|
||||
if _find_library_file(self, "avif"):
|
||||
feature.set("avif", "avif")
|
||||
if avif_h := _find_include_file(self, "avif/avif.h"):
|
||||
with open(avif_h, "rb") as fp:
|
||||
major_version = int(
|
||||
fp.read().split(b"#define AVIF_VERSION_MAJOR ")[1].split()[0]
|
||||
)
|
||||
if major_version >= 1 and _find_library_file(self, "avif"):
|
||||
feature.set("avif", "avif")
|
||||
|
||||
for f in feature:
|
||||
if not feature.get(f) and feature.require(f):
|
||||
|
|
|
@ -16,7 +16,6 @@ except ImportError:
|
|||
# Decoder options as module globals, until there is a way to pass parameters
|
||||
# to Image.open (see https://github.com/python-pillow/Pillow/issues/569)
|
||||
DECODE_CODEC_CHOICE = "auto"
|
||||
# Decoding is only affected by this for libavif **0.8.4** or greater.
|
||||
DEFAULT_MAX_THREADS = 0
|
||||
|
||||
|
||||
|
|
|
@ -257,7 +257,8 @@ class ImageFile(Image.Image):
|
|||
|
||||
def __setstate__(self, state: list[Any]) -> None:
|
||||
self.tile = []
|
||||
self.filename = state[5]
|
||||
if len(state) > 5:
|
||||
self.filename = state[5]
|
||||
super().__setstate__(state)
|
||||
|
||||
def verify(self) -> None:
|
||||
|
|
|
@ -81,7 +81,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
|
|||
|
||||
def _open(self) -> None:
|
||||
# check placable header
|
||||
s = self.fp.read(80)
|
||||
s = self.fp.read(44)
|
||||
|
||||
if s.startswith(b"\xd7\xcd\xc6\x9a\x00\x00"):
|
||||
# placeable windows metafile
|
||||
|
|
|
@ -113,12 +113,12 @@ V = {
|
|||
"BROTLI": "1.1.0",
|
||||
"FREETYPE": "2.13.3",
|
||||
"FRIBIDI": "1.0.16",
|
||||
"HARFBUZZ": "11.1.0",
|
||||
"HARFBUZZ": "11.2.1",
|
||||
"JPEGTURBO": "3.1.0",
|
||||
"LCMS2": "2.17",
|
||||
"LIBAVIF": "1.2.1",
|
||||
"LIBAVIF": "1.3.0",
|
||||
"LIBIMAGEQUANT": "4.3.4",
|
||||
"LIBPNG": "1.6.47",
|
||||
"LIBPNG": "1.6.48",
|
||||
"LIBWEBP": "1.5.0",
|
||||
"OPENJPEG": "2.5.3",
|
||||
"TIFF": "4.7.0",
|
||||
|
@ -389,6 +389,7 @@ DEPS: dict[str, dict[str, Any]] = {
|
|||
"filename": f"libavif-{V['LIBAVIF']}.zip",
|
||||
"license": "LICENSE",
|
||||
"build": [
|
||||
"rustup update",
|
||||
f"{sys.executable} -m pip install meson",
|
||||
*cmds_cmake(
|
||||
"avif_static",
|
||||
|
@ -399,7 +400,6 @@ DEPS: dict[str, dict[str, Any]] = {
|
|||
"-DAVIF_CODEC_DAV1D=LOCAL",
|
||||
"-DAVIF_CODEC_RAV1E=LOCAL",
|
||||
"-DAVIF_CODEC_SVT=LOCAL",
|
||||
"-DCMAKE_POLICY_VERSION_MINIMUM=3.5",
|
||||
),
|
||||
cmd_xcopy("include", "{inc_dir}"),
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue
Block a user