Merge branch 'python-pillow:main' into usepcf
This commit is contained in:
commit
97bdfeb4a5
@ -53,7 +53,7 @@ pushd depends && ./install_imagequant.sh && popd
|
||||
pushd depends && sudo ./install_raqm.sh && popd
|
||||
|
||||
# libavif
|
||||
pushd depends && sudo ./install_libavif.sh && popd
|
||||
pushd depends && ./install_libavif.sh && popd
|
||||
|
||||
# extra test images
|
||||
pushd depends && ./install_extra_test_images.sh && popd
|
||||
|
||||
16
.github/workflows/docs.yml
vendored
16
.github/workflows/docs.yml
vendored
@ -48,6 +48,13 @@ jobs:
|
||||
- name: Build system information
|
||||
run: python3 .github/workflows/system-info.py
|
||||
|
||||
- name: Cache libavif
|
||||
uses: actions/cache@v5
|
||||
id: cache-libavif
|
||||
with:
|
||||
path: ~/cache-libavif
|
||||
key: ${{ runner.os }}-libavif-${{ hashFiles('depends/install_libavif.sh', 'depends/libavif-svt4.patch') }}
|
||||
|
||||
- name: Cache libimagequant
|
||||
uses: actions/cache@v5
|
||||
id: cache-libimagequant
|
||||
@ -55,12 +62,21 @@ jobs:
|
||||
path: ~/cache-libimagequant
|
||||
key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }}
|
||||
|
||||
- name: Cache libwebp
|
||||
uses: actions/cache@v5
|
||||
id: cache-libwebp
|
||||
with:
|
||||
path: ~/cache-libwebp
|
||||
key: ${{ runner.os }}-libwebp-${{ hashFiles('depends/install_webp.sh') }}
|
||||
|
||||
- name: Install Linux dependencies
|
||||
run: |
|
||||
.ci/install.sh
|
||||
env:
|
||||
GHA_PYTHON_VERSION: "3.x"
|
||||
GHA_LIBAVIF_CACHE_HIT: ${{ steps.cache-libavif.outputs.cache-hit }}
|
||||
GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }}
|
||||
GHA_LIBWEBP_CACHE_HIT: ${{ steps.cache-libwebp.outputs.cache-hit }}
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
|
||||
2
.github/workflows/test-docker.yml
vendored
2
.github/workflows/test-docker.yml
vendored
@ -83,7 +83,7 @@ jobs:
|
||||
|
||||
- name: Docker pull
|
||||
run: |
|
||||
docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
|
||||
docker pull ${{ matrix.qemu-arch && format('--platform=linux/{0}', matrix.qemu-arch)}} pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
|
||||
|
||||
- name: Docker build
|
||||
run: |
|
||||
|
||||
20
.github/workflows/test.yml
vendored
20
.github/workflows/test.yml
vendored
@ -61,7 +61,7 @@ jobs:
|
||||
- { python-version: "3.14t", disable-gil: true }
|
||||
- { python-version: "3.13t", disable-gil: true }
|
||||
# Intel
|
||||
- { os: "macos-15-intel", python-version: "3.10" }
|
||||
- { os: "macos-26-intel", python-version: "3.10" }
|
||||
exclude:
|
||||
- { os: "macos-latest", python-version: "3.10" }
|
||||
|
||||
@ -91,6 +91,14 @@ jobs:
|
||||
- name: Build system information
|
||||
run: python3 .github/workflows/system-info.py
|
||||
|
||||
- name: Cache libavif
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
uses: actions/cache@v5
|
||||
id: cache-libavif
|
||||
with:
|
||||
path: ~/cache-libavif
|
||||
key: ${{ runner.os }}-libavif-${{ hashFiles('depends/install_libavif.sh', 'depends/libavif-svt4.patch') }}
|
||||
|
||||
- name: Cache libimagequant
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
uses: actions/cache@v5
|
||||
@ -99,13 +107,23 @@ jobs:
|
||||
path: ~/cache-libimagequant
|
||||
key: ${{ runner.os }}-libimagequant-${{ hashFiles('depends/install_imagequant.sh') }}
|
||||
|
||||
- name: Cache libwebp
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
uses: actions/cache@v5
|
||||
id: cache-libwebp
|
||||
with:
|
||||
path: ~/cache-libwebp
|
||||
key: ${{ runner.os }}-libwebp-${{ hashFiles('depends/install_webp.sh') }}
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
.ci/install.sh
|
||||
env:
|
||||
GHA_PYTHON_VERSION: ${{ matrix.python-version }}
|
||||
GHA_LIBAVIF_CACHE_HIT: ${{ steps.cache-libavif.outputs.cache-hit }}
|
||||
GHA_LIBIMAGEQUANT_CACHE_HIT: ${{ steps.cache-libimagequant.outputs.cache-hit }}
|
||||
GHA_LIBWEBP_CACHE_HIT: ${{ steps.cache-libwebp.outputs.cache-hit }}
|
||||
|
||||
- name: Install macOS dependencies
|
||||
if: startsWith(matrix.os, 'macOS')
|
||||
|
||||
2
.github/workflows/wheels-dependencies.sh
vendored
2
.github/workflows/wheels-dependencies.sh
vendored
@ -96,7 +96,7 @@ else
|
||||
FREETYPE_VERSION=2.14.1
|
||||
fi
|
||||
HARFBUZZ_VERSION=12.3.2
|
||||
LIBPNG_VERSION=1.6.54
|
||||
LIBPNG_VERSION=1.6.55
|
||||
JPEGTURBO_VERSION=3.1.3
|
||||
OPENJPEG_VERSION=2.5.4
|
||||
XZ_VERSION=5.8.2
|
||||
|
||||
14
.github/workflows/wheels.yml
vendored
14
.github/workflows/wheels.yml
vendored
@ -53,19 +53,19 @@ jobs:
|
||||
include:
|
||||
- name: "macOS 10.10 x86_64"
|
||||
platform: macos
|
||||
os: macos-15-intel
|
||||
os: macos-26-intel
|
||||
cibw_arch: x86_64
|
||||
build: "cp3{10,11}*"
|
||||
macosx_deployment_target: "10.10"
|
||||
- name: "macOS 10.13 x86_64"
|
||||
platform: macos
|
||||
os: macos-15-intel
|
||||
os: macos-26-intel
|
||||
cibw_arch: x86_64
|
||||
build: "cp3{12,13}*"
|
||||
macosx_deployment_target: "10.13"
|
||||
- name: "macOS 10.15 x86_64"
|
||||
platform: macos
|
||||
os: macos-15-intel
|
||||
os: macos-26-intel
|
||||
cibw_arch: x86_64
|
||||
build: "{cp314,pp3}*"
|
||||
macosx_deployment_target: "10.15"
|
||||
@ -104,7 +104,7 @@ jobs:
|
||||
cibw_arch: arm64_iphonesimulator
|
||||
- name: "iOS x86_64 simulator"
|
||||
platform: ios
|
||||
os: macos-15-intel
|
||||
os: macos-26-intel
|
||||
cibw_arch: x86_64_iphonesimulator
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
@ -250,7 +250,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Count dists
|
||||
steps:
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: dist-*
|
||||
path: dist
|
||||
@ -269,7 +269,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
name: Upload wheels to scientific-python-nightly-wheels
|
||||
steps:
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: dist-!(sdist)*
|
||||
path: dist
|
||||
@ -291,7 +291,7 @@ jobs:
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@v7
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: dist-*
|
||||
path: dist
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.14.14
|
||||
rev: v0.15.4
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: [--exit-non-zero-on-fix]
|
||||
@ -11,7 +11,7 @@ repos:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.9.3
|
||||
rev: 1.9.4
|
||||
hooks:
|
||||
- id: bandit
|
||||
args: [--severity-level=high]
|
||||
@ -24,7 +24,7 @@ repos:
|
||||
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v21.1.8
|
||||
rev: v22.1.0
|
||||
hooks:
|
||||
- id: clang-format
|
||||
types: [c]
|
||||
@ -38,6 +38,7 @@ repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: check-case-conflict
|
||||
- id: check-executables-have-shebangs
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-merge-conflict
|
||||
@ -51,7 +52,7 @@ repos:
|
||||
exclude: ^\.github/.*TEMPLATE|^Tests/(fonts|images)/
|
||||
|
||||
- repo: https://github.com/python-jsonschema/check-jsonschema
|
||||
rev: 0.36.1
|
||||
rev: 0.37.0
|
||||
hooks:
|
||||
- id: check-github-workflows
|
||||
- id: check-readthedocs
|
||||
@ -68,12 +69,12 @@ repos:
|
||||
- id: sphinx-lint
|
||||
|
||||
- repo: https://github.com/tox-dev/pyproject-fmt
|
||||
rev: v2.12.1
|
||||
rev: v2.16.2
|
||||
hooks:
|
||||
- id: pyproject-fmt
|
||||
|
||||
- repo: https://github.com/abravalheri/validate-pyproject
|
||||
rev: v0.24.1
|
||||
rev: v0.25
|
||||
hooks:
|
||||
- id: validate-pyproject
|
||||
additional_dependencies: [trove-classifiers>=2024.10.12]
|
||||
|
||||
BIN
Tests/images/pal8rletrns.png
Normal file
BIN
Tests/images/pal8rletrns.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
@ -221,6 +221,11 @@ def test_rle8_eof(file_name: str, length: int) -> None:
|
||||
im.load()
|
||||
|
||||
|
||||
def test_rle_delta() -> None:
|
||||
with Image.open("Tests/images/bmp/q/pal8rletrns.bmp") as im:
|
||||
assert_image_equal_tofile(im, "Tests/images/pal8rletrns.png")
|
||||
|
||||
|
||||
def test_unsupported_bmp_bitfields_layout() -> None:
|
||||
fp = io.BytesIO(
|
||||
o32(40) # header size
|
||||
|
||||
@ -310,6 +310,14 @@ def test_roundtrip_save_all_1(tmp_path: Path) -> None:
|
||||
assert reloaded.getpixel((0, 0)) == 255
|
||||
|
||||
|
||||
@pytest.mark.parametrize("size", ((0, 1), (1, 0), (0, 0)))
|
||||
def test_save_zero(size: tuple[int, int]) -> None:
|
||||
b = BytesIO()
|
||||
im = Image.new("RGB", size)
|
||||
with pytest.raises(SystemError):
|
||||
im.save(b, "GIF")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path, mode",
|
||||
(
|
||||
|
||||
@ -37,6 +37,14 @@ def test_sanity(tmp_path: Path) -> None:
|
||||
im.save(f)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("size", ((0, 1), (1, 0), (0, 0)))
|
||||
def test_save_zero(size: tuple[int, int]) -> None:
|
||||
b = io.BytesIO()
|
||||
im = Image.new("1", size)
|
||||
with pytest.raises(ValueError):
|
||||
im.save(b, "PCX")
|
||||
|
||||
|
||||
def test_p_4_planes() -> None:
|
||||
with Image.open("Tests/images/p_4_planes.pcx") as im:
|
||||
assert im.getpixel((0, 0)) == 3
|
||||
|
||||
@ -68,6 +68,14 @@ def test_save(tmp_path: Path) -> None:
|
||||
assert im2.format == "SPIDER"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("size", ((0, 1), (1, 0), (0, 0)))
|
||||
def test_save_zero(size: tuple[int, int]) -> None:
|
||||
b = BytesIO()
|
||||
im = Image.new("1", size)
|
||||
with pytest.raises(SystemError):
|
||||
im.save(b, "SPIDER")
|
||||
|
||||
|
||||
def test_tempfile() -> None:
|
||||
# Arrange
|
||||
im = hopper()
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from io import BytesIO
|
||||
import io
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
@ -23,6 +23,13 @@ def test_reload() -> None:
|
||||
assert_image_equal(im.convert("RGB"), original.convert("RGB"))
|
||||
|
||||
|
||||
def test_save_fp() -> None:
|
||||
palette = ImagePalette.ImagePalette()
|
||||
with io.StringIO() as fp:
|
||||
palette.save(fp)
|
||||
assert not fp.closed
|
||||
|
||||
|
||||
def test_getcolor() -> None:
|
||||
palette = ImagePalette.ImagePalette()
|
||||
assert len(palette.palette) == 0
|
||||
@ -204,7 +211,7 @@ def test_2bit_palette(tmp_path: Path) -> None:
|
||||
|
||||
|
||||
def test_getpalette() -> None:
|
||||
b = BytesIO(b"0 1\n1 2 3 4")
|
||||
b = io.BytesIO(b"0 1\n1 2 3 4")
|
||||
p = PaletteFile.PaletteFile(b)
|
||||
|
||||
palette, rawmode = p.getpalette()
|
||||
@ -216,6 +223,6 @@ def test_invalid_palette() -> None:
|
||||
with pytest.raises(OSError):
|
||||
ImagePalette.load("Tests/images/hopper.jpg")
|
||||
|
||||
b = BytesIO(b"1" * 101)
|
||||
b = io.BytesIO(b"1" * 101)
|
||||
with pytest.raises(SyntaxError, match="bad palette file"):
|
||||
PaletteFile.PaletteFile(b)
|
||||
|
||||
@ -3,66 +3,88 @@ set -eo pipefail
|
||||
|
||||
version=1.3.0
|
||||
|
||||
./download-and-extract.sh libavif-$version https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$version.tar.gz
|
||||
if [[ "$GHA_LIBAVIF_CACHE_HIT" == "true" ]]; then
|
||||
|
||||
pushd libavif-$version
|
||||
LIBDIR=/usr/lib/x86_64-linux-gnu
|
||||
|
||||
# Apply patch for SVT-AV1 4.0 compatibility
|
||||
# Pending release of https://github.com/AOMediaCodec/libavif/pull/2971
|
||||
patch -p1 < ../libavif-svt4.patch
|
||||
# Copy cached files into place
|
||||
sudo cp ~/cache-libavif/lib/* $LIBDIR/
|
||||
sudo cp -r ~/cache-libavif/include/avif /usr/include/
|
||||
|
||||
if [ $(uname) == "Darwin" ] && [ -x "$(command -v brew)" ]; then
|
||||
PREFIX=$(brew --prefix)
|
||||
else
|
||||
PREFIX=/usr
|
||||
|
||||
./download-and-extract.sh libavif-$version https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$version.tar.gz
|
||||
|
||||
pushd libavif-$version
|
||||
|
||||
# Apply patch for SVT-AV1 4.0 compatibility
|
||||
# Pending release of https://github.com/AOMediaCodec/libavif/pull/2971
|
||||
patch -p1 < ../libavif-svt4.patch
|
||||
|
||||
if [ $(uname) == "Darwin" ] && [ -x "$(command -v brew)" ]; then
|
||||
PREFIX=$(brew --prefix)
|
||||
else
|
||||
PREFIX=/usr
|
||||
fi
|
||||
|
||||
PKGCONFIG=${PKGCONFIG:-pkg-config}
|
||||
|
||||
LIBAVIF_CMAKE_FLAGS=()
|
||||
HAS_DECODER=0
|
||||
HAS_ENCODER=0
|
||||
|
||||
if $PKGCONFIG --exists aom; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=SYSTEM)
|
||||
HAS_ENCODER=1
|
||||
HAS_DECODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists dav1d; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_DAV1D=SYSTEM)
|
||||
HAS_DECODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists libgav1; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_LIBGAV1=SYSTEM)
|
||||
HAS_DECODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists rav1e; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_RAV1E=SYSTEM)
|
||||
HAS_ENCODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists SvtAv1Enc; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_SVT=SYSTEM)
|
||||
HAS_ENCODER=1
|
||||
fi
|
||||
|
||||
if [ "$HAS_ENCODER" != 1 ] || [ "$HAS_DECODER" != 1 ]; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=LOCAL)
|
||||
fi
|
||||
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-DCMAKE_INSTALL_NAME_DIR=$PREFIX/lib \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_MACOSX_RPATH=OFF \
|
||||
-DAVIF_LIBSHARPYUV=LOCAL \
|
||||
-DAVIF_LIBYUV=LOCAL \
|
||||
"${LIBAVIF_CMAKE_FLAGS[@]}" \
|
||||
.
|
||||
|
||||
sudo make install
|
||||
|
||||
if [ -n "$GITHUB_ACTIONS" ] && [ "$(uname)" != "Darwin" ]; then
|
||||
# Copy to cache
|
||||
LIBDIR=/usr/lib/x86_64-linux-gnu
|
||||
rm -rf ~/cache-libavif
|
||||
mkdir -p ~/cache-libavif/lib
|
||||
mkdir -p ~/cache-libavif/include
|
||||
cp $LIBDIR/libavif.so* ~/cache-libavif/lib/
|
||||
cp -r /usr/include/avif ~/cache-libavif/include/
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
fi
|
||||
|
||||
PKGCONFIG=${PKGCONFIG:-pkg-config}
|
||||
|
||||
LIBAVIF_CMAKE_FLAGS=()
|
||||
HAS_DECODER=0
|
||||
HAS_ENCODER=0
|
||||
|
||||
if $PKGCONFIG --exists aom; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=SYSTEM)
|
||||
HAS_ENCODER=1
|
||||
HAS_DECODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists dav1d; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_DAV1D=SYSTEM)
|
||||
HAS_DECODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists libgav1; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_LIBGAV1=SYSTEM)
|
||||
HAS_DECODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists rav1e; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_RAV1E=SYSTEM)
|
||||
HAS_ENCODER=1
|
||||
fi
|
||||
|
||||
if $PKGCONFIG --exists SvtAv1Enc; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_SVT=SYSTEM)
|
||||
HAS_ENCODER=1
|
||||
fi
|
||||
|
||||
if [ "$HAS_ENCODER" != 1 ] || [ "$HAS_DECODER" != 1 ]; then
|
||||
LIBAVIF_CMAKE_FLAGS+=(-DAVIF_CODEC_AOM=LOCAL)
|
||||
fi
|
||||
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=$PREFIX \
|
||||
-DCMAKE_INSTALL_NAME_DIR=$PREFIX/lib \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_MACOSX_RPATH=OFF \
|
||||
-DAVIF_LIBSHARPYUV=LOCAL \
|
||||
-DAVIF_LIBYUV=LOCAL \
|
||||
"${LIBAVIF_CMAKE_FLAGS[@]}" \
|
||||
.
|
||||
|
||||
make install
|
||||
|
||||
popd
|
||||
|
||||
@ -3,10 +3,30 @@
|
||||
|
||||
archive=libwebp-1.6.0
|
||||
|
||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||
if [[ "$GHA_LIBWEBP_CACHE_HIT" == "true" ]]; then
|
||||
|
||||
pushd $archive
|
||||
# Copy cached files into place
|
||||
sudo cp ~/cache-libwebp/lib/* /usr/lib/
|
||||
sudo cp -r ~/cache-libwebp/include/webp /usr/include/
|
||||
|
||||
./configure --prefix=/usr --enable-libwebpmux --enable-libwebpdemux && make -j4 && sudo make -j4 install
|
||||
else
|
||||
|
||||
popd
|
||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
|
||||
|
||||
pushd $archive
|
||||
|
||||
./configure --prefix=/usr --enable-libwebpmux --enable-libwebpdemux && make -j4 && sudo make -j4 install
|
||||
|
||||
if [ -n "$GITHUB_ACTIONS" ]; then
|
||||
# Copy to cache
|
||||
rm -rf ~/cache-libwebp
|
||||
mkdir -p ~/cache-libwebp/lib
|
||||
mkdir -p ~/cache-libwebp/include
|
||||
cp /usr/lib/libwebp*.so* /usr/lib/libwebp*.a ~/cache-libwebp/lib/
|
||||
cp /usr/lib/libsharpyuv.so* /usr/lib/libsharpyuv.a ~/cache-libwebp/lib/
|
||||
cp -r /usr/include/webp ~/cache-libwebp/include/
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
fi
|
||||
|
||||
@ -828,16 +828,6 @@ PCX
|
||||
|
||||
Pillow reads and writes PCX files containing ``1``, ``L``, ``P``, or ``RGB`` data.
|
||||
|
||||
PFM
|
||||
^^^
|
||||
|
||||
.. versionadded:: 10.3.0
|
||||
|
||||
Pillow reads and writes grayscale (Pf format) Portable FloatMap (PFM) files
|
||||
containing ``F`` data.
|
||||
|
||||
Color (PF format) PFM files are not supported.
|
||||
|
||||
Opening
|
||||
~~~~~~~
|
||||
|
||||
@ -1081,12 +1071,19 @@ following parameters can also be set:
|
||||
PPM
|
||||
^^^
|
||||
|
||||
Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L``, ``I`` or
|
||||
``RGB`` data.
|
||||
Pillow reads and writes PBM, PGM, PPM, PNM and PFM files containing ``1``, ``L``, ``I``,
|
||||
``RGB`` or ``F`` data.
|
||||
|
||||
"Raw" (P4 to P6) formats can be read, and are used when writing.
|
||||
|
||||
Since Pillow 9.2.0, "plain" (P1 to P3) formats can be read as well.
|
||||
.. versionadded:: 9.2.0
|
||||
"Plain" (P1 to P3) formats can be read.
|
||||
|
||||
.. versionadded:: 10.3.0
|
||||
Grayscale (Pf format) Portable FloatMap (PFM) files containing
|
||||
``F`` data can be read and used when writing.
|
||||
|
||||
Color (PF format) PFM files are not supported.
|
||||
|
||||
QOI
|
||||
^^^
|
||||
|
||||
@ -39,15 +39,15 @@ These platforms are built and tested for every change.
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Gentoo | 3.12 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| macOS 15 Sequoia | 3.10 | x86-64 |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.11, 3.12, 3.13, 3.14, | arm64 |
|
||||
| | PyPy3 | |
|
||||
| macOS 15 Sequoia | 3.11, 3.12, 3.13, 3.14, | arm64 |
|
||||
| | 3.15, PyPy3 | |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| macOS 26 Tahoe | 3.10 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 22.04 LTS (Jammy) | 3.10 | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Ubuntu Linux 24.04 LTS (Noble) | 3.10, 3.11, 3.12, 3.13, | x86-64 |
|
||||
| | 3.14, PyPy3 | |
|
||||
| | 3.14, 3.15, PyPy3 | |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.12 | arm64v8, ppc64le, |
|
||||
| | | s390x |
|
||||
@ -55,7 +55,7 @@ These platforms are built and tested for every change.
|
||||
| Windows Server 2022 | 3.10 | x86 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
| Windows Server 2025 | 3.11, 3.12, 3.13, 3.14, | x86-64 |
|
||||
| | PyPy3 | |
|
||||
| | 3.15, PyPy3 | |
|
||||
| +----------------------------+---------------------+
|
||||
| | 3.13 (MinGW) | x86-64 |
|
||||
+----------------------------------+----------------------------+---------------------+
|
||||
|
||||
@ -62,7 +62,6 @@ optional-dependencies.test-arrow = [
|
||||
"nanoarrow",
|
||||
"pyarrow",
|
||||
]
|
||||
|
||||
optional-dependencies.tests = [
|
||||
"check-manifest",
|
||||
"coverage>=7.4.2",
|
||||
@ -77,16 +76,15 @@ optional-dependencies.tests = [
|
||||
"pytest-xdist",
|
||||
"trove-classifiers>=2024.10.12",
|
||||
]
|
||||
|
||||
optional-dependencies.xmp = [
|
||||
"defusedxml",
|
||||
]
|
||||
urls."Release notes" = "https://pillow.readthedocs.io/en/stable/releasenotes/index.html"
|
||||
urls.Changelog = "https://github.com/python-pillow/Pillow/releases"
|
||||
urls.Documentation = "https://pillow.readthedocs.io"
|
||||
urls.Funding = "https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=pypi"
|
||||
urls.Homepage = "https://python-pillow.github.io"
|
||||
urls.Mastodon = "https://fosstodon.org/@pillow"
|
||||
urls."Release notes" = "https://pillow.readthedocs.io/en/stable/releasenotes/index.html"
|
||||
urls.Source = "https://github.com/python-pillow/Pillow"
|
||||
|
||||
[tool.setuptools]
|
||||
@ -95,70 +93,50 @@ packages = [
|
||||
]
|
||||
include-package-data = true
|
||||
package-dir = { "" = "src" }
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
version = { attr = "PIL.__version__" }
|
||||
dynamic.version = { attr = "PIL.__version__" }
|
||||
|
||||
[tool.cibuildwheel]
|
||||
before-all = ".github/workflows/wheels-dependencies.sh"
|
||||
build-verbosity = 1
|
||||
|
||||
config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable"
|
||||
|
||||
test-command = "cd {project} && .github/workflows/wheels-test.sh"
|
||||
test-extras = "tests"
|
||||
test-requires = [
|
||||
"numpy",
|
||||
]
|
||||
xbuild-tools = [ ]
|
||||
|
||||
[tool.cibuildwheel.ios]
|
||||
xbuild-tools = []
|
||||
# Disable platform guessing on iOS, and disable raqm (since there won't be a
|
||||
# vendor version, and we can't distribute it due to licensing)
|
||||
config-settings = "raqm=disable imagequant=disable platform-guessing=disable"
|
||||
|
||||
ios.config-settings = "raqm=disable imagequant=disable platform-guessing=disable"
|
||||
# iOS needs to be given a specific pytest invocation and list of test sources.
|
||||
test-sources = [
|
||||
ios.test-sources = [
|
||||
"checks",
|
||||
"Tests",
|
||||
"selftest.py",
|
||||
]
|
||||
test-command = [
|
||||
ios.test-command = [
|
||||
"python -m selftest",
|
||||
"python -m pytest -vv -x -W always checks/check_wheel.py Tests",
|
||||
]
|
||||
|
||||
# There's no numpy wheel for iOS (yet...)
|
||||
test-requires = [ ]
|
||||
|
||||
[tool.cibuildwheel.macos]
|
||||
ios.test-requires = []
|
||||
# Disable platform guessing on macOS to avoid picking up Homebrew etc.
|
||||
config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable platform-guessing=disable"
|
||||
|
||||
[tool.cibuildwheel.macos.environment]
|
||||
macos.config-settings = "raqm=enable raqm=vendor fribidi=vendor imagequant=disable platform-guessing=disable"
|
||||
# Isolate macOS build environment from Homebrew etc.
|
||||
PATH = "$(pwd)/build/deps/darwin/bin:$(dirname $(which python3)):/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
|
||||
|
||||
[[tool.cibuildwheel.overrides]]
|
||||
# iOS environment is isolated by cibuildwheel, but needs the dependencies
|
||||
select = "*_iphoneos"
|
||||
environment.PATH = "$(pwd)/build/deps/iphoneos/bin:$PATH"
|
||||
|
||||
[[tool.cibuildwheel.overrides]]
|
||||
# iOS simulator environment is isolated by cibuildwheel, but needs the dependencies
|
||||
select = "*_iphonesimulator"
|
||||
environment.PATH = "$(pwd)/build/deps/iphonesimulator/bin:$PATH"
|
||||
|
||||
[[tool.cibuildwheel.overrides]]
|
||||
select = "*-win32"
|
||||
test-requires = [ ]
|
||||
macos.environment.PATH = "$(pwd)/build/deps/darwin/bin:$(dirname $(which python3)):/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
|
||||
overrides = [
|
||||
# iOS environment is isolated by cibuildwheel, but needs the dependencies
|
||||
{ select = "*_iphoneos", environment.PATH = "$(pwd)/build/deps/iphoneos/bin:$PATH" },
|
||||
# iOS simulator environment is isolated by cibuildwheel, but needs the dependencies
|
||||
{ select = "*_iphonesimulator", environment.PATH = "$(pwd)/build/deps/iphonesimulator/bin:$PATH" },
|
||||
{ select = "*-win32", test-requires = [] },
|
||||
]
|
||||
|
||||
[tool.black]
|
||||
exclude = "wheels/multibuild"
|
||||
|
||||
[tool.ruff]
|
||||
exclude = [ "wheels/multibuild" ]
|
||||
|
||||
fix = true
|
||||
lint.select = [
|
||||
"C4", # flake8-comprehensions
|
||||
@ -207,8 +185,8 @@ lint.isort.required-imports = [
|
||||
[tool.pyproject-fmt]
|
||||
max_supported_python = "3.14"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = "-ra --color=auto"
|
||||
[tool.pytest]
|
||||
addopts = [ "-ra", "--color=auto" ]
|
||||
testpaths = [
|
||||
"Tests",
|
||||
]
|
||||
|
||||
@ -369,7 +369,7 @@ class BmpRleDecoder(ImageFile.PyDecoder):
|
||||
bytes_read = self.fd.read(2)
|
||||
if len(bytes_read) < 2:
|
||||
break
|
||||
right, up = self.fd.read(2)
|
||||
right, up = bytes_read
|
||||
data += b"\x00" * (right + up * self.state.xsize)
|
||||
x = len(data) % self.state.xsize
|
||||
else:
|
||||
|
||||
@ -937,7 +937,13 @@ def _get_optimize(im: Image.Image, info: dict[str, Any]) -> list[int] | None:
|
||||
:param info: encoderinfo
|
||||
:returns: list of indexes of palette entries in use, or None
|
||||
"""
|
||||
if im.mode in ("P", "L") and info and info.get("optimize"):
|
||||
if (
|
||||
im.mode in ("P", "L")
|
||||
and info
|
||||
and info.get("optimize")
|
||||
and im.width != 0
|
||||
and im.height != 0
|
||||
):
|
||||
# Potentially expensive operation.
|
||||
|
||||
# The palette saves 3 bytes per color not used, but palette
|
||||
|
||||
@ -579,10 +579,7 @@ class Parser:
|
||||
pass # not enough data
|
||||
else:
|
||||
flag = hasattr(im, "load_seek") or hasattr(im, "load_read")
|
||||
if flag or len(im.tile) != 1:
|
||||
# custom load code, or multiple tiles
|
||||
self.decode = None
|
||||
else:
|
||||
if not flag and len(im.tile) == 1:
|
||||
# initialize decoder
|
||||
im.load_prepare()
|
||||
d, e, o, a = im.tile[0]
|
||||
|
||||
@ -191,19 +191,24 @@ class ImagePalette:
|
||||
if self.rawmode:
|
||||
msg = "palette contains raw palette data"
|
||||
raise ValueError(msg)
|
||||
open_fp = False
|
||||
if isinstance(fp, str):
|
||||
fp = open(fp, "w")
|
||||
fp.write("# Palette\n")
|
||||
fp.write(f"# Mode: {self.mode}\n")
|
||||
for i in range(256):
|
||||
fp.write(f"{i}")
|
||||
for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
|
||||
try:
|
||||
fp.write(f" {self.palette[j]}")
|
||||
except IndexError:
|
||||
fp.write(" 0")
|
||||
fp.write("\n")
|
||||
fp.close()
|
||||
open_fp = True
|
||||
try:
|
||||
fp.write("# Palette\n")
|
||||
fp.write(f"# Mode: {self.mode}\n")
|
||||
for i in range(256):
|
||||
fp.write(f"{i}")
|
||||
for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
|
||||
try:
|
||||
fp.write(f" {self.palette[j]}")
|
||||
except IndexError:
|
||||
fp.write(" 0")
|
||||
fp.write("\n")
|
||||
finally:
|
||||
if open_fp:
|
||||
fp.close()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
||||
@ -59,11 +59,10 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
+ b"MPF\0"
|
||||
+ b" " * ifd_length
|
||||
)
|
||||
exif = im_frame.encoderinfo.get("exif")
|
||||
if isinstance(exif, Image.Exif):
|
||||
exif = exif.tobytes()
|
||||
im_frame.encoderinfo["exif"] = exif
|
||||
if exif:
|
||||
if exif := im_frame.encoderinfo.get("exif"):
|
||||
if isinstance(exif, Image.Exif):
|
||||
exif = exif.tobytes()
|
||||
im_frame.encoderinfo["exif"] = exif
|
||||
mpf_offset += 4 + len(exif)
|
||||
|
||||
JpegImagePlugin._save(im_frame, fp, filename)
|
||||
|
||||
@ -146,6 +146,10 @@ SAVE = {
|
||||
|
||||
|
||||
def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None:
|
||||
if im.width == 0 or im.height == 0:
|
||||
msg = "Cannot write empty image as PCX"
|
||||
raise ValueError(msg)
|
||||
|
||||
try:
|
||||
version, bits, planes, rawmode = SAVE[im.mode]
|
||||
except KeyError as e:
|
||||
|
||||
@ -1403,8 +1403,7 @@ def _save(
|
||||
|
||||
chunks = [b"cHRM", b"cICP", b"gAMA", b"sBIT", b"sRGB", b"tIME"]
|
||||
|
||||
icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile"))
|
||||
if icc:
|
||||
if icc := im.encoderinfo.get("icc_profile", im.info.get("icc_profile")):
|
||||
# ICC profile
|
||||
# according to PNG spec, the iCCP chunk contains:
|
||||
# Profile name 1-79 bytes (character string)
|
||||
@ -1419,8 +1418,7 @@ def _save(
|
||||
# Disallow sRGB chunks when an iCCP-chunk has been emitted.
|
||||
chunks.remove(b"sRGB")
|
||||
|
||||
info = im.encoderinfo.get("pnginfo")
|
||||
if info:
|
||||
if info := im.encoderinfo.get("pnginfo"):
|
||||
chunks_multiple_allowed = [b"sPLT", b"iTXt", b"tEXt", b"zTXt"]
|
||||
for info_chunk in info.chunks:
|
||||
cid, data = info_chunk[:2]
|
||||
@ -1472,8 +1470,7 @@ def _save(
|
||||
alpha_bytes = colors
|
||||
chunk(fp, b"tRNS", alpha[:alpha_bytes])
|
||||
|
||||
dpi = im.encoderinfo.get("dpi")
|
||||
if dpi:
|
||||
if dpi := im.encoderinfo.get("dpi"):
|
||||
chunk(
|
||||
fp,
|
||||
b"pHYs",
|
||||
@ -1490,8 +1487,7 @@ def _save(
|
||||
chunks.remove(cid)
|
||||
chunk(fp, cid, data)
|
||||
|
||||
exif = im.encoderinfo.get("exif")
|
||||
if exif:
|
||||
if exif := im.encoderinfo.get("exif"):
|
||||
if isinstance(exif, Image.Exif):
|
||||
exif = exif.tobytes(8)
|
||||
if exif.startswith(b"Exif\x00\x00"):
|
||||
|
||||
@ -244,7 +244,7 @@ def loadImageSeries(filelist: list[str] | None = None) -> list[Image.Image] | No
|
||||
|
||||
def makeSpiderHeader(im: Image.Image) -> list[bytes]:
|
||||
nsam, nrow = im.size
|
||||
lenbyt = nsam * 4 # There are labrec records in the header
|
||||
lenbyt = max(1, nsam) * 4 # There are labrec records in the header
|
||||
labrec = int(1024 / lenbyt)
|
||||
if 1024 % lenbyt != 0:
|
||||
labrec += 1
|
||||
|
||||
@ -124,8 +124,10 @@ PyImagingPhotoPut(
|
||||
if (im->mode == IMAGING_MODE_1 || im->mode == IMAGING_MODE_L) {
|
||||
block.pixelSize = 1;
|
||||
block.offset[0] = block.offset[1] = block.offset[2] = block.offset[3] = 0;
|
||||
} else if (im->mode == IMAGING_MODE_RGB || im->mode == IMAGING_MODE_RGBA ||
|
||||
im->mode == IMAGING_MODE_RGBX || im->mode == IMAGING_MODE_RGBa) {
|
||||
} else if (
|
||||
im->mode == IMAGING_MODE_RGB || im->mode == IMAGING_MODE_RGBA ||
|
||||
im->mode == IMAGING_MODE_RGBX || im->mode == IMAGING_MODE_RGBa
|
||||
) {
|
||||
block.pixelSize = 4;
|
||||
block.offset[0] = 0;
|
||||
block.offset[1] = 1;
|
||||
|
||||
@ -485,7 +485,7 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
|
||||
frame = image;
|
||||
} else {
|
||||
frame = avifImageCreateEmpty();
|
||||
if (image == NULL) {
|
||||
if (frame == NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Image creation failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -999,8 +999,9 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
|
||||
status = ImagingLibTiffSetField(
|
||||
&encoder->state, (ttag_t)key_int, PyBytes_AsString(value)
|
||||
);
|
||||
} else if (type == TIFF_DOUBLE || type == TIFF_SRATIONAL ||
|
||||
type == TIFF_RATIONAL) {
|
||||
} else if (
|
||||
type == TIFF_DOUBLE || type == TIFF_SRATIONAL || type == TIFF_RATIONAL
|
||||
) {
|
||||
status = ImagingLibTiffSetField(
|
||||
&encoder->state, (ttag_t)key_int, (FLOAT64)PyFloat_AsDouble(value)
|
||||
);
|
||||
|
||||
@ -170,16 +170,17 @@ export_named_type(struct ArrowSchema *schema, char *format, const char *name) {
|
||||
strncpy(formatp, format, format_len);
|
||||
strncpy(namep, name, name_len);
|
||||
|
||||
*schema = (struct ArrowSchema){// Type description
|
||||
.format = formatp,
|
||||
.name = namep,
|
||||
.metadata = NULL,
|
||||
.flags = 0,
|
||||
.n_children = 0,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &ReleaseExportedSchema
|
||||
*schema = (struct ArrowSchema){
|
||||
// Type description
|
||||
.format = formatp,
|
||||
.name = namep,
|
||||
.metadata = NULL,
|
||||
.flags = 0,
|
||||
.n_children = 0,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &ReleaseExportedSchema
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
@ -287,17 +288,18 @@ export_single_channel_array(Imaging im, struct ArrowArray *array) {
|
||||
im->refcount++;
|
||||
MUTEX_UNLOCK(&im->mutex);
|
||||
// Initialize primitive fields
|
||||
*array = (struct ArrowArray){// Data description
|
||||
.length = length,
|
||||
.offset = 0,
|
||||
.null_count = 0,
|
||||
.n_buffers = 2,
|
||||
.n_children = 0,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &release_const_array,
|
||||
.private_data = im
|
||||
*array = (struct ArrowArray){
|
||||
// Data description
|
||||
.length = length,
|
||||
.offset = 0,
|
||||
.null_count = 0,
|
||||
.n_buffers = 2,
|
||||
.n_children = 0,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &release_const_array,
|
||||
.private_data = im
|
||||
};
|
||||
|
||||
// Allocate list of buffers
|
||||
@ -332,17 +334,18 @@ export_fixed_pixel_array(Imaging im, struct ArrowArray *array) {
|
||||
// Initialize primitive fields
|
||||
// Fixed length arrays are 1 buffer of validity, and the length in pixels.
|
||||
// Data is in a child array.
|
||||
*array = (struct ArrowArray){// Data description
|
||||
.length = length,
|
||||
.offset = 0,
|
||||
.null_count = 0,
|
||||
.n_buffers = 1,
|
||||
.n_children = 1,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &release_const_array,
|
||||
.private_data = im
|
||||
*array = (struct ArrowArray){
|
||||
// Data description
|
||||
.length = length,
|
||||
.offset = 0,
|
||||
.null_count = 0,
|
||||
.n_buffers = 1,
|
||||
.n_children = 1,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &release_const_array,
|
||||
.private_data = im
|
||||
};
|
||||
|
||||
// Allocate list of buffers
|
||||
@ -367,17 +370,18 @@ export_fixed_pixel_array(Imaging im, struct ArrowArray *array) {
|
||||
MUTEX_LOCK(&im->mutex);
|
||||
im->refcount++;
|
||||
MUTEX_UNLOCK(&im->mutex);
|
||||
*array->children[0] = (struct ArrowArray){// Data description
|
||||
.length = length * 4,
|
||||
.offset = 0,
|
||||
.null_count = 0,
|
||||
.n_buffers = 2,
|
||||
.n_children = 0,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &release_const_array,
|
||||
.private_data = im
|
||||
*array->children[0] = (struct ArrowArray){
|
||||
// Data description
|
||||
.length = length * 4,
|
||||
.offset = 0,
|
||||
.null_count = 0,
|
||||
.n_buffers = 2,
|
||||
.n_children = 0,
|
||||
.children = NULL,
|
||||
.dictionary = NULL,
|
||||
// Bookkeeping
|
||||
.release = &release_const_array,
|
||||
.private_data = im
|
||||
};
|
||||
|
||||
array->children[0]->buffers =
|
||||
|
||||
@ -1695,16 +1695,20 @@ ImagingConvertTransparent(Imaging imIn, const ModeID mode, int r, int g, int b)
|
||||
if (mode == IMAGING_MODE_RGBa) {
|
||||
premultiplied = 1;
|
||||
}
|
||||
} else if (imIn->mode == IMAGING_MODE_RGB &&
|
||||
(mode == IMAGING_MODE_LA || mode == IMAGING_MODE_La)) {
|
||||
} else if (
|
||||
imIn->mode == IMAGING_MODE_RGB &&
|
||||
(mode == IMAGING_MODE_LA || mode == IMAGING_MODE_La)
|
||||
) {
|
||||
convert = rgb2la;
|
||||
source_transparency = 1;
|
||||
if (mode == IMAGING_MODE_La) {
|
||||
premultiplied = 1;
|
||||
}
|
||||
} else if ((imIn->mode == IMAGING_MODE_1 || imIn->mode == IMAGING_MODE_I ||
|
||||
imIn->mode == IMAGING_MODE_I_16 || imIn->mode == IMAGING_MODE_L) &&
|
||||
(mode == IMAGING_MODE_RGBA || mode == IMAGING_MODE_LA)) {
|
||||
} else if (
|
||||
(imIn->mode == IMAGING_MODE_1 || imIn->mode == IMAGING_MODE_I ||
|
||||
imIn->mode == IMAGING_MODE_I_16 || imIn->mode == IMAGING_MODE_L) &&
|
||||
(mode == IMAGING_MODE_RGBA || mode == IMAGING_MODE_LA)
|
||||
) {
|
||||
if (imIn->mode == IMAGING_MODE_1) {
|
||||
convert = bit2rgb;
|
||||
} else if (imIn->mode == IMAGING_MODE_I) {
|
||||
|
||||
@ -537,8 +537,9 @@ polygon_generic(
|
||||
// Needed to draw consistent polygons
|
||||
xx[j] = xx[j - 1];
|
||||
j++;
|
||||
} else if ((ymin == current->ymin || ymin == current->ymax) &&
|
||||
current->dx != 0) {
|
||||
} else if (
|
||||
(ymin == current->ymin || ymin == current->ymax) && current->dx != 0
|
||||
) {
|
||||
// Connect discontiguous corners
|
||||
for (k = 0; k < i; k++) {
|
||||
Edge *other_edge = edge_table[k];
|
||||
@ -570,8 +571,10 @@ polygon_generic(
|
||||
adjacent_line_x, adjacent_line_x_other_edge
|
||||
)) +
|
||||
1;
|
||||
} else if (xx[j - 1] < adjacent_line_x - 1 &&
|
||||
xx[j - 1] < adjacent_line_x_other_edge - 1) {
|
||||
} else if (
|
||||
xx[j - 1] < adjacent_line_x - 1 &&
|
||||
xx[j - 1] < adjacent_line_x_other_edge - 1
|
||||
) {
|
||||
xx[j - 1] =
|
||||
roundf(fmin(
|
||||
adjacent_line_x, adjacent_line_x_other_edge
|
||||
|
||||
@ -89,10 +89,12 @@ ImagingGetBBox(Imaging im, int bbox[4], int alpha_only) {
|
||||
INT32 mask = 0xffffffff;
|
||||
if (im->bands == 3) {
|
||||
((UINT8 *)&mask)[3] = 0;
|
||||
} else if (alpha_only &&
|
||||
(im->mode == IMAGING_MODE_RGBa || im->mode == IMAGING_MODE_RGBA ||
|
||||
im->mode == IMAGING_MODE_La || im->mode == IMAGING_MODE_LA ||
|
||||
im->mode == IMAGING_MODE_PA)) {
|
||||
} else if (
|
||||
alpha_only &&
|
||||
(im->mode == IMAGING_MODE_RGBa || im->mode == IMAGING_MODE_RGBA ||
|
||||
im->mode == IMAGING_MODE_La || im->mode == IMAGING_MODE_LA ||
|
||||
im->mode == IMAGING_MODE_PA)
|
||||
) {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
mask = 0x000000ff;
|
||||
#else
|
||||
|
||||
@ -330,8 +330,10 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) {
|
||||
components = 4;
|
||||
color_space = OPJ_CLRSPC_SRGB;
|
||||
pack = j2k_pack_rgba;
|
||||
#if ((OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR == 5 && OPJ_VERSION_BUILD >= 3) || \
|
||||
(OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR > 5) || OPJ_VERSION_MAJOR > 2)
|
||||
#if ( \
|
||||
(OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR == 5 && OPJ_VERSION_BUILD >= 3) || \
|
||||
(OPJ_VERSION_MAJOR == 2 && OPJ_VERSION_MINOR > 5) || OPJ_VERSION_MAJOR > 2 \
|
||||
)
|
||||
} else if (im->mode == IMAGING_MODE_CMYK) {
|
||||
components = 4;
|
||||
color_space = OPJ_CLRSPC_CMYK;
|
||||
|
||||
@ -206,8 +206,10 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t by
|
||||
context->cinfo.out_color_space = JCS_EXT_RGBX;
|
||||
}
|
||||
#endif
|
||||
else if (context->rawmode == IMAGING_RAWMODE_CMYK ||
|
||||
context->rawmode == IMAGING_RAWMODE_CMYK_I) {
|
||||
else if (
|
||||
context->rawmode == IMAGING_RAWMODE_CMYK ||
|
||||
context->rawmode == IMAGING_RAWMODE_CMYK_I
|
||||
) {
|
||||
context->cinfo.out_color_space = JCS_CMYK;
|
||||
} else if (context->rawmode == IMAGING_RAWMODE_YCbCr) {
|
||||
context->cinfo.out_color_space = JCS_YCbCr;
|
||||
|
||||
@ -46,8 +46,9 @@ ImagingConvertMatrix(Imaging im, const ModeID mode, float m[]) {
|
||||
}
|
||||
}
|
||||
ImagingSectionLeave(&cookie);
|
||||
} else if (mode == IMAGING_MODE_HSV || mode == IMAGING_MODE_LAB ||
|
||||
mode == IMAGING_MODE_RGB) {
|
||||
} else if (
|
||||
mode == IMAGING_MODE_HSV || mode == IMAGING_MODE_LAB || mode == IMAGING_MODE_RGB
|
||||
) {
|
||||
imOut = ImagingNewDirty(mode, im->xsize, im->ysize);
|
||||
if (!imOut) {
|
||||
return NULL;
|
||||
|
||||
@ -121,7 +121,7 @@ V = {
|
||||
"LCMS2": "2.18",
|
||||
"LIBAVIF": "1.3.0",
|
||||
"LIBIMAGEQUANT": "4.4.1",
|
||||
"LIBPNG": "1.6.54",
|
||||
"LIBPNG": "1.6.55",
|
||||
"LIBWEBP": "1.6.0",
|
||||
"OPENJPEG": "2.5.4",
|
||||
"TIFF": "4.7.1",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user