Merge branch 'main' into vtf-support

This commit is contained in:
Andrew Murray 2023-12-24 19:45:02 +11:00 committed by GitHub
commit a2729c0db0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
558 changed files with 12217 additions and 6238 deletions

View File

@ -10,48 +10,48 @@ environment:
TEST_OPTIONS: TEST_OPTIONS:
DEPLOY: YES DEPLOY: YES
matrix: matrix:
- PYTHON: C:/Python311 - PYTHON: C:/Python312
ARCHITECTURE: x86 ARCHITECTURE: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
- PYTHON: C:/Python37-x64 - PYTHON: C:/Python38-x64
ARCHITECTURE: x64 ARCHITECTURE: x64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
install: install:
- '%PYTHON%\%EXECUTABLE% --version' - '%PYTHON%\%EXECUTABLE% --version'
- curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/main.zip - '%PYTHON%\%EXECUTABLE% -m pip install --upgrade pip'
- 7z x pillow-depends.zip -oc:\ - curl -fsSL -o pillow-test-images.zip https://github.com/python-pillow/test-images/archive/main.zip
- mv c:\pillow-depends-main c:\pillow-depends - 7z x pillow-test-images.zip -oc:\
- xcopy /S /Y c:\pillow-depends\test_images\* c:\pillow\tests\images - xcopy /S /Y c:\test-images-main\* c:\pillow\tests\images
- 7z x ..\pillow-depends\nasm-2.15.05-win64.zip -oc:\ - curl -fsSL -o nasm-win64.zip https://raw.githubusercontent.com/python-pillow/pillow-depends/main/nasm-2.16.01-win64.zip
- ..\pillow-depends\gs1000w32.exe /S - 7z x nasm-win64.zip -oc:\
- path c:\nasm-2.15.05;C:\Program Files (x86)\gs\gs10.0.0\bin;%PATH% - choco install ghostscript --version=10.0.0.20230317
- path c:\nasm-2.16.01;C:\Program Files\gs\gs10.00.0\bin;%PATH%
- cd c:\pillow\winbuild\ - cd c:\pillow\winbuild\
- ps: | - ps: |
c:\python37\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ c:\python38\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\
c:\pillow\winbuild\build\build_dep_all.cmd c:\pillow\winbuild\build\build_dep_all.cmd
$host.SetShouldExit(0) $host.SetShouldExit(0)
- path C:\pillow\winbuild\build\bin;%PATH% - path C:\pillow\winbuild\build\bin;%PATH%
build_script: build_script:
- ps: |
c:\pillow\winbuild\build\build_pillow.cmd install
$host.SetShouldExit(0)
- cd c:\pillow - cd c:\pillow
- winbuild\build\build_env.cmd
- '%PYTHON%\%EXECUTABLE% -m pip install -v -C raqm=vendor -C fribidi=vendor .'
- '%PYTHON%\%EXECUTABLE% selftest.py --installed' - '%PYTHON%\%EXECUTABLE% selftest.py --installed'
test_script: test_script:
- cd c:\pillow - cd c:\pillow
- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov pytest-timeout' - '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov pytest-timeout defusedxml numpy olefile pyroma'
- c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE% - c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE%
- '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"' - '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"'
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests' - '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests'
#- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest? #- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest?
after_test: after_test:
- python -m pip install codecov - curl -Os https://uploader.codecov.io/latest/windows/codecov.exe
- codecov --file coverage.xml --name %PYTHON% --flags AppVeyor - .\codecov.exe --file coverage.xml --name %PYTHON% --flags AppVeyor
matrix: matrix:
fast_finish: true fast_finish: true
@ -60,18 +60,15 @@ cache:
- '%LOCALAPPDATA%\pip\Cache' - '%LOCALAPPDATA%\pip\Cache'
artifacts: artifacts:
- path: pillow\dist\*.egg - path: pillow\*.egg
name: egg name: egg
- path: pillow\dist\*.wheel - path: pillow\*.whl
name: wheel name: wheel
before_deploy: before_deploy:
- cd c:\pillow - cd c:\pillow
- '%PYTHON%\%EXECUTABLE% -m pip install wheel' - '%PYTHON%\%EXECUTABLE% -m pip wheel -v -C raqm=vendor -C fribidi=vendor .'
- cd c:\pillow\winbuild\ - ps: Get-ChildItem .\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
- c:\pillow\winbuild\build\build_pillow.cmd bdist_wheel
- cd c:\pillow
- ps: Get-ChildItem .\dist\*.* | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
deploy: deploy:
provider: S3 provider: S3

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# gather the coverage data # gather the coverage data
python3 -m pip install codecov python3 -m pip install coverage
if [[ $MATRIX_DOCKER ]]; then if [[ $MATRIX_DOCKER ]]; then
python3 -m coverage xml --ignore-errors python3 -m coverage xml --ignore-errors
else else

View File

@ -22,12 +22,14 @@ set -e
if [[ $(uname) != CYGWIN* ]]; then if [[ $(uname) != CYGWIN* ]]; then
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\ ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev
fi fi
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
python3 -m pip install --upgrade wheel python3 -m pip install --upgrade wheel
PYTHONOPTIMIZE=0 python3 -m pip install cffi # TODO Update condition when cffi supports 3.13
if ! [[ "$GHA_PYTHON_VERSION" == "3.13" ]]; then PYTHONOPTIMIZE=0 python3 -m pip install cffi ; fi
python3 -m pip install coverage python3 -m pip install coverage
python3 -m pip install defusedxml python3 -m pip install defusedxml
python3 -m pip install olefile python3 -m pip install olefile
@ -37,14 +39,25 @@ python3 -m pip install -U pytest-timeout
python3 -m pip install pyroma python3 -m pip install pyroma
if [[ $(uname) != CYGWIN* ]]; then if [[ $(uname) != CYGWIN* ]]; then
python3 -m pip install numpy # TODO Update condition when NumPy supports 3.13
if ! [[ "$GHA_PYTHON_VERSION" == "3.13" ]]; then python3 -m pip install numpy ; fi
# PyQt6 doesn't support PyPy3 # PyQt6 doesn't support PyPy3
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then if [[ $GHA_PYTHON_VERSION == 3.* ]]; then
sudo apt-get -qq install libegl1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0 sudo apt-get -qq install libegl1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0
python3 -m pip install pyqt6 python3 -m pip install pyqt6
fi fi
# Pyroma uses non-isolated build and fails with old setuptools
if [[
$GHA_PYTHON_VERSION == pypy3.9
|| $GHA_PYTHON_VERSION == 3.8
|| $GHA_PYTHON_VERSION == 3.9
]]; then
# To match pyproject.toml
python3 -m pip install "setuptools>=67.8"
fi
# webp # webp
pushd depends && ./install_webp.sh && popd pushd depends && ./install_webp.sh && popd

View File

@ -0,0 +1 @@
cibuildwheel==2.16.2

View File

@ -13,11 +13,7 @@ indent_style = space
trim_trailing_whitespace = true trim_trailing_whitespace = true
[*.rst] [*.{toml,yml}]
# Four-space indentation
indent_size = 4
[*.yml]
# Two-space indentation # Two-space indentation
indent_size = 2 indent_size = 2

6
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,6 @@
# Flake8
8de95676e0fd89f2326b3953488ab66ff29cd2d0
# Format with Black
53a7e3500437a9fd5826bc04758f7116bd7e52dc
# Format the C code with ClangFormat
46b7e86bab79450ec0a2866c6c0c679afb659d17

View File

@ -19,6 +19,7 @@ Please send a pull request to the `main` branch. Please include [documentation](
- Follow PEP 8. - Follow PEP 8.
- When committing only documentation changes please include `[ci skip]` in the commit message to avoid running tests on AppVeyor. - When committing only documentation changes please include `[ci skip]` in the commit message to avoid running tests on AppVeyor.
- Include [release notes](https://github.com/python-pillow/Pillow/tree/main/docs/releasenotes) as needed or appropriate with your bug fixes, feature additions and tests. - Include [release notes](https://github.com/python-pillow/Pillow/tree/main/docs/releasenotes) as needed or appropriate with your bug fixes, feature additions and tests.
- Do not add to the [changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) for proposed changes, as that is updated after changes are merged.
## Reporting Issues ## Reporting Issues

2
.github/mergify.yml vendored
View File

@ -7,7 +7,7 @@ pull_request_rules:
- status-success=Test Successful - status-success=Test Successful
- status-success=Docker Test Successful - status-success=Docker Test Successful
- status-success=Windows Test Successful - status-success=Windows Test Successful
- status-success=MinGW Test Successful - status-success=MinGW
- status-success=Cygwin Test Successful - status-success=Cygwin Test Successful
- status-success=continuous-integration/appveyor/pr - status-success=continuous-integration/appveyor/pr
actions: actions:

View File

@ -2,11 +2,15 @@ name: CIFuzz
on: on:
push: push:
branches:
- "**"
paths: paths:
- ".github/workflows/cifuzz.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
pull_request: pull_request:
paths: paths:
- ".github/workflows/cifuzz.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
workflow_dispatch: workflow_dispatch:
@ -14,7 +18,7 @@ on:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -38,13 +42,13 @@ jobs:
language: python language: python
dry-run: false dry-run: false
- name: Upload New Crash - name: Upload New Crash
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success' if: failure() && steps.build.outcome == 'success'
with: with:
name: artifacts name: artifacts
path: ./out/artifacts path: ./out/artifacts
- name: Upload Legacy Crash - name: Upload Legacy Crash
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: steps.run.outcome == 'success' if: steps.run.outcome == 'success'
with: with:
name: crash name: crash

57
.github/workflows/docs.yml vendored Normal file
View File

@ -0,0 +1,57 @@
name: Docs
on:
push:
branches:
- "**"
paths:
- ".github/workflows/docs.yml"
- "docs/**"
pull_request:
paths:
- ".github/workflows/docs.yml"
- "docs/**"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
jobs:
build:
runs-on: ubuntu-latest
name: Docs
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: pip
cache-dependency-path: ".ci/*.sh"
- name: Build system information
run: python3 .github/workflows/system-info.py
- name: Install Linux dependencies
run: |
.ci/install.sh
env:
GHA_PYTHON_VERSION: "3.x"
- name: Build
run: |
.ci/build.sh
- name: Docs
run: |
make doccheck

View File

@ -2,6 +2,9 @@ name: Lint
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
env:
FORCE_COLOR: 1
permissions: permissions:
contents: read contents: read
@ -17,7 +20,7 @@ jobs:
name: Lint name: Lint
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: pre-commit cache - name: pre-commit cache
uses: actions/cache@v3 uses: actions/cache@v3
@ -28,7 +31,7 @@ jobs:
lint-pre-commit- lint-pre-commit-
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: "3.x" python-version: "3.x"
cache: pip cache: pip
@ -46,3 +49,6 @@ jobs:
run: tox -e lint run: tox -e lint
env: env:
PRE_COMMIT_COLOR: always PRE_COMMIT_COLOR: always
- name: Mypy
run: tox -e mypy

View File

@ -3,8 +3,11 @@
set -e set -e
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype libraqm brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype libraqm
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
# TODO Update condition when cffi supports 3.13
if ! [[ "$GHA_PYTHON_VERSION" == "3.13" ]]; then PYTHONOPTIMIZE=0 python3 -m pip install cffi ; fi
PYTHONOPTIMIZE=0 python3 -m pip install cffi
python3 -m pip install coverage python3 -m pip install coverage
python3 -m pip install defusedxml python3 -m pip install defusedxml
python3 -m pip install olefile python3 -m pip install olefile
@ -13,7 +16,8 @@ python3 -m pip install -U pytest-cov
python3 -m pip install -U pytest-timeout python3 -m pip install -U pytest-timeout
python3 -m pip install pyroma python3 -m pip install pyroma
python3 -m pip install numpy # TODO Update condition when NumPy supports 3.13
if ! [[ "$GHA_PYTHON_VERSION" == "3.13" ]]; then python3 -m pip install numpy ; fi
# extra test images # extra test images
pushd depends && ./install_extra_test_images.sh && popd pushd depends && ./install_extra_test_images.sh && popd

View File

@ -10,7 +10,7 @@ on:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

View File

@ -8,7 +8,7 @@ on:
permissions: permissions:
issues: write issues: write
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -20,7 +20,7 @@ jobs:
steps: steps:
- name: "Check issues" - name: "Check issues"
uses: actions/stale@v7 uses: actions/stale@v9
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
only-labels: "Awaiting OP Action" only-labels: "Awaiting OP Action"

View File

@ -6,6 +6,8 @@ This sort of info is missing from GitHub Actions.
Requested here: Requested here:
https://github.com/actions/virtual-environments/issues/79 https://github.com/actions/virtual-environments/issues/79
""" """
from __future__ import annotations
import os import os
import platform import platform
import sys import sys

View File

@ -1,6 +1,25 @@
name: Test Cygwin name: Test Cygwin
on: [push, pull_request, workflow_dispatch] on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -27,38 +46,63 @@ jobs:
git config --global core.autocrlf input git config --global core.autocrlf input
- name: Checkout Pillow - name: Checkout Pillow
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Install Cygwin - name: Install Cygwin
uses: cygwin/cygwin-install-action@v3 uses: cygwin/cygwin-install-action@v4
with: with:
platform: x86_64 platform: x86_64
packages: > packages: >
ImageMagick gcc-g++ ghostscript jpeg libfreetype-devel gcc-g++
libimagequant-devel libjpeg-devel liblapack-devel ghostscript
liblcms2-devel libopenjp2-devel libraqm-devel ImageMagick
libtiff-devel libwebp-devel libxcb-devel libxcb-xinerama0 jpeg
make netpbm perl libfreetype-devel
libimagequant-devel
libjpeg-devel
liblapack-devel
liblcms2-devel
libopenjp2-devel
libraqm-devel
libtiff-devel
libwebp-devel
libxcb-devel
libxcb-xinerama0
make
netpbm
perl
python3${{ matrix.python-minor-version }}-cffi python3${{ matrix.python-minor-version }}-cffi
python3${{ matrix.python-minor-version }}-cython python3${{ matrix.python-minor-version }}-cython
python3${{ matrix.python-minor-version }}-devel python3${{ matrix.python-minor-version }}-devel
python3${{ matrix.python-minor-version }}-numpy python3${{ matrix.python-minor-version }}-numpy
python3${{ matrix.python-minor-version }}-sip python3${{ matrix.python-minor-version }}-sip
python3${{ matrix.python-minor-version }}-tkinter python3${{ matrix.python-minor-version }}-tkinter
qt5-devel-tools subversion xorg-server-extra zlib-devel wget
xorg-server-extra
zlib-devel
- name: Add Lapack to PATH - name: Add Lapack to PATH
uses: egor-tensin/cleanup-path@v3 uses: egor-tensin/cleanup-path@v3
with: with:
dirs: 'C:\cygwin\bin;C:\cygwin\lib\lapack' dirs: 'C:\cygwin\bin;C:\cygwin\lib\lapack'
- name: Select Python version
run: |
ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3
- name: Get latest NumPy version
id: latest-numpy
shell: bash.exe -eo pipefail -o igncr "{0}"
run: |
python3 -m pip list --outdated | grep numpy | sed -r 's/ +/ /g' | cut -d ' ' -f 3 | sed 's/^/version=/' >> $GITHUB_OUTPUT
- name: pip cache - name: pip cache
uses: actions/cache@v3 uses: actions/cache@v3
with: with:
path: 'C:\cygwin\home\runneradmin\.cache\pip' path: 'C:\cygwin\home\runneradmin\.cache\pip'
key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-${{ hashFiles('.ci/install.sh') }} key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-numpy${{ steps.latest-numpy.outputs.version }}-${{ hashFiles('.ci/install.sh') }}
restore-keys: | restore-keys: |
${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}- ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-numpy${{ steps.latest-numpy.outputs.version }}-
- name: Build system information - name: Build system information
run: | run: |
@ -68,15 +112,15 @@ jobs:
run: | run: |
bash.exe .ci/install.sh bash.exe .ci/install.sh
- name: Install a different NumPy - name: Upgrade NumPy
shell: dash.exe -l "{0}" shell: dash.exe -l "{0}"
run: | run: |
python3 -m pip install -U 'numpy!=1.21.*' python3 -m pip install -U "numpy<1.26"
- name: Build - name: Build
shell: bash.exe -eo pipefail -o igncr "{0}" shell: bash.exe -eo pipefail -o igncr "{0}"
run: | run: |
SETUPTOOLS_USE_DISTUTILS=stdlib .ci/build.sh .ci/build.sh
- name: Test - name: Test
run: | run: |
@ -88,7 +132,7 @@ jobs:
dash.exe -c "mkdir -p Tests/errors" dash.exe -c "mkdir -p Tests/errors"
- name: Upload errors - name: Upload errors
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: failure() if: failure()
with: with:
name: errors name: errors

View File

@ -1,6 +1,25 @@
name: Test Docker name: Test Docker
on: [push, pull_request, workflow_dispatch] on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -24,16 +43,17 @@ jobs:
# Then run the remainder # Then run the remainder
alpine, alpine,
amazon-2-amd64, amazon-2-amd64,
amazon-2023-amd64,
arch, arch,
centos-7-amd64, centos-7-amd64,
centos-stream-8-amd64, centos-stream-8-amd64,
centos-stream-9-amd64, centos-stream-9-amd64,
debian-10-buster-x86, debian-11-bullseye-amd64,
debian-11-bullseye-x86, debian-12-bookworm-x86,
fedora-36-amd64, debian-12-bookworm-amd64,
fedora-37-amd64, fedora-38-amd64,
fedora-39-amd64,
gentoo, gentoo,
ubuntu-18.04-bionic-amd64,
ubuntu-20.04-focal-amd64, ubuntu-20.04-focal-amd64,
ubuntu-22.04-jammy-amd64, ubuntu-22.04-jammy-amd64,
] ]
@ -49,7 +69,7 @@ jobs:
name: ${{ matrix.docker }} name: ${{ matrix.docker }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Build system information - name: Build system information
run: python3 .github/workflows/system-info.py run: python3 .github/workflows/system-info.py
@ -87,6 +107,7 @@ jobs:
with: with:
flags: GHA_Docker flags: GHA_Docker
name: ${{ matrix.docker }} name: ${{ matrix.docker }}
gcov: true
success: success:
permissions: permissions:

View File

@ -1,42 +1,50 @@
name: Test MinGW name: Test MinGW
on: [push, pull_request, workflow_dispatch] on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
build: build:
runs-on: windows-latest runs-on: windows-latest
strategy:
fail-fast: false
matrix:
mingw: ["MINGW32", "MINGW64"]
include:
- mingw: "MINGW32"
name: "MSYS2 MinGW 32-bit"
package: "mingw-w64-i686"
- mingw: "MINGW64"
name: "MSYS2 MinGW 64-bit"
package: "mingw-w64-x86_64"
defaults: defaults:
run: run:
shell: bash.exe --login -eo pipefail "{0}" shell: bash.exe --login -eo pipefail "{0}"
env: env:
MSYSTEM: ${{ matrix.mingw }} MSYSTEM: MINGW64
CHERE_INVOKING: 1 CHERE_INVOKING: 1
timeout-minutes: 30 timeout-minutes: 30
name: ${{ matrix.name }} name: "MinGW"
steps: steps:
- name: Checkout Pillow - name: Checkout Pillow
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Set up shell - name: Set up shell
run: echo "C:\msys64\usr\bin\" >> $env:GITHUB_PATH run: echo "C:\msys64\usr\bin\" >> $env:GITHUB_PATH
@ -45,30 +53,29 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
pacman -S --noconfirm \ pacman -S --noconfirm \
${{ matrix.package }}-python3-cffi \ mingw-w64-x86_64-freetype \
${{ matrix.package }}-python3-numpy \ mingw-w64-x86_64-gcc \
${{ matrix.package }}-python3-olefile \ mingw-w64-x86_64-ghostscript \
${{ matrix.package }}-python3-pip \ mingw-w64-x86_64-lcms2 \
${{ matrix.package }}-python-pyqt6 \ mingw-w64-x86_64-libimagequant \
${{ matrix.package }}-python3-setuptools \ mingw-w64-x86_64-libjpeg-turbo \
${{ matrix.package }}-freetype \ mingw-w64-x86_64-libraqm \
${{ matrix.package }}-gcc \ mingw-w64-x86_64-libtiff \
${{ matrix.package }}-ghostscript \ mingw-w64-x86_64-libwebp \
${{ matrix.package }}-lcms2 \ mingw-w64-x86_64-openjpeg2 \
${{ matrix.package }}-libimagequant \ mingw-w64-x86_64-python3-cffi \
${{ matrix.package }}-libjpeg-turbo \ mingw-w64-x86_64-python3-numpy \
${{ matrix.package }}-libraqm \ mingw-w64-x86_64-python3-olefile \
${{ matrix.package }}-libtiff \ mingw-w64-x86_64-python3-pip \
${{ matrix.package }}-libwebp \ mingw-w64-x86_64-python3-setuptools \
${{ matrix.package }}-openjpeg2 \ mingw-w64-x86_64-python-pyqt6
subversion
python3 -m pip install pyroma pytest pytest-cov pytest-timeout python3 -m pip install pyroma pytest pytest-cov pytest-timeout
pushd depends && ./install_extra_test_images.sh && popd pushd depends && ./install_extra_test_images.sh && popd
- name: Build Pillow - name: Build Pillow
run: CFLAGS="-coverage" python3 -m pip install --global-option="build_ext" . run: SETUPTOOLS_USE_DISTUTILS="stdlib" CFLAGS="-coverage" python3 -m pip install .
- name: Test Pillow - name: Test Pillow
run: | run: |
@ -81,14 +88,4 @@ jobs:
with: with:
file: ./coverage.xml file: ./coverage.xml
flags: GHA_Windows flags: GHA_Windows
name: ${{ matrix.name }} name: "MSYS2 MinGW"
success:
permissions:
contents: none
needs: build
runs-on: ubuntu-latest
name: MinGW Test Successful
steps:
- name: Success
run: echo MinGW Test Successful

View File

@ -1,14 +1,18 @@
name: Test Valgrind name: Test Valgrind
# like the docker tests, but running valgrind only on *.c/*.h changes. # like the Docker tests, but running valgrind only on *.c/*.h changes.
on: on:
push: push:
branches:
- "**"
paths: paths:
- ".github/workflows/test-valgrind.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
pull_request: pull_request:
paths: paths:
- ".github/workflows/test-valgrind.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
workflow_dispatch: workflow_dispatch:
@ -16,7 +20,7 @@ on:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
@ -35,7 +39,7 @@ jobs:
name: ${{ matrix.docker }} name: ${{ matrix.docker }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Build system information - name: Build system information
run: python3 .github/workflows/system-info.py run: python3 .github/workflows/system-info.py
@ -48,5 +52,5 @@ jobs:
run: | run: |
# The Pillow user in the docker container is UID 1000 # The Pillow user in the docker container is UID 1000
sudo chown -R 1000 $GITHUB_WORKSPACE sudo chown -R 1000 $GITHUB_WORKSPACE
docker run --name pillow_container -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }} docker run --name pillow_container -e "PILLOW_VALGRIND_TEST=true" -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
sudo chown -R runner $GITHUB_WORKSPACE sudo chown -R runner $GITHUB_WORKSPACE

View File

@ -1,6 +1,23 @@
name: Test Windows name: Test Windows
on: [push, pull_request, workflow_dispatch] on:
push:
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -15,54 +32,54 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] python-version: ["pypy3.10", "pypy3.9", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
architecture: ["x86", "x64"]
include:
# PyPy 7.3.4+ only ships 64-bit binaries for Windows
- python-version: "pypy3.8"
architecture: "x64"
- python-version: "pypy3.9"
architecture: "x64"
timeout-minutes: 30 timeout-minutes: 30
name: Python ${{ matrix.python-version }} ${{ matrix.architecture }} name: Python ${{ matrix.python-version }}
steps: steps:
- name: Checkout Pillow - name: Checkout Pillow
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Checkout cached dependencies - name: Checkout cached dependencies
uses: actions/checkout@v3 uses: actions/checkout@v4
with: with:
repository: python-pillow/pillow-depends repository: python-pillow/pillow-depends
path: winbuild\depends path: winbuild\depends
- name: Checkout extra test images
uses: actions/checkout@v4
with:
repository: python-pillow/test-images
path: Tests\test-images
# sets env: pythonLocation # sets env: pythonLocation
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture }} allow-prereleases: true
cache: pip cache: pip
cache-dependency-path: ".github/workflows/test-windows.yml" cache-dependency-path: ".github/workflows/test-windows.yml"
- name: Print build system information - name: Print build system information
run: python3 .github/workflows/system-info.py run: python3 .github/workflows/system-info.py
- name: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml - name: python3 -m pip install pytest pytest-cov pytest-timeout defusedxml olefile pyroma
run: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml run: python3 -m pip install pytest pytest-cov pytest-timeout defusedxml olefile pyroma
- name: Install dependencies - name: Install dependencies
id: install id: install
run: | run: |
7z x winbuild\depends\nasm-2.15.05-win64.zip "-o$env:RUNNER_WORKSPACE\" choco install nasm --no-progress
echo "$env:RUNNER_WORKSPACE\nasm-2.15.05" >> $env:GITHUB_PATH echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
winbuild\depends\gs1000w32.exe /S choco install ghostscript --version=10.0.0.20230317 --no-progress
echo "C:\Program Files (x86)\gs\gs10.0.0\bin" >> $env:GITHUB_PATH echo "C:\Program Files\gs\gs10.00.0\bin" >> $env:GITHUB_PATH
xcopy /S /Y winbuild\depends\test_images\* Tests\images\ # Install extra test images
xcopy /S /Y Tests\test-images\* Tests\images
# make cache key depend on VS version # make cache key depend on VS version
& "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" ` & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" `
@ -81,7 +98,7 @@ jobs:
- name: Prepare build - name: Prepare build
if: steps.build-cache.outputs.cache-hit != 'true' if: steps.build-cache.outputs.cache-hit != 'true'
run: | run: |
& python.exe winbuild\build_prepare.py -v --python=$env:pythonLocation --srcdir & python.exe winbuild\build_prepare.py -v
shell: pwsh shell: pwsh
- name: Build dependencies / libjpeg-turbo - name: Build dependencies / libjpeg-turbo
@ -149,9 +166,8 @@ jobs:
- name: Build Pillow - name: Build Pillow
run: | run: |
$FLAGS="" $FLAGS="-C raqm=vendor -C fribidi=vendor"
if ('${{ github.event_name }}' -ne 'pull_request') { $FLAGS="--disable-imagequant" } cmd /c "winbuild\build\build_env.cmd && $env:pythonLocation\python.exe -m pip install -v $FLAGS ."
& winbuild\build\build_pillow.cmd $FLAGS install
& $env:pythonLocation\python.exe selftest.py --installed & $env:pythonLocation\python.exe selftest.py --installed
shell: pwsh shell: pwsh
@ -174,7 +190,7 @@ jobs:
shell: bash shell: bash
- name: Upload errors - name: Upload errors
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: failure() if: failure()
with: with:
name: errors name: errors
@ -190,47 +206,7 @@ jobs:
with: with:
file: ./coverage.xml file: ./coverage.xml
flags: GHA_Windows flags: GHA_Windows
name: ${{ runner.os }} Python ${{ matrix.python-version }} ${{ matrix.architecture }} name: ${{ runner.os }} Python ${{ matrix.python-version }}
- name: Build wheel
id: wheel
if: "github.event_name != 'pull_request'"
run: |
mkdir fribidi\${{ matrix.architecture }}
copy winbuild\build\bin\fribidi* fribidi\${{ matrix.architecture }}
setlocal EnableDelayedExpansion
for %%f in (winbuild\build\license\*) do (
set x=%%~nf
rem Skip FriBiDi license, it is not included in the wheel.
set fribidi=!x:~0,7!
if NOT !fribidi!==fribidi (
rem Skip imagequant license, it is not included in the wheel.
set libimagequant=!x:~0,13!
if NOT !libimagequant!==libimagequant (
echo. >> LICENSE
echo ===== %%~nf ===== >> LICENSE
echo. >> LICENSE
type %%f >> LICENSE
)
)
)
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo dist=dist-%%a >> %GITHUB_OUTPUT%
winbuild\\build\\build_pillow.cmd --disable-imagequant bdist_wheel
shell: cmd
- name: Upload wheel
uses: actions/upload-artifact@v3
if: "github.event_name != 'pull_request'"
with:
name: ${{ steps.wheel.outputs.dist }}
path: dist\*.whl
- name: Upload fribidi.dll
if: "github.event_name != 'pull_request' && matrix.python-version == 3.11"
uses: actions/upload-artifact@v3
with:
name: fribidi
path: fribidi\*
success: success:
permissions: permissions:

View File

@ -1,6 +1,25 @@
name: Test name: Test
on: [push, pull_request, workflow_dispatch] on:
push:
branches:
- "**"
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- ".github/workflows/wheels*"
- ".gitmodules"
- ".travis.yml"
- "docs/**"
- "wheels/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -20,16 +39,17 @@ jobs:
"ubuntu-latest", "ubuntu-latest",
] ]
python-version: [ python-version: [
"pypy3.10",
"pypy3.9", "pypy3.9",
"pypy3.8", "3.13",
"3.12",
"3.11", "3.11",
"3.10", "3.10",
"3.9", "3.9",
"3.8", "3.8",
"3.7",
] ]
include: include:
- python-version: "3.7" - python-version: "3.9"
PYTHONOPTIMIZE: 1 PYTHONOPTIMIZE: 1
REVERSE: "--reverse" REVERSE: "--reverse"
- python-version: "3.8" - python-version: "3.8"
@ -39,12 +59,13 @@ jobs:
name: ${{ matrix.os }} Python ${{ matrix.python-version }} name: ${{ matrix.os }} Python ${{ matrix.python-version }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4 uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
allow-prereleases: true
cache: pip cache: pip
cache-dependency-path: ".ci/*.sh" cache-dependency-path: ".ci/*.sh"
@ -75,7 +96,9 @@ jobs:
python3 -m pip install pytest-reverse python3 -m pip install pytest-reverse
fi fi
if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then
xvfb-run -s '-screen 0 1024x768x24' .ci/test.sh xvfb-run -s '-screen 0 1024x768x24' sway&
export WAYLAND_DISPLAY=wayland-1
.ci/test.sh
else else
.ci/test.sh .ci/test.sh
fi fi
@ -89,17 +112,12 @@ jobs:
mkdir -p Tests/errors mkdir -p Tests/errors
- name: Upload errors - name: Upload errors
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: failure() if: failure()
with: with:
name: errors name: errors
path: Tests/errors path: Tests/errors
- name: Docs
if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.11
run: |
make doccheck
- name: After success - name: After success
run: | run: |
.ci/after_success.sh .ci/after_success.sh
@ -107,9 +125,9 @@ jobs:
- name: Upload coverage - name: Upload coverage
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
with: with:
file: ./coverage.xml
flags: ${{ matrix.os == 'macos-latest' && 'GHA_macOS' || 'GHA_Ubuntu' }} flags: ${{ matrix.os == 'macos-latest' && 'GHA_macOS' || 'GHA_Ubuntu' }}
name: ${{ matrix.os }} Python ${{ matrix.python-version }} name: ${{ matrix.os }} Python ${{ matrix.python-version }}
gcov: true
success: success:
permissions: permissions:

151
.github/workflows/wheels-dependencies.sh vendored Executable file
View File

@ -0,0 +1,151 @@
#!/bin/bash
# Define custom utilities
# Test for macOS with [ -n "$IS_MACOS" ]
if [ -z "$IS_MACOS" ]; then
export MB_ML_LIBC=${AUDITWHEEL_POLICY::9}
export MB_ML_VER=${AUDITWHEEL_POLICY:9}
fi
export PLAT=$CIBW_ARCHS
source wheels/multibuild/common_utils.sh
source wheels/multibuild/library_builders.sh
if [ -z "$IS_MACOS" ]; then
source wheels/multibuild/manylinux_utils.sh
fi
ARCHIVE_SDIR=pillow-depends-main
# Package versions for fresh source builds
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
XZ_VERSION=5.4.5
TIFF_VERSION=4.6.0
LCMS2_VERSION=2.16
if [[ -n "$IS_MACOS" ]]; then
GIFLIB_VERSION=5.1.4
else
GIFLIB_VERSION=5.2.1
fi
if [[ -n "$IS_MACOS" ]] || [[ "$MB_ML_VER" != 2014 ]]; then
ZLIB_VERSION=1.3
else
ZLIB_VERSION=1.2.8
fi
LIBWEBP_VERSION=1.3.2
BZIP2_VERSION=1.0.8
LIBXCB_VERSION=1.16
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)
(cd $out_dir \
&& cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
&& make install)
touch openjpeg-stamp
}
fi
function build_brotli {
local cmake=$(get_modern_cmake)
local out_dir=$(fetch_unpack https://github.com/google/brotli/archive/v$BROTLI_VERSION.tar.gz brotli-1.1.0.tar.gz)
(cd $out_dir \
&& $cmake -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX -DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib . \
&& make install)
if [[ "$MB_ML_LIBC" == "manylinux" ]]; then
cp /usr/local/lib64/libbrotli* /usr/local/lib
cp /usr/local/lib64/pkgconfig/libbrotli* /usr/local/lib/pkgconfig
fi
}
function build {
if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "arm64" ]]; then
export BUILD_PREFIX="/usr/local"
fi
build_xz
if [ -z "$IS_ALPINE" ] && [ -z "$IS_MACOS" ]; then
yum remove -y zlib-devel
fi
build_new_zlib
build_simple xcb-proto 1.16.0 https://xorg.freedesktop.org/archive/individual/proto
if [ -n "$IS_MACOS" ]; then
if [[ "$CIBW_ARCHS" == "arm64" ]]; then
build_simple xorgproto 2023.2 https://www.x.org/pub/individual/proto
build_simple libXau 1.0.11 https://www.x.org/pub/individual/lib
build_simple libpthread-stubs 0.5 https://xcb.freedesktop.org/dist
if [ -f /Library/Frameworks/Python.framework/Versions/Current/share/pkgconfig/xcb-proto.pc ]; then
cp /Library/Frameworks/Python.framework/Versions/Current/share/pkgconfig/xcb-proto.pc /Library/Frameworks/Python.framework/Versions/Current/lib/pkgconfig/xcb-proto.pc
fi
fi
else
sed s/\${pc_sysrootdir\}// /usr/local/share/pkgconfig/xcb-proto.pc > /usr/local/lib/pkgconfig/xcb-proto.pc
fi
build_simple libxcb $LIBXCB_VERSION https://www.x.org/releases/individual/lib
build_libjpeg_turbo
build_tiff
build_libpng
build_lcms2
if [[ -n "$IS_MACOS" ]] && [[ "$CIBW_ARCHS" == "arm64" ]]; then
for dylib in libjpeg.dylib libtiff.dylib liblcms2.dylib; do
cp $BUILD_PREFIX/lib/$dylib /opt/arm64-builds/lib
done
fi
build_openjpeg
ORIGINAL_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -O3 -DNDEBUG"
if [[ -n "$IS_MACOS" ]]; then
CFLAGS="$CFLAGS -Wl,-headerpad_max_install_names"
fi
build_libwebp
CFLAGS=$ORIGINAL_CFLAGS
build_brotli
if [ -n "$IS_MACOS" ]; then
# Custom freetype build
build_simple freetype $FREETYPE_VERSION https://download.savannah.gnu.org/releases/freetype tar.gz --with-harfbuzz=no
else
build_freetype
fi
if [ -z "$IS_MACOS" ]; then
export FREETYPE_LIBS=-lfreetype
export FREETYPE_CFLAGS=-I/usr/local/include/freetype2/
fi
build_simple harfbuzz $HARFBUZZ_VERSION https://github.com/harfbuzz/harfbuzz/releases/download/$HARFBUZZ_VERSION tar.xz --with-freetype=yes --with-glib=no
if [ -z "$IS_MACOS" ]; then
export FREETYPE_LIBS=""
export FREETYPE_CFLAGS=""
fi
}
# Any stuff that you need to do before you start building the wheels
# Runs in the root directory of this repository.
curl -fsSL -o pillow-depends-main.zip https://github.com/python-pillow/pillow-depends/archive/main.zip
untar pillow-depends-main.zip
if [[ -n "$IS_MACOS" ]]; then
# webp, libtiff, libxcb cause a conflict with building webp, libtiff, libxcb
# libxdmcp causes an issue on macOS < 11
# if php is installed, brew tries to reinstall these after installing openblas
# remove cairo to fix building harfbuzz on arm64
# remove lcms2 and libpng to fix building openjpeg on arm64
# remove zstd to avoid inclusion on x86_64
# curl from brew requires zstd, use system curl
brew remove --ignore-dependencies webp libpng libtiff libxcb libxdmcp curl php cairo lcms2 ghostscript zstd
brew install pkg-config
fi
wrap_wheel_builder build
# Append licenses
for filename in wheels/dependency_licenses/*; do
echo -e "\n\n----\n\n$(basename $filename | cut -f 1 -d '.')\n" | cat >> LICENSE
cat $filename >> LICENSE
done

22
.github/workflows/wheels-test.ps1 vendored Normal file
View File

@ -0,0 +1,22 @@
param ([string]$venv, [string]$pillow="C:\pillow")
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
Set-PSDebug -Trace 1
if ("$venv" -like "*\cibw-run-*\pp*-win_amd64\*") {
# unlike CPython, PyPy requires Visual C++ Redistributable to be installed
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri 'https://aka.ms/vs/15/release/vc_redist.x64.exe' -OutFile 'vc_redist.x64.exe'
C:\vc_redist.x64.exe /install /quiet /norestart | Out-Null
}
$env:path += ";$pillow\winbuild\build\bin\"
& "$venv\Scripts\activate.ps1"
& reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\python.exe" /v "GlobalFlag" /t REG_SZ /d "0x02000000" /f
cd $pillow
& python -VV
if (!$?) { exit $LASTEXITCODE }
& python selftest.py
if (!$?) { exit $LASTEXITCODE }
& python -m pytest -vx Tests\check_wheel.py
if (!$?) { exit $LASTEXITCODE }
& python -m pytest -vx Tests
if (!$?) { exit $LASTEXITCODE }

25
.github/workflows/wheels-test.sh vendored Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
set -e
if [[ "$OSTYPE" == "darwin"* ]]; then
brew install fribidi
export PKG_CONFIG_PATH="/usr/local/opt/openblas/lib/pkgconfig"
elif [ "${AUDITWHEEL_POLICY::9}" == "musllinux" ]; then
apk add curl fribidi
else
yum install -y fribidi
fi
if [ "${AUDITWHEEL_POLICY::9}" != "musllinux" ]; then
python3 -m pip install numpy
fi
if [ ! -d "test-images-main" ]; then
curl -fsSL -o pillow-test-images.zip https://github.com/python-pillow/test-images/archive/main.zip
unzip pillow-test-images.zip
mv test-images-main/* Tests/images
fi
# Runs tests
python3 selftest.py
python3 -m pytest Tests/check_wheel.py
python3 -m pytest

206
.github/workflows/wheels.yml vendored Normal file
View File

@ -0,0 +1,206 @@
name: Wheels
on:
push:
paths:
- ".ci/requirements-cibw.txt"
- ".github/workflows/wheel*"
- "wheels/*"
- "winbuild/build_prepare.py"
- "winbuild/fribidi.cmake"
tags:
- "*"
pull_request:
paths:
- ".ci/requirements-cibw.txt"
- ".github/workflows/wheel*"
- "wheels/*"
- "winbuild/build_prepare.py"
- "winbuild/fribidi.cmake"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
FORCE_COLOR: 1
jobs:
build:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: "macOS x86_64"
os: macos-latest
archs: x86_64
macosx_deployment_target: "10.10"
- name: "macOS arm64"
os: macos-latest
archs: arm64
macosx_deployment_target: "11.0"
- name: "manylinux2014 and musllinux x86_64"
os: ubuntu-latest
archs: x86_64
- name: "manylinux_2_28 x86_64"
os: ubuntu-latest
archs: x86_64
build: "*manylinux*"
manylinux: "manylinux_2_28"
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Build wheels
run: |
python3 -m pip install -r .ci/requirements-cibw.txt
python3 -m cibuildwheel --output-dir wheelhouse
env:
CIBW_ARCHS: ${{ matrix.archs }}
CIBW_BUILD: ${{ matrix.build }}
CIBW_MANYLINUX_PYPY_X86_64_IMAGE: ${{ matrix.manylinux }}
CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux }}
CIBW_SKIP: pp38-*
CIBW_TEST_SKIP: "*-macosx_arm64"
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
- uses: actions/upload-artifact@v3
with:
name: dist
path: ./wheelhouse/*.whl
windows:
name: Windows ${{ matrix.arch }}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- arch: x86
cibw_arch: x86
- arch: x64
cibw_arch: AMD64
- arch: ARM64
cibw_arch: ARM64
steps:
- uses: actions/checkout@v4
- name: Checkout extra test images
uses: actions/checkout@v4
with:
repository: python-pillow/test-images
path: Tests\test-images
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Prepare for build
run: |
choco install nasm --no-progress
echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
# Install extra test images
xcopy /S /Y Tests\test-images\* Tests\images
& python.exe -m pip install -r .ci/requirements-cibw.txt
# Cannot cross-compile FriBiDi (only used for tests)
$FLAGS = ("--no-imagequant", "--architecture=${{ matrix.arch }}")
if ('${{ matrix.arch }}' -eq 'ARM64') { $FLAGS += "--no-fribidi" }
& python.exe winbuild\build_prepare.py -v @FLAGS
shell: pwsh
- name: Build wheels
run: |
setlocal EnableDelayedExpansion
for %%f in (winbuild\build\license\*) do (
set x=%%~nf
rem Skip FriBiDi license, it is not included in the wheel.
set fribidi=!x:~0,7!
if NOT !fribidi!==fribidi (
rem Skip imagequant license, it is not included in the wheel.
set libimagequant=!x:~0,13!
if NOT !libimagequant!==libimagequant (
echo. >> LICENSE
echo ===== %%~nf ===== >> LICENSE
echo. >> LICENSE
type %%f >> LICENSE
)
)
)
call winbuild\\build\\build_env.cmd
%pythonLocation%\python.exe -m cibuildwheel . --output-dir wheelhouse
env:
CIBW_ARCHS: ${{ matrix.cibw_arch }}
CIBW_BEFORE_ALL: "{package}\\winbuild\\build\\build_dep_all.cmd"
CIBW_CACHE_PATH: "C:\\cibw"
CIBW_TEST_SKIP: "*-win_arm64"
CIBW_TEST_COMMAND: 'docker run --rm
-v {project}:C:\pillow
-v C:\cibw:C:\cibw
-v %CD%\..\venv-test:%CD%\..\venv-test
-e CI -e GITHUB_ACTIONS
mcr.microsoft.com/windows/servercore:ltsc2022
powershell C:\pillow\.github\workflows\wheels-test.ps1 %CD%\..\venv-test'
shell: cmd
- name: Upload wheels
uses: actions/upload-artifact@v3
with:
name: dist
path: ./wheelhouse/*.whl
- name: Prepare to upload FriBiDi
if: "matrix.arch != 'ARM64'"
run: |
mkdir fribidi\${{ matrix.arch }}
copy winbuild\build\bin\fribidi* fribidi\${{ matrix.arch }}
shell: cmd
- name: Upload fribidi.dll
if: "matrix.arch != 'ARM64'"
uses: actions/upload-artifact@v3
with:
name: fribidi
path: fribidi\*
sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: pip
cache-dependency-path: "Makefile"
- run: make sdist
- uses: actions/upload-artifact@v3
with:
name: dist
path: dist/*.tar.gz
success:
permissions:
contents: none
needs: [build, windows, sdist]
runs-on: ubuntu-latest
name: Wheels Successful
steps:
- name: Success
run: echo Wheels Successful

2
.gitignore vendored
View File

@ -79,7 +79,7 @@ docs/_build/
# JetBrains # JetBrains
.idea .idea
# Extra test images installed from pillow-depends/test_images # Extra test images installed from python-pillow/test-images
Tests/images/README.md Tests/images/README.md
Tests/images/crash_1.tif Tests/images/crash_1.tif
Tests/images/crash_2.tif Tests/images/crash_2.tif

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "multibuild"]
path = wheels/multibuild
url = https://github.com/multi-build/multibuild.git

View File

@ -1,62 +1,63 @@
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/astral-sh/ruff-pre-commit
rev: 22.12.0 rev: v0.1.7
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.12.0
hooks: hooks:
- id: black - id: black
args: [--target-version=py37]
# Only .py files, until https://github.com/psf/black/issues/402 resolved
files: \.py$
types: []
- repo: https://github.com/PyCQA/isort
rev: 5.11.1
hooks:
- id: isort
- repo: https://github.com/PyCQA/bandit - repo: https://github.com/PyCQA/bandit
rev: 1.7.4 rev: 1.7.6
hooks: hooks:
- id: bandit - id: bandit
args: [--severity-level=high] args: [--severity-level=high]
files: ^src/ files: ^src/
- repo: https://github.com/asottile/yesqa
rev: v1.4.0
hooks:
- id: yesqa
- repo: https://github.com/Lucas-C/pre-commit-hooks - repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.3.1 rev: v1.5.4
hooks: hooks:
- id: remove-tabs - id: remove-tabs
exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.opt$) exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.gd$|\.opt$)
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-2020, flake8-implicit-str-concat]
- repo: https://github.com/pre-commit/pygrep-hooks - repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.9.0 rev: v1.10.0
hooks: hooks:
- id: python-check-blanket-noqa
- id: rst-backticks - id: rst-backticks
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 rev: v4.5.0
hooks: hooks:
- id: check-executables-have-shebangs
- id: check-merge-conflict - id: check-merge-conflict
- id: check-json - id: check-json
- id: check-toml
- id: check-yaml - id: check-yaml
- id: end-of-file-fixer
exclude: ^Tests/images/
- id: trailing-whitespace
exclude: ^.github/.*TEMPLATE|^Tests/(fonts|images)/
- repo: https://github.com/sphinx-contrib/sphinx-lint - repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v0.6.7 rev: v0.9.1
hooks: hooks:
- id: sphinx-lint - id: sphinx-lint
- repo: https://github.com/tox-dev/pyproject-fmt
rev: 1.5.3
hooks:
- id: pyproject-fmt
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.15
hooks:
- id: validate-pyproject
- repo: https://github.com/tox-dev/tox-ini-fmt - repo: https://github.com/tox-dev/tox-ini-fmt
rev: 0.5.2 rev: 1.3.1
hooks: hooks:
- id: tox-ini-fmt - id: tox-ini-fmt

View File

@ -1,5 +1,12 @@
version: 2 version: 2
formats: [pdf]
build:
os: ubuntu-22.04
tools:
python: "3"
python: python:
install: install:
- method: pip - method: pip

52
.travis.yml Normal file
View File

@ -0,0 +1,52 @@
if: tag IS present OR type = api
env:
global:
- CIBW_ARCHS=aarch64
- CIBW_SKIP=pp38-*
language: python
# Default Python version is usually 3.6
python: "3.12"
dist: jammy
services: docker
jobs:
include:
- name: "manylinux2014 aarch64"
os: linux
arch: arm64
env:
- CIBW_BUILD="*manylinux*"
- CIBW_MANYLINUX_AARCH64_IMAGE=manylinux2014
- CIBW_MANYLINUX_PYPY_AARCH64_IMAGE=manylinux2014
- name: "manylinux_2_28 aarch64"
os: linux
arch: arm64
env:
- CIBW_BUILD="*manylinux*"
- CIBW_MANYLINUX_AARCH64_IMAGE=manylinux_2_28
- CIBW_MANYLINUX_PYPY_AARCH64_IMAGE=manylinux_2_28
- name: "musllinux aarch64"
os: linux
arch: arm64
env:
- CIBW_BUILD="*musllinux*"
install:
- python3 -m pip install -r .ci/requirements-cibw.txt
script:
- python3 -m cibuildwheel --output-dir wheelhouse
- ls -l "${TRAVIS_BUILD_DIR}/wheelhouse/"
# Upload wheels to GitHub Releases
deploy:
provider: releases
api_key: $GITHUB_RELEASE_TOKEN
file_glob: true
file: "${TRAVIS_BUILD_DIR}/wheelhouse/*.whl"
on:
repo: python-pillow/Pillow
tags: true
skip_cleanup: true

View File

@ -2,9 +2,450 @@
Changelog (Pillow) Changelog (Pillow)
================== ==================
9.4.0 (unreleased) 10.2.0 (unreleased)
-------------------
- Fix incorrect color blending for overlapping glyphs #7497
[ZachNagengast, nulano, radarhere]
- Attempt memory mapping when tile args is a string #7565
[radarhere]
- Fill identical pixels with transparency in subsequent frames when saving GIF #7568
[radarhere]
- Corrected duration when combining multiple GIF frames into single frame #7521
[radarhere]
- Handle disposing GIF background from outside palette #7515
[radarhere]
- Seek past the data when skipping a PSD layer #7483
[radarhere]
- Import plugins relative to the module #7576
[deliangyang, jaxx0n]
- Translate encoder error codes to strings; deprecate ``ImageFile.raise_oserror()`` #7609
[bgilbert, radarhere]
- Support reading BC4U and DX10 BC1 images #6486
[REDxEYE, radarhere, hugovk]
- Optimize ImageStat.Stat.extrema #7593
[florath, radarhere]
- Handle pathlib.Path in FreeTypeFont #7578
[radarhere, hugovk, nulano]
- Added support for reading DX10 BC4 DDS images #7603
[sambvfx, radarhere]
- Optimized ImageStat.Stat.count #7599
[florath]
- Correct PDF palette size when saving #7555
[radarhere]
- Fixed closing file pointer with olefile 0.47 #7594
[radarhere]
- Raise ValueError when TrueType font size is not greater than zero #7584, #7587
[akx, radarhere]
- If absent, do not try to close fp when closing image #7557
[RaphaelVRossi, radarhere]
- Allow configuring JPEG restart marker interval on save #7488
[bgilbert, radarhere]
- Decrement reference count for PyObject #7549
[radarhere]
- Implement ``streamtype=1`` option for tables-only JPEG encoding #7491
[bgilbert, radarhere]
- If save_all PNG only has one frame, do not create animated image #7522
[radarhere]
- Fixed frombytes() for images with a zero dimension #7493
[radarhere]
10.1.0 (2023-10-15)
-------------------
- Added TrueType default font to allow for different sizes #7354
[radarhere]
- Fixed invalid argument warning #7442
[radarhere]
- Added ImageOps cover method #7412
[radarhere, hugovk]
- Catch struct.error from truncated EXIF when reading JPEG DPI #7458
[radarhere]
- Consider default image when selecting mode for PNG save_all #7437
[radarhere]
- Support BGR;15, BGR;16 and BGR;24 access, unpacking and putdata #7303
[radarhere]
- Added CMYK to RGB unpacker #7310
[radarhere]
- Improved flexibility of XMP parsing #7274
[radarhere]
- Support reading 8-bit YCbCr TIFF images #7415
[radarhere]
- Allow saving I;16B images as PNG #7302
[radarhere]
- Corrected drawing I;16 points and writing I;16 text #7257
[radarhere]
- Set blue channel to 128 for BC5S #7413
[radarhere]
- Increase flexibility when reading IPTC fields #7319
[radarhere]
- Set C palette to be empty by default #7289
[radarhere]
- Added gs_binary to control Ghostscript use on all platforms #7392
[radarhere]
- Read bounding box information from the trailer of EPS files if specified #7382
[nopperl, radarhere]
- Added reading 8-bit color DDS images #7426
[radarhere]
- Added has_transparency_data #7420
[radarhere, hugovk]
- Fixed bug when reading BC5S DDS images #7401
[radarhere]
- Prevent TIFF orientation from being applied more than once #7383
[radarhere]
- Use previous pixel alpha for QOI_OP_RGB #7357
[radarhere]
- Added BC5U reading #7358
[radarhere]
- Allow getpixel() to accept a list #7355
[radarhere, homm]
- Allow GaussianBlur and BoxBlur to accept a sequence of x and y radii #7336
[radarhere]
- Expand JPEG buffer size when saving optimized or progressive #7345
[radarhere]
- Added session type check for Linux in ImageGrab.grabclipboard() #7332
[TheNooB2706, radarhere, hugovk]
- Allow "loop=None" when saving GIF images #7329
[radarhere]
- Fixed transparency when saving P mode images to PDF #7323
[radarhere]
- Added saving LA images as PDFs #7299
[radarhere]
- Set SMaskInData to 1 for PDFs with alpha #7316, #7317
[radarhere]
- Changed Image mode property to be read-only by default #7307
[radarhere]
- Silence exceptions in _repr_jpeg_ and _repr_png_ #7266
[mtreinish, radarhere]
- Do not use transparency when saving GIF if it has been removed when normalizing mode #7284
[radarhere]
- Fix missing symbols when libtiff depends on libjpeg #7270
[heitbaum]
10.0.1 (2023-09-15)
-------------------
- Updated libwebp to 1.3.2 #7395
[radarhere]
- Updated zlib to 1.3 #7344
[radarhere]
10.0.0 (2023-07-01)
-------------------
- Fixed deallocating mask images #7246
[radarhere]
- Added ImageFont.MAX_STRING_LENGTH #7244
[radarhere, hugovk]
- Fix Windows build with pyproject.toml #7230
[hugovk, nulano, radarhere]
- Do not close provided file handles with libtiff #7199
[radarhere]
- Convert to HSV if mode is HSV in getcolor() #7226
[radarhere]
- Added alpha_only argument to getbbox() #7123
[radarhere. hugovk]
- Prioritise speed in _repr_png_ #7242
[radarhere]
- Do not use CFFI access by default on PyPy #7236
[radarhere]
- Limit size even if one dimension is zero in decompression bomb check #7235
[radarhere]
- Use --config-settings instead of deprecated --global-option #7171
[radarhere]
- Better C integer definitions #6645
[Yay295, hugovk]
- Fixed finding dependencies on Cygwin #7175
[radarhere]
- Changed grabclipboard() to use PNG instead of JPG compression on macOS #7219
[abey79, radarhere]
- Added in_place argument to ImageOps.exif_transpose() #7092
[radarhere]
- Fixed calling putpalette() on L and LA images before load() #7187
[radarhere]
- Fixed saving TIFF multiframe images with LONG8 tag types #7078
[radarhere]
- Fixed combining single duration across duplicate APNG frames #7146
[radarhere]
- Remove temporary file when error is raised #7148
[radarhere]
- Do not use temporary file when grabbing clipboard on Linux #7200
[radarhere]
- If the clipboard fails to open on Windows, wait and try again #7141
[radarhere]
- Fixed saving multiple 1 mode frames to GIF #7181
[radarhere]
- Replaced absolute PIL import with relative import #7173
[radarhere]
- Replaced deprecated Py_FileSystemDefaultEncoding for Python >= 3.12 #7192
[radarhere]
- Improved wl-paste mimetype handling in ImageGrab #7094
[rrcgat, radarhere]
- Added _repr_jpeg_() for IPython display_jpeg #7135
[n3011, radarhere, nulano]
- Use "/sbin/ldconfig" if ldconfig is not found #7068
[radarhere]
- Prefer screenshots using XCB over gnome-screenshot #7143
[nulano, radarhere]
- Fixed joined corners for ImageDraw rounded_rectangle() odd dimensions #7151
[radarhere]
- Support reading signed 8-bit TIFF images #7111
[radarhere]
- Added width argument to ImageDraw regular_polygon #7132
[radarhere]
- Support I mode for ImageFilter.BuiltinFilter #7108
[radarhere]
- Raise error from stderr of Linux ImageGrab.grabclipboard() command #7112
[radarhere]
- Added unpacker from I;16B to I;16 #7125
[radarhere]
- Support float font sizes #7107
[radarhere]
- Use later value for duplicate xref entries in PdfParser #7102
[radarhere]
- Load before getting size in __getstate__ #7105
[bigcat88, radarhere]
- Fixed type handling for include and lib directories #7069
[adisbladis, radarhere]
- Remove deprecations for Pillow 10.0.0 #7059, #7080
[hugovk, radarhere]
- Drop support for soon-EOL Python 3.7 #7058
[hugovk, radarhere]
9.5.0 (2023-04-01)
------------------ ------------------
- Added ImageSourceData to TAGS_V2 #7053
[radarhere]
- Clear PPM half token after use #7052
[radarhere]
- Removed absolute path to ldconfig #7044
[radarhere]
- Support custom comments and PLT markers when saving JPEG2000 images #6903
[joshware, radarhere, hugovk]
- Load before getting size in __array_interface__ #7034
[radarhere]
- Support creating BGR;15, BGR;16 and BGR;24 images, but drop support for BGR;32 #7010
[radarhere]
- Consider transparency when applying APNG blend mask #7018
[radarhere]
- Round duration when saving animated WebP images #6996
[radarhere]
- Added reading of JPEG2000 comments #6909
[radarhere]
- Decrement reference count #7003
[radarhere, nulano]
- Allow libtiff_support_custom_tags to be missing #7020
[radarhere]
- Improved I;16N support #6834
[radarhere]
- Added QOI reading #6852
[radarhere, hugovk]
- Added saving RGBA images as PDFs #6925
[radarhere]
- Do not raise an error if os.environ does not contain PATH #6935
[radarhere, hugovk]
- Close OleFileIO instance when closing or exiting FPX or MIC #7005
[radarhere]
- Added __int__ to IFDRational for Python >= 3.11 #6998
[radarhere]
- Added memoryview support to Dib.frombytes() #6988
[radarhere, nulano]
- Close file pointer copy in the libtiff encoder if still open #6986
[fcarron, radarhere]
- Raise an error if ImageDraw co-ordinates are incorrectly ordered #6978
[radarhere]
- Added "corners" argument to ImageDraw rounded_rectangle() #6954
[radarhere]
- Added memoryview support to frombytes() #6974
[radarhere]
- Allow comments in FITS images #6973
[radarhere]
- Support saving PDF with different X and Y resolutions #6961
[jvanderneutstulen, radarhere, hugovk]
- Fixed writing int as UNDEFINED tag #6950
[radarhere]
- Raise an error if EXIF data is too long when saving JPEG #6939
[radarhere]
- Handle more than one directory returned by pkg-config #6896
[sebastic, radarhere]
- Do not retry past formats when loading all formats for the first time #6902
[radarhere]
- Do not retry specified formats if they failed when opening #6893
[radarhere]
- Do not unintentionally load TIFF format at first #6892
[radarhere]
- Stop reading when EPS line becomes too long #6897
[radarhere]
- Allow writing IFDRational to BYTE tag #6890
[radarhere]
- Raise ValueError for BoxBlur filter with negative radius #6874
[hugovk, radarhere]
- Support arbitrary number of loaded modules on Windows #6761
[javidcf, radarhere, nulano]
9.4.0 (2023-01-02)
------------------
- Fixed null pointer dereference crash with malformed font #6846
[wiredfool, radarhere]
- Return from ImagingFill early if image has a zero dimension #6842
[radarhere]
- Reversed deprecations for Image constants, except for duplicate Resampling attributes #6830
[radarhere]
- Improve exception traceback readability #6836
[hugovk, radarhere]
- Do not attempt to read IFD1 if absent #6840
[radarhere]
- Fixed writing int as ASCII tag #6800
[radarhere]
- If available, use wl-paste or xclip for grabclipboard() on Linux #6783
[radarhere]
- Added signed option when saving JPEG2000 images #6709
[radarhere]
- Patch OpenJPEG to include ARM64 fix #6718
[radarhere]
- Added support for I;16 modes in putdata() #6825
[radarhere]
- Added conversion from RGBa to RGB #6708
[radarhere]
- Added DDS support for uncompressed L and LA images #6820 - Added DDS support for uncompressed L and LA images #6820
[radarhere, REDxEYE] [radarhere, REDxEYE]
@ -1819,7 +2260,7 @@ Changelog (Pillow)
- Cache EXIF information #3498 - Cache EXIF information #3498
[Glandos] [Glandos]
- Added transparency for all PNG greyscale modes #3744 - Added transparency for all PNG grayscale modes #3744
[radarhere] [radarhere]
- Fix deprecation warnings in Python 3.8 #3749 - Fix deprecation warnings in Python 3.8 #3749
@ -4321,7 +4762,7 @@ Changelog (Pillow)
- Fix Bicubic interpolation #970 - Fix Bicubic interpolation #970
[homm] [homm]
- Support for 4-bit greyscale TIFF images #980 - Support for 4-bit grayscale TIFF images #980
[hugovk] [hugovk]
- Updated manifest #957 - Updated manifest #957
@ -5471,8 +5912,8 @@ http://svn.effbot.org/public/pil/
a polyline, independent of line angle. a polyline, independent of line angle.
- Fixed bearing calculation and clipping in the ImageFont truetype - Fixed bearing calculation and clipping in the ImageFont truetype
renderer; this could lead to clipped text, or crashes in the low- renderer; this could lead to clipped text, or crashes in the low-level
level _imagingft module. (based on input from Adam Twardoch and _imagingft module. (based on input from Adam Twardoch and
others). others).
- Added ImageQt wrapper module, for converting PIL Image objects to - Added ImageQt wrapper module, for converting PIL Image objects to
@ -5553,8 +5994,7 @@ http://svn.effbot.org/public/pil/
1.1.5c2 and 1.1.5 final 1.1.5c2 and 1.1.5 final
----------------------- -----------------------
- Added experimental PERSPECTIVE transform method (from Jeff Breiden- - Added experimental PERSPECTIVE transform method (from Jeff Breidenbach).
bach).
1.1.5c1 1.1.5c1
------- -------
@ -5626,8 +6066,8 @@ http://svn.effbot.org/public/pil/
- Fixed BILINEAR/BICUBIC/ANTIALIAS filtering for mode "LA". - Fixed BILINEAR/BICUBIC/ANTIALIAS filtering for mode "LA".
- Added "getcolors()" method. This is similar to the existing histo- - Added "getcolors()" method. This is similar to the existing histogram
gram method, but looks at color values instead of individual layers, method, but looks at color values instead of individual layers,
and returns an unsorted list of (count, color) tuples. and returns an unsorted list of (count, color) tuples.
By default, the method returns None if finds more than 256 colors. By default, the method returns None if finds more than 256 colors.
@ -5843,8 +6283,8 @@ http://svn.effbot.org/public/pil/
- Added limited support for "bitfield compression" in BMP files - Added limited support for "bitfield compression" in BMP files
and DIB buffers, for 15-bit, 16-bit, and 32-bit images. This and DIB buffers, for 15-bit, 16-bit, and 32-bit images. This
also fixes a problem with ImageGrab module when copying screen- also fixes a problem with ImageGrab module when copying screendumps
dumps from the clipboard on 15/16/32-bit displays. from the clipboard on 15/16/32-bit displays.
- Added experimental WAL (Quake 2 textures) loader. To use this - Added experimental WAL (Quake 2 textures) loader. To use this
loader, import WalImageFile and call the "open" method in that loader, import WalImageFile and call the "open" method in that
@ -5955,8 +6395,8 @@ http://svn.effbot.org/public/pil/
1.1.3 final 1.1.3 final
----------- -----------
- Made setup.py look for old versions of zlib. For some back- - Made setup.py look for old versions of zlib. For some background,
ground, see: https://zlib.net/advisory-2002-03-11.txt see: https://zlib.net/advisory-2002-03-11.txt
1.1.3c2 1.1.3c2
------- -------
@ -6147,8 +6587,8 @@ http://svn.effbot.org/public/pil/
supports all major PIL image modes (including F and I). supports all major PIL image modes (including F and I).
- The ImageFile module now includes a Parser class, which can - The ImageFile module now includes a Parser class, which can
be used to incrementally decode an image file (while down- be used to incrementally decode an image file (while downloading
loading it from the net, for example). See the handbook for it from the net, for example). See the handbook for
details. details.
- "show" now converts non-standard modes to "L" or "RGB" (as - "show" now converts non-standard modes to "L" or "RGB" (as
@ -6286,8 +6726,8 @@ http://svn.effbot.org/public/pil/
- The Image "transform" method now supports Image.QUAD transforms. - The Image "transform" method now supports Image.QUAD transforms.
The data argument is an 8-tuple giving the upper left, lower The data argument is an 8-tuple giving the upper left, lower
left, lower right, and upper right corner of the source quadri- left, lower right, and upper right corner of the source quadrilateral.
lateral. Also added Image.MESH transform which takes a list Also added Image.MESH transform which takes a list
of quadrilaterals. of quadrilaterals.
- The Image "resize", "rotate", and "transform" methods now support - The Image "resize", "rotate", and "transform" methods now support
@ -6397,7 +6837,7 @@ The test suite includes 750 individual tests.
- You can now convert directly between all modes supported by - You can now convert directly between all modes supported by
PIL. When converting colour images to "P", PIL defaults to PIL. When converting colour images to "P", PIL defaults to
a "web" palette and dithering. When converting greyscale a "web" palette and dithering. When converting grayscale
images to "1", PIL uses a thresholding and dithering. images to "1", PIL uses a thresholding and dithering.
- Added a "dither" option to "convert". By default, "convert" - Added a "dither" option to "convert". By default, "convert"
@ -6475,13 +6915,13 @@ The test suite includes 530 individual tests.
- Fixed "paste" to allow a mask also for mode "F" images. - Fixed "paste" to allow a mask also for mode "F" images.
- The BMP driver now saves mode "1" images. When loading images, the mode - The BMP driver now saves mode "1" images. When loading images, the mode
is set to "L" for 8-bit files with greyscale palettes, and to "P" for is set to "L" for 8-bit files with grayscale palettes, and to "P" for
other 8-bit files. other 8-bit files.
- The IM driver now reads and saves "1" images (file modes "0 1" or "L 1"). - The IM driver now reads and saves "1" images (file modes "0 1" or "L 1").
- The JPEG and GIF drivers now saves "1" images. For JPEG, the image - The JPEG and GIF drivers now saves "1" images. For JPEG, the image
is saved as 8-bit greyscale (it will load as mode "L"). For GIF, the is saved as 8-bit grayscale (it will load as mode "L"). For GIF, the
image will be loaded as a "P" image. image will be loaded as a "P" image.
- Fixed a potential buffer overrun in the GIF encoder. - Fixed a potential buffer overrun in the GIF encoder.
@ -6512,8 +6952,8 @@ The test suite includes 400 individual tests.
neither "short", "int" nor "long" are 32-bit wide. neither "short", "int" nor "long" are 32-bit wide.
- Added file= and data= keyword arguments to PhotoImage and BitmapImage. - Added file= and data= keyword arguments to PhotoImage and BitmapImage.
This allows you to use them as drop-in replacements for the corre- This allows you to use them as drop-in replacements for the corresponding
sponding Tkinter classes. Tkinter classes.
- Removed bogus references to the crack coder (ImagingCrack). - Removed bogus references to the crack coder (ImagingCrack).
@ -6785,7 +7225,7 @@ The test suite includes 400 individual tests.
drawing capabilities can be used to render vector and metafile drawing capabilities can be used to render vector and metafile
formats. formats.
- Added restricted drivers for images from Image Tools (greyscale - Added restricted drivers for images from Image Tools (grayscale
only) and LabEye/IFUNC (common interchange modes only). only) and LabEye/IFUNC (common interchange modes only).
- Some minor improvements to the sample scripts provided in the - Some minor improvements to the sample scripts provided in the

View File

@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is
Pillow is the friendly PIL fork. It is Pillow is the friendly PIL fork. It is
Copyright © 2010-2022 by Alex Clark and contributors Copyright © 2010-2023 by Jeffrey A. Clark (Alex) and contributors.
Like PIL, Pillow is licensed under the open source HPND License: Like PIL, Pillow is licensed under the open source HPND License:
@ -13,8 +13,8 @@ By obtaining, using, and/or copying this software and/or its associated
documentation, you agree that you have read, understood, and will comply documentation, you agree that you have read, understood, and will comply
with the following terms and conditions: with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its Permission to use, copy, modify and distribute this software and its
associated documentation for any purpose and without fee is hereby granted, documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appears in all copies, and that provided that the above copyright notice appears in all copies, and that
both that copyright notice and this permission notice appear in supporting both that copyright notice and this permission notice appear in supporting
documentation, and that the name of Secret Labs AB or the author not be documentation, and that the name of Secret Labs AB or the author not be

View File

@ -5,8 +5,10 @@ include *.md
include *.py include *.py
include *.rst include *.rst
include *.sh include *.sh
include *.toml
include *.txt include *.txt
include *.yaml include *.yaml
include .flake8
include LICENSE include LICENSE
include Makefile include Makefile
include tox.ini include tox.ini
@ -15,6 +17,7 @@ graft src
graft depends graft depends
graft winbuild graft winbuild
graft docs graft docs
graft _custom_build
# build/src control detritus # build/src control detritus
exclude .appveyor.yml exclude .appveyor.yml
@ -28,3 +31,4 @@ global-exclude .git*
global-exclude *.pyc global-exclude *.pyc
global-exclude *.so global-exclude *.so
prune .ci prune .ci
prune wheels

View File

@ -16,10 +16,16 @@ coverage:
python3 -m coverage report python3 -m coverage report
.PHONY: doc .PHONY: doc
doc: .PHONY: html
doc html:
python3 -c "import PIL" > /dev/null 2>&1 || python3 -m pip install . python3 -c "import PIL" > /dev/null 2>&1 || python3 -m pip install .
$(MAKE) -C docs html $(MAKE) -C docs html
.PHONY: htmlview
htmlview:
python3 -c "import PIL" > /dev/null 2>&1 || python3 -m pip install .
$(MAKE) -C docs htmlview
.PHONY: doccheck .PHONY: doccheck
doccheck: doccheck:
$(MAKE) doc $(MAKE) doc
@ -38,19 +44,15 @@ help:
@echo " coverage run coverage test (in progress)" @echo " coverage run coverage test (in progress)"
@echo " doc make HTML docs" @echo " doc make HTML docs"
@echo " docserve run an HTTP server on the docs directory" @echo " docserve run an HTTP server on the docs directory"
@echo " html to make standalone HTML files" @echo " html make HTML docs"
@echo " inplace make inplace extension" @echo " htmlview open the index page built by the html target in your browser"
@echo " install make and install" @echo " install make and install"
@echo " install-coverage make and install with C coverage" @echo " install-coverage make and install with C coverage"
@echo " lint run the lint checks" @echo " lint run the lint checks"
@echo " lint-fix run Black and isort to (mostly) fix lint issues" @echo " lint-fix run Ruff to (mostly) fix lint issues"
@echo " release-test run code and package tests before release" @echo " release-test run code and package tests before release"
@echo " test run tests on installed Pillow" @echo " test run tests on installed Pillow"
.PHONY: inplace
inplace: clean
python3 -m pip install -e --global-option="build_ext" --global-option="--inplace" .
.PHONY: install .PHONY: install
install: install:
python3 -m pip -v install . python3 -m pip -v install .
@ -58,7 +60,7 @@ install:
.PHONY: install-coverage .PHONY: install-coverage
install-coverage: install-coverage:
CFLAGS="-coverage -Werror=implicit-function-declaration" python3 -m pip -v install --global-option="build_ext" . CFLAGS="-coverage -Werror=implicit-function-declaration" python3 -m pip -v install .
python3 selftest.py python3 selftest.py
.PHONY: debug .PHONY: debug
@ -67,10 +69,11 @@ debug:
# for our stuff, kills optimization, and redirects to dev null so we # for our stuff, kills optimization, and redirects to dev null so we
# see any build failures. # see any build failures.
make clean > /dev/null make clean > /dev/null
CFLAGS='-g -O0' python3 -m pip -v install --global-option="build_ext" . > /dev/null CFLAGS='-g -O0' python3 -m pip -v install . > /dev/null
.PHONY: release-test .PHONY: release-test
release-test: release-test:
python3 Tests/check_release_notes.py
python3 -m pip install -e .[tests] python3 -m pip install -e .[tests]
python3 selftest.py python3 selftest.py
python3 -m pytest Tests python3 -m pytest Tests
@ -115,6 +118,6 @@ lint:
.PHONY: lint-fix .PHONY: lint-fix
lint-fix: lint-fix:
python3 -c "import black" > /dev/null 2>&1 || python3 -m pip install black python3 -c "import black" > /dev/null 2>&1 || python3 -m pip install black
python3 -c "import isort" > /dev/null 2>&1 || python3 -m pip install isort python3 -m black .
python3 -m black --target-version py37 . python3 -c "import ruff" > /dev/null 2>&1 || python3 -m pip install ruff
python3 -m isort . python3 -m ruff --fix .

View File

@ -6,8 +6,8 @@
## Python Imaging Library (Fork) ## Python Imaging Library (Fork)
Pillow is the friendly PIL fork by [Alex Clark and Pillow is the friendly PIL fork by [Jeffrey A. Clark (Alex) and
Contributors](https://github.com/python-pillow/Pillow/graphs/contributors). contributors](https://github.com/python-pillow/Pillow/graphs/contributors).
PIL is the Python Imaging Library by Fredrik Lundh and Contributors. PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
As of 2019, Pillow development is As of 2019, Pillow development is
[supported by Tidelift](https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise). [supported by Tidelift](https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise).
@ -45,12 +45,12 @@ As of 2019, Pillow development is
<a href="https://ci.appveyor.com/project/python-pillow/Pillow"><img <a href="https://ci.appveyor.com/project/python-pillow/Pillow"><img
alt="AppVeyor CI build status (Windows)" alt="AppVeyor CI build status (Windows)"
src="https://img.shields.io/appveyor/build/python-pillow/Pillow/main.svg?label=Windows%20build"></a> src="https://img.shields.io/appveyor/build/python-pillow/Pillow/main.svg?label=Windows%20build"></a>
<a href="https://github.com/python-pillow/pillow-wheels/actions"><img <a href="https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml"><img
alt="GitHub Actions wheels build status (Wheels)" alt="GitHub Actions build status (Wheels)"
src="https://github.com/python-pillow/pillow-wheels/workflows/Wheels/badge.svg"></a> src="https://github.com/python-pillow/Pillow/workflows/Wheels/badge.svg"></a>
<a href="https://app.travis-ci.com/github/python-pillow/pillow-wheels"><img <a href="https://app.travis-ci.com/github/python-pillow/Pillow"><img
alt="Travis CI wheels build status (aarch64)" alt="Travis CI wheels build status (aarch64)"
src="https://img.shields.io/travis/com/python-pillow/pillow-wheels/main.svg?label=aarch64%20wheels"></a> src="https://img.shields.io/travis/com/python-pillow/Pillow/main.svg?label=aarch64%20wheels"></a>
<a href="https://app.codecov.io/gh/python-pillow/Pillow"><img <a href="https://app.codecov.io/gh/python-pillow/Pillow"><img
alt="Code coverage" alt="Code coverage"
src="https://codecov.io/gh/python-pillow/Pillow/branch/main/graph/badge.svg"></a> src="https://codecov.io/gh/python-pillow/Pillow/branch/main/graph/badge.svg"></a>
@ -74,9 +74,9 @@ As of 2019, Pillow development is
<a href="https://pypi.org/project/Pillow/"><img <a href="https://pypi.org/project/Pillow/"><img
alt="Number of PyPI downloads" alt="Number of PyPI downloads"
src="https://img.shields.io/pypi/dm/pillow.svg"></a> src="https://img.shields.io/pypi/dm/pillow.svg"></a>
<a href="https://bestpractices.coreinfrastructure.org/projects/6331"><img <a href="https://www.bestpractices.dev/projects/6331"><img
alt="OpenSSF Best Practices" alt="OpenSSF Best Practices"
src="https://bestpractices.coreinfrastructure.org/projects/6331/badge"></a> src="https://www.bestpractices.dev/projects/6331/badge"></a>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -88,6 +88,10 @@ As of 2019, Pillow development is
<a href="https://twitter.com/PythonPillow"><img <a href="https://twitter.com/PythonPillow"><img
alt="Follow on https://twitter.com/PythonPillow" alt="Follow on https://twitter.com/PythonPillow"
src="https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg"></a> src="https://img.shields.io/badge/tweet-on%20Twitter-00aced.svg"></a>
<a href="https://fosstodon.org/@pillow"><img
alt="Follow on https://fosstodon.org/@pillow"
src="https://img.shields.io/badge/publish-on%20Mastodon-595aff.svg"
rel="me"></a>
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -10,30 +10,28 @@ 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 * [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/3154
* [ ] Develop and prepare release in `main` branch. * [ ] Develop and prepare release in `main` branch.
* [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions) and [AppVeyor](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in `main` branch. * [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions) and [AppVeyor](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in `main` branch.
* [ ] Check that all of the wheel builds [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels) pass the tests in Travis CI and GitHub Actions. * [ ] Check that all of the wheel builds pass the tests in the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml) and [Travis CI](https://app.travis-ci.com/github/python-pillow/pillow) jobs by manually triggering them.
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py` * [ ] In compliance with [PEP 440](https://peps.python.org/pep-0440/), update version identifier in `src/PIL/_version.py`
* [ ] Update `CHANGES.rst`. * [ ] Update `CHANGES.rst`.
* [ ] Run pre-release check via `make release-test` in a freshly cloned repo. * [ ] Run pre-release check via `make release-test` in a freshly cloned repo.
* [ ] Create branch and tag for release e.g.: * [ ] Create branch and tag for release e.g.:
```bash ```bash
git branch 5.2.x git branch 5.2.x
git tag 5.2.0 git tag 5.2.0
git push --all
git push --tags git push --tags
``` ```
* [ ] Create and check source distribution: * [ ] Create [source and binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#source-and-binary-distributions)
```bash * [ ] Check and upload all source and binary distributions e.g.:
make sdist
```
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#binary-distributions)
* [ ] Check and upload all binaries and source distributions e.g.:
```bash ```bash
python3 -m twine check --strict dist/* python3 -m twine check --strict dist/*
python3 -m twine upload dist/Pillow-5.2.0* python3 -m twine upload dist/Pillow-5.2.0*
``` ```
* [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) * [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases)
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), increment and append `.dev0` to version identifier in `src/PIL/_version.py` * [ ] 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 ## Point Release
Released as needed for security, installation or critical bug fixes. Released as needed for security, installation or critical bug fixes.
@ -45,29 +43,28 @@ Released as needed for security, installation or critical bug fixes.
git checkout -t remotes/origin/5.2.x git checkout -t remotes/origin/5.2.x
``` ```
* [ ] Cherry pick individual commits from `main` branch to release branch e.g. `5.2.x`, then `git push`. * [ ] Cherry pick individual commits from `main` branch to release branch e.g. `5.2.x`, then `git push`.
* [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions) and [AppVeyor](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in release branch e.g. `5.2.x`. * [ ] Check [GitHub Actions](https://github.com/python-pillow/Pillow/actions) and [AppVeyor](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in release branch e.g. `5.2.x`.
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py` * [ ] 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`. * [ ] Run pre-release check via `make release-test`.
* [ ] Create tag for release e.g.: * [ ] Create tag for release e.g.:
```bash ```bash
git tag 5.2.1 git tag 5.2.1
git push
git push --tags git push --tags
``` ```
* [ ] Create and check source distribution: * [ ] Create and check source distribution:
```bash ```bash
make sdist make sdist
``` ```
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#binary-distributions) * [ ] Create [source and binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#source-and-binary-distributions)
* [ ] Check and upload all binaries and source distributions e.g.: * [ ] Check and upload all source and binary distributions e.g.:
```bash ```bash
python3 -m twine check --strict dist/* python3 -m twine check --strict dist/*
python3 -m twine upload dist/Pillow-5.2.1* python3 -m twine upload dist/Pillow-5.2.1*
``` ```
* [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) * [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) and then:
```bash
git push
```
## Embargoed Release ## Embargoed Release
@ -83,35 +80,32 @@ Released as needed privately to individual vendors for critical security-related
```bash ```bash
git checkout 2.5.x git checkout 2.5.x
git tag 2.5.3 git tag 2.5.3
git push origin 2.5.x
git push origin --tags git push origin --tags
``` ```
* [ ] Create and check source distribution: * [ ] Create and check source distribution:
```bash ```bash
make sdist make sdist
``` ```
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#binary-distributions) * [ ] Create [source and binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#source-and-binary-distributions)
* [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) * [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) and then:
## Binary Distributions
### Windows
* [ ] Download the artifacts from the [GitHub Actions "Test Windows" workflow](https://github.com/python-pillow/Pillow/actions/workflows/test-windows.yml)
and copy into `dist/`
### Mac and Linux
* [ ] Use the [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels):
```bash ```bash
git clone https://github.com/python-pillow/pillow-wheels git push origin 2.5.x
cd pillow-wheels
./update-pillow-tag.sh [[release tag]]
``` ```
* [ ] Download wheels from the [Pillow Wheel Builder release](https://github.com/python-pillow/pillow-wheels/releases)
and copy into `dist/` ## Source and Binary Distributions
* [ ] Download sdist and wheels from the [GitHub Actions "Wheels" workflow](https://github.com/python-pillow/Pillow/actions/workflows/wheels.yml)
and copy into `dist/`. For example using [GitHub CLI](https://github.com/cli/cli):
```bash
gh run download --dir dist
# select dist
```
* [ ] Download the Linux aarch64 wheels created by Travis CI from [GitHub releases](https://github.com/python-pillow/Pillow/releases)
and copy into `dist`.
## Publicize Release ## Publicize Release
* [ ] Announce release availability via [Twitter](https://twitter.com/pythonpillow) e.g. https://twitter.com/PythonPillow/status/1013789184354603010 * [ ] Announce release availability via [Twitter](https://twitter.com/pythonpillow) and [Mastodon](https://fosstodon.org/@pillow) e.g. https://twitter.com/PythonPillow/status/1013789184354603010
## Documentation ## Documentation

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import annotations
import sys import sys

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import time import time
from PIL import PyAccess from PIL import PyAccess
@ -27,31 +28,25 @@ def timer(func, label, *args):
for x in range(iterations): for x in range(iterations):
func(*args) func(*args)
if time.time() - starttime > 10: if time.time() - starttime > 10:
print(
"{}: breaking at {} iterations, {:.6f} per iteration".format(
label, x + 1, (time.time() - starttime) / (x + 1.0)
)
)
break break
if x == iterations - 1: endtime = time.time()
endtime = time.time() print(
print( "{}: completed {} iterations in {:.4f}s, {:.6f}s per iteration".format(
"{}: {:.4f} s {:.6f} per iteration".format( label, x + 1, endtime - starttime, (endtime - starttime) / (x + 1.0)
label, endtime - starttime, (endtime - starttime) / (x + 1.0)
)
) )
)
def test_direct(): def test_direct():
im = hopper() im = hopper()
im.load() im.load()
# im = Image.new( "RGB", (2000, 2000), (1, 3, 2)) # im = Image.new("RGB", (2000, 2000), (1, 3, 2))
caccess = im.im.pixel_access(False) caccess = im.im.pixel_access(False)
access = PyAccess.new(im, False) access = PyAccess.new(im, False)
assert caccess[(0, 0)] == access[(0, 0)] assert caccess[(0, 0)] == access[(0, 0)]
print("Size: %sx%s" % im.size) print(f"Size: {im.width}x{im.height}")
timer(iterate_get, "PyAccess - get", im.size, access) timer(iterate_get, "PyAccess - get", im.size, access)
timer(iterate_set, "PyAccess - set", im.size, access) timer(iterate_set, "PyAccess - set", im.size, access)
timer(iterate_get, "C-api - get", im.size, caccess) timer(iterate_get, "C-api - get", im.size, caccess)

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import annotations
from PIL import Image from PIL import Image

View File

@ -1,10 +1,10 @@
from __future__ import annotations
from PIL import Image from PIL import Image
TEST_FILE = "Tests/images/fli_overflow.fli" TEST_FILE = "Tests/images/fli_overflow.fli"
def test_fli_overflow(): def test_fli_overflow():
# this should not crash with a malloc error or access violation # this should not crash with a malloc error or access violation
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()

View File

@ -1,5 +1,6 @@
# Tests potential DOS of IcnsImagePlugin with 0 length block. # Tests potential DOS of IcnsImagePlugin with 0 length block.
# Run from anywhere that PIL is importable. # Run from anywhere that PIL is importable.
from __future__ import annotations
from io import BytesIO from io import BytesIO

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import annotations
import pytest import pytest
from PIL import Image from PIL import Image

View File

@ -1,5 +1,6 @@
# Tests potential DOS of Jpeg2kImagePlugin with 0 length block. # Tests potential DOS of Jpeg2kImagePlugin with 0 length block.
# Run from anywhere that PIL is importable. # Run from anywhere that PIL is importable.
from __future__ import annotations
from io import BytesIO from io import BytesIO

1
Tests/check_j2k_leaks.py Executable file → Normal file
View File

@ -1,3 +1,4 @@
from __future__ import annotations
from io import BytesIO from io import BytesIO
import pytest import pytest

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import pytest import pytest
from PIL import Image from PIL import Image

View File

@ -12,6 +12,7 @@
# the output should be empty. There may be python issues # the output should be empty. There may be python issues
# in the valgrind especially if run in a debug python # in the valgrind especially if run in a debug python
# version. # version.
from __future__ import annotations
from PIL import Image from PIL import Image

View File

@ -1,3 +1,4 @@
from __future__ import annotations
from io import BytesIO from io import BytesIO
import pytest import pytest
@ -75,43 +76,42 @@ post-patch:
""" """
def test_qtables_leak(): standard_l_qtable = (
# fmt: off
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99,
# fmt: on
)
standard_chrominance_qtable = (
# fmt: off
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
# fmt: on
)
@pytest.mark.parametrize(
"qtables",
(
(standard_l_qtable, standard_chrominance_qtable),
[standard_l_qtable, standard_chrominance_qtable],
),
)
def test_qtables_leak(qtables):
im = hopper("RGB") im = hopper("RGB")
standard_l_qtable = [
int(s)
for s in """
16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99
""".split(
None
)
]
standard_chrominance_qtable = [
int(s)
for s in """
17 18 24 47 99 99 99 99
18 21 26 66 99 99 99 99
24 26 56 99 99 99 99 99
47 66 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
""".split(
None
)
]
qtables = [standard_l_qtable, standard_chrominance_qtable]
for _ in range(iterations): for _ in range(iterations):
test_output = BytesIO() test_output = BytesIO()
im.save(test_output, "JPEG", qtables=qtables) im.save(test_output, "JPEG", qtables=qtables)

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import sys import sys
import pytest import pytest

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import sys import sys
import pytest import pytest

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import pytest import pytest
from PIL import Image from PIL import Image

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import zlib import zlib
from io import BytesIO from io import BytesIO
@ -23,7 +24,6 @@ def test_ignore_dos_text():
def test_dos_text(): def test_dos_text():
try: try:
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()

View File

@ -0,0 +1,7 @@
from __future__ import annotations
import sys
from pathlib import Path
for rst in Path("docs/releasenotes").glob("[1-9]*.rst"):
if "TODO" in open(rst).read():
sys.exit(f"Error: remove TODO from {rst}")

42
Tests/check_wheel.py Normal file
View File

@ -0,0 +1,42 @@
from __future__ import annotations
import sys
from PIL import features
def test_wheel_modules():
expected_modules = {"pil", "tkinter", "freetype2", "littlecms2", "webp"}
# tkinter is not available in cibuildwheel installed CPython on Windows
try:
import tkinter
assert tkinter
except ImportError:
expected_modules.remove("tkinter")
assert set(features.get_supported_modules()) == expected_modules
def test_wheel_codecs():
expected_codecs = {"jpg", "jpg_2000", "zlib", "libtiff"}
assert set(features.get_supported_codecs()) == expected_codecs
def test_wheel_features():
expected_features = {
"webp_anim",
"webp_mux",
"transp_webp",
"raqm",
"fribidi",
"harfbuzz",
"libjpeg_turbo",
"xcb",
}
if sys.platform == "win32":
expected_features.remove("xcb")
assert set(features.get_supported_features()) == expected_features

View File

@ -1,3 +1,4 @@
from __future__ import annotations
import io import io

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import annotations
import base64 import base64
import os import os

Binary file not shown.

View File

@ -37,4 +37,4 @@ The Font Software may be sold as part of a larger software package but no copy o
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr. Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr.

Binary file not shown.

View File

@ -2,7 +2,6 @@
NotoNastaliqUrdu-Regular.ttf and NotoSansSymbols-Regular.ttf, from https://github.com/googlei18n/noto-fonts NotoNastaliqUrdu-Regular.ttf and NotoSansSymbols-Regular.ttf, from https://github.com/googlei18n/noto-fonts
NotoSans-Regular.ttf, from https://www.google.com/get/noto/ NotoSans-Regular.ttf, from https://www.google.com/get/noto/
NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/ NotoSansJP-Thin.otf, from https://www.google.com/get/noto/help/cjk/
NotoColorEmoji.ttf, from https://github.com/googlefonts/noto-emoji
AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype AdobeVFPrototype.ttf, from https://github.com/adobe-fonts/adobe-variable-font-prototype
TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny TINY5x3GX.ttf, from http://velvetyne.fr/fonts/tiny
ArefRuqaa-Regular.ttf, from https://github.com/google/fonts/tree/master/ofl/arefruqaa ArefRuqaa-Regular.ttf, from https://github.com/google/fonts/tree/master/ofl/arefruqaa
@ -25,3 +24,5 @@ FreeMono.ttf is licensed under GPLv3.
10x20-ISO8859-1.pcf, from https://packages.ubuntu.com/xenial/xfonts-base 10x20-ISO8859-1.pcf, from https://packages.ubuntu.com/xenial/xfonts-base
"Public domain font. Share and enjoy." "Public domain font. Share and enjoy."
CBDTTestFont.ttf and EBDTTestFont.ttf from https://github.com/nulano/font-tests are public domain.

Binary file not shown.

View File

@ -0,0 +1,10 @@
STARTFONT
FONT ÿ
SIZE 10
FONTBOUNDINGBOX
CHARS
STARTCHAR
ENCODING
BBX 2 5
ENDCHAR
ENDFONT

View File

@ -1,10 +1,12 @@
""" """
Helper functions. Helper functions.
""" """
from __future__ import annotations
import logging import logging
import os import os
import shutil import shutil
import subprocess
import sys import sys
import sysconfig import sysconfig
import tempfile import tempfile
@ -20,7 +22,7 @@ logger = logging.getLogger(__name__)
HAS_UPLOADER = False HAS_UPLOADER = False
if os.environ.get("SHOW_ERRORS", None): if os.environ.get("SHOW_ERRORS"):
# local img.show for errors. # local img.show for errors.
HAS_UPLOADER = True HAS_UPLOADER = True
@ -91,11 +93,11 @@ def assert_image_equal(a, b, msg=None):
if HAS_UPLOADER: if HAS_UPLOADER:
try: try:
url = test_image_results.upload(a, b) url = test_image_results.upload(a, b)
logger.error(f"Url for test images: {url}") logger.error("URL for test images: %s", url)
except Exception: except Exception:
pass pass
assert False, msg or "got different content" pytest.fail(msg or "got different content")
def assert_image_equal_tofile(a, filename, msg=None, mode=None): def assert_image_equal_tofile(a, filename, msg=None, mode=None):
@ -126,7 +128,7 @@ def assert_image_similar(a, b, epsilon, msg=None):
if HAS_UPLOADER: if HAS_UPLOADER:
try: try:
url = test_image_results.upload(a, b) url = test_image_results.upload(a, b)
logger.error(f"Url for test images: {url}") logger.exception("URL for test images: %s", url)
except Exception: except Exception:
pass pass
raise e raise e
@ -258,11 +260,21 @@ def hopper(mode=None, cache={}):
def djpeg_available(): def djpeg_available():
return bool(shutil.which("djpeg")) if shutil.which("djpeg"):
try:
subprocess.check_call(["djpeg", "-version"])
return True
except subprocess.CalledProcessError: # pragma: no cover
return False
def cjpeg_available(): def cjpeg_available():
return bool(shutil.which("cjpeg")) if shutil.which("cjpeg"):
try:
subprocess.check_call(["cjpeg", "-version"])
return True
except subprocess.CalledProcessError: # pragma: no cover
return False
def netpbm_available(): def netpbm_available():
@ -271,7 +283,7 @@ def netpbm_available():
def magick_command(): def magick_command():
if sys.platform == "win32": if sys.platform == "win32":
magickhome = os.environ.get("MAGICK_HOME", "") magickhome = os.environ.get("MAGICK_HOME")
if magickhome: if magickhome:
imagemagick = [os.path.join(magickhome, "convert.exe")] imagemagick = [os.path.join(magickhome, "convert.exe")]
graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"] graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"]

View File

@ -22,4 +22,3 @@ and that the name of ICC shall not be used in advertising or publicity
pertaining to distribution of the software without specific, written pertaining to distribution of the software without specific, written
prior permission. ICC makes no representations about the suitability prior permission. ICC makes no representations about the suitability
of this software for any purpose. of this software for any purpose.

BIN
Tests/images/8bit.s.tif Normal file

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 331 B

View File

Before

Width:  |  Height:  |  Size: 668 B

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

BIN
Tests/images/bc1.dds Executable file

Binary file not shown.

BIN
Tests/images/bc1_typeless.dds Executable file

Binary file not shown.

Binary file not shown.

BIN
Tests/images/bc4_unorm.dds Normal file

Binary file not shown.

BIN
Tests/images/bc4_unorm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

BIN
Tests/images/bc4u.dds Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 95 KiB

BIN
Tests/images/bc5u.dds Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

BIN
Tests/images/cbdt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

BIN
Tests/images/cbdt_mask.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

BIN
Tests/images/comment.jp2 Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Binary file not shown.

BIN
Tests/images/hopper.qoi Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Some files were not shown because too many files have changed in this diff Show More