diff --git a/.appveyor.yml b/.appveyor.yml index f86500b4848..1cca224ab3f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,8 +25,8 @@ install: - mv c:\pillow-depends-main c:\pillow-depends - xcopy /S /Y c:\pillow-depends\test_images\* c:\pillow\tests\images - 7z x ..\pillow-depends\nasm-2.15.05-win64.zip -oc:\ -- ..\pillow-depends\gs9550w32.exe /S -- path c:\nasm-2.15.05;C:\Program Files (x86)\gs\gs9.55.0\bin;%PATH% +- ..\pillow-depends\gs9561w32.exe /S +- path c:\nasm-2.15.05;C:\Program Files (x86)\gs\gs9.56.1\bin;%PATH% - cd c:\pillow\winbuild\ - ps: | c:\python37\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\ @@ -43,7 +43,7 @@ build_script: test_script: - cd c:\pillow -- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov' +- '%PYTHON%\%EXECUTABLE% -m pip install pytest pytest-cov pytest-timeout' - c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE% - '%PYTHON%\%EXECUTABLE% -c "from PIL import Image"' - '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests' diff --git a/.ci/after_success.sh b/.ci/after_success.sh index 53832c573dd..23a6fcd4d45 100755 --- a/.ci/after_success.sh +++ b/.ci/after_success.sh @@ -3,7 +3,7 @@ # gather the coverage data python3 -m pip install codecov if [[ $MATRIX_DOCKER ]]; then - coverage xml --ignore-errors + python3 -m coverage xml --ignore-errors else - coverage xml + python3 -m coverage xml fi diff --git a/.ci/build.sh b/.ci/build.sh index a2e3041bd27..e678f68ec85 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -2,7 +2,7 @@ set -e -coverage erase +python3 -m coverage erase if [ $(uname) == "Darwin" ]; then export CPPFLAGS="-I/usr/local/miniconda/include"; fi diff --git a/.ci/install.sh b/.ci/install.sh index efc57a6414a..c588af42ffa 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -13,13 +13,17 @@ aptget_update() return 1 fi } -aptget_update || aptget_update retry || aptget_update retry +if [[ $(uname) != CYGWIN* ]]; then + aptget_update || aptget_update retry || aptget_update retry +fi set -e -sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ - ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\ - cmake meson imagemagick libharfbuzz-dev libfribidi-dev +if [[ $(uname) != CYGWIN* ]]; then + sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ + ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\ + cmake meson imagemagick libharfbuzz-dev libfribidi-dev +fi python3 -m pip install --upgrade pip python3 -m pip install --upgrade wheel @@ -32,24 +36,28 @@ python3 -m pip install -U pytest-cov python3 -m pip install -U pytest-timeout python3 -m pip install pyroma python3 -m pip install test-image-results -python3 -m pip install numpy - -# PyQt5 doesn't support PyPy3 -if [[ $GHA_PYTHON_VERSION == 3.* ]]; then - # arm64, ppc64le, s390x CPUs: - # "ERROR: Could not find a version that satisfies the requirement pyqt5" - sudo apt-get -qq install libxcb-xinerama0 pyqt5-dev-tools - python3 -m pip install pyqt5 -fi -# webp -pushd depends && ./install_webp.sh && popd +if [[ $(uname) != CYGWIN* ]]; then + # TODO Remove condition when NumPy supports 3.11 + if ! [ "$GHA_PYTHON_VERSION" == "3.11-dev" ]; then python3 -m pip install numpy ; fi -# libimagequant -pushd depends && ./install_imagequant.sh && popd + # PyQt6 doesn't support PyPy3 + if [[ $GHA_PYTHON_VERSION == 3.* ]]; then + sudo apt-get -qq install libegl1 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxkbcommon-x11-0 + python3 -m pip install pyqt6 + fi -# raqm -pushd depends && ./install_raqm.sh && popd + # webp + pushd depends && ./install_webp.sh && popd -# extra test images -pushd depends && ./install_extra_test_images.sh && popd + # libimagequant + pushd depends && ./install_imagequant.sh && popd + + # raqm + pushd depends && ./install_raqm.sh && popd + + # extra test images + pushd depends && ./install_extra_test_images.sh && popd +else + cd depends && ./install_extra_test_images.sh && cd .. +fi diff --git a/.editorconfig b/.editorconfig index 798ab753c77..d74549fe2ac 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,7 +16,6 @@ trim_trailing_whitespace = true [*.yml] # Two-space indentation indent_size = 2 -indent_style = space # Tab indentation (no size specified) [Makefile] diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index bc958774497..ba2b7d8ed26 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -4,7 +4,7 @@ Bug fixes, feature additions, tests, documentation and more can be contributed v ## Bug fixes, feature additions, etc. -Please send a pull request to the `main` branch. Please include [documentation](https://pillow.readthedocs.io) and [tests](../Tests/README.rst) for new features. Tests or documentation without bug fixes or feature additions are welcome too. Feel free to ask questions [via issues](https://github.com/python-pillow/Pillow/issues/new), [Gitter](https://gitter.im/python-pillow/Pillow) or irc://irc.freenode.net#pil +Please send a pull request to the `main` branch. Please include [documentation](https://pillow.readthedocs.io) and [tests](../Tests/README.rst) for new features. Tests or documentation without bug fixes or feature additions are welcome too. Feel free to ask questions [via issues](https://github.com/python-pillow/Pillow/issues/new), [discussions](https://github.com/python-pillow/Pillow/discussions/new), [Gitter](https://gitter.im/python-pillow/Pillow) or irc://irc.freenode.net#pil - Fork the Pillow repository. - Create a branch from `main`. diff --git a/.github/mergify.yml b/.github/mergify.yml index 8b289bda671..8dfa07f4ec5 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -8,6 +8,7 @@ pull_request_rules: - status-success=Docker Test Successful - status-success=Windows Test Successful - status-success=MinGW Test Successful + - status-success=Cygwin Test Successful - status-success=continuous-integration/appveyor/pr actions: merge: diff --git a/.github/workflows/macos-install.sh b/.github/workflows/macos-install.sh index 8260cf8d8d3..06b82964559 100755 --- a/.github/workflows/macos-install.sh +++ b/.github/workflows/macos-install.sh @@ -15,7 +15,8 @@ python3 -m pip install pyroma python3 -m pip install test-image-results echo -e "[openblas]\nlibraries = openblas\nlibrary_dirs = /usr/local/opt/openblas/lib" >> ~/.numpy-site.cfg -python3 -m pip install numpy +# TODO Remove condition when NumPy supports 3.11 +if ! [ "$GHA_PYTHON_VERSION" == "3.11-dev" ]; then python3 -m pip install numpy ; fi # extra test images pushd depends && ./install_extra_test_images.sh && popd diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000000..cc5e0d488ab --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,27 @@ +name: Close stale issues + +on: + schedule: + - cron: "10 0 * * *" + workflow_dispatch: + +permissions: + issues: write + +jobs: + stale: + if: github.repository_owner == 'python-pillow' + + runs-on: ubuntu-latest + + steps: + - name: "Check issues" + uses: actions/stale@v5 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + only-labels: "Awaiting OP Action" + close-issue-message: "Closing this issue as no feedback has been received." + days-before-stale: 7 + days-before-issue-close: 0 + days-before-pr-close: -1 + labels-to-remove-when-unstale: "Awaiting OP Action" diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml new file mode 100644 index 00000000000..2e8fc9c09f0 --- /dev/null +++ b/.github/workflows/test-cygwin.yml @@ -0,0 +1,107 @@ +name: Test Cygwin + +on: [push, pull_request, workflow_dispatch] + +jobs: + build: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python-minor-version: [7, 8, 9] + + timeout-minutes: 40 + + name: Python 3.${{ matrix.python-minor-version }} + + steps: + - name: Fix line endings + run: | + git config --global core.autocrlf input + + - name: Checkout Pillow + uses: actions/checkout@v3 + + - name: Install Cygwin + uses: cygwin/cygwin-install-action@v2 + with: + platform: x86_64 + packages: > + ImageMagick gcc-g++ ghostscript jpeg 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 }}-cython + python3${{ matrix.python-minor-version }}-devel + python3${{ matrix.python-minor-version }}-numpy + python3${{ matrix.python-minor-version }}-sip + python3${{ matrix.python-minor-version }}-tkinter + qt5-devel-tools subversion xorg-server-extra zlib-devel + + - name: Add Lapack to PATH + uses: egor-tensin/cleanup-path@v1 + with: + dirs: 'C:\cygwin\bin;C:\cygwin\lib\lapack' + + - name: pip cache + uses: actions/cache@v3 + with: + path: 'C:\cygwin\home\runneradmin\.cache\pip' + key: ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-${{ hashFiles('.ci/install.sh') }} + restore-keys: | + ${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}- + + - name: Build system information + run: | + dash.exe -c "python3 .github/workflows/system-info.py" + + - name: Install dependencies + run: | + bash.exe .ci/install.sh + + - name: Install a different NumPy + shell: dash.exe -l "{0}" + run: | + python3 -m pip install -U 'numpy!=1.21.*' + + - name: Build + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + .ci/build.sh + + - name: Test + run: | + bash.exe xvfb-run -s '-screen 0 1024x768x24' .ci/test.sh + + - name: Prepare to upload errors + if: failure() + run: | + dash.exe -c "mkdir -p Tests/errors" + + - name: Upload errors + uses: actions/upload-artifact@v3 + if: failure() + with: + name: errors + path: Tests/errors + + - name: After success + run: | + bash.exe .ci/after_success.sh + + - name: Upload coverage + uses: codecov/codecov-action@v3 + with: + file: ./coverage.xml + flags: GHA_Cygwin + name: Cygwin Python 3.${{ matrix.python-minor-version }} + + success: + needs: build + runs-on: ubuntu-latest + name: Cygwin Test Successful + steps: + - name: Success + run: echo Cygwin Test Successful diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index f583eae1087..2b4dc6b5232 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -11,9 +11,9 @@ jobs: matrix: docker: [ # Run slower jobs first to give them a headstart and reduce waiting time - ubuntu-20.04-focal-arm64v8, - ubuntu-20.04-focal-ppc64le, - ubuntu-20.04-focal-s390x, + ubuntu-22.04-jammy-arm64v8, + ubuntu-22.04-jammy-ppc64le, + ubuntu-22.04-jammy-s390x, # Then run the remainder alpine, amazon-2-amd64, @@ -23,19 +23,20 @@ jobs: centos-stream-9-amd64, debian-10-buster-x86, debian-11-bullseye-x86, - fedora-34-amd64, fedora-35-amd64, + fedora-36-amd64, gentoo, ubuntu-18.04-bionic-amd64, ubuntu-20.04-focal-amd64, + ubuntu-22.04-jammy-amd64, ] dockerTag: [main] include: - - docker: "ubuntu-20.04-focal-arm64v8" + - docker: "ubuntu-22.04-jammy-arm64v8" qemu-arch: "aarch64" - - docker: "ubuntu-20.04-focal-ppc64le" + - docker: "ubuntu-22.04-jammy-ppc64le" qemu-arch: "ppc64le" - - docker: "ubuntu-20.04-focal-s390x" + - docker: "ubuntu-22.04-jammy-s390x" qemu-arch: "s390x" name: ${{ matrix.docker }} diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 64289cc3aae..358461b388b 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"] architecture: ["x86", "x64"] include: # PyPy 7.3.4+ only ships 64-bit binaries for Windows @@ -41,10 +41,10 @@ jobs: cache-dependency-path: ".github/workflows/test-windows.yml" - name: Print build system information - run: python .github/workflows/system-info.py + run: python3 .github/workflows/system-info.py - - name: python -m pip install wheel pytest pytest-cov pytest-timeout defusedxml - run: python -m pip install wheel pytest pytest-cov pytest-timeout defusedxml + - name: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml + run: python3 -m pip install wheel pytest pytest-cov pytest-timeout defusedxml - name: Install dependencies id: install @@ -52,8 +52,8 @@ jobs: 7z x winbuild\depends\nasm-2.15.05-win64.zip "-o$env:RUNNER_WORKSPACE\" echo "$env:RUNNER_WORKSPACE\nasm-2.15.05" >> $env:GITHUB_PATH - winbuild\depends\gs9550w32.exe /S - echo "C:\Program Files (x86)\gs\gs9.55.0\bin" >> $env:GITHUB_PATH + winbuild\depends\gs9561w32.exe /S + echo "C:\Program Files (x86)\gs\gs9.56.1\bin" >> $env:GITHUB_PATH xcopy /S /Y winbuild\depends\test_images\* Tests\images\ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fef442cfd4f..d41f4b57196 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,6 +15,7 @@ jobs: python-version: [ "pypy-3.8", "pypy-3.7", + "3.11-dev", "3.10", "3.9", "3.8", @@ -59,6 +60,8 @@ jobs: if: startsWith(matrix.os, 'macOS') run: | .github/workflows/macos-install.sh + env: + GHA_PYTHON_VERSION: ${{ matrix.python-version }} - name: Build run: | @@ -93,7 +96,7 @@ jobs: - name: Docs if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.10 run: | - python3 -m pip install sphinx-copybutton sphinx-issues sphinx-removed-in sphinx-rtd-theme sphinxext-opengraph + python3 -m pip install furo sphinx-copybutton sphinx-issues sphinx-removed-in sphinxext-opengraph make doccheck - name: After success diff --git a/.github/workflows/tidelift.yml b/.github/workflows/tidelift.yml index 2e8c9b73012..9a3192f9d7d 100644 --- a/.github/workflows/tidelift.yml +++ b/.github/workflows/tidelift.yml @@ -4,9 +4,11 @@ on: - cron: "30 2 * * *" # daily at 02:30 UTC push: paths: + - "Pipfile*" - ".github/workflows/tidelift.yml" pull_request: paths: + - "Pipfile*" - ".github/workflows/tidelift.yml" workflow_dispatch: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b546505656a..1806db54cdb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/psf/black - rev: fc0be6eb1e2a96091e6f64009ee5e9081bf8b6c6 # frozen: 22.1.0 + rev: 22.3.0 hooks: - id: black args: ["--target-version", "py37"] @@ -9,38 +9,43 @@ repos: types: [] - repo: https://github.com/PyCQA/isort - rev: c5e8fa75dda5f764d20f66a215d71c21cfa198e1 # frozen: 5.10.1 + rev: 5.10.1 hooks: - id: isort - repo: https://github.com/asottile/yesqa - rev: 35cf7dc24fa922927caded7a21b2a8cb04bf8e10 # frozen: v1.3.0 + rev: v1.3.0 hooks: - id: yesqa - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: ca52c4245639abd55c970e6bbbca95cab3de22d8 # frozen: v1.1.13 + rev: v1.2.0 hooks: - id: remove-tabs exclude: (Makefile$|\.bat$|\.cmake$|\.eps$|\.fits$|\.opt$) - repo: https://github.com/PyCQA/flake8 - rev: cbeb4c9c4137cff1568659fcc48e8b85cddd0c8d # frozen: 4.0.1 + rev: 4.0.1 hooks: - id: flake8 additional_dependencies: [flake8-2020, flake8-implicit-str-concat] - repo: https://github.com/pre-commit/pygrep-hooks - rev: 6f51a66bba59954917140ec2eeeaa4d5e630e6ce # frozen: v1.9.0 + rev: v1.9.0 hooks: - id: python-check-blanket-noqa - id: rst-backticks - repo: https://github.com/pre-commit/pre-commit-hooks - rev: 8fe62d14e0b4d7d845a7022c5c2c3ae41bdd3f26 # frozen: v4.1.0 + rev: v4.2.0 hooks: - id: check-merge-conflict - id: check-yaml + - repo: https://github.com/sphinx-contrib/sphinx-lint + rev: v0.6 + hooks: + - id: sphinx-lint + ci: - autoupdate_schedule: quarterly + autoupdate_schedule: monthly diff --git a/CHANGES.rst b/CHANGES.rst index 904a61ce1c5..7f998cea184 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,9 +2,183 @@ Changelog (Pillow) ================== -9.1.0 (unreleased) +9.2.0 (unreleased) ------------------ +- Added apply_transparency() #6352 + [radarhere] + +- Fixed behaviour change from endian fix #6197 + [radarhere] + +- Allow remapping P images with RGBA palettes #6350 + [radarhere] + +- Fixed drawing translucent 1px high polygons #6278 + [radarhere] + +- Pad COLORMAP to 768 items when saving TIFF #6232 + [radarhere] + +- Fix P -> PA conversion #6337 + [RedShy, radarhere] + +- Once exif data is parsed, do not reload unless it changes #6335 + [radarhere] + +- Only try to connect discontiguous corners at the end of edges #6303 + [radarhere] + +- Improve transparency handling when saving GIF images #6176 + [radarhere] + +- Do not update GIF frame position until local image is found #6219 + [radarhere] + +- Netscape GIF extension belongs after the global color table #6211 + [radarhere] + +- Only write GIF comments at the beginning of the file #6300 + [raygard, radarhere] + +- Separate multiple GIF comment blocks with newlines #6294 + [raygard, radarhere] + +- Always use GIF89a for comments #6292 + [raygard, radarhere] + +- Ignore compression value from BMP info dictionary when saving as TIFF #6231 + [radarhere] + +- If font is file-like object, do not re-read from object to get variant #6234 + [radarhere] + +- Raise ValueError when trying to access internal fp after close #6213 + [radarhere] + +- Support more affine expression forms in im.point() #6254 + [benrg, radarhere] + +- Populate Python palette in fromarray() #6283 + [radarhere] + +- Raise ValueError if PNG chunks are truncated #6253 + [radarhere] + +- Use durations from each frame by default when saving GIFs #6265 + [radarhere] + +- Adjust BITSPERSAMPLE to match SAMPLESPERPIXEL when opening TIFFs #6270 + [radarhere] + +- Search pkgconf system libs/cflags #6138 + [jameshilliard, radarhere] + +- Raise ValueError for invalid PPM maxval #6242 + [radarhere] + +- Corrected screencapture argument in ImageGrab.grab() #6244 + [axt-one] + +- Deprecate support for Qt 5 (PyQt5 and PySide2) #6237 + [hugovk, radarhere] + +- Increase wait time of temporary file deletion on Windows #6224 + [AlexTedeschi] + +- Deprecate FreeTypeFont.getmask2 fill parameter #6220 + [nulano, radarhere, hugovk] + +- Round lut values where necessary #6188 + [radarhere] + +- Load before getting size in resize() #6190 + [radarhere] + +- Load image before performing size calculations in thumbnail() #6186 + [radarhere] + +- Deprecated PhotoImage.paste() box parameter #6178 + [radarhere] + +9.1.1 (2022-05-17) +------------------ + +- When reading past the end of a TGA scan line, reduce bytes left. CVE-2022-30595 + [radarhere] + +- Do not open images with zero or negative height #6269 + [radarhere] + +9.1.0 (2022-04-01) +------------------ + +- Add support for multiple component transformation to JPEG2000 #5500 + [scaramallion, radarhere, hugovk] + +- Fix loading FriBiDi on Alpine #6165 + [nulano] + +- Added setting for converting GIF P frames to RGB #6150 + [radarhere] + +- Allow 1 mode images to be inverted #6034 + [radarhere] + +- Raise ValueError when trying to save empty JPEG #6159 + [radarhere] + +- Always save TIFF with contiguous planar configuration #5973 + [radarhere] + +- Connected discontiguous polygon corners #5980 + [radarhere] + +- Ensure Tkinter hook is activated for getimage() #6032 + [radarhere] + +- Use screencapture arguments to crop on macOS #6152 + [radarhere] + +- Do not mark L mode JPEG as 1 bit in PDF #6151 + [radarhere] + +- Added support for reading I;16R TIFF images #6132 + [radarhere] + +- If an error occurs after creating a file, remove the file #6134 + [radarhere] + +- Fixed calling DisplayViewer or XVViewer without a title #6136 + [radarhere] + +- Retain RGBA transparency when saving multiple GIF frames #6128 + [radarhere] + +- Save additional ICO frames with other bit depths if supplied #6122 + [radarhere] + +- Handle EXIF data truncated to just the header #6124 + [radarhere] + +- Added support for reading BMP images with RLE8 compression #6102 + [radarhere] + +- Support Python distributions where _tkinter is compiled in #6006 + [lukegb] + +- Added support for PPM arbitrary maxval #6119 + [radarhere] + +- Added BigTIFF reading #6097 + [radarhere] + +- When converting, clip I;16 to be unsigned, not signed #6112 + [radarhere] + +- Fixed loading L mode GIF with transparency #6086 + [radarhere] + - Improved handling of PPM header #5121 [Piolie, radarhere] @@ -3068,7 +3242,7 @@ Changelog (Pillow) - Change function declaration to match Tcl_CmdProc type #1966 [homm] -- Integer overflow checks on all calls to *alloc #1781 +- Integer overflow checks on all calls to \*alloc #1781 [wiredfool] - Change equals method on Image so it short circuits #1967 @@ -4704,10 +4878,10 @@ Changelog (Pillow) [aclark4life] Pre-fork --------- +======== 0.2b5-1.1.7 -+++++++++++ +----------- :: @@ -4741,1740 +4915,1787 @@ Pre-fork Ka-Ping Yee, and many others (if your name should be on this list, let me know.) - *** Changes from release 1.1.6 to 1.1.7 *** - - This section may not be fully complete. For changes since this file - was last updated, see the repository revision history: - - http://svn.effbot.org/public/pil/ - - (1.1.7 final) - - + Set GIF loop info property to the number of iterations if a NETSCAPE - loop extension is present, instead of always setting it to 1 (from - Valentino Volonghi). - - (1.1.7c1 released) - - + Improved PNG compression (from Alexey Borzenkov). - - + Read interlaced PNG files (from Conrado Porto Lopes Gouvêa) - - + Added various TGA improvements from Alexey Borzenkov, including - support for specifying image orientation. - - + Bumped block threshold to 16 megabytes, made size estimation a bit - more accurate. This speeds up allocation of large images. - - + Fixed rounding error in ImagingDrawWideLine. - - "gormish" writes: ImagingDrawWideLine() in Draw.c has a bug in every - version I've seen, which leads to different width lines depending on - the order of the points in the line. This is especially bad at some - angles where a 'width=2' line can completely disappear. - - + Added support for RGBA mode to the SGI module (based on code by - Karsten Hiddemann). - - + Handle repeated IPTC tags (adapted from a patch by Eric Bruning). +1.1.6 to 1.1.7 +-------------- - Eric writes: According to the specification, some IPTC tags can be - repeated, e.g., tag 2:25 (keywords). PIL 1.1.6 only retained the last - instance of that tag. Below is a patch to store all tags. If there are - multiple tag instances, they are stored in a (python) list. Single tag - instances remain as strings. +This section may not be fully complete. For changes since this file +was last updated, see the repository revision history: +http://svn.effbot.org/public/pil/ - + Fixed potential crash in ImageFilter for small target images - (reported by Zac Burns and Daniel Fetchinson). +1.1.7 final +----------- - + Use BMP instead of JPEG as temporary show format on Mac OS X. +- Set GIF loop info property to the number of iterations if a NETSCAPE + loop extension is present, instead of always setting it to 1 (from + Valentino Volonghi). - + Fixed putpixel/new for I;16 with colors > 255. +1.1.7c1 +------- - + Added integer power support to ImagingMath. +- Improved PNG compression (from Alexey Borzenkov). - + Added limited support for I;16L mode (explicit little endian). +- Read interlaced PNG files (from Conrado Porto Lopes Gouvêa) - + Moved WMF support into Image.core; enable WMF rendering by default - if renderer is available. +- Added various TGA improvements from Alexey Borzenkov, including + support for specifying image orientation. - + Mark the ARG plugin as obsolete. +- Bumped block threshold to 16 megabytes, made size estimation a bit + more accurate. This speeds up allocation of large images. - + Added version query mechanism to ImageCms and ImageFont, for - debugging. +- Fixed rounding error in ImagingDrawWideLine. - + Added (experimental) ImageCms function for fetching the ICC profile - for the current display (currently Windows only). + "gormish" writes: ImagingDrawWideLine() in Draw.c has a bug in every + version I've seen, which leads to different width lines depending on + the order of the points in the line. This is especially bad at some + angles where a 'width=2' line can completely disappear. - Added HWND/HDC support to ImageCms.get_display_profile(). +- Added support for RGBA mode to the SGI module (based on code by + Karsten Hiddemann). - + Added WMF renderer (Windows only). +- Handle repeated IPTC tags (adapted from a patch by Eric Bruning). - + Added ImagePointHandler and ImageTransformHandler mixins; made - ImageCmsTransform work with im.point. + Eric writes: According to the specification, some IPTC tags can be + repeated, e.g., tag 2:25 (keywords). PIL 1.1.6 only retained the last + instance of that tag. Below is a patch to store all tags. If there are + multiple tag instances, they are stored in a (python) list. Single tag + instances remain as strings. - + Fixed potential endless loop in the XVThumbnail reader (from Nikolai - Ugelvik). +- Fixed potential crash in ImageFilter for small target images + (reported by Zac Burns and Daniel Fetchinson). - + Added Kevin Cazabon's pyCMS package. +- Use BMP instead of JPEG as temporary show format on Mac OS X. - The C code has been moved to _imagingcms.c, the Python interface - module is installed as PIL.ImageCMS. +- Fixed putpixel/new for I;16 with colors > 255. - Added support for in-memory ICC profiles. +- Added integer power support to ImagingMath. - Unified buildTransform and buildTransformFromOpenProfiles. +- Added limited support for I;16L mode (explicit little endian). - The profile can now be either a filename, a profile object, or a - file-like object containing an in-memory profile. +- Moved WMF support into Image.core; enable WMF rendering by default + if renderer is available. - Additional fixes from Florian Böch: +- Mark the ARG plugin as obsolete. - Very nice - it just needs LCMS flags support so we can use black - point compensation and softproofing :) See attached patches. They - also fix a naming issue which could cause confusion - display - profile (ImageCms wording) actually means proof profile (lcms - wording), so I changed variable names and docstrings where - applicable. Patches are tested under Python 2.6. +- Added version query mechanism to ImageCms and ImageFont, for + debugging. - + Improved support for layer names in PSD files (from Sylvain Baubeau) +- Added (experimental) ImageCms function for fetching the ICC profile + for the current display (currently Windows only). - Sylvain writes: I needed to be able to retrieve the names of the - layers in a PSD files. But PsdImagePlugin.py didn't do the job so I - wrote this very small patch. + Added HWND/HDC support to ImageCms.get_display_profile(). - + Improved RGBA support for ImageTk for 8.4 and newer (from Con - Radchenko). +- Added WMF renderer (Windows only). - This replaces the slow run-length based encoding model with true - compositing at the Tk level. +- Added ImagePointHandler and ImageTransformHandler mixins; made + ImageCmsTransform work with im.point. - + Added support for 16- and 32-bit images to McIdas loader. +- Fixed potential endless loop in the XVThumbnail reader (from Nikolai + Ugelvik). - Based on file samples and stand-alone reader code provided by Craig - Swank. +- Added Kevin Cazabon's pyCMS package. - + Added ImagePalette support to putpalette. + The C code has been moved to _imagingcms.c, the Python interface + module is installed as PIL.ImageCMS. - + Fixed problem with incremental parsing of PNG files. + Added support for in-memory ICC profiles. - + Make selftest.py report non-zero status on failure (from Mark - Sienkiewicz) + Unified buildTransform and buildTransformFromOpenProfiles. - + Add big endian save support and multipage infrastructure to the TIFF - writer (from Sebastian Haase). + The profile can now be either a filename, a profile object, or a + file-like object containing an in-memory profile. - + Handle files with GPS IFD but no basic EXIF IFD (reported by Kurt - Schwehr). + Additional fixes from Florian Böch: - + Added zTXT support (from Andrew Kuchling via Lowell Alleman). + Very nice - it just needs LCMS flags support so we can use black + point compensation and softproofing :) See attached patches. They + also fix a naming issue which could cause confusion - display + profile (ImageCms wording) actually means proof profile (lcms + wording), so I changed variable names and docstrings where + applicable. Patches are tested under Python 2.6. - + Fixed potential infinite loop bug in ImageFont (from Guilherme Polo). +- Improved support for layer names in PSD files (from Sylvain Baubeau) - + Added sample ICC profiles (from Kevin Cazabon) + Sylvain writes: I needed to be able to retrieve the names of the + layers in a PSD files. But PsdImagePlugin.py didn't do the job so I + wrote this very small patch. - + Fixed array interface for I, F, and RGBA/RGBX images. +- Improved RGBA support for ImageTk for 8.4 and newer (from Con + Radchenko). - + Added Chroma subsampling support for JPEG (from Justin Huff). + This replaces the slow run-length based encoding model with true + compositing at the Tk level. - Justin writes: Attached is a patch (against PIL 1.1.6) to provide - control over the chroma subsampling done by the JPEG encoder. This - is often useful for reducing compression artifacts around edges of - clipart and text. +- Added support for 16- and 32-bit images to McIdas loader. - + Added USM/Gaussian Blur code from Kevin Cazabon. + Based on file samples and stand-alone reader code provided by Craig + Swank. - + Fixed bug w. uninitialized image data when cropping outside the - source image. +- Added ImagePalette support to putpalette. - + Use ImageShow to implement the Image.show method. +- Fixed problem with incremental parsing of PNG files. - Most notably, this picks the 'display' utility when available. It - also allows application code to register new display utilities via - the ImageShow registry. +- Make selftest.py report non-zero status on failure (from Mark + Sienkiewicz) - + Release the GIL in the PNG compressor (from Michael van Tellingen). +- Add big endian save support and multipage infrastructure to the TIFF + writer (from Sebastian Haase). - + Revised JPEG CMYK handling. +- Handle files with GPS IFD but no basic EXIF IFD (reported by Kurt + Schwehr). - Always assume Adobe behaviour, both when reading and writing (based on - a patch by Kevin Cazabon, and test data by Tim V. and Charlie Clark, and - additional debugging by Michael van Tellingen). +- Added zTXT support (from Andrew Kuchling via Lowell Alleman). - + Support for preserving ICC profiles (by Florian Böch via Tim Hatch). +- Fixed potential infinite loop bug in ImageFont (from Guilherme Polo). - Florian writes: +- Added sample ICC profiles (from Kevin Cazabon) - It's a beta, so still needs some testing, but should allow you to: - - retain embedded ICC profiles when saving from/to JPEG, PNG, TIFF. - Existing code doesn't need to be changed. - - access embedded profiles in JPEG, PNG, PSD, TIFF. +- Fixed array interface for I, F, and RGBA/RGBX images. - It also includes patches for TIFF to retain IPTC, Photoshop and XMP - metadata when saving as TIFF again, read/write TIFF resolution - information correctly, and to correct inverted CMYK JPEG files. +- Added Chroma subsampling support for JPEG (from Justin Huff). - + Fixed potential memory leak in median cut quantizer (from Evgeny Salmin). + Justin writes: Attached is a patch (against PIL 1.1.6) to provide + control over the chroma subsampling done by the JPEG encoder. This + is often useful for reducing compression artifacts around edges of + clipart and text. - + Fixed OverflowError when reading upside-down BMP images. +- Added USM/Gaussian Blur code from Kevin Cazabon. - + Added resolution save option for PDF files. +- Fixed bug w. uninitialized image data when cropping outside the + source image. - Andreas Kostyrka writes: I've included a patched PdfImagePlugin.py - based on 1.1.6 as included in Ubuntu, that supports a "resolution" - save option. Not great, but it makes the PDF saving more useful by - allowing PDFs that are not exactly 72dpi. +- Use ImageShow to implement the Image.show method. - + Look for Tcl/Tk include files in version-specific include directory - (from Encolpe Degoute). + Most notably, this picks the 'display' utility when available. It + also allows application code to register new display utilities via + the ImageShow registry. - + Fixed grayscale rounding error in ImageColor.getcolor (from Tim - Hatch). +- Release the GIL in the PNG compressor (from Michael van Tellingen). - + Fixed calculation of mean value in ImageEnhance.Contrast (reported - by "roop" and Scott David Daniels). +- Revised JPEG CMYK handling. - + Fixed truetype positioning when first character has a negative left - bearing (from Ned Batchelder): + Always assume Adobe behaviour, both when reading and writing (based on + a patch by Kevin Cazabon, and test data by Tim V. and Charlie Clark, and + additional debugging by Michael van Tellingen). - Ned writes: In PIL 1.1.6, ImageDraw.text will position the string - incorrectly if the first character has a negative left bearing. To - see the problem, show a string like "///" in an italic font. The - first slash will be clipped at the left, and the string will be - mis-positioned. +- Support for preserving ICC profiles (by Florian Böch via Tim Hatch). - + Fixed resolution unit bug in tiff reader/writer (based on code by - Florian Höch, Gary Bloom, and others). + Florian writes: - + Added simple transparency support for RGB images (reported by - Sebastian Spaeth). + It's a beta, so still needs some testing, but should allow you to: - + Added support for Unicode filenames in ImageFont.truetype (from Donn - Ingle). + - retain embedded ICC profiles when saving from/to JPEG, PNG, TIFF. + Existing code doesn't need to be changed. + - access embedded profiles in JPEG, PNG, PSD, TIFF. - + Fixed potential crash in ImageFont.getname method (from Donn Ingle). + It also includes patches for TIFF to retain IPTC, Photoshop and XMP + metadata when saving as TIFF again, read/write TIFF resolution + information correctly, and to correct inverted CMYK JPEG files. - + Fixed encoding issue in PIL/WalImageFile (from Santiago M. Mola). +- Fixed potential memory leak in median cut quantizer (from Evgeny Salmin). - *** Changes from release 1.1.5 to 1.1.6 *** +- Fixed OverflowError when reading upside-down BMP images. - (1.1.6 released) +- Added resolution save option for PDF files. - + Fixed some 64-bit compatibility warnings for Python 2.5. + Andreas Kostyrka writes: I've included a patched PdfImagePlugin.py + based on 1.1.6 as included in Ubuntu, that supports a "resolution" + save option. Not great, but it makes the PDF saving more useful by + allowing PDFs that are not exactly 72dpi. - + Added threading support for the Sane driver (from Abel Deuring). +- Look for Tcl/Tk include files in version-specific include directory + (from Encolpe Degoute). - (1.1.6b2 released) +- Fixed grayscale rounding error in ImageColor.getcolor (from Tim + Hatch). - + Added experimental "floodfill" function to the ImageDraw module - (based on code by Eric Raymond). +- Fixed calculation of mean value in ImageEnhance.Contrast (reported + by "roop" and Scott David Daniels). - + The default arguments for "frombuffer" doesn't match "fromstring" - and the documentation; this is a bug, and will most likely be fixed - in a future version. In this release, PIL prints a warning message - instead. To silence the warning, change any calls of the form - "frombuffer(mode, size, data)" to +- Fixed truetype positioning when first character has a negative left + bearing (from Ned Batchelder): - frombuffer(mode, size, data, "raw", mode, 0, 1) + Ned writes: In PIL 1.1.6, ImageDraw.text will position the string + incorrectly if the first character has a negative left bearing. To + see the problem, show a string like "///" in an italic font. The + first slash will be clipped at the left, and the string will be + mis-positioned. - + Added "fromarray" function, which takes an object implementing the - NumPy array interface and creates a PIL Image from it. (from Travis - Oliphant). +- Fixed resolution unit bug in tiff reader/writer (based on code by + Florian Höch, Gary Bloom, and others). - + Added NumPy array interface support (__array_interface__) to the - Image class (based on code by Travis Oliphant). +- Added simple transparency support for RGB images (reported by + Sebastian Spaeth). - This allows you to easily convert between PIL image memories and - NumPy arrays: +- Added support for Unicode filenames in ImageFont.truetype (from Donn + Ingle). - import numpy, Image +- Fixed potential crash in ImageFont.getname method (from Donn Ingle). - im = Image.open('hopper.jpg') +- Fixed encoding issue in PIL/WalImageFile (from Santiago M. Mola). - a = numpy.asarray(im) # a is readonly +1.1.6 +----- - im = Image.fromarray(a) +- Fixed some 64-bit compatibility warnings for Python 2.5. - + Fixed CMYK polarity for JPEG images, by treating all images as - "Adobe CMYK" images. (thanks to Cesare Leonardi and Kevin Cazabon - for samples, debugging, and patches). +- Added threading support for the Sane driver (from Abel Deuring). - (1.1.6b1 released) +1.1.6b2 +------- - + Added 'expand' option to the Image 'rotate' method. If true, the - output image is made large enough to hold the entire rotated image. +- Added experimental "floodfill" function to the ImageDraw module + (based on code by Eric Raymond). - + Changed the ImageDraw 'line' method to always draw the last pixel in - a polyline, independent of line angle. +- The default arguments for "frombuffer" doesn't match "fromstring" + and the documentation; this is a bug, and will most likely be fixed + in a future version. In this release, PIL prints a warning message + instead. To silence the warning, change any calls of the form + "frombuffer(mode, size, data)" to:: - + Fixed bearing calculation and clipping in the ImageFont truetype - renderer; this could lead to clipped text, or crashes in the low- - level _imagingft module. (based on input from Adam Twardoch and - others). + frombuffer(mode, size, data, "raw", mode, 0, 1) - + Added ImageQt wrapper module, for converting PIL Image objects to - QImage objects in an efficient way. +- Added "fromarray" function, which takes an object implementing the + NumPy array interface and creates a PIL Image from it. (from Travis + Oliphant). - + Fixed 'getmodebands' to return the number of bands also for "PA" - and "LA" modes. Added 'getmodebandnames' helper that return the - band names. +- Added NumPy array interface support (__array_interface__) to the + Image class (based on code by Travis Oliphant). - (1.1.6a2 released) + This allows you to easily convert between PIL image memories and + NumPy arrays:: - + Added float/double support to the TIFF loader (from Russell - Nelson). + import numpy, Image + im = Image.open('hopper.jpg') + a = numpy.asarray(im) # a is readonly + im = Image.fromarray(a) - + Fixed broken use of realloc() in path.c (from Jan Matejek) +- Fixed CMYK polarity for JPEG images, by treating all images as + "Adobe CMYK" images. (thanks to Cesare Leonardi and Kevin Cazabon + for samples, debugging, and patches). - + Added save support for Spider images (from William Baxter). +1.1.6b1 +------- - + Fixed broken 'paste' and 'resize' operations in pildriver - (from Bill Janssen). +- Added 'expand' option to the Image 'rotate' method. If true, the + output image is made large enough to hold the entire rotated image. - + Added support for duplex scanning to the Sane interface (Abel - Deuring). +- Changed the ImageDraw 'line' method to always draw the last pixel in + a polyline, independent of line angle. - (1.1.6a1 released) +- Fixed bearing calculation and clipping in the ImageFont truetype + renderer; this could lead to clipped text, or crashes in the low- + level _imagingft module. (based on input from Adam Twardoch and + others). - + Fixed a memory leak in "convert(mode)", when converting from - L to P. +- Added ImageQt wrapper module, for converting PIL Image objects to + QImage objects in an efficient way. - + Added pixel access object. The "load" method now returns a - access object that can be used to directly get and set pixel - values, using ordinary [x, y] notation: +- Fixed 'getmodebands' to return the number of bands also for "PA" + and "LA" modes. Added 'getmodebandnames' helper that return the + band names. - pixel = im.load() - v = pixel[x, y] - pixel[x, y] = v +1.1.6a2 +------- - If you're accessing more than a few pixels, this is a lot - faster than using getpixel/putpixel. +- Added float/double support to the TIFF loader (from Russell + Nelson). - + Fixed building on Cygwin (from Miki Tebeka). +- Fixed broken use of realloc() in path.c (from Jan Matejek) - + Fixed "point(callable)" on unloaded images (reported by Håkan - Karlsson). +- Added save support for Spider images (from William Baxter). - + Fixed size bug in ImageWin.ImageWindow constructor (from Victor - Reijs) +- Fixed broken 'paste' and 'resize' operations in pildriver + (from Bill Janssen). - + Fixed ImageMath float() and int() operations for Python 2.4 - (reported by Don Rozenberg). +- Added support for duplex scanning to the Sane interface (Abel + Deuring). - + Fixed "RuntimeError: encoder error -8 in tostring" problem for - wide "RGB", "I", and "F" images. +1.1.6a1 +------- - + Fixed line width calculation. +- Fixed a memory leak in "convert(mode)", when converting from + L to P. - (1.1.6a0 released) +- Added pixel access object. The "load" method now returns a + access object that can be used to directly get and set pixel + values, using ordinary [x, y] notation:: - + Fixed byte order issue in Image.paste(ink) (from Ka-Ping Yee). + pixel = im.load() + v = pixel[x, y] + pixel[x, y] = v - + Fixed off-by-0.5 errors in the ANTIALIAS code (based on input - from Douglas Bagnall). + If you're accessing more than a few pixels, this is a lot + faster than using getpixel/putpixel. - + Added buffer interface support to the Path constructor. If - a buffer is provided, it is assumed to contain a flat array - of float coordinates (e.g. array.array('f', seq)). +- Fixed building on Cygwin (from Miki Tebeka). - + Added new ImageMath module. +- Fixed "point(callable)" on unloaded images (reported by Håkan + Karlsson). - + Fixed ImageOps.equalize when used with a small number of distinct - values (reported by David Kirtley). +- Fixed size bug in ImageWin.ImageWindow constructor (from Victor + Reijs) - + Fixed potential integer division in PSDraw.image (from Eric Etheridge). +- Fixed ImageMath float() and int() operations for Python 2.4 + (reported by Don Rozenberg). - *** Changes from release 1.1 to 1.1.5 *** +- Fixed "RuntimeError: encoder error -8 in tostring" problem for + wide "RGB", "I", and "F" images. - (1.1.5c2 and 1.1.5 final released) +- Fixed line width calculation. - + Added experimental PERSPECTIVE transform method (from Jeff Breiden- - bach). +1.1.6a0 +------- - (1.1.5c1 released) +- Fixed byte order issue in Image.paste(ink) (from Ka-Ping Yee). - + Make sure "thumbnail" never generates zero-wide or zero-high images - (reported by Gene Skonicki) +- Fixed off-by-0.5 errors in the ANTIALIAS code (based on input + from Douglas Bagnall). - + Fixed a "getcolors" bug that could result in a zero count for some - colors (reported by Richard Oudkerk). +- Added buffer interface support to the Path constructor. If + a buffer is provided, it is assumed to contain a flat array + of float coordinates (e.g. array.array('f', seq)). - + Changed default "convert" palette to avoid "rounding errors" when - round-tripping white source pixels (reported by Henryk Gerlach and - Jeff Epler). +- Added new ImageMath module. - (1.1.5b3 released) +- Fixed ImageOps.equalize when used with a small number of distinct + values (reported by David Kirtley). - + Don't crash in "quantize" method if the number of colors requested - is larger than 256. This release raises a ValueError exception; - future versions may return a mode "RGB" image instead (reported - by Richard Oudkerk). +- Fixed potential integer division in PSDraw.image (from Eric Etheridge). - + Added WBMP read/write support (based on code by Duncan Booth). +1.1.5c2 and 1.1.5 final +----------------------- - (1.1.5b2 released) +- Added experimental PERSPECTIVE transform method (from Jeff Breiden- + bach). - + Added DPI read/write support to the PNG codec. The decoder sets - the info["dpi"] attribute for PNG files with appropriate resolution - settings. The encoder uses the "dpi" option (based on code by Niki - Spahiev). +1.1.5c1 +------- - + Added limited support for "point" mappings from mode "I" to mode "L". - Only 16-bit values are supported (other values are clipped), the lookup - table must contain exactly 65536 entries, and the mode argument must be - set to "L". +- Make sure "thumbnail" never generates zero-wide or zero-high images + (reported by Gene Skonicki) - + Added support for Mac OS X icns files (based on code by Bob Ippolito). +- Fixed a "getcolors" bug that could result in a zero count for some + colors (reported by Richard Oudkerk). - + Added "ModeFilter" support to the ImageFilter module. +- Changed default "convert" palette to avoid "rounding errors" when + round-tripping white source pixels (reported by Henryk Gerlach and + Jeff Epler). - + Added support for Spider images (from William Baxter). See the - comments in PIL/SpiderImagePlugin.py for more information on this - format. +1.1.5b3 +------- - (1.1.5b1 released) +- Don't crash in "quantize" method if the number of colors requested + is larger than 256. This release raises a ValueError exception; + future versions may return a mode "RGB" image instead (reported + by Richard Oudkerk). - + Added new Sane release (from Ralph Heinkel). See the Sane/README - and Sane/CHANGES files for more information. +- Added WBMP read/write support (based on code by Duncan Booth). - + Added experimental PngInfo chunk container to the PngImageFile - module. This can be used to add arbitrary chunks to a PNG file. - Create a PngInfo instance, use "add" or "add_text" to add chunks, - and pass the instance as the "pnginfo" option when saving the - file. +1.1.5b2 +------- - + Added "getpalette" method. This returns the palette as a list, - or None if the image has no palette. To modify the palette, use - "getpalette" to fetch the current palette, modify the list, and - put it back using "putpalette". +- Added DPI read/write support to the PNG codec. The decoder sets + the info["dpi"] attribute for PNG files with appropriate resolution + settings. The encoder uses the "dpi" option (based on code by Niki + Spahiev). - + Added optional flattening to the ImagePath "tolist" method. - tolist() or tolist(0) returns a list of 2-tuples, as before. - tolist(1) returns a flattened list instead. +- Added limited support for "point" mappings from mode "I" to mode "L". + Only 16-bit values are supported (other values are clipped), the lookup + table must contain exactly 65536 entries, and the mode argument must be + set to "L". - (1.1.5a5 released) +- Added support for Mac OS X icns files (based on code by Bob Ippolito). - + Fixed BILINEAR/BICUBIC/ANTIALIAS filtering for mode "LA". +- Added "ModeFilter" support to the ImageFilter module. - + Added "getcolors()" method. This is similar to the existing histo- - gram method, but looks at color values instead of individual layers, - and returns an unsorted list of (count, color) tuples. +- Added support for Spider images (from William Baxter). See the + comments in PIL/SpiderImagePlugin.py for more information on this + format. - By default, the method returns None if finds more than 256 colors. - If you need to look for more colors, you can pass in a limit (this - is used to allocate internal tables, so you probably don't want to - pass in too large values). +1.1.5b1 +------- - + Build improvements: Fixed building under AIX, improved detection of - FreeType2 and Mac OS X framework libraries, and more. Many thanks - to everyone who helped test the new "setup.py" script! +- Added new Sane release (from Ralph Heinkel). See the Sane/README + and Sane/CHANGES files for more information. - (1.1.5a4 released) +- Added experimental PngInfo chunk container to the PngImageFile + module. This can be used to add arbitrary chunks to a PNG file. + Create a PngInfo instance, use "add" or "add_text" to add chunks, + and pass the instance as the "pnginfo" option when saving the + file. - + The "save" method now looks for a file format driver before - creating the file. +- Added "getpalette" method. This returns the palette as a list, + or None if the image has no palette. To modify the palette, use + "getpalette" to fetch the current palette, modify the list, and + put it back using "putpalette". - + Don't use antialiased truetype fonts when drawing in mode "P", "I", - and "F" images. +- Added optional flattening to the ImagePath "tolist" method. + tolist() or tolist(0) returns a list of 2-tuples, as before. + tolist(1) returns a flattened list instead. - + Rewrote the "setup.py" file. The new version scans for available - support libraries, and configures both the libImaging core library - and the bindings in one step. +1.1.5a5 +------- - To use specific versions of the libraries, edit the ROOT variables - in the setup.py file. +- Fixed BILINEAR/BICUBIC/ANTIALIAS filtering for mode "LA". - + Removed threaded "show" viewer; use the old "show" implementation - instead (Windows). +- Added "getcolors()" method. This is similar to the existing histo- + gram method, but looks at color values instead of individual layers, + and returns an unsorted list of (count, color) tuples. - + Added deprecation warnings to Image.offset, ImageDraw.setink, and - ImageDraw.setfill. + By default, the method returns None if finds more than 256 colors. + If you need to look for more colors, you can pass in a limit (this + is used to allocate internal tables, so you probably don't want to + pass in too large values). - + Added width option to ImageDraw.line(). The current implementation - works best for straight lines; it does not support line joins, so - polylines won't look good. +- Build improvements: Fixed building under AIX, improved detection of + FreeType2 and Mac OS X framework libraries, and more. Many thanks + to everyone who helped test the new "setup.py" script! - + ImageDraw.Draw is now a factory function instead of a class. If - you need to create custom draw classes, inherit from the ImageDraw - class. All other code should use the factory function. +1.1.5a4 +------- - + Fixed loading of certain PCX files (problem reported by Greg - Hamilton, who also provided samples). +- The "save" method now looks for a file format driver before + creating the file. - + Changed _imagingft.c to require FreeType 2.1 or newer. The - module can still be built with earlier versions; see comments - in _imagingft.c for details. +- Don't use antialiased truetype fonts when drawing in mode "P", "I", + and "F" images. - (1.1.5a3 released) +- Rewrote the "setup.py" file. The new version scans for available + support libraries, and configures both the libImaging core library + and the bindings in one step. - + Added 'getim' method, which returns a PyCObject wrapping an - Imaging pointer. The description string is set to IMAGING_MAGIC. - See Imaging.h for pointer and string declarations. + To use specific versions of the libraries, edit the ROOT variables + in the setup.py file. - + Fixed reading of TIFF JPEG images (problem reported by Ulrik - Svensson). +- Removed threaded "show" viewer; use the old "show" implementation + instead (Windows). - + Made ImageColor work under Python 1.5.2 +- Added deprecation warnings to Image.offset, ImageDraw.setink, and + ImageDraw.setfill. - + Fixed division by zero "equalize" on very small images (from - Douglas Bagnall). +- Added width option to ImageDraw.line(). The current implementation + works best for straight lines; it does not support line joins, so + polylines won't look good. - (1.1.5a2 released) +- ImageDraw.Draw is now a factory function instead of a class. If + you need to create custom draw classes, inherit from the ImageDraw + class. All other code should use the factory function. - + The "paste" method now supports the alternative "paste(im, mask)" - syntax (in this case, the box defaults to im's bounding box). +- Fixed loading of certain PCX files (problem reported by Greg + Hamilton, who also provided samples). - + The "ImageFile.Parser" class now works also for PNG files with - more than one IDAT block. +- Changed _imagingft.c to require FreeType 2.1 or newer. The + module can still be built with earlier versions; see comments + in _imagingft.c for details. - + Added DPI read/write to the TIFF codec, and fixed writing of - rational values. The decoder sets the info["dpi"] attribute - for TIFF files with appropriate resolution settings. The - encoder uses the "dpi" option. +1.1.5a3 +------- - + Disable interlacing for small (or narrow) GIF images, to - work around what appears to be a hard-to-find bug in PIL's - GIF encoder. +- Added 'getim' method, which returns a PyCObject wrapping an + Imaging pointer. The description string is set to IMAGING_MAGIC. + See Imaging.h for pointer and string declarations. - + Fixed writing of mode "P" PDF images. Made mode "1" PDF - images smaller. +- Fixed reading of TIFF JPEG images (problem reported by Ulrik + Svensson). - + Made the XBM reader a bit more robust; the file may now start - with a few whitespace characters. +- Made ImageColor work under Python 1.5.2 - + Added support for enhanced metafiles to the WMF driver. The - separate PILWMF kit lets you render both placeable WMF files - and EMF files as raster images. See +- Fixed division by zero "equalize" on very small images (from + Douglas Bagnall). - http://effbot.org/downloads#pilwmf +1.1.5a2 +------- - (1.1.5a1 released) +- The "paste" method now supports the alternative "paste(im, mask)" + syntax (in this case, the box defaults to im's bounding box). - + Replaced broken WMF driver with a WMF stub plugin (see below). +- The "ImageFile.Parser" class now works also for PNG files with + more than one IDAT block. - + Fixed writing of mode "1", "L", and "CMYK" PDF images (based on - input from Nicholas Riley and others). +- Added DPI read/write to the TIFF codec, and fixed writing of + rational values. The decoder sets the info["dpi"] attribute + for TIFF files with appropriate resolution settings. The + encoder uses the "dpi" option. - + Fixed adaptive palette conversion for zero-width or zero-height - images (from Chris Cogdon) +- Disable interlacing for small (or narrow) GIF images, to + work around what appears to be a hard-to-find bug in PIL's + GIF encoder. - + Fixed reading of PNG images from QuickTime 6 (from Paul Pharr) +- Fixed writing of mode "P" PDF images. Made mode "1" PDF + images smaller. - + Added support for StubImageFile plugins, including stub plugins - for BUFR, FITS, GRIB, and HDF5 files. A stub plugin can identify - a given file format, but relies on application code to open and - save files in that format. +- Made the XBM reader a bit more robust; the file may now start + with a few whitespace characters. - + Added optional "encoding" argument to the ImageFont.truetype - factory. This argument can be used to specify non-Unicode character - maps for fonts that support that. For example, to draw text using - the Microsoft Symbol font, use: +- Added support for enhanced metafiles to the WMF driver. The + separate PILWMF kit lets you render both placeable WMF files + and EMF files as raster images. See + http://effbot.org/downloads#pilwmf - font = ImageFont.truetype("symbol.ttf", 16, encoding="symb") - draw.text((0, 0), unichr(0xF000 + 0xAA)) +1.1.5a1 +------- - (note that the symbol font uses characters in the 0xF000-0xF0FF - range) +- Replaced broken WMF driver with a WMF stub plugin (see below). - Common encodings are "unic" (Unicode), "symb" (Microsoft Symbol), - "ADOB" (Adobe Standard), "ADBE" (Adobe Expert), and "armn" (Apple - Roman). See the FreeType documentation for more information. +- Fixed writing of mode "1", "L", and "CMYK" PDF images (based on + input from Nicholas Riley and others). - + Made "putalpha" a bit more robust; you can now attach an alpha - layer to a plain "L" or "RGB" image, and you can also specify - constant alphas instead of alpha layers (using integers or colour - names). +- Fixed adaptive palette conversion for zero-width or zero-height + images (from Chris Cogdon) - + Added experimental "LA" mode support. +- Fixed reading of PNG images from QuickTime 6 (from Paul Pharr) - An "LA" image is an "L" image with an attached transparency layer. - Note that support for "LA" is not complete; some operations may - fail or produce unexpected results. +- Added support for StubImageFile plugins, including stub plugins + for BUFR, FITS, GRIB, and HDF5 files. A stub plugin can identify + a given file format, but relies on application code to open and + save files in that format. - + Added "RankFilter", "MinFilter", "MedianFilter", and "MaxFilter" - classes to the ImageFilter module. +- Added optional "encoding" argument to the ImageFont.truetype + factory. This argument can be used to specify non-Unicode character + maps for fonts that support that. For example, to draw text using + the Microsoft Symbol font, use:: - + Improved support for applications using multiple threads; PIL - now releases the global interpreter lock for many CPU-intensive - operations (based on work by Kevin Cazabon). + font = ImageFont.truetype("symbol.ttf", 16, encoding="symb") + draw.text((0, 0), unichr(0xF000 + 0xAA)) - + Ignore Unicode characters in the PCF loader (from Andres Polit) + (note that the symbol font uses characters in the 0xF000-0xF0FF + range) - + Fixed typo in OleFileIO.loadfat, which could affect loading of - FlashPix and Image Composer images (Daniel Haertle) + Common encodings are "unic" (Unicode), "symb" (Microsoft Symbol), + "ADOB" (Adobe Standard), "ADBE" (Adobe Expert), and "armn" (Apple + Roman). See the FreeType documentation for more information. - + Fixed building on platforms that have Freetype but don't have - Tcl/Tk (Jack Jansen, Luciano Nocera, Piet van Oostrum and others) +- Made "putalpha" a bit more robust; you can now attach an alpha + layer to a plain "L" or "RGB" image, and you can also specify + constant alphas instead of alpha layers (using integers or colour + names). - + Added EXIF GPSInfo read support for JPEG files. To extract - GPSInfo information, open the file, extract the exif dictionary, - and check for the key 0x8825 (GPSInfo). If present, it contains - a dictionary mapping GPS keys to GPS values. For a list of keys, - see the EXIF specification. +- Added experimental "LA" mode support. - The "ExifTags" module contains a GPSTAGS dictionary mapping GPS - tags to tag names. + An "LA" image is an "L" image with an attached transparency layer. + Note that support for "LA" is not complete; some operations may + fail or produce unexpected results. - + Added DPI read support to the PCX and DCX codecs (info["dpi"]). +- Added "RankFilter", "MinFilter", "MedianFilter", and "MaxFilter" + classes to the ImageFilter module. - + The "show" methods now uses a built-in image viewer on Windows. - This viewer creates an instance of the ImageWindow class (see - below) and keeps it running in a separate thread. NOTE: This - was disabled in 1.1.5a4. +- Improved support for applications using multiple threads; PIL + now releases the global interpreter lock for many CPU-intensive + operations (based on work by Kevin Cazabon). - + Added experimental "Window" and "ImageWindow" classes to the - ImageWin module. These classes allow you to create a WCK-style - toplevel window, and use it to display raster data. +- Ignore Unicode characters in the PCF loader (from Andres Polit) - + Fixed some Python 1.5.2 issues (to build under 1.5.2, use the - Makefile.pre.in/Setup.in approach) +- Fixed typo in OleFileIO.loadfat, which could affect loading of + FlashPix and Image Composer images (Daniel Haertle) - + Added support for the TIFF FillOrder tag. PIL can read mode "1", - "L", "P" and "RGB" images with non-standard FillOrder (based on - input from Jeff Breidenbach). +- Fixed building on platforms that have Freetype but don't have + Tcl/Tk (Jack Jansen, Luciano Nocera, Piet van Oostrum and others) - (1.1.4 final released) +- Added EXIF GPSInfo read support for JPEG files. To extract + GPSInfo information, open the file, extract the exif dictionary, + and check for the key 0x8825 (GPSInfo). If present, it contains + a dictionary mapping GPS keys to GPS values. For a list of keys, + see the EXIF specification. - + Fixed ImageTk build problem on Unix. + The "ExifTags" module contains a GPSTAGS dictionary mapping GPS + tags to tag names. - (1.1.4b2 released) +- Added DPI read support to the PCX and DCX codecs (info["dpi"]). - + Improved building on Mac OS X (from Jack Jansen). +- The "show" methods now uses a built-in image viewer on Windows. + This viewer creates an instance of the ImageWindow class (see + below) and keeps it running in a separate thread. NOTE: This + was disabled in 1.1.5a4. - + Improved building on Windows with MinGW (from Klamer Shutte). +- Added experimental "Window" and "ImageWindow" classes to the + ImageWin module. These classes allow you to create a WCK-style + toplevel window, and use it to display raster data. - + If no font is specified, ImageDraw now uses the embedded default - font. Use the "load" or "truetype" methods to load a real font. +- Fixed some Python 1.5.2 issues (to build under 1.5.2, use the + Makefile.pre.in/Setup.in approach) - + Added embedded default font to the ImageFont module (currently - an 8-pixel Courier font, taken from the X window distribution). +- Added support for the TIFF FillOrder tag. PIL can read mode "1", + "L", "P" and "RGB" images with non-standard FillOrder (based on + input from Jeff Breidenbach). - (1.1.4b1 released) +1.1.4 final +----------- - + Added experimental EXIF support for JPEG files. To extract EXIF - information from a JPEG file, open the file as usual, and call the - "_getexif" method. If successful, this method returns a dictionary - mapping EXIF TIFF tags to values. If the file does not contain EXIF - data, the "_getexif" method returns None. +- Fixed ImageTk build problem on Unix. - The "ExifTags" module contains a dictionary mapping tags to tag - names. +1.1.4b2 +------- - This interface will most likely change in future versions. +- Improved building on Mac OS X (from Jack Jansen). - + Fixed a bug when using the "transparency" option with the GIF - writer. +- Improved building on Windows with MinGW (from Klamer Shutte). - + Added limited support for "bitfield compression" in BMP files - and DIB buffers, for 15-bit, 16-bit, and 32-bit images. This - also fixes a problem with ImageGrab module when copying screen- - dumps from the clipboard on 15/16/32-bit displays. +- If no font is specified, ImageDraw now uses the embedded default + font. Use the "load" or "truetype" methods to load a real font. - + Added experimental WAL (Quake 2 textures) loader. To use this - loader, import WalImageFile and call the "open" method in that - module. +- Added embedded default font to the ImageFont module (currently + an 8-pixel Courier font, taken from the X window distribution). - (1.1.4a4 released) +1.1.4b1 +------- - + Added updated SANE driver (Andrew Kuchling, Abel Deuring) +- Added experimental EXIF support for JPEG files. To extract EXIF + information from a JPEG file, open the file as usual, and call the + "_getexif" method. If successful, this method returns a dictionary + mapping EXIF TIFF tags to values. If the file does not contain EXIF + data, the "_getexif" method returns None. - + Use Python's "mmap" module on non-Windows platforms to read some - uncompressed formats using memory mapping. Also added a "frombuffer" - function that allows you to access the contents of an existing string - or buffer object as if it were an image object. + The "ExifTags" module contains a dictionary mapping tags to tag + names. - + Fixed a memory leak that could appear when processing mode "P" - images (from Pier Paolo Glave) + This interface will most likely change in future versions. - + Ignore Unicode characters in the BDF loader (from Graham Dumpleton) +- Fixed a bug when using the "transparency" option with the GIF + writer. - (1.1.4a3 released; windows only) +- Added limited support for "bitfield compression" in BMP files + and DIB buffers, for 15-bit, 16-bit, and 32-bit images. This + also fixes a problem with ImageGrab module when copying screen- + dumps from the clipboard on 15/16/32-bit displays. - + Added experimental RGBA-on-RGB drawing support. To use RGBA - colours on an RGB image, pass "RGBA" as the second string to - the ImageDraw.Draw constructor. +- Added experimental WAL (Quake 2 textures) loader. To use this + loader, import WalImageFile and call the "open" method in that + module. - + Added support for non-ASCII strings (Latin-1) and Unicode - to the truetype font renderer. +1.1.4a4 +------- - + The ImageWin "Dib" object can now be constructed directly from - an image object. +- Added updated SANE driver (Andrew Kuchling, Abel Deuring) - + The ImageWin module now allows you use window handles as well - as device contexts. To use a window handle, wrap the handle in - an ImageWin.HWND object, and pass in this object instead of the - device context. +- Use Python's "mmap" module on non-Windows platforms to read some + uncompressed formats using memory mapping. Also added a "frombuffer" + function that allows you to access the contents of an existing string + or buffer object as if it were an image object. - (1.1.4a2 released) +- Fixed a memory leak that could appear when processing mode "P" + images (from Pier Paolo Glave) - + Improved support for 16-bit unsigned integer images (mode "I;16"). - This includes TIFF reader support, and support for "getextrema" - and "point" (from Klamer Shutte). +- Ignore Unicode characters in the BDF loader (from Graham Dumpleton) - + Made the BdfFontFile reader a bit more robust (from Kevin Cazabon - and Dmitry Vasiliev) +1.1.4a3 released; Windows only +------------------------------ - + Changed TIFF writer to always write Compression tag, even when - using the default compression (from Greg Couch). +- Added experimental RGBA-on-RGB drawing support. To use RGBA + colours on an RGB image, pass "RGBA" as the second string to + the ImageDraw.Draw constructor. - + Added "show" support for Mac OS X (from Dan Wolfe). +- Added support for non-ASCII strings (Latin-1) and Unicode + to the truetype font renderer. - + Added clipboard support to the "ImageGrab" module (Windows only). - The "grabclipboard" function returns an Image object, a list of - filenames (not in 1.1.4), or None if neither was found. +- The ImageWin "Dib" object can now be constructed directly from + an image object. - (1.1.4a1 released) +- The ImageWin module now allows you use window handles as well + as device contexts. To use a window handle, wrap the handle in + an ImageWin.HWND object, and pass in this object instead of the + device context. - + Improved support for drawing RGB data in palette images. You can - now use RGB tuples or colour names (see below) when drawing in a - mode "P" image. The drawing layer automatically assigns color - indexes, as long as you don't use more than 256 unique colours. +1.1.4a2 +------- - + Moved self test from MiniTest/test.py to ./selftest.py. +- Improved support for 16-bit unsigned integer images (mode "I;16"). + This includes TIFF reader support, and support for "getextrema" + and "point" (from Klamer Shutte). - + Added support for CSS3-style color strings to most places that - accept colour codes/tuples. This includes the "ImageDraw" module, - the Image "new" function, and the Image "paste" method. +- Made the BdfFontFile reader a bit more robust (from Kevin Cazabon + and Dmitry Vasiliev) - Colour strings can use one of the following formats: "#f00", - "#ff0000", "rgb(255,0,0)", "rgb(100%,0%,0%)", "hsl(0, 100%, 50%)", - or "red" (most X11-style colour names are supported). See the - documentation for the "ImageColor" module for more information. +- Changed TIFF writer to always write Compression tag, even when + using the default compression (from Greg Couch). - + Fixed DCX decoder (based on input from Larry Bates) +- Added "show" support for Mac OS X (from Dan Wolfe). - + Added "IptcImagePlugin.getiptcinfo" helper to extract IPTC/NAA - newsphoto properties from JPEG, TIFF, or IPTC files. +- Added clipboard support to the "ImageGrab" module (Windows only). + The "grabclipboard" function returns an Image object, a list of + filenames (not in 1.1.4), or None if neither was found. - + Support for TrueType/OpenType fonts has been added to - the standard distribution. You need the freetype 2.0 - library. +1.1.4a1 +------- - + Made the PCX reader a bit more robust when reading 2-bit - and 4-bit PCX images with odd image sizes. +- Improved support for drawing RGB data in palette images. You can + now use RGB tuples or colour names (see below) when drawing in a + mode "P" image. The drawing layer automatically assigns color + indexes, as long as you don't use more than 256 unique colours. - + Added "Kernel" class to the ImageFilter module. This class - allows you to filter images with user-defined 3x3 and 5x5 - convolution kernels. +- Moved self test from MiniTest/test.py to ./selftest.py. - + Added "putdata" support for mode "I", "F" and "RGB". +- Added support for CSS3-style color strings to most places that + accept colour codes/tuples. This includes the "ImageDraw" module, + the Image "new" function, and the Image "paste" method. - + The GIF writer now supports the transparency option (from - Denis Benoit). + Colour strings can use one of the following formats: "#f00", + "#ff0000", "rgb(255,0,0)", "rgb(100%,0%,0%)", "hsl(0, 100%, 50%)", + or "red" (most X11-style colour names are supported). See the + documentation for the "ImageColor" module for more information. - + A HTML version of the module documentation is now shipped - with the source code distribution. You'll find the files in - the Doc subdirectory. +- Fixed DCX decoder (based on input from Larry Bates) - + Added support for Palm pixmaps (from Bill Janssen). This - change was listed for 1.1.3, but the "PalmImagePlugin" driver - didn't make it into the distribution. +- Added "IptcImagePlugin.getiptcinfo" helper to extract IPTC/NAA + newsphoto properties from JPEG, TIFF, or IPTC files. - + Improved decoder error messages. +- Support for TrueType/OpenType fonts has been added to + the standard distribution. You need the freetype 2.0 + library. - (1.1.3 final released) +- Made the PCX reader a bit more robust when reading 2-bit + and 4-bit PCX images with odd image sizes. - + Made setup.py look for old versions of zlib. For some back- - ground, see: https://zlib.net/advisory-2002-03-11.txt +- Added "Kernel" class to the ImageFilter module. This class + allows you to filter images with user-defined 3x3 and 5x5 + convolution kernels. - (1.1.3c2 released) +- Added "putdata" support for mode "I", "F" and "RGB". - + Added setup.py file (tested on Unix and Windows). You still - need to build libImaging/imaging.lib in the traditional way, - but the setup.py script takes care of the rest. +- The GIF writer now supports the transparency option (from + Denis Benoit). - The old Setup.in/Makefile.pre.in build method is still - supported. +- A HTML version of the module documentation is now shipped + with the source code distribution. You'll find the files in + the Doc subdirectory. - + Fixed segmentation violation in ANTIALIAS filter (an internal - buffer wasn't properly allocated). +- Added support for Palm pixmaps (from Bill Janssen). This + change was listed for 1.1.3, but the "PalmImagePlugin" driver + didn't make it into the distribution. - (1.1.3c1 released) +- Improved decoder error messages. - + Added ANTIALIAS downsampling filter for high-quality "resize" - and "thumbnail" operations. Also added filter option to the - "thumbnail" operation; the default value is NEAREST, but this - will most likely change in future versions. +1.1.3 final +----------- - + Fixed plugin loader to be more robust if the __file__ - variable isn't set. +- Made setup.py look for old versions of zlib. For some back- + ground, see: https://zlib.net/advisory-2002-03-11.txt - + Added seek/tell support (for layers) to the PhotoShop - loader. Layer 0 is the main image. +1.1.3c2 +------- - + Added new (but experimental) "ImageOps" module, which provides - shortcuts for commonly used operations on entire images. +- Added setup.py file (tested on Unix and Windows). You still + need to build libImaging/imaging.lib in the traditional way, + but the setup.py script takes care of the rest. - + Don't mess up when loading PNG images if the decoder leaves - data in the output buffer. This could cause internal errors - on some PNG images, with some versions of ZLIB. (Bug report - and patch provided by Bernhard Herzog.) + The old Setup.in/Makefile.pre.in build method is still + supported. - + Don't mess up on Unicode filenames. +- Fixed segmentation violation in ANTIALIAS filter (an internal + buffer wasn't properly allocated). - + Don't mess up when drawing on big endian platforms. +1.1.3c1 +------- - + Made the TIFF loader a bit more robust; it can now read some - more slightly broken TIFF files (based on input from Ted Wright, - Bob Klimek, and D. Alan Stewart) +- Added ANTIALIAS downsampling filter for high-quality "resize" + and "thumbnail" operations. Also added filter option to the + "thumbnail" operation; the default value is NEAREST, but this + will most likely change in future versions. - + Added OS/2 EMX build files (from Andrew MacIntyre) +- Fixed plugin loader to be more robust if the __file__ + variable isn't set. - + Change "ImageFont" to reject image files if they don't have the - right mode. Older versions could leak memory for "P" images. - (Bug reported by Markus Gritsch). +- Added seek/tell support (for layers) to the PhotoShop + loader. Layer 0 is the main image. - + Renamed some internal functions to avoid potential build - problem on Mac OS X. +- Added new (but experimental) "ImageOps" module, which provides + shortcuts for commonly used operations on entire images. - + Added DL_EXPORT where relevant (for Cygwin, based on input - from Robert Yodlowski) +- Don't mess up when loading PNG images if the decoder leaves + data in the output buffer. This could cause internal errors + on some PNG images, with some versions of ZLIB. (Bug report + and patch provided by Bernhard Herzog.) - + (re)moved bogus __init__ call in BdfFontFile (bug spotted - by Fred Clare) +- Don't mess up on Unicode filenames. - + Added "ImageGrab" support (Windows only) +- Don't mess up when drawing on big endian platforms. - + Added support for XBM hotspots (based on code contributed by - Bernhard Herzog). +- Made the TIFF loader a bit more robust; it can now read some + more slightly broken TIFF files (based on input from Ted Wright, + Bob Klimek, and D. Alan Stewart) - + Added write support for more TIFF tags, namely the Artist, - Copyright, DateTime, ResolutionUnit, Software, XResolution and - YResolution tags (from Greg Couch) +- Added OS/2 EMX build files (from Andrew MacIntyre) - + Added TransposedFont wrapper to ImageFont module +- Change "ImageFont" to reject image files if they don't have the + right mode. Older versions could leak memory for "P" images. + (Bug reported by Markus Gritsch). - + Added "optimize" flag to GIF encoder. If optimize is present - and non-zero, PIL will work harder to create a small file. +- Renamed some internal functions to avoid potential build + problem on Mac OS X. - + Raise "EOFError" (not IndexError) when reading beyond the - end of a TIFF sequence. +- Added DL_EXPORT where relevant (for Cygwin, based on input + from Robert Yodlowski) - + Support rewind ("seek(0)") for GIF and TIFF sequences. +- (re)moved bogus __init__ call in BdfFontFile (bug spotted + by Fred Clare) - + Load grayscale GIF images as mode "L" +- Added "ImageGrab" support (Windows only) - + Added DPI read/write support to the JPEG codec. The decoder - sets the info["dpi"] attribute for JPEG files with JFIF dpi - settings. The encoder uses the "dpi" option: +- Added support for XBM hotspots (based on code contributed by + Bernhard Herzog). - im = Image.open("file.jpg") - dpi = im.info["dpi"] # raises KeyError if DPI not known - im.save("out.jpg", dpi=dpi) +- Added write support for more TIFF tags, namely the Artist, + Copyright, DateTime, ResolutionUnit, Software, XResolution and + YResolution tags (from Greg Couch) - Note that PIL doesn't always preserve the "info" attribute - for normal image operations. +- Added TransposedFont wrapper to ImageFont module - (1.1.2c1 and 1.1.2 final released) +- Added "optimize" flag to GIF encoder. If optimize is present + and non-zero, PIL will work harder to create a small file. - + Adapted to Python 2.1. Among other things, all uses of the - "regex" module have been replaced with "re". +- Raise "EOFError" (not IndexError) when reading beyond the + end of a TIFF sequence. - + Fixed attribute error when reading large PNG files (this bug - was introduced in maintenance code released after the 1.1.1 - release) +- Support rewind ("seek(0)") for GIF and TIFF sequences. - + Ignore non-string objects in sys.path +- Load grayscale GIF images as mode "L" - + Fixed Image.transform(EXTENT) for negative xoffsets +- Added DPI read/write support to the JPEG codec. The decoder + sets the info["dpi"] attribute for JPEG files with JFIF dpi + settings. The encoder uses the "dpi" option:: - + Fixed loading of image plugins if PIL is installed as a package. - (The plugin loader now always looks in the directory where the - Image.py module itself is found, even if that directory isn't on - the standard search path) + im = Image.open("file.jpg") + dpi = im.info["dpi"] # raises KeyError if DPI not known + im.save("out.jpg", dpi=dpi) - + The Png plugin has been added to the list of preloaded standard - formats + Note that PIL doesn't always preserve the "info" attribute + for normal image operations. - + Fixed bitmap/text drawing in fill mode. +1.1.2c1 and 1.1.2 final +----------------------- - + Fixed "getextrema" to work also for multiband images. +- Adapted to Python 2.1. Among other things, all uses of the + "regex" module have been replaced with "re". - + Added transparency support for L and P images to the PNG codec. +- Fixed attribute error when reading large PNG files (this bug + was introduced in maintenance code released after the 1.1.1 + release) - + Improved support for read-only images. The "load" method now - sets the "readonly" attribute for memory-mapped images. Operations - that modifies an image in place (such as "paste" and drawing operations) - creates an in-memory copy of the image, if necessary. (before this - change, any attempt to modify a memory-mapped image resulted in a - core dump...) +- Ignore non-string objects in sys.path - + Added special cases for lists everywhere PIL expects a sequence. - This should speed up things like "putdata" and drawing operations. +- Fixed Image.transform(EXTENT) for negative xoffsets - + The Image.offset method is deprecated. Use the ImageChops.offset - function instead. +- Fixed loading of image plugins if PIL is installed as a package. + (The plugin loader now always looks in the directory where the + Image.py module itself is found, even if that directory isn't on + the standard search path) - + Changed ImageChops operators to copy palette and info dictionary - from the first image argument. +- The Png plugin has been added to the list of preloaded standard + formats - (1.1.1 released) +- Fixed bitmap/text drawing in fill mode. - + Additional fixes for Python 1.6/2.0, including TIFF "save" bug. +- Fixed "getextrema" to work also for multiband images. - + Changed "init" to properly load plugins when PIL is used as a - package. +- Added transparency support for L and P images to the PNG codec. - + Fixed broken "show" method (on Unix) +- Improved support for read-only images. The "load" method now + sets the "readonly" attribute for memory-mapped images. Operations + that modifies an image in place (such as "paste" and drawing operations) + creates an in-memory copy of the image, if necessary. (before this + change, any attempt to modify a memory-mapped image resulted in a + core dump...) - *** Changes from release 1.0 to 1.1 *** +- Added special cases for lists everywhere PIL expects a sequence. + This should speed up things like "putdata" and drawing operations. - + Adapted to Python 1.6 ("append" and other method changes) +- The Image.offset method is deprecated. Use the ImageChops.offset + function instead. - + Fixed Image.paste when pasting with solid colour and matte - layers ("L" or "RGBA" masks) (bug reported by Robert Kern) +- Changed ImageChops operators to copy palette and info dictionary + from the first image argument. - + To make it easier to distribute prebuilt versions of PIL, - the tkinit binding stuff has been moved to a separate - extension module, named "_imagingtk". +1.1.1 +----- - *** Changes from release 0.3b2 to 1.0 final *** +- Additional fixes for Python 1.6/2.0, including TIFF "save" bug. - + If there's no 16-bit integer (like on a Cray T3E), set - INT16 to the smallest integer available. Most of the - library works just fine anyway (from Bill Crutchfield) +- Changed "init" to properly load plugins when PIL is used as a + package. - + Tweaks to make drawing work on big-endian platforms. +- Fixed broken "show" method (on Unix) - (1.0c2 released) +1.0 to 1.1 +---------- - + If PIL is built with the WITH_TKINTER flag, ImageTk can - automatically hook into a standard Tkinter build. You - no longer need to build your own Tkinter to use the - ImageTk module. +- Adapted to Python 1.6 ("append" and other method changes) - The old way still works, though. For more information, - see Tk/install.txt. +- Fixed Image.paste when pasting with solid colour and matte + layers ("L" or "RGBA" masks) (bug reported by Robert Kern) - + Some tweaks to ImageTk to support multiple Tk interpreters - (from Greg Couch). +- To make it easier to distribute prebuilt versions of PIL, + the tkinit binding stuff has been moved to a separate + extension module, named "_imagingtk". - + ImageFont "load_path" now scans directory mentioned in .pth - files (from Richard Jones). - - (1.0c1 released) - - + The TIFF plugin has been rewritten. The new plugin fully - supports all major PIL image modes (including F and I). - - + The ImageFile module now includes a Parser class, which can - be used to incrementally decode an image file (while down- - loading it from the net, for example). See the handbook for - details. - - + "show" now converts non-standard modes to "L" or "RGB" (as - appropriate), rather than writing weird things to disk for - "xv" to choke upon. (bug reported by Les Schaffer). - - (1.0b2 released) - - + Major speedups for rotate, transform(EXTENT), and transform(AFFINE) - when using nearest neighbour resampling. - - + Modified ImageDraw to be compatible with the Arrow graphics - interface. See the handbook for details. - - + PIL now automatically loads file codecs when used as a package - (from The Dragon De Monsyne). Also included an __init__.py file - in the standard distribution. - - + The GIF encoder has been modified to produce much smaller files. - - PIL now uses a run-length encoding method to encode GIF files. - On a random selection of GIF images grabbed from the web, this - version makes the images about twice as large as the original - LZW files, where the earlier version made them over 5 times - larger. YMMV, of course. - - + Added PCX write support (works with "1", "P", "L", and "RGB") - - + Added "bitmap" and "textsize" methods to ImageDraw. - - + Improved font rendering code. Fixed a bug or two, and moved - most of the time critical stuff to C. - - + Removed "bdf2pil.py". Use "pilfont.py" instead! - - + Improved 16-bit support (still experimental, though). +0.3b2 to 1.0 final +------------------ - The following methods now support "I;16" and "I;16B" images: - "getpixel", "copy", "convert" (to and from mode "I"), "resize", - "rotate", and "transform" with nearest neighbour filters, and - "save" using the IM format. The "new" and "open" functions - also work as expected. On Windows, 16-bit files are memory - mapped. +- If there's no 16-bit integer (like on a Cray T3E), set + INT16 to the smallest integer available. Most of the + library works just fine anyway (from Bill Crutchfield) - NOTE: ALL other operations are still UNDEFINED on 16-bit images. +- Tweaks to make drawing work on big-endian platforms. - + The "paste" method now supports constant sources. +1.0c2 +----- - Just pass a colour value (a number or a tuple, depending on - the target image mode) instead of the source image. +- If PIL is built with the WITH_TKINTER flag, ImageTk can + automatically hook into a standard Tkinter build. You + no longer need to build your own Tkinter to use the + ImageTk module. - This was in fact implemented in an inefficient way in - earlier versions (the "paste" method generated a temporary - source image if you passed it a colour instead of an image). - In this version, this is handled on the C level instead. + The old way still works, though. For more information, + see Tk/install.txt. - + Added experimental "RGBa" mode support. +- Some tweaks to ImageTk to support multiple Tk interpreters + (from Greg Couch). - An "RGBa" image is an RGBA image where the colour components - have have been premultiplied with the alpha value. PIL allows - you to convert an RGBA image to an RGBa image, and to paste - RGBa images on top of RGB images. Since this saves a bunch - of multiplications and shifts, it is typically about twice - as fast an ordinary RGBA paste. +- ImageFont "load_path" now scans directory mentioned in .pth + files (from Richard Jones). - + Eliminated extra conversion step when pasting "RGBA" or "RGBa" - images on top of "RGB" images. +1.0c1 +----- - + Fixed Image.BICUBIC resampling for "RGB" images. +- The TIFF plugin has been rewritten. The new plugin fully + supports all major PIL image modes (including F and I). - + Fixed PCX image file handler to properly read 8-bit PCX - files (bug introduced in 1.0b1, reported by Bernhard - Herzog) +- The ImageFile module now includes a Parser class, which can + be used to incrementally decode an image file (while down- + loading it from the net, for example). See the handbook for + details. - + Fixed PSDraw "image" method to restore the coordinate - system. +- "show" now converts non-standard modes to "L" or "RGB" (as + appropriate), rather than writing weird things to disk for + "xv" to choke upon. (bug reported by Les Schaffer). - + Fixed "blend" problem when applied to images that was - not already loaded (reported by Edward C. Jones) +1.0b2 +----- - + Fixed -f option to "pilconvert.py" (from Anthony Baxter) +- Major speedups for rotate, transform(EXTENT), and transform(AFFINE) + when using nearest neighbour resampling. - (1.0b1 released) +- Modified ImageDraw to be compatible with the Arrow graphics + interface. See the handbook for details. - + Added Toby J. Sargeant's quantization package. To enable - quantization, use the "palette" option to "convert": +- PIL now automatically loads file codecs when used as a package + (from The Dragon De Monsyne). Also included an __init__.py file + in the standard distribution. - imOut = im.convert("P", palette=Image.ADAPTIVE) +- The GIF encoder has been modified to produce much smaller files. - This can be used with "L", "P", and "RGB" images. In this - version, dithering cannot be used with adaptive palettes. + PIL now uses a run-length encoding method to encode GIF files. + On a random selection of GIF images grabbed from the web, this + version makes the images about twice as large as the original + LZW files, where the earlier version made them over 5 times + larger. YMMV, of course. - Note: ADAPTIVE currently maps to median cut quantization - with 256 colours. The quantization package also contains - a maximum coverage quantizer, which will be supported by - future versions of PIL. +- Added PCX write support (works with "1", "P", "L", and "RGB") - + Added Eric S. Raymond's "pildriver" image calculator to the - distribution. See the docstring for more information. +- Added "bitmap" and "textsize" methods to ImageDraw. - + The "offset" method no longer dumps core if given positive - offsets (from Charles Waldman). +- Improved font rendering code. Fixed a bug or two, and moved + most of the time critical stuff to C. - + Fixed a resource leak that could cause ImageWin to run out of - GDI resources (from Roger Burnham). +- Removed "bdf2pil.py". Use "pilfont.py" instead! - + Added "arc", "chord", and "pieslice" methods to ImageDraw (inspired - by code contributed by Richard Jones). +- Improved 16-bit support (still experimental, though). - + Added experimental 16-bit support, via modes "I;16" (little endian - data) and "I;16B" (big endian). Only a few methods properly support - such images (see above). + The following methods now support "I;16" and "I;16B" images: + "getpixel", "copy", "convert" (to and from mode "I"), "resize", + "rotate", and "transform" with nearest neighbour filters, and + "save" using the IM format. The "new" and "open" functions + also work as expected. On Windows, 16-bit files are memory + mapped. - + Added XV thumbnail file handler (from Gene Cash). + NOTE: ALL other operations are still UNDEFINED on 16-bit images. - + Fixed BMP image file handler to handle palette images with small - palettes (from Rob Hooft). +- The "paste" method now supports constant sources. - + Fixed Sun raster file handler for palette images (from Charles - Waldman). + Just pass a colour value (a number or a tuple, depending on + the target image mode) instead of the source image. - + Improved various internal error messages. + This was in fact implemented in an inefficient way in + earlier versions (the "paste" method generated a temporary + source image if you passed it a colour instead of an image). + In this version, this is handled on the C level instead. - + Fixed Path constructor to handle arbitrary sequence objects. This - also affects the ImageDraw class (from Richard Jones). +- Added experimental "RGBa" mode support. - + Fixed a bug in JpegDecode that caused PIL to report "decoder error - -2" for some progressive JPEG files (reported by Magnus Källström, - who also provided samples). + An "RGBa" image is an RGBA image where the colour components + have have been premultiplied with the alpha value. PIL allows + you to convert an RGBA image to an RGBa image, and to paste + RGBa images on top of RGB images. Since this saves a bunch + of multiplications and shifts, it is typically about twice + as fast an ordinary RGBA paste. - + Fixed a bug in JpegImagePlugin that caused PIL to hang when loading - JPEG files using 16-bit quantization tables. +- Eliminated extra conversion step when pasting "RGBA" or "RGBa" + images on top of "RGB" images. - + The Image "transform" method now supports Image.QUAD transforms. - The data argument is an 8-tuple giving the upper left, lower - left, lower right, and upper right corner of the source quadri- - lateral. Also added Image.MESH transform which takes a list - of quadrilaterals. +- Fixed Image.BICUBIC resampling for "RGB" images. - + The Image "resize", "rotate", and "transform" methods now support - Image.BILINEAR (2x2) and Image.BICUBIC (4x4) resampling filters. - Filters can be used with all transform methods. +- Fixed PCX image file handler to properly read 8-bit PCX + files (bug introduced in 1.0b1, reported by Bernhard + Herzog) - + The ImageDraw "rectangle" method now includes both the right - and the bottom edges when drawing filled rectangles. +- Fixed PSDraw "image" method to restore the coordinate + system. - + The TGA decoder now works properly for runlength encoded images - which have more than one byte per pixel. +- Fixed "blend" problem when applied to images that was + not already loaded (reported by Edward C. Jones) - + "getbands" on an YCbCr image now returns ("Y", "Cb", "Cr") +- Fixed -f option to "pilconvert.py" (from Anthony Baxter) - + Some file drivers didn't handle the optional "modify" argument - to the load method. This resulted in exceptions when you used - "paste" (and other methods that modify an image in place) on a - newly opened file. +1.0b1 +----- - *** Changes from release 0.2 (b5) to 0.3 (b2) *** +- Added Toby J. Sargeant's quantization package. To enable + quantization, use the "palette" option to "convert":: - (0.3b2 released) + imOut = im.convert("P", palette=Image.ADAPTIVE) - The test suite includes 825 individual tests. + This can be used with "L", "P", and "RGB" images. In this + version, dithering cannot be used with adaptive palettes. - + An Image "getbands" method has been added. It returns a tuple - containing the individual band names for this image. To figure - out how many bands an image has, use "len(im.getbands())". + Note: ADAPTIVE currently maps to median cut quantization + with 256 colours. The quantization package also contains + a maximum coverage quantizer, which will be supported by + future versions of PIL. - + An Image "putpixel" method has been added. +- Added Eric S. Raymond's "pildriver" image calculator to the + distribution. See the docstring for more information. - + The Image "point" method can now be used to convert "L" images - to any other format, via a lookup table. That table should - contain 256 values for each band in the output image. +- The "offset" method no longer dumps core if given positive + offsets (from Charles Waldman). - + Some file drivers (including FLI/FLC, GIF, and IM) accidentally - overwrote the offset method with an internal attribute. All - drivers have been updated to use private attributes where - possible. +- Fixed a resource leak that could cause ImageWin to run out of + GDI resources (from Roger Burnham). - + The Image "histogram" method now works for "I" and "F" images. - For these modes, PIL divides the range between the min and - max values used in the image into 256 bins. You can also - pass in your own min and max values via the "extrema" option: +- Added "arc", "chord", and "pieslice" methods to ImageDraw (inspired + by code contributed by Richard Jones). - h = im.histogram(extrema=(0, 255)) +- Added experimental 16-bit support, via modes "I;16" (little endian + data) and "I;16B" (big endian). Only a few methods properly support + such images (see above). - + An Image "getextrema" method has been added. It returns the - min and max values used in the image. In this release, this - works for single band images only. +- Added XV thumbnail file handler (from Gene Cash). - + Changed the PNG driver to load and save mode "I" images as - 16-bit images. When saving, values outside the range 0..65535 - are clipped. +- Fixed BMP image file handler to handle palette images with small + palettes (from Rob Hooft). - + Fixed ImageFont.py to work with the new "pilfont" compiler. +- Fixed Sun raster file handler for palette images (from Charles + Waldman). - + Added JPEG "save" and "draft" support for mode "YCbCr" images. - Note that if you save an "YCbCr" image as a JPEG file and read - it back, it is read as an RGB file. To get around this, you - can use the "draft" method: +- Improved various internal error messages. - im = Image.open("color.jpg") - im.draft("YCbCr", im.size) +- Fixed Path constructor to handle arbitrary sequence objects. This + also affects the ImageDraw class (from Richard Jones). - + Read "RGBA" TGA images. Also fixed the orientation bug; all - images should now come out the right way. +- Fixed a bug in JpegDecode that caused PIL to report "decoder error + -2" for some progressive JPEG files (reported by Magnus Källström, + who also provided samples). - + Changed mode name (and internal representation) from "YCrCb" - to "YCbCr" (!) - *** WARNING: MAY BREAK EXISTING CODE *** +- Fixed a bug in JpegImagePlugin that caused PIL to hang when loading + JPEG files using 16-bit quantization tables. - (0.3b1 released) +- The Image "transform" method now supports Image.QUAD transforms. + The data argument is an 8-tuple giving the upper left, lower + left, lower right, and upper right corner of the source quadri- + lateral. Also added Image.MESH transform which takes a list + of quadrilaterals. - The test suite includes 750 individual tests. +- The Image "resize", "rotate", and "transform" methods now support + Image.BILINEAR (2x2) and Image.BICUBIC (4x4) resampling filters. + Filters can be used with all transform methods. - + The "pilfont" package is now included in the standard PIL - distribution. The pilfont utility can be used to convert - X BDF and PCF raster font files to a format understood by - the ImageFont module. +- The ImageDraw "rectangle" method now includes both the right + and the bottom edges when drawing filled rectangles. - + GIF files are now interlaced by default. To write a - non-interlaced file, pass interlace=0 to the "save" - method. +- The TGA decoder now works properly for runlength encoded images + which have more than one byte per pixel. - + The default string format has changed for the "fromstring" - and "tostring" methods. - *** WARNING: MAY BREAK EXISTING CODE *** +- "getbands" on an YCbCr image now returns ("Y", "Cb", "Cr") - NOTE: If no extra arguments are given, the first line in - the string buffer is the top line of the image, instead of - the bottom line. For RGB images, the string now contains - 3 bytes per pixel instead of 4. These changes were made - to make the methods compatible with the "fromstring" - factory function. +- Some file drivers didn't handle the optional "modify" argument + to the load method. This resulted in exceptions when you used + "paste" (and other methods that modify an image in place) on a + newly opened file. - To get the old behaviour, use the following syntax: +0.3b2 +----- - data = im.tostring("raw", "RGBX", 0, -1) - im.fromstring(data, "raw", "RGBX", 0, -1) +The test suite includes 825 individual tests. - + "new" no longer gives a MemoryError if the width or height - is zero (this only happened on platforms where malloc(0) - or calloc(0) returns NULL). +- An Image "getbands" method has been added. It returns a tuple + containing the individual band names for this image. To figure + out how many bands an image has, use "len(im.getbands())". - + "new" now adds a default palette object to "P" images. +- An Image "putpixel" method has been added. - + You can now convert directly between all modes supported by - PIL. When converting colour images to "P", PIL defaults to - a "web" palette and dithering. When converting greyscale - images to "1", PIL uses a thresholding and dithering. +- The Image "point" method can now be used to convert "L" images + to any other format, via a lookup table. That table should + contain 256 values for each band in the output image. - + Added a "dither" option to "convert". By default, "convert" - uses floyd-steinberg error diffusion for "P" and "1" targets, - so this option is only used to *disable* dithering. Allowed - values are NONE (no dithering) or FLOYDSTEINBERG (default). +- Some file drivers (including FLI/FLC, GIF, and IM) accidentally + overwrote the offset method with an internal attribute. All + drivers have been updated to use private attributes where + possible. - imOut = im.convert("P", dither=Image.NONE) +- The Image "histogram" method now works for "I" and "F" images. + For these modes, PIL divides the range between the min and + max values used in the image into 256 bins. You can also + pass in your own min and max values via the "extrema" option:: - + Added a full set of "I" decoders. You can use "fromstring" - (and file decoders) to read any standard integer type as an - "I" image. + h = im.histogram(extrema=(0, 255)) - + Added some support for "YCbCr" images (creation, conversion - from/to "L" and "RGB", IM YCC load/save) +- An Image "getextrema" method has been added. It returns the + min and max values used in the image. In this release, this + works for single band images only. - + "getpixel" now works properly with fractional coordinates. +- Changed the PNG driver to load and save mode "I" images as + 16-bit images. When saving, values outside the range 0..65535 + are clipped. - + ImageDraw "setink" now works with "I", "F", "RGB", "RGBA", - "RGBX", "CMYK", and "YCbCr" images. +- Fixed ImageFont.py to work with the new "pilfont" compiler. - + ImImagePlugin no longer attaches palettes to "RGB" images. +- Added JPEG "save" and "draft" support for mode "YCbCr" images. + Note that if you save an "YCbCr" image as a JPEG file and read + it back, it is read as an RGB file. To get around this, you + can use the "draft" method:: - + Various minor fixes. + im = Image.open("color.jpg") + im.draft("YCbCr", im.size) - (0.3a4 released) +- Read "RGBA" TGA images. Also fixed the orientation bug; all + images should now come out the right way. - + Added experimental IPTC/NAA support. +- Changed mode name (and internal representation) from "YCrCb" + to "YCbCr" (!) + **WARNING: MAY BREAK EXISTING CODE** - + Eliminated AttributeError exceptions after "crop" (from - Skip Montanaro) +0.3b1 +----- - + Reads some uncompressed formats via memory mapping (this - is currently supported on Win32 only) +The test suite includes 750 individual tests. - + Fixed some last minute glitches in the last alpha release - (Types instead of types in Image.py, version numbers, etc.) +- The "pilfont" package is now included in the standard PIL + distribution. The pilfont utility can be used to convert + X BDF and PCF raster font files to a format understood by + the ImageFont module. - + Eliminated some more bogus compiler warnings. +- GIF files are now interlaced by default. To write a + non-interlaced file, pass interlace=0 to the "save" + method. - + Various fixes to make PIL compile and run smoother on Macs - (from Jack Jansen). +- The default string format has changed for the "fromstring" + and "tostring" methods. + **WARNING: MAY BREAK EXISTING CODE** - + Fixed "fromstring" and "tostring" for mode "I" images. + NOTE: If no extra arguments are given, the first line in + the string buffer is the top line of the image, instead of + the bottom line. For RGB images, the string now contains + 3 bytes per pixel instead of 4. These changes were made + to make the methods compatible with the "fromstring" + factory function. - (0.3a3 released) + To get the old behaviour, use the following syntax:: - The test suite includes 530 individual tests. + data = im.tostring("raw", "RGBX", 0, -1) + im.fromstring(data, "raw", "RGBX", 0, -1) - + Eliminated unexpected side-effect in "paste" with matte. "paste" - now works properly also if compiled with "gcc". +- "new" no longer gives a MemoryError if the width or height + is zero (this only happened on platforms where malloc(0) + or calloc(0) returns NULL). - + Adapted to Python 1.5 (build issues only) +- "new" now adds a default palette object to "P" images. - + Fixed the ImageDraw "point" method to draw also the last - point (!). +- You can now convert directly between all modes supported by + PIL. When converting colour images to "P", PIL defaults to + a "web" palette and dithering. When converting greyscale + images to "1", PIL uses a thresholding and dithering. - + Added "I" and "RGBX" support to Image.new. +- Added a "dither" option to "convert". By default, "convert" + uses floyd-steinberg error diffusion for "P" and "1" targets, + so this option is only used to *disable* dithering. Allowed + values are NONE (no dithering) or FLOYDSTEINBERG (default). + :: - + The plugin path is now properly prepended to the module search - path when a plugin module is imported. + imOut = im.convert("P", dither=Image.NONE) - + Added "draw" method to the ImageWin.Dib class. This is used by - Topaz to print images on Windows printers. +- Added a full set of "I" decoders. You can use "fromstring" + (and file decoders) to read any standard integer type as an + "I" image. - + "convert" now supports conversions from "P" to "1" and "F". +- Added some support for "YCbCr" images (creation, conversion + from/to "L" and "RGB", IM YCC load/save) - + "paste" can now take a colour instead of an image as the first argument. - The colour must match the colour argument given to the new function, and - match the mode of the target image. +- "getpixel" now works properly with fractional coordinates. - + Fixed "paste" to allow a mask also for mode "F" images. +- ImageDraw "setink" now works with "I", "F", "RGB", "RGBA", + "RGBX", "CMYK", and "YCbCr" images. - + 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 - other 8-bit files. +- ImImagePlugin no longer attaches palettes to "RGB" images. - + The IM driver now reads and saves "1" images (file modes "0 1" or "L 1"). +- Various minor fixes. - + 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 - image will be loaded as a "P" image. +0.3a4 +----- - + Fixed a potential buffer overrun in the GIF encoder. +- Added experimental IPTC/NAA support. - (0.3a2 released) +- Eliminated AttributeError exceptions after "crop" (from + Skip Montanaro) - The test suite includes 400 individual tests. +- Reads some uncompressed formats via memory mapping (this + is currently supported on Win32 only) - + Improvements to the test suite revealed a number of minor bugs, which - are all fixed. Note that crop/paste, 32-bit ImageDraw, and ImageFont - are still weak spots in this release. +- Fixed some last minute glitches in the last alpha release + (Types instead of types in Image.py, version numbers, etc.) - + Added "putpalette" method to the Image class. You can use this - to add or modify the palette for "P" and "L" images. If a palette - is added to an "L" image, it is automatically converted to a "P" - image. +- Eliminated some more bogus compiler warnings. - + Fixed ImageDraw to properly handle 32-bit image memories - ("RGB", "RGBA", "CMYK", "F") +- Various fixes to make PIL compile and run smoother on Macs + (from Jack Jansen). - + Fixed "fromstring" and "tostring" not to mess up the mode attribute - in default mode. +- Fixed "fromstring" and "tostring" for mode "I" images. - + Changed ImPlatform.h to work on CRAY's (don't have one at home, so I - haven't tried it). The previous version assumed that either "short" - or "int" were 16-bit wide. PIL still won't compile on platforms where - neither "short", "int" nor "long" are 32-bit wide. +0.3a3 +----- - + Added file= and data= keyword arguments to PhotoImage and BitmapImage. - This allows you to use them as drop-in replacements for the corre- - sponding Tkinter classes. +The test suite includes 530 individual tests. - + Removed bogus references to the crack coder (ImagingCrack). +- Eliminated unexpected side-effect in "paste" with matte. "paste" + now works properly also if compiled with "gcc". - (0.3a1 released) +- Adapted to Python 1.5 (build issues only) - + Make sure image is loaded in "tostring". +- Fixed the ImageDraw "point" method to draw also the last + point (!). - + Added floating point packer (native 32-bit floats only). +- Added "I" and "RGBX" support to Image.new. - *** Changes from release 0.1b1 to 0.2 (b5) *** +- The plugin path is now properly prepended to the module search + path when a plugin module is imported. - + Modified "fromstring" and "tostring" methods to use file codecs. - Also added "fromstring" factory method to create an image directly - from data in a string. +- Added "draw" method to the ImageWin.Dib class. This is used by + Topaz to print images on Windows printers. - + Added support for 32-bit floating point images (mode "F"). You - can convert between "L" and "F" images, and apply a subset of the - available image processing methods on the "F" image. You can also - read virtually any data format into a floating point image memory; - see the section on "Decoding Floating Point Data" in the handbook - for more information. +- "convert" now supports conversions from "P" to "1" and "F". - (0.2b5 released; on windows only) +- "paste" can now take a colour instead of an image as the first argument. + The colour must match the colour argument given to the new function, and + match the mode of the target image. - + Fixed the tobitmap() method to work properly for small bitmaps. +- Fixed "paste" to allow a mask also for mode "F" images. - + Added RMS and standard deviation to the ImageStat.Stat class. Also - modified the constructor to take an optional feature mask, and also - to accept either an image or a list containing the histogram data. +- 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 + other 8-bit files. - + The BitmapImage code in ImageTk can now use a special bitmap - decoder, which has to be patched into Tk. See the "Tk/pilbitmap.txt" - file for details. If not installed, bitmaps are transferred to Tk as - XBM strings. +- The IM driver now reads and saves "1" images (file modes "0 1" or "L 1"). - + The PhotoImage code in ImageTk now uses a Tcl command ("PyImagingPaste") - instead of a special image type. This gives somewhat better performance, - and also allows PIL to support transparency. - *** WARNING: TKAPPINIT MUST BE MODIFIED *** +- 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 + image will be loaded as a "P" image. - + ImageTk now honours the alpha layer in RGBA images. Only fully - transparent pixels are made transparent (that is, the alpha layer - is treated as a mask). To treat the alpha laters as a matte, you - must paste the image on the background before handing it over to - ImageTk. +- Fixed a potential buffer overrun in the GIF encoder. - + Added McIdas reader (supports 8-bit images only). +0.3a2 +----- - + PIL now preloads drivers for BMP, GIF, JPEG, PPM, and TIFF. As - long as you only load and save these formats, you don't have to - wait for a full scan for drivers. To force scanning, call the - Image.init() function. +The test suite includes 400 individual tests. - + The "seek" and "tell" methods are now always available, also for - single-frame images. +- Improvements to the test suite revealed a number of minor bugs, which + are all fixed. Note that crop/paste, 32-bit ImageDraw, and ImageFont + are still weak spots in this release. - + Added optional mask argument to histogram method. The mask may - be an "1" or "L" image with the same size as the original image. - Only pixels where the mask is non-zero are included in the - histogram. +- Added "putpalette" method to the Image class. You can use this + to add or modify the palette for "P" and "L" images. If a palette + is added to an "L" image, it is automatically converted to a "P" + image. - + The "paste" method now allows you to specify only the lower left - corner (a 2-tuple), instead of the full region (a 4-tuple). +- Fixed ImageDraw to properly handle 32-bit image memories + ("RGB", "RGBA", "CMYK", "F") - + Reverted to old plugin scanning model; now scans all directory - names in the path when looking for plugins. +- Fixed "fromstring" and "tostring" not to mess up the mode attribute + in default mode. - + Added PIXAR raster support. Only uncompressed ("dumped") RGB - images can currently be read (based on information provided - by Greg Coats). +- Changed ImPlatform.h to work on CRAY's (don't have one at home, so I + haven't tried it). The previous version assumed that either "short" + or "int" were 16-bit wide. PIL still won't compile on platforms where + neither "short", "int" nor "long" are 32-bit wide. - + Added FlashPix (FPX) read support. Reads all pixel formats, but - only the highest resolution is read, and the viewing transform is - currently ignored. +- Added file= and data= keyword arguments to PhotoImage and BitmapImage. + This allows you to use them as drop-in replacements for the corre- + sponding Tkinter classes. - + Made PNG encoding somewhat more efficient in "optimize" mode; a - bug in 0.2b4 didn't enable all predictor filters when optimized - storage were requested. +- Removed bogus references to the crack coder (ImagingCrack). - + Added Microsoft Image Composer (MIC) read support. When opened, - the first sprite in the file is loaded. You can use the seek method - to load additional sprites from the file. +0.3a1 +----- - + Properly reads "P" and "CMYK" PSD images. +- Make sure image is loaded in "tostring". - + "pilconvert" no longer optimizes by default; use the -o option to - make the file as small as possible (at the expense of speed); use - the -q option to set the quality when compressing to JPEG. +- Added floating point packer (native 32-bit floats only). - + Fixed "crop" not to drop the palette for "P" images. +0.1b1 to 0.2 (b5) +----------------- - + Added and verified FLC support. +- Modified "fromstring" and "tostring" methods to use file codecs. + Also added "fromstring" factory method to create an image directly + from data in a string. - + Paste with "L" or "RGBA" alpha is now several times faster on most - platforms. +- Added support for 32-bit floating point images (mode "F"). You + can convert between "L" and "F" images, and apply a subset of the + available image processing methods on the "F" image. You can also + read virtually any data format into a floating point image memory; + see the section on "Decoding Floating Point Data" in the handbook + for more information. - + Changed Image.new() to initialize the image to black, as described - in the handbook. To get an uninitialized image, use None as the - colour. +0.2b5 released; on windows only +------------------------------- - + Fixed the PDF encoder to produce a valid header; Acrobat no longer - complains when you load PDF images created by PIL. +- Fixed the tobitmap() method to work properly for small bitmaps. - + PIL only scans fully-qualified directory names in the path when - looking for plugins. - *** WARNING: MAY BREAK EXISTING CODE *** +- Added RMS and standard deviation to the ImageStat.Stat class. Also + modified the constructor to take an optional feature mask, and also + to accept either an image or a list containing the histogram data. - + Faster implementation of "save" used when filename is given, - or when file object has "fileno" and "flush" methods. +- The BitmapImage code in ImageTk can now use a special bitmap + decoder, which has to be patched into Tk. See the "Tk/pilbitmap.txt" + file for details. If not installed, bitmaps are transferred to Tk as + XBM strings. - + Don't crash in "crop" if region extends outside the source image. +- The PhotoImage code in ImageTk now uses a Tcl command ("PyImagingPaste") + instead of a special image type. This gives somewhat better performance, + and also allows PIL to support transparency. + **WARNING: TKAPPINIT MUST BE MODIFIED** - + Eliminated a massive memory leak in the "save" function. +- ImageTk now honours the alpha layer in RGBA images. Only fully + transparent pixels are made transparent (that is, the alpha layer + is treated as a mask). To treat the alpha laters as a matte, you + must paste the image on the background before handing it over to + ImageTk. - + The GIF decoder doesn't crash if the code size is set to an illegal - value. This could happen since another bug didn't handle local - palettes properly if they didn't have the same size as the - global palette (not very common). +- Added McIdas reader (supports 8-bit images only). - + Added predictor support (TIFF 6.0 section 14) to the TIFF decoder. +- PIL now preloads drivers for BMP, GIF, JPEG, PPM, and TIFF. As + long as you only load and save these formats, you don't have to + wait for a full scan for drivers. To force scanning, call the + Image.init() function. - + Fixed palette and padding problems in BMP driver. Now properly - writes "1", "L", "P" and "RGB" images. +- The "seek" and "tell" methods are now always available, also for + single-frame images. - + Fixed getpixel()/getdata() to return correct pixel values. +- Added optional mask argument to histogram method. The mask may + be an "1" or "L" image with the same size as the original image. + Only pixels where the mask is non-zero are included in the + histogram. - + Added PSD (PhotoShop) read support. Reads both uncompressed - and compressed images of most types. +- The "paste" method now allows you to specify only the lower left + corner (a 2-tuple), instead of the full region (a 4-tuple). - + Added GIF write support (writes "uncompressed" GIF files only, - due to unresolvable licensing issues). The "gifmaker.py" script - can be used to create GIF animations. +- Reverted to old plugin scanning model; now scans all directory + names in the path when looking for plugins. - + Reads 8-bit "L" and "P" TGA images. Also reads 16-bit "RGB" - images. +- Added PIXAR raster support. Only uncompressed ("dumped") RGB + images can currently be read (based on information provided + by Greg Coats). - + Added FLI read support. This driver has only been tested - on a few FLI samples. +- Added FlashPix (FPX) read support. Reads all pixel formats, but + only the highest resolution is read, and the viewing transform is + currently ignored. - + Reads 2-bit and 4-bit PCX images. +- Made PNG encoding somewhat more efficient in "optimize" mode; a + bug in 0.2b4 didn't enable all predictor filters when optimized + storage were requested. - + Added MSP read and write support. Both version 1 and 2 can be - read, but only version 1 (uncompressed) files are written. +- Added Microsoft Image Composer (MIC) read support. When opened, + the first sprite in the file is loaded. You can use the seek method + to load additional sprites from the file. - + Fixed a bug in the FLI/FLC identification code that caused the - driver to raise an exception when parsing valid FLI/FLC files. +- Properly reads "P" and "CMYK" PSD images. - + Improved performance when loading file format plugins, and when - opening files. +- "pilconvert" no longer optimizes by default; use the -o option to + make the file as small as possible (at the expense of speed); use + the -q option to set the quality when compressing to JPEG. - + Added GIF animation support, via the "seek" and "tell" methods. - You can use "player.py" to play an animated GIF file. +- Fixed "crop" not to drop the palette for "P" images. - + Removed MNG support, since the spec is changing faster than I - can change the code. I've added support for the experimental - ARG format instead. Contact me for more information on this - format. +- Added and verified FLC support. - + Added keyword options to the "save" method. The following options - are currently supported: +- Paste with "L" or "RGBA" alpha is now several times faster on most + platforms. - Format Option Description - -------------------------------------------------------- - JPEG optimize Minimize output file at the - expense of compression speed. +- Changed Image.new() to initialize the image to black, as described + in the handbook. To get an uninitialized image, use None as the + colour. - JPEG progressive Enable progressive output. - The option value is ignored. +- Fixed the PDF encoder to produce a valid header; Acrobat no longer + complains when you load PDF images created by PIL. - JPEG quality Set compression quality (1-100). - The default value is 75. +- PIL only scans fully-qualified directory names in the path when + looking for plugins. + **WARNING: MAY BREAK EXISTING CODE** - JPEG smooth Smooth dithered images. - Value is strength (1-100). - Default is off (0). +- Faster implementation of "save" used when filename is given, + or when file object has "fileno" and "flush" methods. - PNG optimize Minimize output file at the - expense of compression speed. +- Don't crash in "crop" if region extends outside the source image. - Expect more options in future releases. Also note that - file writers silently ignore unknown options. +- Eliminated a massive memory leak in the "save" function. - + Plugged memory leaks in the PNG and TIFF decoders. +- The GIF decoder doesn't crash if the code size is set to an illegal + value. This could happen since another bug didn't handle local + palettes properly if they didn't have the same size as the + global palette (not very common). - + Added PNG write support. +- Added predictor support (TIFF 6.0 section 14) to the TIFF decoder. - + (internal) RGB unpackers and converters now set the pad byte - to 255 (full opacity). +- Fixed palette and padding problems in BMP driver. Now properly + writes "1", "L", "P" and "RGB" images. - + Properly handles the "transparency" property for GIF, PNG - and XPM files. +- Fixed getpixel()/getdata() to return correct pixel values. - + Added a "putalpha" method, allowing you to attach a "1" or "L" - image as the alpha layer to an "RGBA" image. +- Added PSD (PhotoShop) read support. Reads both uncompressed + and compressed images of most types. - + Various improvements to the sample scripts: +- Added GIF write support (writes "uncompressed" GIF files only, + due to unresolvable licensing issues). The "gifmaker.py" script + can be used to create GIF animations. - "pilconvert" Carries out some extra tricks in order to make - the resulting file as small as possible. +- Reads 8-bit "L" and "P" TGA images. Also reads 16-bit "RGB" + images. - "explode" (NEW) Split an image sequence into individual frames. +- Added FLI read support. This driver has only been tested + on a few FLI samples. - "gifmaker" (NEW) Convert a sequence file into a GIF animation. - Note that the GIF encoder create "uncompressed" GIF - files, so animations created by this script are - rather large (typically 2-5 times the compressed - sizes). +- Reads 2-bit and 4-bit PCX images. - "image2py" (NEW) Convert a single image to a python module. See - comments in this script for details. +- Added MSP read and write support. Both version 1 and 2 can be + read, but only version 1 (uncompressed) files are written. - "player" If multiple images are given on the command line, - they are interpreted as frames in a sequence. The - script assumes that they all have the same size. - Also note that this script now can play FLI/FLC - and GIF animations. +- Fixed a bug in the FLI/FLC identification code that caused the + driver to raise an exception when parsing valid FLI/FLC files. - This player can also execute embedded Python - animation applets (ARG format only). +- Improved performance when loading file format plugins, and when + opening files. - "viewer" Transparent images ("P" with transparency property, - and "RGBA") are superimposed on the standard Tk back- - ground. +- Added GIF animation support, via the "seek" and "tell" methods. + You can use "player.py" to play an animated GIF file. - + Fixed colour argument to "new". For multilayer images, pass a - tuple: (Red, Green, Blue), (Red, Green, Blue, Alpha), or (Cyan, - Magenta, Yellow, Black). +- Removed MNG support, since the spec is changing faster than I + can change the code. I've added support for the experimental + ARG format instead. Contact me for more information on this + format. - + Added XPM (X pixmap) read support. +- Added keyword options to the "save" method. The following options + are currently supported: - (0.2b3 released) + .. list-table:: + :widths: 25 25 50 + :header-rows: 1 - + Added MNG (multi-image network graphics) read support. "Ming" - is a proposed animation standard, based on the PNG file format. + * - Format + - Option + - Description + * - JPEG + - optimize + - Minimize output file at the expense of compression speed. + * - JPEG + - progressive + - Enable progressive output. The option value is ignored. + * - JPEG + - quality + - Set compression quality (1-100). The default value is 75. + * - JPEG + - smooth + - Smooth dithered images. Value is strength (1-100). Default is off (0). + * - PNG + - optimize + - Minimize output file at the expense of compression speed. - You can use the "player" sample script to display some flavours - of this format. The MNG standard is still under development, - as is this driver. More information, including sample files, - can be found at + Expect more options in future releases. Also note that + file writers silently ignore unknown options. - + Added a "verify" method to images loaded from file. This method - scans the file for errors, without actually decoding the image - data, and raises a suitable exception if it finds any problems. - Currently implemented for PNG and MNG files only. +- Plugged memory leaks in the PNG and TIFF decoders. - + Added support for interlaced GIF images. +- Added PNG write support. - + Added PNG read support -- if linked with the ZLIB compression library, - PIL reads all kinds of PNG images, except interlaced files. +- (internal) RGB unpackers and converters now set the pad byte + to 255 (full opacity). - + Improved PNG identification support -- doesn't mess up on unknown - chunks, identifies all possible PNG modes, and verifies checksum - on PNG header chunks. +- Properly handles the "transparency" property for GIF, PNG + and XPM files. - + Added an experimental reader for placable Windows Meta Files (WMF). - This reader is still very incomplete, but it illustrates how PIL's - drawing capabilities can be used to render vector and metafile - formats. +- Added a "putalpha" method, allowing you to attach a "1" or "L" + image as the alpha layer to an "RGBA" image. - + Added restricted drivers for images from Image Tools (greyscale - only) and LabEye/IFUNC (common interchange modes only). +- Various improvements to the sample scripts: - + Some minor improvements to the sample scripts provided in the - "Scripts" directory. + .. list-table:: + :widths: 25 75 - + The test images have been moved to the "Images" directory. + * - pilconvert + - Carries out some extra tricks in order to make + the resulting file as small as possible. + * - explode + - (NEW) Split an image sequence into individual frames. + * - gifmaker + - (NEW) Convert a sequence file into a GIF animation. + Note that the GIF encoder create "uncompressed" GIF + files, so animations created by this script are + rather large (typically 2-5 times the compressed + sizes). + * - image2py + - (NEW) Convert a single image to a python module. See + comments in this script for details. + * - player + - If multiple images are given on the command line, + they are interpreted as frames in a sequence. The + script assumes that they all have the same size. + Also note that this script now can play FLI/FLC + and GIF animations. + + This player can also execute embedded Python + animation applets (ARG format only). + * - viewer + - Transparent images ("P" with transparency property, + and "RGBA") are superimposed on the standard Tk background. + +- Fixed colour argument to "new". For multilayer images, pass a + tuple: (Red, Green, Blue), (Red, Green, Blue, Alpha), or (Cyan, + Magenta, Yellow, Black). + +- Added XPM (X pixmap) read support. + +0.2b3 +----- + +- Added MNG (multi-image network graphics) read support. "Ming" + is a proposed animation standard, based on the PNG file format. + + You can use the "player" sample script to display some flavours + of this format. The MNG standard is still under development, + as is this driver. More information, including sample files, + can be found at + +- Added a "verify" method to images loaded from file. This method + scans the file for errors, without actually decoding the image + data, and raises a suitable exception if it finds any problems. + Currently implemented for PNG and MNG files only. + +- Added support for interlaced GIF images. + +- Added PNG read support -- if linked with the ZLIB compression library, + PIL reads all kinds of PNG images, except interlaced files. + +- Improved PNG identification support -- doesn't mess up on unknown + chunks, identifies all possible PNG modes, and verifies checksum + on PNG header chunks. + +- Added an experimental reader for placable Windows Meta Files (WMF). + This reader is still very incomplete, but it illustrates how PIL's + drawing capabilities can be used to render vector and metafile + formats. + +- Added restricted drivers for images from Image Tools (greyscale + only) and LabEye/IFUNC (common interchange modes only). + +- Some minor improvements to the sample scripts provided in the + "Scripts" directory. + +- The test images have been moved to the "Images" directory. - (0.2b2 released) - (0.2b1 released; Windows only) +0.2b2 released. 0.2b1 released for Windows only +----------------------------------------------- - + Fixed filling of complex polygons. The ImageDraw "line" and - "polygon" methods also accept Path objects. +- Fixed filling of complex polygons. The ImageDraw "line" and + "polygon" methods also accept Path objects. - + The ImageTk "PhotoImage" object can now be constructed directly - from an image. You can also pass the object itself to Tkinter, - instead of using the "image" attribute. Finally, using "paste" - on a displayed image automatically updates the display. +- The ImageTk "PhotoImage" object can now be constructed directly + from an image. You can also pass the object itself to Tkinter, + instead of using the "image" attribute. Finally, using "paste" + on a displayed image automatically updates the display. - + The ImageTk "BitmapImage" object allows you to create transparent - overlays from 1-bit images. You can pass the object itself to - Tkinter. The constructor takes the same arguments as the Tkinter - BitmapImage class; use the "foreground" option to set the colour - of the overlay. +- The ImageTk "BitmapImage" object allows you to create transparent + overlays from 1-bit images. You can pass the object itself to + Tkinter. The constructor takes the same arguments as the Tkinter + BitmapImage class; use the "foreground" option to set the colour + of the overlay. - + Added a "putdata" method to the Image class. This can be used to - load a 1-layer image with data from a sequence object or a string. - An optional floating point scale and offset can be used to adjust - the data to fit into the 8-bit pixel range. Also see the "getdata" - method. +- Added a "putdata" method to the Image class. This can be used to + load a 1-layer image with data from a sequence object or a string. + An optional floating point scale and offset can be used to adjust + the data to fit into the 8-bit pixel range. Also see the "getdata" + method. - + Added the EXTENT method to the Image "transform" method. This can - be used to quickly crop, stretch, shrink, or mirror a subregion - from another image. +- Added the EXTENT method to the Image "transform" method. This can + be used to quickly crop, stretch, shrink, or mirror a subregion + from another image. - + Adapted to Python 1.4. +- Adapted to Python 1.4. - + Added a project makefile for Visual C++ 4.x. This allows you to - easily build a dynamically linked version of PIL for Windows 95 - and NT. +- Added a project makefile for Visual C++ 4.x. This allows you to + easily build a dynamically linked version of PIL for Windows 95 + and NT. - + A Tk "booster" patch for Windows is available. It gives dramatic - performance improvements for some displays. Has been tested with - Tk 4.2 only, but is likely to work with Tk 4.1 as well. See the Tk - subdirectory for details. +- A Tk "booster" patch for Windows is available. It gives dramatic + performance improvements for some displays. Has been tested with + Tk 4.2 only, but is likely to work with Tk 4.1 as well. See the Tk + subdirectory for details. - + You can now save 1-bit images in the XBM format. In addition, the - Image class now provides a "tobitmap" method which returns a string - containing an XBM representation of the image. Quite handy to use - with Tk. +- You can now save 1-bit images in the XBM format. In addition, the + Image class now provides a "tobitmap" method which returns a string + containing an XBM representation of the image. Quite handy to use + with Tk. - + More conversions, including "RGB" to "1" and more. +- More conversions, including "RGB" to "1" and more. - (0.2a1 released) +0.2a1 +----- - + Where earlier versions accepted lists, this version accepts arbitrary - Python sequences (including strings, in some cases). A few resource - leaks were plugged in the process. +- Where earlier versions accepted lists, this version accepts arbitrary + Python sequences (including strings, in some cases). A few resource + leaks were plugged in the process. - + The Image "paste" method now allows the box to extend outside - the target image. The size of the box, the image to be pasted, - and the optional mask must still match. +- The Image "paste" method now allows the box to extend outside + the target image. The size of the box, the image to be pasted, + and the optional mask must still match. - + The ImageDraw module now supports filled polygons, outlined and - filled ellipses, and text. Font support is rudimentary, though. +- The ImageDraw module now supports filled polygons, outlined and + filled ellipses, and text. Font support is rudimentary, though. - + The Image "point" method now takes an optional mode argument, - allowing you to convert the image while translating it. Currently, - this can only be used to convert "L" or "P" images to "1" images - (creating thresholded images or "matte" masks). +- The Image "point" method now takes an optional mode argument, + allowing you to convert the image while translating it. Currently, + this can only be used to convert "L" or "P" images to "1" images + (creating thresholded images or "matte" masks). - + An Image "getpixel" method has been added. For single band images, - it returns the pixel value at a given position as an integer. - For n-band images, it returns an n-tuple of integers. +- An Image "getpixel" method has been added. For single band images, + it returns the pixel value at a given position as an integer. + For n-band images, it returns an n-tuple of integers. - + An Image "getdata" method has been added. It returns a sequence - object representing the image as a 1-dimensional array. Only len() - and [] can be used with this sequence. This method returns a - reference to the existing image data, so changes in the image - will be immediately reflected in the sequence object. +- An Image "getdata" method has been added. It returns a sequence + object representing the image as a 1-dimensional array. Only len() + and [] can be used with this sequence. This method returns a + reference to the existing image data, so changes in the image + will be immediately reflected in the sequence object. - + Fixed alignment problems in the Windows BMP writer. +- Fixed alignment problems in the Windows BMP writer. - + If converting an "RGB" image to "RGB" or "L", you can give a second - argument containing a colour conversion matrix. +- If converting an "RGB" image to "RGB" or "L", you can give a second + argument containing a colour conversion matrix. - + An Image "getbbox" method has been added. It returns the bounding - box of data in an image, considering the value 0 as background. +- An Image "getbbox" method has been added. It returns the bounding + box of data in an image, considering the value 0 as background. - + An Image "offset" method has been added. It returns a new image - where the contents of the image have been offset the given distance - in X and/or Y direction. Data wraps between edges. +- An Image "offset" method has been added. It returns a new image + where the contents of the image have been offset the given distance + in X and/or Y direction. Data wraps between edges. - + Saves PDF images. The driver creates a binary PDF 1.1 files, using - JPEG compression for "L", "RGB", and "CMYK" images, and hex encoding - (same as for PostScript) for other formats. +- Saves PDF images. The driver creates a binary PDF 1.1 files, using + JPEG compression for "L", "RGB", and "CMYK" images, and hex encoding + (same as for PostScript) for other formats. - + The "paste" method now accepts "1" masks. Zero means transparent, - any other pixel value means opaque. This is faster than using an - "L" transparency mask. +- The "paste" method now accepts "1" masks. Zero means transparent, + any other pixel value means opaque. This is faster than using an + "L" transparency mask. - + Properly writes EPS files (and properly prints images to PostScript - printers as well). +- Properly writes EPS files (and properly prints images to PostScript + printers as well). - + Reads 4-bit BMP files, as well as 4 and 8-bit Windows ICO and CUR - files. Cursor animations are not supported. +- Reads 4-bit BMP files, as well as 4 and 8-bit Windows ICO and CUR + files. Cursor animations are not supported. - + Fixed alignment problems in the Sun raster loader. +- Fixed alignment problems in the Sun raster loader. - + Added "draft" and "thumbnail" methods. The draft method is used - to optimize loading of JPEG and PCD files, the thumbnail method is - used to create a thumbnail representation of an image. +- Added "draft" and "thumbnail" methods. The draft method is used + to optimize loading of JPEG and PCD files, the thumbnail method is + used to create a thumbnail representation of an image. - + Added Windows display support, via the ImageWin class (see the - handbook for details). +- Added Windows display support, via the ImageWin class (see the + handbook for details). - + Added raster conversion for EPS files. This requires GNU or Aladdin - Ghostscript, and probably works on UNIX only. +- Added raster conversion for EPS files. This requires GNU or Aladdin + Ghostscript, and probably works on UNIX only. - + Reads PhotoCD (PCD) images. The base resolution (768x512) can be - read from a PhotoCD file. +- Reads PhotoCD (PCD) images. The base resolution (768x512) can be + read from a PhotoCD file. - + Eliminated some compiler warnings. Bindings now compile cleanly in C++ - mode. Note that the Imaging library itself must be compiled in C mode. +- Eliminated some compiler warnings. Bindings now compile cleanly in C++ + mode. Note that the Imaging library itself must be compiled in C mode. - + Added "bdf2pil.py", which converts BDF fonts into images with associated - metrics. This is definitely work in progress. For info, see description - in script for details. +- Added "bdf2pil.py", which converts BDF fonts into images with associated + metrics. This is definitely work in progress. For info, see description + in script for details. - + Fixed a bug in the "ImageEnhance.py" module. +- Fixed a bug in the "ImageEnhance.py" module. - + Fixed a bug in the netpbm save hack in "GifImagePlugin.py" +- Fixed a bug in the netpbm save hack in "GifImagePlugin.py" - + Fixed 90 and 270 degree rotation of rectangular images. +- Fixed 90 and 270 degree rotation of rectangular images. - + Properly reads 8-bit TIFF palette-color images. +- Properly reads 8-bit TIFF palette-color images. - + Reads plane separated RGB and CMYK TIFF images. +- Reads plane separated RGB and CMYK TIFF images. - + Added driver debug mode. This is enabled by setting Image.DEBUG - to a non-zero value. Try the -D option to "pilfile.py" and see what - happens. +- Added driver debug mode. This is enabled by setting Image.DEBUG + to a non-zero value. Try the -D option to "pilfile.py" and see what + happens. - + Don't crash on "atend" constructs in PostScript files. +- Don't crash on "atend" constructs in PostScript files. - + Only the Image module imports _imaging directly. Other modules - should refer to the binding module as "Image.core". +- Only the Image module imports _imaging directly. Other modules + should refer to the binding module as "Image.core". - *** Changes from release 0.0 to 0.1 (b1) *** +0.0 to 0.1 (b1) +--------------- - + A handbook is available (distributed separately). +- A handbook is available (distributed separately). - + The coordinate system is changed so that (0,0) is now located - in the upper left corner. This is in compliancy with ISO 12087 - and 90% of all other image processing and graphics libraries. +- The coordinate system is changed so that (0,0) is now located + in the upper left corner. This is in compliancy with ISO 12087 + and 90% of all other image processing and graphics libraries. - + Modes "1" (bilevel) and "P" (palette) have been introduced. Note - that bilevel images are stored with one byte per pixel. +- Modes "1" (bilevel) and "P" (palette) have been introduced. Note + that bilevel images are stored with one byte per pixel. - + The Image "crop" and "paste" methods now accepts None as the - box argument, to refer to the full image (self, that is). +- The Image "crop" and "paste" methods now accepts None as the + box argument, to refer to the full image (self, that is). - + The Image "crop" method now works properly. +- The Image "crop" method now works properly. - + The Image "point" method is now available. You can use either a - lookup table or a function taking one argument. +- The Image "point" method is now available. You can use either a + lookup table or a function taking one argument. - + The Image join function has been renamed to "merge". +- The Image join function has been renamed to "merge". - + An Image "composite" function has been added. It is identical - to copy() followed by paste(mask). +- An Image "composite" function has been added. It is identical + to copy() followed by paste(mask). - + An Image "eval" function has been added. It is currently identical - to point(function); that is, only a single image can be processed. +- An Image "eval" function has been added. It is currently identical + to point(function); that is, only a single image can be processed. - + A set of channel operations has been added. See the "ImageChops" - module, test_chops.py, and the handbook for details. +- A set of channel operations has been added. See the "ImageChops" + module, test_chops.py, and the handbook for details. - + Added the "pilconvert" utility, which converts image files. Note - that the number of output formats are still quite restricted. +- Added the "pilconvert" utility, which converts image files. Note + that the number of output formats are still quite restricted. - + Added the "pilfile" utility, which quickly identifies image files - (without loading them, in most cases). +- Added the "pilfile" utility, which quickly identifies image files + (without loading them, in most cases). - + Added the "pilprint" utility, which prints image files to PostScript - printers. +- Added the "pilprint" utility, which prints image files to PostScript + printers. - + Added a rudimentary version of the "pilview" utility, which is - simple image viewer based on Tk. Only File/Exit and Image/Next - works properly. +- Added a rudimentary version of the "pilview" utility, which is + simple image viewer based on Tk. Only File/Exit and Image/Next + works properly. - + An interface to Tk has been added. See "Lib/ImageTk.py" and README - for details. +- An interface to Tk has been added. See "Lib/ImageTk.py" and README + for details. - + An interface to Jack Jansen's Img library has been added (thanks to - Jack). This allows you to read images through the Img extensions file - format handlers. See the file "Lib/ImgExtImagePlugin.py" for details. +- An interface to Jack Jansen's Img library has been added (thanks to + Jack). This allows you to read images through the Img extensions file + format handlers. See the file "Lib/ImgExtImagePlugin.py" for details. - + PostScript printing is provided through the PSDraw module. See the - handbook for details. +- PostScript printing is provided through the PSDraw module. See the + handbook for details. diff --git a/Makefile b/Makefile index 26359859965..219dda1de50 100644 --- a/Makefile +++ b/Makefile @@ -77,7 +77,7 @@ release-test: -rm dist/*.egg -rmdir dist python3 -m pytest -qq - python3 -m check-manifest + python3 -m check_manifest python3 -m pyroma . $(MAKE) readme @@ -85,6 +85,8 @@ release-test: sdist: python3 -m build --help > /dev/null 2>&1 || python3 -m pip install build python3 -m build --sdist + python3 -m twine --help > /dev/null 2>&1 || python3 -m pip install twine + python3 -m twine check --strict dist/* .PHONY: test test: diff --git a/README.md b/README.md index 7bff737a289..5e9adaf7e95 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,9 @@ As of 2019, Pillow development is GitHub Actions build status (Test MinGW) + GitHub Actions build status (Test Cygwin) GitHub Actions build status (Test Docker) diff --git a/RELEASING.md b/RELEASING.md index cbedd449c0c..aa7511c8a41 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -24,13 +24,12 @@ Released quarterly on January 2nd, April 1st, July 1st and October 15th. * [ ] Create and check source distribution: ```bash make sdist - twine check dist/* ``` * [ ] 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 - twine check dist/* - twine upload dist/Pillow-5.2.0* + python3 -m twine check --strict dist/* + python3 -m twine upload dist/Pillow-5.2.0* ``` * [ ] 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` @@ -61,13 +60,12 @@ Released as needed for security, installation or critical bug fixes. * [ ] Create and check source distribution: ```bash make sdist - twine check dist/* ``` * [ ] 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 - twine check dist/* - twine upload dist/Pillow-5.2.1* + python3 -m twine check --strict dist/* + python3 -m twine upload dist/Pillow-5.2.1* ``` * [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) @@ -91,7 +89,6 @@ Released as needed privately to individual vendors for critical security-related * [ ] Create and check source distribution: ```bash make sdist - twine check dist/* ``` * [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/main/RELEASING.md#binary-distributions) * [ ] Publish the [release on GitHub](https://github.com/python-pillow/Pillow/releases) diff --git a/Tests/README.rst b/Tests/README.rst index 55464578702..2d014e5a46e 100644 --- a/Tests/README.rst +++ b/Tests/README.rst @@ -8,7 +8,7 @@ Dependencies Install:: - python3 -m pip install pytest pytest-cov + python3 -m pip install pytest pytest-cov pytest-timeout Execution --------- diff --git a/Tests/helper.py b/Tests/helper.py index feccce6bcf9..13c6955e41d 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -324,7 +324,7 @@ def is_mingw(): return sysconfig.get_platform() == "mingw" -class cached_property: +class CachedProperty: def __init__(self, func): self.func = func diff --git a/Tests/images/16bit.r.tif b/Tests/images/16bit.r.tif new file mode 100644 index 00000000000..0f3996e95eb Binary files /dev/null and b/Tests/images/16bit.r.tif differ diff --git a/Tests/images/comment_after_last_frame.gif b/Tests/images/comment_after_last_frame.gif new file mode 100644 index 00000000000..9f5c7b8da47 Binary files /dev/null and b/Tests/images/comment_after_last_frame.gif differ diff --git a/Tests/images/cross_scan_line_truncated.tga b/Tests/images/cross_scan_line_truncated.tga new file mode 100644 index 00000000000..cec4357e3ac Binary files /dev/null and b/Tests/images/cross_scan_line_truncated.tga differ diff --git a/Tests/images/decompression_bomb.ico b/Tests/images/decompression_bomb.ico index 0efc9eaf74b..2ecfa8586e8 100644 Binary files a/Tests/images/decompression_bomb.ico and b/Tests/images/decompression_bomb.ico differ diff --git a/Tests/images/duplicate_number_of_loops.gif b/Tests/images/duplicate_number_of_loops.gif new file mode 100644 index 00000000000..ac315ee99f3 Binary files /dev/null and b/Tests/images/duplicate_number_of_loops.gif differ diff --git a/Tests/images/hopper_32bit.pgm b/Tests/images/hopper_32bit.pgm deleted file mode 100644 index 63728fb7dd1..00000000000 Binary files a/Tests/images/hopper_32bit.pgm and /dev/null differ diff --git a/Tests/images/hopper_32bit_plain.pgm b/Tests/images/hopper_32bit_plain.pgm deleted file mode 100644 index 16eb1955971..00000000000 --- a/Tests/images/hopper_32bit_plain.pgm +++ /dev/null @@ -1,4 +0,0 @@ -P2 -128 128 -2147483647 -210537600 185273088 117901056 218959104 244223616 244223616 151587072 185273088 286331136 294752640 227380608 193694592 252645120 252645120 218959104 252645120 303174144 311595648 269488128 202116096 185273088 193694592 202116096 261066624 277909632 252645120 176851584 261066624 185273088 926365440 1928524416 1364283648 1524292224 1389548160 1541135232 985315968 185273088 328438656 303174144 151587072 429496704 1456920192 597926784 168430080 320017152 1019001984 1726408320 1979053440 2080111488 2038003968 2021160960 2012739456 1979053440 1659036288 387389184 488447232 867414912 766356864 783199872 791621376 842150400 825307392 884257920 858993408 842150400 749513856 842150400 791621376 783199872 842150400 842150400 825307392 816885888 800042880 800042880 800042880 800042880 808464384 833728896 850571904 842150400 833728896 816885888 816885888 842150400 842150400 850571904 858993408 842150400 842150400 842150400 833728896 825307392 833728896 833728896 825307392 825307392 825307392 825307392 833728896 833728896 833728896 833728896 833728896 833728896 833728896 825307392 825307392 833728896 842150400 850571904 850571904 833728896 825307392 833728896 858993408 909522432 943208448 968472960 968472960 976894464 976894464 976894464 968472960 943208448 934786944 934786944 943208448 210537600 185273088 134744064 227380608 235802112 235802112 143165568 168430080 269488128 277909632 210537600 176851584 244223616 244223616 227380608 269488128 286331136 311595648 261066624 185273088 176851584 176851584 193694592 244223616 210537600 269488128 218959104 227380608 252645120 1103217024 1490606208 774778368 1465341696 496868736 404232192 741092352 530554752 261066624 168430080 227380608 471604224 1414812672 614769792 244223616 143165568 261066624 673720320 1221118080 1692722304 2029582464 2046425472 2029582464 1987474944 1726408320 353703168 320017152 774778368 800042880 833728896 698984832 614769792 682141824 774778368 825307392 825307392 850571904 825307392 825307392 867414912 808464384 774778368 833728896 833728896 800042880 800042880 858993408 867414912 816885888 800042880 816885888 842150400 833728896 825307392 833728896 850571904 850571904 867414912 858993408 858993408 850571904 858993408 842150400 833728896 833728896 833728896 825307392 842150400 825307392 825307392 825307392 825307392 833728896 833728896 842150400 842150400 842150400 833728896 833728896 825307392 825307392 825307392 833728896 858993408 850571904 842150400 850571904 892679424 917943936 960051456 968472960 985315968 985315968 993737472 976894464 960051456 951629952 951629952 960051456 210537600 202116096 143165568 235802112 235802112 227380608 126322560 160008576 261066624 269488128 193694592 168430080 235802112 244223616 218959104 269488128 261066624 294752640 261066624 193694592 185273088 193694592 202116096 244223616 294752640 244223616 185273088 235802112 286331136 1002158976 825307392 522133248 1423234176 564240768 244223616 252645120 202116096 277909632 378967680 176851584 606348288 1456920192 480025728 151587072 235802112 294752640 202116096 328438656 437918208 1692722304 1987474944 2021160960 1995896448 1886416896 1162167552 244223616 303174144 345281664 311595648 244223616 437918208 320017152 345281664 437918208 378967680 538976256 698984832 858993408 842150400 951629952 816885888 909522432 833728896 833728896 825307392 825307392 816885888 816885888 850571904 892679424 850571904 842150400 842150400 850571904 858993408 858993408 858993408 858993408 884257920 867414912 867414912 858993408 858993408 842150400 833728896 833728896 850571904 842150400 825307392 825307392 825307392 833728896 842150400 850571904 842150400 833728896 833728896 833728896 833728896 825307392 825307392 825307392 867414912 858993408 850571904 850571904 867414912 901100928 943208448 985315968 985315968 993737472 993737472 985315968 968472960 960051456 968472960 976894464 193694592 185273088 151587072 244223616 244223616 218959104 117901056 160008576 269488128 286331136 193694592 176851584 235802112 252645120 218959104 277909632 261066624 311595648 261066624 193694592 185273088 202116096 210537600 235802112 320017152 227380608 176851584 244223616 244223616 589505280 345281664 682141824 1507449216 505290240 202116096 210537600 252645120 227380608 303174144 176851584 471604224 1482184704 522133248 185273088 185273088 252645120 261066624 277909632 261066624 1600085760 2071689984 1221118080 1077952512 1448498688 480025728 218959104 328438656 244223616 218959104 665298816 1061109504 1027423488 623191296 446339712 395810688 395810688 395810688 345281664 673720320 808464384 901100928 783199872 825307392 842150400 825307392 816885888 867414912 917943936 867414912 774778368 858993408 858993408 858993408 867414912 875836416 875836416 867414912 850571904 875836416 867414912 867414912 858993408 858993408 850571904 850571904 850571904 850571904 842150400 842150400 833728896 833728896 842150400 850571904 850571904 825307392 833728896 833728896 833728896 842150400 842150400 833728896 833728896 842150400 850571904 850571904 842150400 850571904 884257920 934786944 976894464 960051456 968472960 968472960 960051456 960051456 960051456 968472960 976894464 176851584 185273088 160008576 235802112 235802112 210537600 126322560 176851584 277909632 286331136 210537600 176851584 235802112 252645120 227380608 269488128 261066624 303174144 277909632 193694592 185273088 202116096 210537600 227380608 193694592 261066624 235802112 193694592 185273088 303174144 176851584 715827840 1397969664 404232192 244223616 202116096 303174144 303174144 261066624 160008576 741092352 1423234176 277909632 218959104 244223616 202116096 294752640 269488128 378967680 1726408320 1701143808 395810688 227380608 151587072 269488128 261066624 336860160 1280068608 1170589056 614769792 1145324544 2004317952 951629952 269488128 1027423488 1414812672 665298816 395810688 353703168 446339712 808464384 934786944 850571904 867414912 884257920 875836416 850571904 850571904 875836416 901100928 867414912 867414912 875836416 875836416 892679424 884257920 867414912 858993408 858993408 858993408 867414912 867414912 858993408 858993408 858993408 858993408 858993408 858993408 858993408 858993408 858993408 858993408 858993408 850571904 850571904 850571904 850571904 850571904 850571904 850571904 850571904 842150400 825307392 842150400 858993408 850571904 850571904 867414912 901100928 934786944 917943936 926365440 934786944 934786944 934786944 934786944 943208448 951629952 176851584 185273088 168430080 252645120 235802112 210537600 126322560 185273088 277909632 286331136 210537600 176851584 244223616 244223616 210537600 252645120 252645120 303174144 269488128 176851584 160008576 185273088 193694592 210537600 218959104 286331136 218959104 176851584 218959104 210537600 185273088 698984832 1482184704 429496704 286331136 252645120 286331136 227380608 185273088 286331136 757935360 1473763200 336860160 252645120 193694592 210537600 261066624 168430080 395810688 1819044864 715827840 362124672 168430080 176851584 218959104 741092352 1970631936 2105376000 2122219008 1768515840 1170589056 2130640512 1431655680 1339019136 2096954496 2130640512 2046425472 1431655680 345281664 395810688 454761216 800042880 901100928 808464384 800042880 909522432 926365440 850571904 816885888 867414912 892679424 875836416 884257920 892679424 892679424 892679424 875836416 858993408 842150400 842150400 850571904 850571904 867414912 858993408 867414912 867414912 858993408 867414912 867414912 875836416 867414912 867414912 858993408 850571904 875836416 867414912 858993408 850571904 842150400 842150400 842150400 842150400 842150400 850571904 850571904 850571904 850571904 858993408 867414912 884257920 892679424 892679424 901100928 909522432 909522432 917943936 926365440 934786944 168430080 202116096 185273088 269488128 235802112 202116096 126322560 176851584 252645120 269488128 202116096 185273088 252645120 261066624 218959104 261066624 252645120 303174144 261066624 176851584 151587072 185273088 185273088 202116096 294752640 261066624 176851584 193694592 210537600 202116096 218959104 707406336 1406391168 454761216 210537600 210537600 320017152 311595648 244223616 160008576 707406336 1423234176 336860160 168430080 168430080 311595648 261066624 336860160 387389184 1549556736 1381126656 1246382592 235802112 193694592 1044266496 2088532992 1869573888 1322176128 1962210432 2054846976 2139062016 2096954496 2038003968 2130640512 2071689984 1760094336 1726408320 1936945920 1633771776 421075200 362124672 1145324544 1625350272 1296911616 985315968 867414912 875836416 884257920 892679424 901100928 892679424 884257920 884257920 884257920 884257920 884257920 875836416 867414912 842150400 850571904 850571904 850571904 867414912 858993408 858993408 858993408 875836416 875836416 875836416 867414912 867414912 867414912 867414912 867414912 884257920 867414912 858993408 842150400 833728896 833728896 842150400 850571904 858993408 850571904 842150400 850571904 858993408 858993408 858993408 850571904 867414912 884257920 901100928 909522432 909522432 909522432 917943936 926365440 185273088 210537600 185273088 277909632 244223616 202116096 109479552 168430080 227380608 252645120 202116096 176851584 252645120 261066624 218959104 261066624 269488128 328438656 277909632 168430080 151587072 176851584 193694592 202116096 202116096 227380608 210537600 218959104 151587072 235802112 227380608 648455808 1431655680 505290240 176851584 261066624 311595648 218959104 252645120 235802112 917943936 1322176128 252645120 193694592 261066624 261066624 244223616 909522432 1819044864 2113797504 2139062016 1136903040 202116096 555819264 1027423488 724249344 1019001984 800042880 623191296 858993408 1397969664 1894838400 1869573888 1381126656 850571904 741092352 1094795520 1035844992 614769792 850571904 294752640 429496704 1979053440 2122219008 2071689984 1692722304 1204275072 909522432 867414912 901100928 901100928 892679424 892679424 875836416 884257920 884257920 884257920 867414912 850571904 850571904 850571904 850571904 858993408 858993408 858993408 858993408 892679424 884257920 867414912 858993408 858993408 867414912 875836416 875836416 867414912 858993408 842150400 825307392 825307392 833728896 850571904 858993408 858993408 850571904 833728896 842150400 858993408 875836416 875836416 875836416 875836416 892679424 901100928 909522432 917943936 917943936 926365440 926365440 193694592 227380608 968472960 336860160 202116096 185273088 134744064 143165568 235802112 294752640 185273088 151587072 353703168 286331136 193694592 244223616 227380608 328438656 218959104 202116096 151587072 185273088 143165568 176851584 244223616 235802112 244223616 168430080 160008576 210537600 252645120 665298816 1448498688 446339712 218959104 269488128 286331136 294752640 252645120 218959104 825307392 1364283648 261066624 294752640 210537600 370546176 1633771776 2080111488 2147483520 2105376000 2139062016 884257920 252645120 235802112 244223616 1145324544 1600085760 2038003968 1953788928 1204275072 1962210432 1667457792 1785358848 1684300800 1237961088 2063268480 1827466368 1785358848 698984832 218959104 395810688 311595648 1549556736 2139062016 2088532992 2122219008 2113797504 1760094336 1069531008 892679424 926365440 909522432 842150400 960051456 808464384 943208448 901100928 858993408 867414912 867414912 875836416 867414912 875836416 867414912 867414912 875836416 884257920 867414912 858993408 867414912 867414912 858993408 867414912 884257920 850571904 850571904 842150400 833728896 833728896 842150400 858993408 875836416 842150400 858993408 875836416 867414912 858993408 850571904 858993408 867414912 867414912 867414912 867414912 867414912 875836416 884257920 901100928 901100928 185273088 311595648 1717986816 757935360 303174144 126322560 176851584 143165568 311595648 218959104 109479552 168430080 336860160 185273088 244223616 252645120 303174144 286331136 218959104 218959104 176851584 134744064 151587072 227380608 235802112 227380608 202116096 202116096 261066624 227380608 235802112 623191296 1431655680 446339712 210537600 277909632 294752640 286331136 235802112 202116096 842150400 1364283648 269488128 117901056 656877312 1911681408 2088532992 2130640512 2063268480 2130640512 2096954496 724249344 218959104 277909632 277909632 1010580480 1566399744 1835887872 1877995392 2063268480 2105376000 2063268480 2113797504 2105376000 2096954496 1920102912 1911681408 1785358848 732670848 437918208 235802112 277909632 1237961088 2130640512 2130640512 2038003968 2130640512 2122219008 1987474944 1532713728 968472960 842150400 892679424 926365440 909522432 892679424 825307392 917943936 875836416 867414912 867414912 867414912 867414912 875836416 867414912 875836416 867414912 858993408 850571904 867414912 867414912 858993408 867414912 884257920 858993408 858993408 850571904 850571904 842150400 850571904 867414912 875836416 850571904 850571904 858993408 858993408 850571904 850571904 850571904 850571904 867414912 867414912 867414912 867414912 875836416 884257920 901100928 901100928 134744064 294752640 1793780352 1877995392 370546176 210537600 134744064 294752640 210537600 252645120 202116096 218959104 227380608 362124672 202116096 218959104 218959104 235802112 277909632 185273088 126322560 193694592 252645120 143165568 277909632 269488128 202116096 176851584 235802112 210537600 261066624 623191296 1431655680 471604224 227380608 277909632 294752640 269488128 227380608 185273088 951629952 1364283648 261066624 757935360 2105376000 2139062016 2096954496 2088532992 2088532992 2038003968 1861152384 530554752 336860160 210537600 261066624 454761216 1793780352 1717986816 1793780352 1903259904 1844309376 1835887872 1751672832 1835887872 1953788928 1852730880 1507449216 1827466368 597926784 328438656 437918208 404232192 1288490112 2139062016 2096954496 2139062016 2122219008 2139062016 2139062016 2088532992 1768515840 1052688000 892679424 943208448 926365440 816885888 976894464 825307392 858993408 858993408 858993408 858993408 858993408 867414912 858993408 867414912 858993408 850571904 850571904 858993408 858993408 858993408 867414912 884257920 867414912 867414912 867414912 858993408 858993408 858993408 875836416 884257920 875836416 867414912 867414912 867414912 867414912 867414912 867414912 858993408 875836416 867414912 875836416 875836416 884257920 892679424 901100928 909522432 168430080 328438656 1667457792 2021160960 1077952512 682141824 1448498688 766356864 227380608 244223616 176851584 193694592 277909632 1052688000 320017152 202116096 286331136 286331136 286331136 210537600 101058048 143165568 143165568 193694592 227380608 244223616 244223616 193694592 168430080 202116096 261066624 606348288 1431655680 505290240 227380608 269488128 311595648 269488128 235802112 202116096 1002158976 1246382592 496868736 2063268480 2038003968 2122219008 2071689984 1894838400 1456920192 1456920192 1743251328 496868736 101058048 193694592 185273088 320017152 909522432 1827466368 1709565312 2071689984 2105376000 2105376000 2113797504 2063268480 2105376000 2080111488 1751672832 1381126656 353703168 193694592 244223616 218959104 976894464 1987474944 2122219008 2130640512 2046425472 2130640512 2122219008 2130640512 2130640512 1852730880 968472960 884257920 884257920 934786944 850571904 875836416 842150400 850571904 842150400 842150400 842150400 842150400 842150400 842150400 858993408 842150400 842150400 858993408 867414912 858993408 858993408 875836416 875836416 875836416 875836416 867414912 867414912 867414912 875836416 884257920 892679424 875836416 867414912 867414912 875836416 875836416 867414912 850571904 875836416 875836416 884257920 884257920 884257920 892679424 901100928 909522432 218959104 244223616 1642193280 2113797504 1987474944 1928524416 1642193280 614769792 261066624 218959104 176851584 218959104 303174144 1532713728 791621376 269488128 202116096 286331136 218959104 202116096 202116096 252645120 58950528 193694592 176851584 210537600 210537600 235802112 185273088 218959104 210537600 538976256 1448498688 547397760 210537600 244223616 294752640 252645120 244223616 218959104 917943936 1313754624 1802201856 2071689984 2122219008 2029582464 1330597632 1153746048 960051456 505290240 277909632 202116096 176851584 269488128 218959104 320017152 1549556736 1852730880 1288490112 1802201856 2088532992 2130640512 2139062016 2147483520 2088532992 2012739456 1305333120 1827466368 892679424 336860160 277909632 328438656 496868736 1052688000 1600085760 1827466368 2113797504 2122219008 2071689984 2113797504 2046425472 2113797504 1600085760 884257920 867414912 867414912 884257920 858993408 842150400 842150400 842150400 850571904 842150400 842150400 842150400 842150400 858993408 833728896 842150400 850571904 858993408 850571904 850571904 867414912 858993408 867414912 867414912 867414912 858993408 850571904 858993408 867414912 875836416 858993408 850571904 842150400 858993408 858993408 850571904 842150400 875836416 875836416 875836416 875836416 884257920 892679424 909522432 917943936 294752640 1128481536 1911681408 2029582464 2004317952 1987474944 1364283648 320017152 227380608 252645120 235802112 210537600 261066624 1667457792 1381126656 227380608 286331136 303174144 800042880 858993408 202116096 117901056 227380608 151587072 252645120 480025728 168430080 218959104 210537600 218959104 202116096 538976256 1431655680 581083776 202116096 227380608 294752640 235802112 244223616 218959104 842150400 1650614784 2004317952 2080111488 1928524416 1027423488 842150400 395810688 134744064 176851584 117901056 193694592 126322560 134744064 269488128 210537600 1103217024 1381126656 1701143808 1911681408 1894838400 2122219008 2071689984 2105376000 1793780352 1768515840 1608507264 1684300800 774778368 277909632 395810688 261066624 294752640 202116096 277909632 833728896 1423234176 1844309376 2063268480 2122219008 2122219008 2130640512 2021160960 1077952512 960051456 842150400 833728896 917943936 858993408 858993408 858993408 867414912 858993408 858993408 858993408 867414912 850571904 842150400 842150400 858993408 858993408 850571904 850571904 867414912 850571904 858993408 867414912 867414912 858993408 850571904 850571904 850571904 875836416 867414912 858993408 850571904 858993408 858993408 858993408 858993408 867414912 867414912 875836416 875836416 892679424 901100928 926365440 926365440 1440077184 1936945920 2029582464 2113797504 2046425472 1936945920 968472960 134744064 286331136 286331136 151587072 168430080 345281664 1785358848 1793780352 715827840 673720320 1600085760 1751672832 682141824 185273088 202116096 168430080 160008576 412653696 1162167552 320017152 176851584 202116096 193694592 244223616 530554752 1414812672 597926784 202116096 227380608 303174144 227380608 244223616 218959104 816885888 1835887872 2046425472 1979053440 892679424 454761216 117901056 151587072 109479552 101058048 783199872 943208448 269488128 218959104 143165568 328438656 1052688000 2004317952 1953788928 1760094336 1364283648 1911681408 2096954496 2080111488 1616928768 1785358848 1979053440 1995896448 732670848 345281664 328438656 269488128 294752640 875836416 286331136 336860160 227380608 682141824 1296911616 1616928768 2088532992 2004317952 1953788928 1760094336 783199872 960051456 901100928 875836416 867414912 867414912 867414912 867414912 867414912 867414912 867414912 867414912 858993408 850571904 850571904 867414912 867414912 850571904 850571904 858993408 850571904 858993408 867414912 867414912 858993408 850571904 842150400 850571904 884257920 884257920 875836416 867414912 867414912 867414912 875836416 884257920 867414912 875836416 867414912 875836416 892679424 909522432 934786944 943208448 1507449216 1886416896 2029582464 2080111488 2088532992 2088532992 1448498688 522133248 227380608 286331136 193694592 311595648 387389184 1684300800 1936945920 1886416896 2021160960 1936945920 1355862144 252645120 252645120 168430080 101058048 185273088 454761216 1793780352 597926784 202116096 227380608 202116096 286331136 446339712 1414812672 606348288 202116096 235802112 320017152 235802112 252645120 227380608 757935360 1920102912 1962210432 1136903040 218959104 101058048 168430080 892679424 825307392 387389184 277909632 1254804096 235802112 530554752 648455808 320017152 825307392 1591664256 1625350272 1608507264 1776937344 1305333120 808464384 901100928 1423234176 1583242752 1625350272 1726408320 833728896 387389184 530554752 294752640 631612800 1162167552 235802112 842150400 934786944 227380608 286331136 640034304 1372705152 2004317952 1995896448 1894838400 1035844992 867414912 892679424 901100928 867414912 875836416 867414912 867414912 867414912 867414912 875836416 867414912 867414912 850571904 850571904 867414912 867414912 850571904 850571904 858993408 850571904 858993408 867414912 867414912 858993408 850571904 842150400 842150400 867414912 867414912 875836416 867414912 850571904 850571904 867414912 884257920 858993408 858993408 867414912 875836416 892679424 909522432 934786944 943208448 227380608 421075200 1010580480 2080111488 2054846976 1717986816 1616928768 757935360 252645120 303174144 210537600 640034304 1397969664 1995896448 1970631936 1953788928 1987474944 1810623360 488447232 277909632 210537600 244223616 67372032 176851584 589505280 1928524416 1212696576 218959104 480025728 993737472 404232192 488447232 1440077184 656877312 193694592 193694592 303174144 277909632 210537600 244223616 707406336 1557978240 1187432064 210537600 193694592 218959104 227380608 1473763200 1717986816 1616928768 1541135232 1229539584 1625350272 1869573888 1970631936 1802201856 1810623360 1019001984 825307392 303174144 269488128 412653696 320017152 311595648 320017152 412653696 690563328 1499027712 1633771776 1945367424 2038003968 1465341696 1549556736 1162167552 1819044864 1835887872 1482184704 446339712 816885888 488447232 395810688 1381126656 2054846976 1869573888 1339019136 892679424 917943936 884257920 892679424 850571904 901100928 850571904 909522432 858993408 867414912 867414912 884257920 867414912 858993408 858993408 867414912 875836416 867414912 858993408 867414912 858993408 858993408 850571904 850571904 850571904 858993408 867414912 875836416 884257920 892679424 901100928 892679424 892679424 901100928 901100928 909522432 901100928 901100928 901100928 909522432 917943936 934786944 943208448 218959104 227380608 707406336 2054846976 1608507264 538976256 480025728 353703168 227380608 437918208 1237961088 1844309376 2063268480 1995896448 2046425472 2021160960 1970631936 892679424 269488128 252645120 227380608 84215040 286331136 160008576 631612800 1911681408 1751672832 1204275072 1642193280 1069531008 269488128 345281664 1414812672 682141824 210537600 193694592 303174144 277909632 210537600 210537600 185273088 42107520 134744064 151587072 84215040 210537600 185273088 387389184 1145324544 1263225600 463182720 1473763200 1911681408 1507449216 1473763200 1886416896 2012739456 1979053440 2046425472 1616928768 960051456 656877312 261066624 454761216 892679424 1659036288 2071689984 1970631936 2004317952 1920102912 1684300800 1995896448 1945367424 1179010560 1557978240 1692722304 1591664256 1877995392 1701143808 387389184 193694592 362124672 1591664256 1549556736 917943936 454761216 353703168 791621376 892679424 858993408 884257920 842150400 901100928 867414912 858993408 858993408 884257920 858993408 850571904 850571904 858993408 858993408 858993408 850571904 867414912 867414912 858993408 858993408 858993408 867414912 875836416 884257920 892679424 901100928 909522432 909522432 901100928 901100928 917943936 926365440 917943936 917943936 917943936 917943936 926365440 934786944 943208448 951629952 134744064 311595648 665298816 1979053440 1069531008 235802112 235802112 185273088 252645120 345281664 800042880 1490606208 1861152384 2088532992 2046425472 2012739456 1894838400 1431655680 370546176 277909632 134744064 151587072 202116096 235802112 926365440 1995896448 1852730880 1515870720 1456920192 429496704 227380608 412653696 1372705152 724249344 210537600 193694592 286331136 277909632 185273088 160008576 210537600 134744064 134744064 160008576 126322560 134744064 84215040 185273088 109479552 294752640 505290240 892679424 437918208 286331136 1515870720 1659036288 1448498688 1221118080 842150400 631612800 530554752 656877312 421075200 640034304 589505280 682141824 1212696576 1339019136 1793780352 1827466368 1103217024 648455808 934786944 943208448 151587072 311595648 842150400 1616928768 1456920192 1339019136 1372705152 412653696 454761216 244223616 151587072 126322560 235802112 395810688 875836416 884257920 884257920 842150400 909522432 875836416 884257920 875836416 884257920 875836416 858993408 858993408 867414912 867414912 858993408 858993408 875836416 875836416 867414912 867414912 875836416 884257920 892679424 901100928 892679424 901100928 909522432 917943936 909522432 909522432 917943936 926365440 917943936 917943936 926365440 934786944 934786944 943208448 951629952 951629952 168430080 277909632 522133248 1743251328 547397760 261066624 244223616 117901056 176851584 320017152 168430080 311595648 623191296 1659036288 2080111488 2071689984 2029582464 1936945920 909522432 252645120 227380608 395810688 791621376 1179010560 1751672832 1995896448 1650614784 1532713728 791621376 176851584 193694592 303174144 1339019136 757935360 185273088 210537600 277909632 218959104 160008576 117901056 58950528 151587072 151587072 126322560 58950528 117901056 185273088 160008576 218959104 109479552 92636544 218959104 471604224 261066624 261066624 277909632 269488128 286331136 252645120 168430080 252645120 218959104 160008576 303174144 244223616 202116096 378967680 286331136 387389184 412653696 513711744 589505280 1456920192 1515870720 1583242752 538976256 210537600 202116096 800042880 1153746048 471604224 286331136 210537600 151587072 218959104 92636544 202116096 117901056 774778368 892679424 884257920 850571904 892679424 875836416 892679424 892679424 901100928 901100928 892679424 892679424 892679424 884257920 884257920 875836416 884257920 884257920 884257920 884257920 884257920 892679424 892679424 901100928 892679424 901100928 909522432 909522432 909522432 909522432 917943936 926365440 909522432 917943936 926365440 934786944 943208448 943208448 951629952 951629952 244223616 286331136 505290240 1246382592 269488128 261066624 235802112 160008576 160008576 202116096 210537600 160008576 320017152 1650614784 2004317952 976894464 1094795520 1659036288 1717986816 488447232 218959104 404232192 715827840 1263225600 1692722304 1861152384 1844309376 1490606208 370546176 202116096 218959104 320017152 1313754624 783199872 151587072 227380608 252645120 160008576 109479552 109479552 143165568 101058048 117901056 193694592 160008576 101058048 143165568 25264512 176851584 134744064 117901056 227380608 134744064 218959104 202116096 109479552 168430080 151587072 218959104 185273088 303174144 202116096 252645120 202116096 261066624 244223616 193694592 235802112 311595648 202116096 210537600 311595648 825307392 1094795520 1861152384 1776937344 673720320 277909632 185273088 126322560 109479552 143165568 126322560 75793536 134744064 117901056 50529024 151587072 623191296 850571904 850571904 858993408 867414912 850571904 875836416 901100928 909522432 917943936 917943936 917943936 917943936 909522432 901100928 901100928 901100928 901100928 901100928 892679424 892679424 892679424 892679424 892679424 909522432 909522432 917943936 917943936 909522432 917943936 926365440 934786944 917943936 926365440 934786944 943208448 951629952 951629952 951629952 951629952 117901056 261066624 362124672 505290240 218959104 286331136 218959104 151587072 244223616 244223616 261066624 294752640 227380608 1684300800 1583242752 370546176 261066624 320017152 774778368 715827840 168430080 202116096 168430080 269488128 1086374016 1877995392 1894838400 1566399744 934786944 235802112 227380608 244223616 1271647104 842150400 160008576 218959104 210537600 117901056 101058048 109479552 84215040 151587072 92636544 58950528 193694592 101058048 109479552 202116096 92636544 151587072 117901056 58950528 160008576 126322560 117901056 277909632 269488128 185273088 160008576 168430080 117901056 126322560 193694592 134744064 185273088 92636544 168430080 235802112 143165568 252645120 227380608 235802112 353703168 774778368 404232192 235802112 151587072 202116096 67372032 143165568 101058048 67372032 109479552 151587072 84215040 143165568 92636544 176851584 522133248 850571904 858993408 884257920 884257920 867414912 884257920 926365440 917943936 926365440 934786944 934786944 926365440 917943936 909522432 909522432 917943936 917943936 909522432 909522432 901100928 901100928 892679424 892679424 926365440 926365440 926365440 926365440 917943936 917943936 934786944 943208448 934786944 943208448 943208448 951629952 960051456 968472960 968472960 968472960 227380608 286331136 235802112 269488128 404232192 303174144 185273088 185273088 218959104 261066624 92636544 261066624 336860160 1701143808 858993408 294752640 277909632 370546176 311595648 336860160 218959104 109479552 151587072 117901056 825307392 2004317952 1616928768 1600085760 1642193280 429496704 117901056 269488128 1229539584 934786944 176851584 168430080 143165568 101058048 143165568 92636544 143165568 109479552 160008576 92636544 126322560 134744064 151587072 33686016 117901056 58950528 143165568 143165568 16843008 168430080 126322560 42107520 92636544 126322560 160008576 218959104 143165568 168430080 160008576 160008576 143165568 168430080 202116096 168430080 185273088 235802112 84215040 134744064 101058048 75793536 151587072 67372032 134744064 84215040 0 117901056 101058048 101058048 109479552 126322560 33686016 67372032 160008576 134744064 522133248 909522432 884257920 917943936 909522432 901100928 917943936 926365440 917943936 926365440 943208448 943208448 926365440 917943936 917943936 926365440 934786944 934786944 926365440 917943936 917943936 917943936 909522432 909522432 934786944 934786944 934786944 926365440 917943936 917943936 926365440 934786944 934786944 934786944 943208448 943208448 951629952 960051456 976894464 976894464 168430080 345281664 218959104 244223616 328438656 336860160 252645120 126322560 160008576 218959104 202116096 185273088 378967680 1389548160 277909632 311595648 261066624 294752640 269488128 227380608 176851584 176851584 126322560 151587072 1061109504 1877995392 673720320 328438656 1221118080 1061109504 227380608 193694592 1195853568 993737472 210537600 151587072 92636544 101058048 168430080 101058048 126322560 75793536 160008576 101058048 151587072 134744064 117901056 126322560 101058048 109479552 58950528 134744064 160008576 8421504 143165568 75793536 109479552 92636544 92636544 67372032 92636544 109479552 75793536 101058048 126322560 92636544 75793536 101058048 58950528 58950528 134744064 92636544 101058048 143165568 42107520 75793536 101058048 58950528 202116096 75793536 117901056 33686016 134744064 84215040 151587072 143165568 84215040 109479552 538976256 926365440 892679424 917943936 909522432 917943936 901100928 909522432 926365440 934786944 951629952 951629952 934786944 926365440 926365440 934786944 934786944 934786944 926365440 926365440 926365440 926365440 926365440 926365440 926365440 926365440 926365440 917943936 901100928 901100928 917943936 926365440 934786944 926365440 934786944 934786944 943208448 951629952 968472960 976894464 193694592 269488128 235802112 286331136 311595648 336860160 227380608 168430080 235802112 202116096 151587072 252645120 370546176 480025728 303174144 227380608 294752640 286331136 286331136 252645120 185273088 126322560 126322560 151587072 1237961088 1397969664 210537600 117901056 244223616 429496704 235802112 168430080 1094795520 1002158976 185273088 117901056 109479552 134744064 134744064 126322560 117901056 134744064 109479552 101058048 117901056 101058048 92636544 109479552 67372032 101058048 109479552 101058048 92636544 109479552 101058048 58950528 84215040 109479552 92636544 84215040 117901056 101058048 75793536 92636544 117901056 101058048 92636544 92636544 101058048 101058048 92636544 84215040 84215040 101058048 101058048 84215040 84215040 109479552 101058048 67372032 109479552 84215040 101058048 109479552 109479552 143165568 143165568 92636544 538976256 943208448 909522432 917943936 875836416 951629952 909522432 976894464 943208448 943208448 951629952 951629952 934786944 926365440 926365440 926365440 926365440 934786944 943208448 943208448 943208448 943208448 934786944 934786944 926365440 926365440 917943936 917943936 926365440 943208448 943208448 951629952 951629952 934786944 917943936 917943936 934786944 943208448 934786944 934786944 202116096 269488128 235802112 286331136 303174144 328438656 210537600 143165568 185273088 227380608 202116096 269488128 269488128 328438656 235802112 269488128 269488128 277909632 286331136 261066624 193694592 143165568 134744064 151587072 1111638528 538976256 185273088 210537600 134744064 143165568 168430080 227380608 1044266496 1035844992 160008576 117901056 101058048 134744064 126322560 117901056 75793536 151587072 134744064 84215040 84215040 126322560 126322560 151587072 126322560 126322560 109479552 92636544 75793536 84215040 117901056 160008576 101058048 117901056 109479552 101058048 117901056 109479552 75793536 84215040 75793536 84215040 84215040 84215040 101058048 109479552 117901056 109479552 75793536 109479552 117901056 101058048 75793536 75793536 84215040 92636544 67372032 33686016 58950528 84215040 67372032 84215040 126322560 143165568 471604224 926365440 934786944 951629952 917943936 968472960 917943936 976894464 951629952 951629952 960051456 960051456 951629952 943208448 943208448 943208448 951629952 951629952 960051456 960051456 951629952 951629952 943208448 943208448 951629952 943208448 934786944 934786944 934786944 943208448 943208448 951629952 951629952 934786944 917943936 917943936 926365440 934786944 934786944 934786944 193694592 269488128 244223616 294752640 294752640 320017152 193694592 134744064 176851584 218959104 210537600 244223616 202116096 202116096 202116096 311595648 261066624 269488128 286331136 269488128 202116096 151587072 134744064 151587072 488447232 193694592 303174144 109479552 84215040 193694592 185273088 176851584 1002158976 1111638528 134744064 134744064 101058048 126322560 117901056 117901056 176851584 134744064 75793536 92636544 160008576 134744064 50529024 50529024 92636544 67372032 84215040 143165568 134744064 92636544 75793536 101058048 92636544 92636544 92636544 92636544 101058048 109479552 92636544 101058048 117901056 117901056 117901056 109479552 101058048 92636544 92636544 84215040 117901056 101058048 101058048 109479552 117901056 117901056 109479552 117901056 117901056 75793536 101058048 143165568 117901056 84215040 101058048 101058048 404232192 934786944 951629952 976894464 934786944 976894464 926365440 976894464 960051456 960051456 968472960 976894464 968472960 960051456 960051456 960051456 968472960 968472960 976894464 976894464 968472960 960051456 960051456 951629952 968472960 968472960 960051456 951629952 943208448 951629952 951629952 960051456 943208448 934786944 926365440 917943936 926365440 934786944 934786944 934786944 193694592 269488128 235802112 294752640 294752640 311595648 185273088 117901056 218959104 210537600 151587072 210537600 244223616 210537600 244223616 311595648 277909632 277909632 286331136 261066624 202116096 134744064 126322560 143165568 143165568 269488128 235802112 151587072 176851584 202116096 117901056 210537600 985315968 1187432064 134744064 151587072 101058048 126322560 109479552 109479552 109479552 117901056 101058048 92636544 101058048 84215040 92636544 160008576 151587072 109479552 75793536 92636544 109479552 109479552 117901056 126322560 143165568 117901056 126322560 134744064 117901056 117901056 134744064 143165568 126322560 134744064 134744064 143165568 160008576 160008576 176851584 185273088 151587072 126322560 109479552 109479552 101058048 84215040 84215040 101058048 92636544 50529024 67372032 101058048 101058048 126322560 134744064 109479552 353703168 960051456 960051456 976894464 926365440 960051456 943208448 1002158976 976894464 976894464 985315968 985315968 976894464 976894464 976894464 976894464 985315968 985315968 985315968 985315968 985315968 976894464 976894464 968472960 976894464 976894464 968472960 960051456 960051456 960051456 960051456 960051456 943208448 934786944 934786944 926365440 934786944 934786944 943208448 951629952 193694592 252645120 235802112 286331136 286331136 320017152 185273088 126322560 235802112 210537600 134744064 202116096 286331136 218959104 277909632 303174144 294752640 294752640 277909632 235802112 176851584 126322560 117901056 143165568 235802112 269488128 168430080 235802112 101058048 109479552 126322560 202116096 976894464 1179010560 134744064 143165568 92636544 117901056 101058048 109479552 42107520 117901056 143165568 117901056 126322560 134744064 75793536 67372032 109479552 185273088 269488128 311595648 362124672 429496704 463182720 471604224 421075200 353703168 336860160 320017152 244223616 227380608 261066624 244223616 320017152 336860160 395810688 454761216 538976256 614769792 673720320 707406336 741092352 673720320 555819264 421075200 269488128 151587072 109479552 101058048 109479552 101058048 101058048 101058048 67372032 109479552 143165568 109479552 261066624 951629952 968472960 968472960 943208448 968472960 960051456 1010580480 976894464 985315968 993737472 993737472 985315968 976894464 985315968 993737472 976894464 976894464 976894464 976894464 976894464 976894464 985315968 985315968 976894464 976894464 968472960 968472960 968472960 968472960 968472960 976894464 951629952 951629952 943208448 943208448 943208448 943208448 960051456 960051456 193694592 261066624 227380608 269488128 277909632 311595648 193694592 126322560 193694592 218959104 168430080 202116096 286331136 193694592 286331136 286331136 303174144 294752640 277909632 244223616 168430080 126322560 117901056 143165568 218959104 218959104 277909632 151587072 75793536 176851584 176851584 160008576 976894464 1094795520 126322560 126322560 101058048 109479552 117901056 117901056 134744064 92636544 67372032 101058048 117901056 84215040 151587072 311595648 640034304 833728896 1035844992 1120060032 1136903040 1145324544 1153746048 1145324544 1120060032 1027423488 1019001984 985315968 858993408 808464384 833728896 808464384 850571904 850571904 909522432 985315968 1077952512 1170589056 1221118080 1246382592 1170589056 1187432064 1212696576 1195853568 1103217024 816885888 421075200 117901056 75793536 67372032 117901056 126322560 84215040 84215040 117901056 92636544 168430080 934786944 960051456 993737472 985315968 993737472 976894464 1002158976 993737472 993737472 1002158976 993737472 993737472 985315968 993737472 993737472 985315968 976894464 976894464 976894464 976894464 985315968 993737472 993737472 985315968 976894464 976894464 976894464 976894464 985315968 985315968 985315968 960051456 960051456 960051456 960051456 951629952 960051456 968472960 985315968 202116096 269488128 227380608 269488128 269488128 303174144 193694592 143165568 160008576 227380608 185273088 193694592 277909632 185273088 303174144 261066624 294752640 277909632 269488128 244223616 185273088 117901056 117901056 151587072 193694592 151587072 244223616 185273088 210537600 176851584 84215040 218959104 1044266496 1035844992 160008576 101058048 84215040 109479552 109479552 101058048 134744064 101058048 75793536 101058048 151587072 320017152 749513856 1212696576 1322176128 1381126656 1431655680 1431655680 1440077184 1448498688 1482184704 1507449216 1507449216 1431655680 1456920192 1465341696 1330597632 1280068608 1313754624 1280068608 1339019136 1330597632 1347440640 1381126656 1456920192 1490606208 1482184704 1456920192 1423234176 1389548160 1355862144 1355862144 1414812672 1347440640 1086374016 808464384 311595648 143165568 50529024 92636544 101058048 101058048 117901056 143165568 143165568 960051456 968472960 1002158976 993737472 1002158976 993737472 993737472 1010580480 1010580480 1010580480 1010580480 993737472 993737472 1002158976 1002158976 993737472 993737472 985315968 985315968 976894464 985315968 985315968 985315968 993737472 993737472 993737472 993737472 993737472 993737472 993737472 993737472 976894464 985315968 976894464 968472960 968472960 968472960 985315968 1002158976 218959104 277909632 227380608 261066624 269488128 303174144 193694592 134744064 143165568 227380608 168430080 176851584 277909632 210537600 328438656 261066624 269488128 269488128 269488128 244223616 193694592 126322560 117901056 143165568 210537600 235802112 210537600 227380608 126322560 151587072 160008576 160008576 1103217024 1010580480 193694592 109479552 101058048 109479552 92636544 92636544 84215040 193694592 210537600 261066624 623191296 1103217024 1381126656 1423234176 1440077184 1381126656 1372705152 1473763200 1591664256 1633771776 1659036288 1667457792 1642193280 1566399744 1642193280 1701143808 1600085760 1574821248 1616928768 1583242752 1608507264 1583242752 1591664256 1633771776 1667457792 1684300800 1650614784 1600085760 1482184704 1507449216 1499027712 1431655680 1431655680 1448498688 1381126656 1263225600 1077952512 597926784 193694592 126322560 126322560 109479552 126322560 160008576 176851584 1002158976 976894464 976894464 976894464 985315968 993737472 1002158976 1019001984 1019001984 1019001984 1010580480 1002158976 1002158976 1002158976 1010580480 1010580480 1002158976 993737472 985315968 985315968 985315968 985315968 985315968 1002158976 1002158976 1010580480 993737472 1002158976 1002158976 993737472 993737472 985315968 993737472 993737472 993737472 976894464 976894464 993737472 1010580480 631612800 320017152 244223616 320017152 244223616 320017152 218959104 143165568 151587072 244223616 210537600 218959104 193694592 303174144 303174144 252645120 277909632 261066624 252645120 261066624 202116096 117901056 117901056 151587072 176851584 269488128 193694592 176851584 210537600 117901056 126322560 202116096 1044266496 1094795520 109479552 101058048 84215040 117901056 134744064 126322560 353703168 682141824 589505280 732670848 1153746048 1364283648 1482184704 1532713728 1473763200 1499027712 1524292224 1549556736 1566399744 1616928768 1659036288 1692722304 1726408320 1692722304 1633771776 1659036288 1650614784 1650614784 1743251328 1726408320 1616928768 1726408320 1726408320 1684300800 1608507264 1768515840 1768515840 1701143808 1701143808 1532713728 1566399744 1440077184 1524292224 1440077184 1448498688 1296911616 1296911616 1061109504 791621376 522133248 109479552 101058048 143165568 109479552 218959104 1010580480 993737472 960051456 1010580480 1002158976 1027423488 1002158976 1019001984 1010580480 1002158976 1002158976 1010580480 1010580480 1002158976 993737472 1002158976 993737472 985315968 993737472 993737472 993737472 993737472 985315968 993737472 993737472 993737472 993737472 993737472 993737472 993737472 993737472 1002158976 1002158976 993737472 1002158976 1019001984 1027423488 1044266496 1052688000 1591664256 277909632 286331136 303174144 218959104 547397760 353703168 168430080 193694592 210537600 126322560 244223616 210537600 227380608 235802112 252645120 252645120 252645120 252645120 261066624 202116096 126322560 126322560 151587072 202116096 294752640 235802112 202116096 202116096 143165568 151587072 160008576 1002158976 1187432064 109479552 101058048 160008576 50529024 33686016 303174144 749513856 774778368 707406336 968472960 1305333120 1431655680 1499027712 1473763200 1524292224 1524292224 1566399744 1600085760 1642193280 1692722304 1717986816 1726408320 1675879296 1667457792 1675879296 1726408320 1684300800 1633771776 1667457792 1642193280 1717986816 1709565312 1684300800 1692722304 1659036288 1625350272 1591664256 1600085760 1608507264 1701143808 1490606208 1423234176 1456920192 1440077184 1406391168 1313754624 1313754624 1187432064 1153746048 791621376 488447232 134744064 151587072 84215040 252645120 993737472 976894464 960051456 1002158976 968472960 1002158976 1019001984 1027423488 1019001984 1010580480 1010580480 1019001984 1019001984 1019001984 1010580480 1019001984 1010580480 1002158976 1002158976 1010580480 1010580480 1002158976 993737472 1002158976 1002158976 1010580480 1010580480 1010580480 1010580480 1010580480 1010580480 1010580480 1010580480 1010580480 1019001984 1019001984 1027423488 1035844992 1035844992 1970631936 1263225600 252645120 404232192 1145324544 1482184704 277909632 92636544 235802112 294752640 244223616 244223616 210537600 277909632 235802112 244223616 210537600 227380608 261066624 261066624 202116096 126322560 126322560 151587072 193694592 261066624 235802112 218959104 193694592 168430080 202116096 160008576 1035844992 1120060032 101058048 151587072 101058048 126322560 286331136 589505280 698984832 648455808 842150400 1162167552 1313754624 1397969664 1490606208 1482184704 1583242752 1608507264 1642193280 1650614784 1608507264 1574821248 1541135232 1532713728 1625350272 1650614784 1667457792 1717986816 1667457792 1600085760 1642193280 1625350272 1549556736 1600085760 1583242752 1499027712 1490606208 1355862144 1229539584 1162167552 1229539584 1221118080 1330597632 1339019136 1271647104 1322176128 1330597632 1355862144 1305333120 1237961088 1221118080 1094795520 766356864 261066624 92636544 168430080 345281664 1027423488 1019001984 1002158976 1035844992 993737472 1035844992 1061109504 1035844992 1027423488 1019001984 1027423488 1035844992 1035844992 1035844992 1027423488 1035844992 1027423488 1019001984 1019001984 1027423488 1019001984 1010580480 1010580480 1019001984 1027423488 1027423488 1035844992 1035844992 1035844992 1035844992 1035844992 1019001984 1019001984 1027423488 1035844992 1035844992 1035844992 1027423488 1027423488 1953788928 1894838400 850571904 1701143808 1945367424 808464384 235802112 117901056 597926784 1002158976 202116096 244223616 227380608 235802112 244223616 244223616 193694592 227380608 261066624 252645120 193694592 117901056 117901056 160008576 227380608 261066624 244223616 244223616 202116096 176851584 210537600 160008576 1061109504 1136903040 117901056 126322560 16843008 134744064 345281664 530554752 648455808 741092352 1044266496 1195853568 1204275072 1313754624 1397969664 1406391168 1305333120 1280068608 1229539584 1162167552 1120060032 1136903040 1221118080 1296911616 1532713728 1616928768 1659036288 1675879296 1633771776 1625350272 1701143808 1642193280 1465341696 1549556736 1524292224 1347440640 1305333120 1136903040 1086374016 1128481536 1019001984 1145324544 1347440640 1364283648 1532713728 1364283648 1288490112 1305333120 1313754624 1271647104 1153746048 1136903040 1010580480 589505280 185273088 109479552 404232192 1044266496 1035844992 985315968 1010580480 1010580480 1010580480 1019001984 1035844992 1035844992 1027423488 1035844992 1044266496 1044266496 1044266496 1035844992 1044266496 1035844992 1027423488 1035844992 1035844992 1035844992 1035844992 1027423488 1044266496 1044266496 1044266496 1044266496 1044266496 1044266496 1035844992 1035844992 1027423488 1027423488 1035844992 1035844992 1044266496 1044266496 1044266496 1044266496 1886416896 2021160960 2012739456 1911681408 1566399744 345281664 160008576 168430080 648455808 1827466368 446339712 311595648 218959104 143165568 362124672 286331136 210537600 227380608 252645120 227380608 176851584 126322560 126322560 151587072 235802112 244223616 227380608 244223616 202116096 134744064 176851584 160008576 985315968 1195853568 143165568 101058048 117901056 185273088 320017152 589505280 791621376 884257920 1069531008 1153746048 1246382592 1372705152 1414812672 1414812672 1406391168 1313754624 1212696576 1145324544 1153746048 1195853568 1288490112 1372705152 1406391168 1557978240 1625350272 1616928768 1583242752 1633771776 1717986816 1616928768 1600085760 1482184704 1372705152 1313754624 1313754624 985315968 791621376 825307392 791621376 892679424 1077952512 1263225600 1482184704 1389548160 1499027712 1237961088 1221118080 1330597632 1288490112 968472960 1010580480 640034304 362124672 202116096 480025728 1077952512 1077952512 1002158976 1019001984 1061109504 1061109504 1019001984 1044266496 1035844992 1035844992 1035844992 1044266496 1052688000 1044266496 1044266496 1044266496 1035844992 1035844992 1035844992 1052688000 1052688000 1052688000 1044266496 1061109504 1061109504 1052688000 1052688000 1044266496 1035844992 1027423488 1027423488 1044266496 1035844992 1035844992 1035844992 1044266496 1061109504 1069531008 1077952512 2012739456 1920102912 1894838400 1869573888 800042880 252645120 303174144 92636544 808464384 1903259904 1305333120 303174144 261066624 842150400 1296911616 404232192 227380608 244223616 244223616 227380608 176851584 126322560 117901056 134744064 160008576 202116096 168430080 168430080 143165568 109479552 160008576 185273088 1010580480 1069531008 143165568 160008576 134744064 252645120 606348288 884257920 875836416 951629952 1044266496 1204275072 1339019136 1322176128 1288490112 1305333120 1305333120 1162167552 985315968 926365440 926365440 943208448 968472960 976894464 1271647104 1440077184 1515870720 1490606208 1456920192 1549556736 1675879296 1616928768 1583242752 1499027712 1372705152 1237961088 1103217024 842150400 732670848 774778368 673720320 522133248 581083776 538976256 480025728 538976256 530554752 623191296 648455808 791621376 791621376 842150400 960051456 698984832 345281664 261066624 623191296 1111638528 1094795520 1027423488 1035844992 1103217024 1077952512 1044266496 1044266496 1044266496 1035844992 1044266496 1052688000 1052688000 1052688000 1044266496 1052688000 1044266496 1044266496 1052688000 1061109504 1061109504 1061109504 1052688000 1069531008 1069531008 1061109504 1061109504 1052688000 1044266496 1035844992 1035844992 1052688000 1052688000 1044266496 1044266496 1052688000 1069531008 1086374016 1094795520 1894838400 1970631936 1894838400 1936945920 749513856 303174144 101058048 126322560 665298816 1903259904 1995896448 892679424 1465341696 1903259904 1111638528 244223616 227380608 235802112 244223616 218959104 193694592 160008576 134744064 117901056 151587072 286331136 227380608 126322560 109479552 126322560 168430080 168430080 1120060032 985315968 168430080 143165568 58950528 286331136 858993408 943208448 816885888 884257920 985315968 1246382592 1322176128 1212696576 1254804096 1246382592 1221118080 1077952512 917943936 842150400 842150400 901100928 1002158976 1111638528 1027423488 1246382592 1423234176 1482184704 1456920192 1524292224 1684300800 1701143808 1642193280 1490606208 1254804096 1120060032 1010580480 850571904 538976256 303174144 488447232 698984832 858993408 783199872 774778368 673720320 362124672 362124672 951629952 783199872 378967680 589505280 741092352 783199872 362124672 353703168 757935360 1120060032 1061109504 1010580480 1019001984 1044266496 1010580480 1035844992 1061109504 1052688000 1044266496 1052688000 1052688000 1052688000 1052688000 1044266496 1069531008 1069531008 1061109504 1061109504 1061109504 1069531008 1061109504 1052688000 1069531008 1069531008 1069531008 1069531008 1069531008 1061109504 1061109504 1052688000 1061109504 1061109504 1061109504 1061109504 1069531008 1077952512 1086374016 1086374016 1945367424 2054846976 2038003968 1903259904 1785358848 463182720 269488128 143165568 833728896 1827466368 2012739456 1979053440 1802201856 1583242752 353703168 176851584 202116096 227380608 244223616 235802112 210537600 168430080 126322560 109479552 277909632 480025728 378967680 168430080 126322560 143165568 168430080 126322560 1069531008 1061109504 202116096 92636544 210537600 488447232 968472960 960051456 842150400 774778368 682141824 757935360 606348288 404232192 412653696 244223616 227380608 261066624 320017152 345281664 311595648 286331136 387389184 496868736 757935360 1069531008 1414812672 1642193280 1642193280 1625350272 1709565312 1734829824 1667457792 1524292224 1263225600 993737472 606348288 589505280 884257920 1263225600 1019001984 1120060032 1187432064 1254804096 1019001984 1246382592 1945367424 909522432 235802112 395810688 353703168 437918208 614769792 715827840 538976256 522133248 968472960 1221118080 1120060032 1103217024 1103217024 1061109504 1027423488 1103217024 1069531008 1061109504 1052688000 1052688000 1061109504 1061109504 1052688000 1044266496 1094795520 1086374016 1077952512 1069531008 1069531008 1069531008 1061109504 1052688000 1069531008 1077952512 1077952512 1077952512 1077952512 1077952512 1077952512 1077952512 1061109504 1069531008 1069531008 1077952512 1077952512 1077952512 1077952512 1077952512 1499027712 1979053440 1734829824 1835887872 1970631936 1423234176 227380608 488447232 1667457792 1936945920 1903259904 1877995392 1802201856 800042880 320017152 176851584 218959104 227380608 218959104 269488128 126322560 631612800 429496704 412653696 1195853568 1372705152 252645120 185273088 92636544 151587072 134744064 160008576 1027423488 1019001984 261066624 160008576 294752640 850571904 1120060032 909522432 715827840 547397760 252645120 429496704 513711744 429496704 261066624 985315968 1600085760 1456920192 1195853568 1044266496 1052688000 1254804096 1271647104 808464384 682141824 538976256 976894464 1254804096 1616928768 1633771776 1549556736 1515870720 1381126656 1187432064 909522432 1019001984 1482184704 1153746048 985315968 429496704 320017152 362124672 513711744 648455808 1010580480 1019001984 1305333120 1684300800 522133248 404232192 749513856 589505280 581083776 774778368 909522432 800042880 1111638528 1061109504 1136903040 1103217024 1086374016 1111638528 1061109504 1061109504 1069531008 1069531008 1069531008 1069531008 1061109504 1061109504 1061109504 1061109504 1077952512 1077952512 1086374016 1094795520 1094795520 1086374016 1086374016 1086374016 1077952512 1077952512 1077952512 1086374016 1086374016 1086374016 1077952512 1077952512 1086374016 1077952512 1077952512 1077952512 1077952512 1077952512 1086374016 1086374016 1237961088 1802201856 589505280 480025728 816885888 1280068608 774778368 480025728 1709565312 1861152384 1844309376 1835887872 1600085760 353703168 244223616 202116096 202116096 235802112 218959104 261066624 176851584 606348288 917943936 1094795520 1532713728 665298816 143165568 84215040 151587072 143165568 126322560 160008576 1044266496 985315968 261066624 446339712 631612800 1002158976 1027423488 791621376 572662272 480025728 151587072 235802112 134744064 345281664 1061109504 1086374016 1145324544 825307392 496868736 404232192 378967680 336860160 757935360 1288490112 1162167552 1103217024 1170589056 1204275072 1414812672 1431655680 1423234176 1246382592 1204275072 1027423488 1061109504 1077952512 1010580480 917943936 395810688 665298816 261066624 437918208 387389184 353703168 530554752 741092352 656877312 606348288 665298816 589505280 505290240 336860160 345281664 682141824 1027423488 1254804096 1456920192 1322176128 1069531008 1145324544 1120060032 1086374016 1103217024 1145324544 1086374016 1086374016 1086374016 1077952512 1077952512 1077952512 1077952512 1077952512 1094795520 1094795520 1103217024 1103217024 1103217024 1094795520 1094795520 1086374016 1086374016 1086374016 1086374016 1094795520 1086374016 1086374016 1086374016 1077952512 1069531008 1077952512 1077952512 1086374016 1086374016 1094795520 1103217024 1103217024 1170589056 1574821248 303174144 320017152 168430080 277909632 244223616 227380608 1044266496 1827466368 1962210432 1936945920 1819044864 951629952 294752640 235802112 227380608 286331136 227380608 218959104 168430080 404232192 917943936 943208448 926365440 286331136 151587072 117901056 109479552 134744064 176851584 143165568 1061109504 1128481536 244223616 446339712 976894464 1111638528 901100928 614769792 395810688 412653696 488447232 437918208 235802112 850571904 951629952 1010580480 749513856 421075200 336860160 294752640 320017152 294752640 471604224 631612800 1002158976 960051456 943208448 1237961088 1263225600 1120060032 1179010560 1136903040 1111638528 892679424 1195853568 1136903040 917943936 488447232 665298816 395810688 126322560 311595648 320017152 362124672 387389184 614769792 665298816 766356864 1019001984 842150400 673720320 682141824 757935360 1069531008 1195853568 909522432 1120060032 1414812672 1111638528 1162167552 1052688000 1077952512 1162167552 1103217024 1103217024 1103217024 1103217024 1103217024 1103217024 1103217024 1094795520 1094795520 1111638528 1111638528 1120060032 1120060032 1111638528 1111638528 1103217024 1094795520 1103217024 1103217024 1103217024 1103217024 1094795520 1094795520 1094795520 1086374016 1077952512 1086374016 1094795520 1103217024 1103217024 1103217024 1103217024 1103217024 993737472 934786944 218959104 269488128 261066624 210537600 109479552 117901056 345281664 1675879296 1936945920 1726408320 1936945920 1692722304 387389184 126322560 185273088 277909632 244223616 202116096 227380608 522133248 1002158976 875836416 311595648 84215040 176851584 193694592 75793536 134744064 202116096 151587072 951629952 1179010560 286331136 480025728 1296911616 1145324544 968472960 901100928 597926784 698984832 496868736 555819264 412653696 749513856 589505280 842150400 412653696 362124672 471604224 210537600 143165568 378967680 741092352 875836416 564240768 707406336 774778368 1179010560 1077952512 1406391168 1625350272 1608507264 1389548160 1237961088 1288490112 1237961088 884257920 1052688000 934786944 816885888 741092352 673720320 623191296 656877312 741092352 783199872 901100928 1061109504 1280068608 1162167552 1237961088 1077952512 943208448 909522432 1019001984 589505280 522133248 1212696576 1162167552 1128481536 1044266496 1077952512 1170589056 1044266496 1120060032 1120060032 1120060032 1120060032 1120060032 1120060032 1120060032 1120060032 1128481536 1128481536 1128481536 1128481536 1128481536 1120060032 1111638528 1103217024 1103217024 1103217024 1111638528 1111638528 1111638528 1111638528 1103217024 1103217024 1103217024 1111638528 1120060032 1120060032 1111638528 1103217024 1094795520 1086374016 648455808 522133248 336860160 168430080 193694592 286331136 151587072 126322560 235802112 1684300800 1229539584 362124672 867414912 1507449216 976894464 193694592 218959104 269488128 261066624 176851584 143165568 530554752 968472960 1044266496 850571904 67372032 117901056 143165568 168430080 134744064 151587072 160008576 951629952 1136903040 286331136 682141824 1170589056 732670848 707406336 892679424 917943936 926365440 884257920 1077952512 901100928 698984832 665298816 623191296 581083776 547397760 614769792 631612800 850571904 842150400 850571904 1086374016 1153746048 1263225600 1271647104 1305333120 842150400 1490606208 1734829824 1734829824 1566399744 1044266496 1490606208 1414812672 1305333120 1145324544 1061109504 1237961088 1136903040 1086374016 1002158976 934786944 993737472 1136903040 1187432064 1120060032 1195853568 1254804096 1397969664 1120060032 1010580480 960051456 1153746048 1221118080 513711744 1027423488 1086374016 1086374016 1153746048 1094795520 1111638528 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 1136903040 1136903040 1136903040 1136903040 1128481536 1120060032 1111638528 1103217024 1111638528 1111638528 1120060032 1128481536 1128481536 1128481536 1128481536 1128481536 1120060032 1128481536 1128481536 1128481536 1120060032 1111638528 1103217024 1094795520 328438656 202116096 193694592 269488128 286331136 277909632 117901056 101058048 336860160 1709565312 665298816 235802112 294752640 269488128 454761216 227380608 227380608 202116096 244223616 244223616 202116096 505290240 749513856 985315968 1263225600 690563328 117901056 134744064 160008576 168430080 143165568 134744064 1010580480 1086374016 210537600 783199872 917943936 682141824 909522432 951629952 960051456 884257920 1237961088 1288490112 968472960 926365440 640034304 597926784 522133248 597926784 858993408 1229539584 1440077184 1355862144 1204275072 1280068608 1229539584 1465341696 1616928768 1423234176 825307392 1440077184 1667457792 1743251328 1692722304 1414812672 1431655680 1532713728 1288490112 1170589056 1473763200 1414812672 1532713728 1625350272 1532713728 1372705152 1162167552 1389548160 1423234176 1305333120 1330597632 1322176128 1330597632 1103217024 993737472 1263225600 1339019136 1187432064 707406336 1019001984 1111638528 1069531008 1162167552 1111638528 1086374016 1187432064 1136903040 1136903040 1136903040 1136903040 1136903040 1136903040 1136903040 1136903040 1145324544 1145324544 1145324544 1136903040 1136903040 1128481536 1120060032 1111638528 1120060032 1120060032 1128481536 1128481536 1136903040 1136903040 1136903040 1136903040 1111638528 1120060032 1120060032 1128481536 1128481536 1128481536 1128481536 1128481536 168430080 218959104 235802112 269488128 227380608 202116096 109479552 126322560 378967680 1254804096 168430080 261066624 311595648 168430080 202116096 134744064 261066624 235802112 235802112 227380608 168430080 193694592 160008576 269488128 724249344 909522432 193694592 210537600 101058048 176851584 160008576 143165568 1052688000 1136903040 185273088 538976256 698984832 581083776 1027423488 926365440 875836416 917943936 1170589056 1372705152 1094795520 1094795520 825307392 732670848 741092352 934786944 1170589056 1507449216 1515870720 1532713728 1406391168 1246382592 1128481536 1524292224 1675879296 1246382592 1035844992 1583242752 1726408320 1642193280 1709565312 1515870720 1145324544 1574821248 1608507264 1347440640 1187432064 1448498688 1566399744 1490606208 1397969664 1305333120 1162167552 1330597632 1431655680 1339019136 1397969664 1355862144 1372705152 1237961088 1044266496 1347440640 1583242752 1296911616 732670848 1120060032 1153746048 1094795520 1103217024 1136903040 1120060032 1145324544 1136903040 1136903040 1145324544 1145324544 1145324544 1145324544 1145324544 1153746048 1145324544 1145324544 1145324544 1145324544 1145324544 1136903040 1128481536 1120060032 1120060032 1120060032 1136903040 1136903040 1136903040 1136903040 1128481536 1128481536 1120060032 1120060032 1120060032 1120060032 1128481536 1128481536 1136903040 1136903040 227380608 176851584 218959104 176851584 261066624 244223616 134744064 126322560 277909632 480025728 227380608 294752640 244223616 244223616 210537600 202116096 185273088 277909632 252645120 193694592 193694592 126322560 92636544 126322560 168430080 252645120 218959104 235802112 134744064 117901056 143165568 160008576 926365440 1111638528 235802112 429496704 858993408 538976256 1162167552 1246382592 1069531008 774778368 1103217024 1246382592 1170589056 1120060032 1153746048 1002158976 858993408 1136903040 1111638528 1313754624 1229539584 1103217024 993737472 1162167552 1659036288 1600085760 1456920192 1010580480 1330597632 1650614784 1734829824 1726408320 1650614784 1726408320 1204275072 1431655680 1515870720 1717986816 1583242752 1296911616 1271647104 1111638528 1187432064 1077952512 1120060032 1179010560 1456920192 1414812672 1263225600 1271647104 1271647104 1221118080 1179010560 1002158976 1364283648 1372705152 800042880 1179010560 1111638528 1153746048 1086374016 1162167552 1145324544 1128481536 1145324544 1145324544 1145324544 1145324544 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1145324544 1136903040 1128481536 1136903040 1136903040 1145324544 1136903040 1136903040 1128481536 1120060032 1120060032 1136903040 1136903040 1120060032 1120060032 1120060032 1128481536 1128481536 1128481536 185273088 202116096 193694592 235802112 269488128 218959104 134744064 117901056 202116096 185273088 218959104 252645120 244223616 210537600 193694592 218959104 218959104 269488128 227380608 218959104 160008576 109479552 134744064 92636544 117901056 151587072 168430080 202116096 117901056 160008576 151587072 143165568 943208448 1128481536 185273088 261066624 1027423488 623191296 1313754624 1221118080 976894464 808464384 1153746048 1187432064 1263225600 1162167552 1254804096 1044266496 825307392 1103217024 1120060032 1128481536 1170589056 1221118080 1490606208 1726408320 1717986816 1616928768 1414812672 1027423488 1549556736 1642193280 1768515840 1734829824 1743251328 1760094336 1499027712 1254804096 1625350272 1684300800 1684300800 1768515840 1684300800 1583242752 1423234176 1296911616 1322176128 1465341696 1499027712 1414812672 1313754624 1271647104 1246382592 1212696576 951629952 623191296 1111638528 1355862144 1052688000 1069531008 1136903040 1162167552 1111638528 1120060032 1153746048 1179010560 1162167552 1153746048 1145324544 1145324544 1153746048 1162167552 1153746048 1153746048 1153746048 1145324544 1153746048 1170589056 1162167552 1145324544 1128481536 1136903040 1153746048 1153746048 1153746048 1145324544 1136903040 1128481536 1120060032 1120060032 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 1128481536 202116096 210537600 210537600 235802112 269488128 210537600 126322560 101058048 176851584 176851584 202116096 244223616 235802112 193694592 176851584 193694592 227380608 269488128 235802112 210537600 168430080 126322560 143165568 117901056 92636544 185273088 134744064 134744064 218959104 160008576 160008576 168430080 1010580480 1187432064 101058048 412653696 1002158976 850571904 1372705152 1229539584 816885888 808464384 1103217024 1120060032 1271647104 1288490112 1280068608 1019001984 1035844992 1212696576 1406391168 1574821248 1684300800 1751672832 1793780352 1734829824 1675879296 1760094336 1254804096 1355862144 1616928768 1633771776 1726408320 1785358848 1768515840 1701143808 1760094336 1339019136 1448498688 1633771776 1709565312 1684300800 1684300800 1701143808 1608507264 1507449216 1515870720 1524292224 1414812672 1322176128 1347440640 1288490112 1044266496 1347440640 1136903040 682141824 934786944 1347440640 1237961088 1195853568 1195853568 1170589056 1103217024 1103217024 1145324544 1128481536 1162167552 1153746048 1145324544 1145324544 1153746048 1162167552 1153746048 1153746048 1170589056 1153746048 1153746048 1162167552 1162167552 1145324544 1145324544 1153746048 1153746048 1153746048 1153746048 1145324544 1136903040 1136903040 1128481536 1128481536 1136903040 1136903040 1128481536 1128481536 1128481536 1136903040 1136903040 1136903040 193694592 202116096 210537600 227380608 261066624 193694592 117901056 101058048 185273088 193694592 210537600 252645120 244223616 210537600 185273088 210537600 227380608 261066624 218959104 193694592 160008576 126322560 151587072 126322560 151587072 160008576 134744064 134744064 218959104 92636544 160008576 193694592 934786944 1162167552 480025728 1313754624 1608507264 1111638528 1313754624 1296911616 800042880 1019001984 1212696576 1052688000 1145324544 1271647104 1263225600 1136903040 850571904 1035844992 1549556736 1785358848 1751672832 1776937344 1819044864 1776937344 1776937344 1650614784 1069531008 1557978240 1667457792 1726408320 1717986816 1785358848 1768515840 1709565312 1726408320 1541135232 1077952512 1482184704 1642193280 1650614784 1709565312 1692722304 1532713728 1414812672 1448498688 1414812672 1322176128 1280068608 1280068608 1128481536 1162167552 1355862144 1482184704 951629952 1044266496 1187432064 1246382592 1170589056 1153746048 1136903040 1128481536 1162167552 1187432064 1162167552 1162167552 1153746048 1153746048 1153746048 1153746048 1162167552 1162167552 1153746048 1179010560 1162167552 1153746048 1162167552 1162167552 1153746048 1153746048 1170589056 1153746048 1153746048 1145324544 1145324544 1145324544 1145324544 1145324544 1145324544 1136903040 1136903040 1145324544 1145324544 1136903040 1136903040 1136903040 1136903040 185273088 193694592 202116096 218959104 252645120 193694592 126322560 117901056 176851584 193694592 218959104 252645120 252645120 227380608 218959104 218959104 218959104 252645120 202116096 176851584 143165568 109479552 151587072 117901056 176851584 109479552 185273088 151587072 160008576 151587072 143165568 101058048 707406336 1423234176 1254804096 1532713728 1659036288 1414812672 1515870720 1145324544 1086374016 1389548160 1381126656 1035844992 993737472 1162167552 1204275072 1254804096 1212696576 1069531008 1389548160 1701143808 1743251328 1760094336 1692722304 1616928768 1507449216 1027423488 1010580480 1473763200 1583242752 1717986816 1726408320 1675879296 1751672832 1768515840 1776937344 1642193280 1010580480 842150400 1263225600 1423234176 1448498688 1414812672 1423234176 1499027712 1591664256 1566399744 1406391168 1237961088 1162167552 1136903040 1229539584 1397969664 1549556736 1339019136 1052688000 1187432064 1212696576 1162167552 1153746048 1153746048 1145324544 1153746048 1153746048 1120060032 1170589056 1162167552 1153746048 1153746048 1162167552 1162167552 1162167552 1162167552 1170589056 1153746048 1153746048 1162167552 1170589056 1153746048 1162167552 1170589056 1153746048 1153746048 1153746048 1145324544 1153746048 1153746048 1162167552 1162167552 1145324544 1145324544 1145324544 1145324544 1145324544 1145324544 1145324544 1145324544 176851584 193694592 193694592 210537600 235802112 185273088 117901056 117901056 151587072 176851584 202116096 235802112 244223616 227380608 227380608 235802112 227380608 252645120 202116096 168430080 143165568 109479552 134744064 109479552 126322560 134744064 210537600 151587072 143165568 227380608 109479552 294752640 1111638528 1397969664 1322176128 1524292224 1659036288 1406391168 1440077184 1305333120 1347440640 1566399744 1440077184 1077952512 1002158976 1120060032 1111638528 1221118080 1372705152 1111638528 1153746048 1355862144 1566399744 1591664256 1313754624 1120060032 875836416 833728896 1364283648 1515870720 1591664256 1701143808 1760094336 1701143808 1734829824 1709565312 1667457792 1709565312 1532713728 1069531008 943208448 985315968 850571904 867414912 1120060032 1406391168 1473763200 1499027712 1389548160 1145324544 1170589056 1187432064 1195853568 1364283648 1532713728 1229539584 1010580480 1296911616 1179010560 1153746048 1162167552 1179010560 1153746048 1162167552 1170589056 1145324544 1170589056 1162167552 1153746048 1153746048 1162167552 1170589056 1162167552 1162167552 1162167552 1153746048 1153746048 1179010560 1179010560 1162167552 1153746048 1162167552 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1162167552 1162167552 1145324544 1145324544 1145324544 1145324544 1153746048 1153746048 1162167552 1162167552 202116096 210537600 202116096 210537600 218959104 168430080 109479552 117901056 151587072 168430080 210537600 235802112 235802112 244223616 235802112 235802112 218959104 244223616 202116096 176851584 151587072 134744064 151587072 109479552 126322560 168430080 160008576 176851584 151587072 84215040 210537600 1044266496 1456920192 1448498688 1263225600 1591664256 1701143808 1448498688 1372705152 1440077184 1347440640 1515870720 1465341696 1195853568 1069531008 1086374016 1077952512 1187432064 1397969664 1305333120 1094795520 816885888 783199872 892679424 892679424 884257920 614769792 1229539584 1574821248 1490606208 1549556736 1633771776 1717986816 1675879296 1701143808 1709565312 1633771776 1616928768 1490606208 1389548160 976894464 1364283648 1465341696 1423234176 1515870720 1541135232 1381126656 1330597632 1322176128 1195853568 1229539584 1153746048 1296911616 1431655680 1431655680 1052688000 1313754624 1263225600 1153746048 1128481536 1145324544 1162167552 1136903040 1162167552 1195853568 1187432064 1179010560 1170589056 1162167552 1162167552 1170589056 1170589056 1170589056 1162167552 1162167552 1153746048 1162167552 1179010560 1179010560 1162167552 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1162167552 1162167552 1162167552 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1170589056 1170589056 202116096 210537600 210537600 202116096 218959104 168430080 101058048 109479552 160008576 185273088 218959104 235802112 244223616 235802112 235802112 227380608 210537600 227380608 185273088 176851584 160008576 143165568 168430080 117901056 151587072 160008576 134744064 185273088 134744064 143165568 724249344 1574821248 1541135232 1482184704 1204275072 1616928768 1650614784 1280068608 1288490112 1490606208 1372705152 1440077184 1465341696 1229539584 1077952512 1052688000 1120060032 1212696576 1212696576 1389548160 1372705152 1254804096 1271647104 1381126656 1313754624 1061109504 816885888 1431655680 1330597632 1263225600 1423234176 1482184704 1608507264 1583242752 1507449216 1440077184 1473763200 1263225600 1263225600 1229539584 800042880 1035844992 1482184704 1557978240 1566399744 1473763200 1347440640 1280068608 1280068608 1296911616 1229539584 1162167552 1280068608 1431655680 1246382592 1339019136 1431655680 1263225600 1204275072 1170589056 1170589056 1162167552 1120060032 1136903040 1145324544 1120060032 1179010560 1170589056 1162167552 1162167552 1170589056 1170589056 1170589056 1170589056 1179010560 1162167552 1170589056 1179010560 1179010560 1162167552 1153746048 1162167552 1162167552 1153746048 1153746048 1153746048 1153746048 1162167552 1162167552 1162167552 1153746048 1153746048 1153746048 1162167552 1162167552 1162167552 1162167552 1162167552 176851584 202116096 193694592 210537600 218959104 168430080 109479552 126322560 143165568 176851584 202116096 218959104 218959104 210537600 202116096 202116096 176851584 210537600 160008576 176851584 160008576 143165568 168430080 117901056 117901056 151587072 160008576 126322560 134744064 513711744 1347440640 1473763200 1448498688 1490606208 1212696576 1616928768 1675879296 1145324544 1237961088 1381126656 1557978240 1431655680 1389548160 1162167552 1061109504 1111638528 1212696576 1212696576 1136903040 1288490112 1339019136 1423234176 1507449216 1549556736 1322176128 800042880 656877312 867414912 682141824 749513856 1010580480 1061109504 1212696576 1254804096 1263225600 1212696576 934786944 842150400 463182720 673720320 429496704 724249344 1221118080 1431655680 1431655680 1347440640 1389548160 1347440640 1280068608 1372705152 1271647104 1170589056 1246382592 985315968 1372705152 1507449216 1221118080 1372705152 1145324544 1120060032 1145324544 1170589056 1170589056 1195853568 1195853568 1162167552 1179010560 1170589056 1162167552 1162167552 1170589056 1179010560 1170589056 1170589056 1195853568 1179010560 1170589056 1179010560 1170589056 1162167552 1162167552 1179010560 1162167552 1153746048 1153746048 1153746048 1153746048 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1170589056 1170589056 126322560 252645120 202116096 160008576 328438656 151587072 101058048 151587072 210537600 84215040 218959104 277909632 218959104 202116096 151587072 218959104 202116096 261066624 210537600 143165568 143165568 168430080 168430080 75793536 126322560 117901056 168430080 176851584 614769792 1254804096 1456920192 1490606208 1456920192 1448498688 1246382592 1625350272 1574821248 1153746048 1254804096 1440077184 1263225600 1246382592 825307392 1061109504 1136903040 1111638528 1221118080 1322176128 1204275072 1246382592 1347440640 1355862144 1414812672 1263225600 850571904 656877312 1305333120 1052688000 513711744 505290240 555819264 640034304 757935360 757935360 707406336 656877312 791621376 623191296 741092352 1254804096 833728896 378967680 858993408 1170589056 1263225600 1204275072 1339019136 1263225600 1313754624 1389548160 1305333120 1305333120 1179010560 1069531008 1077952512 1128481536 1381126656 1280068608 1179010560 1153746048 1153746048 1162167552 1162167552 1153746048 1170589056 1187432064 1162167552 1179010560 1187432064 1179010560 1179010560 1170589056 1179010560 1187432064 1204275072 1195853568 1179010560 1170589056 1162167552 1153746048 1153746048 1145324544 1153746048 1145324544 1145324544 1145324544 1162167552 1162167552 1162167552 1153746048 1162167552 1162167552 1162167552 1162167552 1170589056 1179010560 1187432064 1187432064 235802112 185273088 151587072 311595648 185273088 176851584 143165568 25264512 168430080 210537600 168430080 176851584 227380608 176851584 168430080 168430080 176851584 185273088 143165568 143165568 143165568 151587072 168430080 168430080 101058048 168430080 185273088 816885888 1372705152 1372705152 1482184704 1482184704 1456920192 1448498688 1254804096 1608507264 1557978240 1263225600 1280068608 1431655680 1372705152 1288490112 1389548160 1482184704 1263225600 1103217024 1195853568 1296911616 1347440640 1204275072 1389548160 1330597632 1271647104 1120060032 640034304 1044266496 1440077184 1397969664 1339019136 1347440640 1296911616 1010580480 631612800 336860160 513711744 951629952 1204275072 1263225600 1229539584 1322176128 1086374016 488447232 429496704 909522432 1128481536 1195853568 1237961088 1237961088 1347440640 1355862144 1271647104 1381126656 1600085760 1440077184 1490606208 1339019136 1490606208 1254804096 1162167552 1145324544 1145324544 1162167552 1170589056 1162167552 1162167552 1170589056 1162167552 1179010560 1187432064 1179010560 1179010560 1170589056 1179010560 1187432064 1195853568 1187432064 1179010560 1162167552 1153746048 1153746048 1153746048 1153746048 1145324544 1136903040 1136903040 1136903040 1145324544 1153746048 1153746048 1145324544 1153746048 1153746048 1162167552 1162167552 1170589056 1170589056 1179010560 1179010560 176851584 218959104 303174144 488447232 227380608 58950528 160008576 176851584 101058048 202116096 252645120 269488128 261066624 193694592 176851584 176851584 176851584 160008576 134744064 134744064 168430080 160008576 126322560 151587072 101058048 261066624 1195853568 1490606208 1296911616 1482184704 1499027712 1465341696 1448498688 1431655680 1280068608 1600085760 1549556736 1355862144 1229539584 1339019136 1515870720 1456920192 1574821248 1600085760 1490606208 1162167552 1179010560 1330597632 1381126656 1246382592 1271647104 1305333120 1077952512 732670848 842150400 1322176128 1381126656 1339019136 1406391168 1330597632 1414812672 1355862144 1221118080 1069531008 1128481536 1313754624 1237961088 1305333120 1254804096 1170589056 1322176128 1010580480 404232192 555819264 858993408 951629952 1103217024 1229539584 1339019136 1372705152 1313754624 1347440640 1507449216 1566399744 1347440640 1524292224 1440077184 1179010560 1153746048 1153746048 1153746048 1170589056 1179010560 1170589056 1170589056 1179010560 1162167552 1179010560 1179010560 1179010560 1170589056 1170589056 1179010560 1179010560 1179010560 1170589056 1162167552 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1145324544 1136903040 1136903040 1145324544 1153746048 1145324544 1145324544 1145324544 1145324544 1153746048 1153746048 1162167552 1162167552 1170589056 1179010560 555819264 311595648 1061109504 656877312 218959104 193694592 84215040 101058048 269488128 109479552 185273088 210537600 185273088 210537600 168430080 143165568 168430080 193694592 168430080 126322560 176851584 160008576 92636544 126322560 277909632 1271647104 1473763200 1431655680 1482184704 1397969664 1490606208 1431655680 1440077184 1397969664 1280068608 1600085760 1541135232 1381126656 1061109504 1128481536 1541135232 1633771776 1557978240 1675879296 1482184704 1179010560 1246382592 1339019136 1389548160 1288490112 1212696576 1170589056 808464384 538976256 1229539584 1339019136 1372705152 1406391168 1456920192 1389548160 1423234176 1465341696 1473763200 1372705152 1473763200 1347440640 1296911616 1305333120 1372705152 1305333120 1372705152 1263225600 715827840 378967680 724249344 884257920 1187432064 1263225600 1221118080 1280068608 1254804096 1397969664 1600085760 1465341696 1448498688 1440077184 1229539584 1136903040 1162167552 1145324544 1153746048 1179010560 1187432064 1170589056 1170589056 1179010560 1162167552 1179010560 1179010560 1179010560 1170589056 1170589056 1170589056 1179010560 1170589056 1162167552 1162167552 1153746048 1153746048 1153746048 1153746048 1153746048 1162167552 1153746048 1145324544 1145324544 1153746048 1153746048 1153746048 1145324544 1145324544 1145324544 1145324544 1145324544 1153746048 1162167552 1162167552 1170589056 1389548160 1305333120 1153746048 252645120 160008576 126322560 134744064 92636544 126322560 202116096 185273088 193694592 193694592 134744064 160008576 193694592 168430080 168430080 185273088 134744064 151587072 126322560 176851584 454761216 1111638528 1313754624 1473763200 1456920192 1456920192 1482184704 1490606208 1490606208 1473763200 1389548160 1296911616 1633771776 1566399744 1355862144 901100928 901100928 1389548160 1574821248 1549556736 1591664256 1019001984 1128481536 1322176128 1237961088 1456920192 1254804096 1305333120 960051456 572662272 816885888 1246382592 1364283648 1414812672 1524292224 1473763200 1532713728 1482184704 1566399744 1675879296 1616928768 1616928768 1524292224 1524292224 1347440640 1397969664 1431655680 1397969664 1313754624 1229539584 715827840 614769792 858993408 1094795520 1212696576 1288490112 1397969664 1280068608 1237961088 1608507264 1549556736 1313754624 1296911616 1237961088 1145324544 1145324544 1136903040 1145324544 1179010560 1179010560 1170589056 1162167552 1170589056 1170589056 1179010560 1179010560 1179010560 1170589056 1170589056 1170589056 1179010560 1162167552 1162167552 1153746048 1153746048 1153746048 1153746048 1162167552 1162167552 1162167552 1153746048 1153746048 1153746048 1162167552 1162167552 1153746048 1153746048 1145324544 1145324544 1145324544 1153746048 1153746048 1162167552 1162167552 1162167552 1701143808 1381126656 867414912 235802112 134744064 218959104 84215040 126322560 353703168 631612800 294752640 210537600 269488128 92636544 176851584 202116096 168430080 134744064 185273088 168430080 151587072 134744064 362124672 934786944 1330597632 1355862144 1465341696 1549556736 1414812672 1414812672 1557978240 1524292224 1482184704 1397969664 1296911616 1633771776 1608507264 1330597632 833728896 724249344 917943936 1296911616 1414812672 1027423488 277909632 783199872 1187432064 1414812672 1423234176 1347440640 1296911616 892679424 640034304 1136903040 1153746048 1431655680 1414812672 1507449216 1431655680 1583242752 1473763200 1541135232 1675879296 1625350272 1616928768 1583242752 1541135232 1515870720 1524292224 1448498688 1406391168 1322176128 1288490112 1111638528 656877312 1128481536 1263225600 1355862144 1381126656 1271647104 1271647104 825307392 993737472 1280068608 1145324544 1355862144 1296911616 1136903040 1145324544 1128481536 1136903040 1153746048 1162167552 1145324544 1153746048 1162167552 1170589056 1170589056 1179010560 1179010560 1170589056 1170589056 1170589056 1179010560 1170589056 1170589056 1162167552 1162167552 1162167552 1162167552 1170589056 1170589056 1153746048 1145324544 1145324544 1145324544 1153746048 1153746048 1145324544 1136903040 1145324544 1145324544 1145324544 1145324544 1153746048 1162167552 1153746048 1162167552 1557978240 1440077184 421075200 193694592 227380608 109479552 101058048 513711744 1052688000 741092352 235802112 101058048 218959104 168430080 143165568 101058048 160008576 160008576 193694592 151587072 185273088 218959104 421075200 985315968 1153746048 1448498688 1456920192 1490606208 1431655680 1431655680 1608507264 1431655680 1440077184 1414812672 1313754624 1591664256 1625350272 1339019136 892679424 673720320 833728896 968472960 976894464 505290240 210537600 707406336 1120060032 1322176128 1339019136 1456920192 1355862144 1044266496 909522432 1195853568 1212696576 1322176128 1254804096 1145324544 1069531008 1120060032 1069531008 1153746048 1397969664 1465341696 1313754624 1204275072 1086374016 1187432064 1204275072 1170589056 1221118080 1347440640 1221118080 1296911616 901100928 1246382592 1406391168 1423234176 1414812672 1280068608 1128481536 640034304 648455808 909522432 1515870720 1372705152 1195853568 1128481536 1153746048 1145324544 1136903040 1153746048 1153746048 1145324544 1153746048 1170589056 1153746048 1170589056 1179010560 1170589056 1170589056 1162167552 1170589056 1179010560 1179010560 1179010560 1170589056 1170589056 1170589056 1170589056 1179010560 1179010560 1153746048 1145324544 1145324544 1145324544 1145324544 1145324544 1145324544 1136903040 1145324544 1145324544 1145324544 1145324544 1153746048 1162167552 1162167552 1170589056 1650614784 1440077184 555819264 202116096 126322560 168430080 101058048 623191296 951629952 210537600 235802112 227380608 126322560 202116096 101058048 202116096 126322560 168430080 202116096 84215040 160008576 269488128 336860160 682141824 1061109504 1381126656 1473763200 1490606208 1465341696 1423234176 1499027712 1524292224 1414812672 1414812672 1313754624 1549556736 1625350272 1355862144 968472960 673720320 707406336 875836416 1212696576 892679424 370546176 378967680 1153746048 1339019136 1355862144 1423234176 1583242752 1195853568 1111638528 1153746048 1229539584 1111638528 774778368 572662272 640034304 648455808 656877312 648455808 791621376 858993408 665298816 656877312 673720320 648455808 564240768 631612800 623191296 842150400 985315968 1187432064 1322176128 1406391168 1591664256 1397969664 1271647104 1305333120 1254804096 572662272 757935360 1204275072 1288490112 1179010560 1246382592 1136903040 1170589056 1153746048 1162167552 1162167552 1162167552 1153746048 1162167552 1179010560 1153746048 1170589056 1179010560 1170589056 1170589056 1162167552 1170589056 1179010560 1187432064 1187432064 1179010560 1170589056 1170589056 1179010560 1179010560 1179010560 1162167552 1153746048 1153746048 1153746048 1153746048 1153746048 1153746048 1145324544 1145324544 1145324544 1145324544 1145324544 1153746048 1162167552 1162167552 1170589056 1877995392 1675879296 1136903040 227380608 168430080 143165568 75793536 614769792 437918208 277909632 202116096 185273088 235802112 109479552 126322560 176851584 160008576 185273088 185273088 117901056 126322560 303174144 421075200 387389184 1010580480 1263225600 1490606208 1499027712 1515870720 1423234176 1524292224 1507449216 1431655680 1414812672 1305333120 1549556736 1541135232 1136903040 943208448 690563328 564240768 513711744 454761216 505290240 370546176 336860160 976894464 1229539584 1339019136 1440077184 1532713728 1524292224 1103217024 1052688000 833728896 673720320 564240768 766356864 850571904 892679424 993737472 943208448 783199872 732670848 833728896 1103217024 1364283648 1305333120 1221118080 1313754624 1288490112 1195853568 1094795520 1237961088 1271647104 1557978240 1490606208 1456920192 1330597632 1322176128 1103217024 682141824 816885888 1162167552 1397969664 1406391168 1162167552 1195853568 1153746048 1162167552 1162167552 1179010560 1179010560 1170589056 1170589056 1170589056 1179010560 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1204275072 1187432064 1170589056 1162167552 1170589056 1170589056 1162167552 1153746048 1170589056 1170589056 1170589056 1170589056 1153746048 1145324544 1145324544 1136903040 1128481536 1136903040 1145324544 1153746048 1153746048 1153746048 1170589056 1179010560 1263225600 1414812672 1448498688 538976256 92636544 193694592 16843008 833728896 505290240 143165568 218959104 176851584 168430080 168430080 143165568 176851584 168430080 176851584 176851584 134744064 151587072 294752640 395810688 378967680 791621376 1296911616 1473763200 1482184704 1490606208 1448498688 1524292224 1507449216 1440077184 1389548160 1313754624 1574821248 1448498688 985315968 926365440 926365440 513711744 261066624 126322560 269488128 353703168 378967680 884257920 1221118080 1288490112 1280068608 1482184704 1532713728 1322176128 1145324544 1187432064 1153746048 1221118080 1237961088 1271647104 1389548160 1490606208 1440077184 1414812672 1499027712 1499027712 1389548160 1448498688 1490606208 1440077184 1347440640 1263225600 1271647104 1355862144 1162167552 1448498688 1507449216 1473763200 1322176128 1406391168 1288490112 1002158976 690563328 901100928 1195853568 1465341696 1372705152 1195853568 1153746048 1170589056 1170589056 1170589056 1179010560 1170589056 1170589056 1170589056 1170589056 1187432064 1179010560 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1179010560 1170589056 1170589056 1162167552 1153746048 1153746048 1162167552 1170589056 1170589056 1170589056 1170589056 1170589056 1153746048 1145324544 1145324544 1145324544 1136903040 1145324544 1153746048 1162167552 1162167552 1162167552 1170589056 1179010560 665298816 101058048 766356864 968472960 210537600 101058048 202116096 1254804096 800042880 92636544 185273088 160008576 117901056 193694592 117901056 176851584 176851584 160008576 151587072 143165568 168430080 286331136 378967680 362124672 538976256 1237961088 1482184704 1499027712 1482184704 1456920192 1507449216 1473763200 1414812672 1389548160 1322176128 1549556736 1381126656 917943936 968472960 1086374016 976894464 538976256 277909632 277909632 345281664 320017152 648455808 1103217024 1204275072 1296911616 1507449216 1423234176 1330597632 1136903040 1364283648 1246382592 1221118080 1280068608 1288490112 1271647104 1389548160 1524292224 1499027712 1389548160 1414812672 1347440640 1364283648 1288490112 1179010560 1179010560 1271647104 1423234176 1397969664 1162167552 1406391168 1549556736 1322176128 1322176128 1296911616 1204275072 791621376 741092352 1019001984 1221118080 1372705152 1195853568 1187432064 1187432064 1187432064 1179010560 1179010560 1170589056 1170589056 1179010560 1187432064 1179010560 1187432064 1179010560 1179010560 1170589056 1170589056 1170589056 1170589056 1170589056 1153746048 1162167552 1170589056 1162167552 1145324544 1136903040 1153746048 1170589056 1170589056 1170589056 1170589056 1170589056 1153746048 1153746048 1145324544 1145324544 1153746048 1153746048 1162167552 1162167552 1162167552 1162167552 1170589056 1179010560 235802112 185273088 151587072 235802112 151587072 151587072 117901056 960051456 1103217024 244223616 185273088 176851584 160008576 176851584 84215040 193694592 168430080 160008576 143165568 109479552 143165568 286331136 387389184 345281664 378967680 1010580480 1499027712 1515870720 1482184704 1473763200 1499027712 1456920192 1406391168 1406391168 1305333120 1507449216 1381126656 1002158976 1035844992 1052688000 1229539584 1187432064 1010580480 522133248 244223616 227380608 471604224 1002158976 1212696576 1229539584 1355862144 1482184704 1381126656 1094795520 1322176128 1355862144 1237961088 1170589056 1145324544 1136903040 1077952512 1019001984 968472960 901100928 833728896 875836416 985315968 1027423488 1145324544 1364283648 1406391168 1347440640 1313754624 1179010560 1355862144 1322176128 1330597632 1195853568 1221118080 1061109504 741092352 842150400 1027423488 1170589056 1221118080 1086374016 1195853568 1204275072 1204275072 1187432064 1187432064 1179010560 1179010560 1179010560 1187432064 1187432064 1195853568 1187432064 1187432064 1179010560 1179010560 1170589056 1170589056 1170589056 1162167552 1162167552 1162167552 1162167552 1145324544 1145324544 1153746048 1162167552 1170589056 1170589056 1170589056 1170589056 1162167552 1153746048 1153746048 1145324544 1153746048 1153746048 1162167552 1162167552 1153746048 1153746048 1162167552 1170589056 160008576 227380608 151587072 202116096 151587072 126322560 75793536 202116096 917943936 362124672 210537600 176851584 227380608 151587072 117901056 218959104 160008576 168430080 160008576 109479552 143165568 328438656 412653696 345281664 370546176 698984832 1397969664 1507449216 1473763200 1473763200 1499027712 1431655680 1397969664 1381126656 1271647104 1490606208 1414812672 1061109504 1052688000 1010580480 1170589056 1094795520 1237961088 1246382592 976894464 454761216 235802112 816885888 1103217024 1204275072 1195853568 1397969664 1237961088 1187432064 1288490112 1313754624 1397969664 1339019136 1288490112 1162167552 976894464 850571904 850571904 867414912 884257920 800042880 867414912 968472960 1120060032 1271647104 1246382592 1179010560 1339019136 1305333120 1271647104 1263225600 1237961088 1145324544 1204275072 884257920 858993408 993737472 951629952 1136903040 1170589056 1195853568 1212696576 1170589056 1195853568 1195853568 1195853568 1195853568 1195853568 1187432064 1195853568 1187432064 1204275072 1195853568 1187432064 1187432064 1179010560 1179010560 1179010560 1179010560 1195853568 1179010560 1162167552 1162167552 1162167552 1162167552 1162167552 1153746048 1170589056 1170589056 1170589056 1170589056 1162167552 1153746048 1153746048 1145324544 1145324544 1145324544 1153746048 1153746048 1145324544 1145324544 1145324544 1153746048 193694592 143165568 193694592 151587072 92636544 151587072 160008576 151587072 336860160 277909632 202116096 134744064 210537600 143165568 168430080 176851584 160008576 160008576 160008576 151587072 210537600 370546176 429496704 345281664 404232192 471604224 1120060032 1431655680 1448498688 1456920192 1499027712 1397969664 1423234176 1364283648 1246382592 1499027712 1414812672 1010580480 1019001984 1044266496 1187432064 1103217024 1120060032 1128481536 1094795520 842150400 471604224 732670848 1019001984 1246382592 1153746048 1195853568 1069531008 1322176128 1355862144 1212696576 1153746048 1237961088 1229539584 1187432064 1271647104 1414812672 1465341696 1406391168 1364283648 1280068608 1288490112 1212696576 1120060032 1136903040 1212696576 1330597632 1364283648 1347440640 1237961088 1372705152 1120060032 1170589056 1187432064 690563328 917943936 1086374016 1010580480 1162167552 1153746048 1221118080 1195853568 1170589056 1195853568 1204275072 1212696576 1212696576 1212696576 1204275072 1195853568 1187432064 1212696576 1195853568 1195853568 1187432064 1187432064 1187432064 1187432064 1187432064 1212696576 1187432064 1170589056 1162167552 1179010560 1179010560 1170589056 1153746048 1179010560 1179010560 1179010560 1170589056 1162167552 1153746048 1145324544 1145324544 1136903040 1145324544 1145324544 1145324544 1136903040 1136903040 1145324544 1153746048 227380608 101058048 168430080 244223616 193694592 92636544 16843008 109479552 58950528 160008576 193694592 109479552 160008576 134744064 160008576 126322560 151587072 126322560 176851584 252645120 328438656 404232192 404232192 362124672 404232192 421075200 732670848 1313754624 1397969664 1431655680 1482184704 1397969664 1414812672 1381126656 1280068608 1490606208 1381126656 1002158976 1044266496 1069531008 1077952512 1061109504 1086374016 1086374016 1019001984 808464384 480025728 715827840 1153746048 1094795520 1086374016 1212696576 1271647104 1313754624 1355862144 1414812672 1406391168 1339019136 1305333120 1440077184 1633771776 1633771776 1583242752 1600085760 1608507264 1557978240 1600085760 1574821248 1532713728 1532713728 1515870720 1507449216 1330597632 1212696576 1280068608 1162167552 1212696576 1077952512 1237961088 732670848 909522432 1128481536 1145324544 1204275072 1153746048 1195853568 1162167552 1212696576 1204275072 1212696576 1204275072 1204275072 1204275072 1212696576 1204275072 1212696576 1195853568 1195853568 1195853568 1195853568 1187432064 1195853568 1195853568 1195853568 1204275072 1195853568 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 1187432064 1187432064 1179010560 1179010560 1162167552 1153746048 1145324544 1136903040 1136903040 1145324544 1153746048 1153746048 1145324544 1145324544 1153746048 1162167552 143165568 218959104 160008576 185273088 67372032 101058048 134744064 117901056 168430080 134744064 193694592 134744064 160008576 134744064 168430080 134744064 151587072 92636544 176851584 353703168 429496704 421075200 387389184 378967680 378967680 446339712 446339712 1221118080 1355862144 1431655680 1473763200 1381126656 1372705152 1440077184 1339019136 1465341696 1347440640 1061109504 1094795520 1027423488 1044266496 1111638528 1111638528 1094795520 1103217024 1010580480 597926784 589505280 1221118080 1035844992 1120060032 1153746048 1339019136 1221118080 1271647104 1330597632 1221118080 1364283648 1364283648 1389548160 1566399744 1650614784 1642193280 1667457792 1633771776 1515870720 1549556736 1616928768 1616928768 1566399744 1473763200 1490606208 1271647104 1212696576 1128481536 960051456 1153746048 1136903040 1212696576 1052688000 976894464 1145324544 1204275072 1170589056 1195853568 1212696576 1195853568 1221118080 1221118080 1204275072 1204275072 1212696576 1204275072 1212696576 1221118080 1229539584 1195853568 1195853568 1195853568 1195853568 1195853568 1195853568 1195853568 1204275072 1179010560 1187432064 1195853568 1187432064 1170589056 1170589056 1179010560 1195853568 1195853568 1187432064 1187432064 1179010560 1162167552 1145324544 1136903040 1136903040 1145324544 1153746048 1153746048 1162167552 1153746048 1153746048 1162167552 1170589056 151587072 176851584 185273088 160008576 126322560 101058048 92636544 109479552 168430080 151587072 143165568 151587072 151587072 134744064 134744064 151587072 117901056 210537600 353703168 429496704 429496704 387389184 370546176 370546176 378967680 429496704 480025728 774778368 1339019136 1347440640 1389548160 1254804096 1313754624 1583242752 1237961088 1305333120 1271647104 1019001984 1179010560 1044266496 1061109504 1103217024 1086374016 1145324544 1069531008 1120060032 513711744 320017152 1136903040 1229539584 1019001984 1103217024 1170589056 1229539584 1120060032 1271647104 1322176128 1355862144 1330597632 1296911616 1423234176 1431655680 1557978240 1583242752 1448498688 1465341696 1549556736 1633771776 1625350272 1499027712 1372705152 1339019136 1120060032 1019001984 909522432 1069531008 1061109504 1019001984 1162167552 1077952512 1094795520 1153746048 1195853568 1221118080 1221118080 1204275072 1229539584 1204275072 1229539584 1195853568 1179010560 1195853568 1204275072 1204275072 1204275072 1229539584 1212696576 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1187432064 1187432064 1187432064 1187432064 1187432064 1187432064 1187432064 1187432064 1204275072 1195853568 1195853568 1187432064 1179010560 1170589056 1170589056 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 160008576 176851584 185273088 168430080 126322560 101058048 101058048 117901056 117901056 202116096 210537600 126322560 109479552 143165568 160008576 160008576 210537600 294752640 395810688 446339712 429496704 404232192 378967680 362124672 378967680 421075200 488447232 513711744 1128481536 1347440640 1431655680 1145324544 1280068608 1642193280 1246382592 1153746048 1103217024 993737472 1170589056 1019001984 1187432064 960051456 1069531008 1212696576 1103217024 1086374016 538976256 648455808 1406391168 1204275072 926365440 960051456 1086374016 1162167552 1027423488 1170589056 1313754624 1305333120 1237961088 1212696576 1339019136 1330597632 1389548160 1355862144 1263225600 1372705152 1414812672 1389548160 1389548160 1381126656 1280068608 1136903040 993737472 707406336 800042880 665298816 800042880 1229539584 1136903040 412653696 1204275072 1094795520 1136903040 1162167552 1221118080 1237961088 1162167552 1204275072 1187432064 1170589056 1187432064 1195853568 1212696576 1195853568 1221118080 1237961088 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1195853568 1195853568 1187432064 1187432064 1187432064 1187432064 1187432064 1195853568 1204275072 1195853568 1195853568 1187432064 1170589056 1170589056 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 160008576 176851584 176851584 168430080 126322560 109479552 117901056 117901056 143165568 235802112 193694592 126322560 160008576 185273088 168430080 176851584 336860160 370546176 437918208 463182720 446339712 412653696 378967680 362124672 387389184 454761216 496868736 378967680 816885888 1330597632 1406391168 1170589056 1237961088 1650614784 1221118080 1052688000 985315968 934786944 1136903040 1027423488 1128481536 1103217024 1094795520 1296911616 1019001984 766356864 235802112 1473763200 1448498688 1288490112 1044266496 749513856 673720320 783199872 791621376 926365440 1179010560 1246382592 1237961088 1212696576 1229539584 1136903040 1128481536 1069531008 1111638528 1229539584 1254804096 1195853568 1162167552 1170589056 1052688000 867414912 665298816 555819264 446339712 572662272 1069531008 1389548160 1052688000 134744064 480025728 1019001984 1187432064 1187432064 1204275072 1221118080 1271647104 1187432064 1179010560 1187432064 1195853568 1204275072 1195853568 1187432064 1195853568 1229539584 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1212696576 1204275072 1195853568 1187432064 1187432064 1187432064 1195853568 1195853568 1204275072 1204275072 1195853568 1187432064 1170589056 1162167552 1162167552 1153746048 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 1162167552 160008576 176851584 176851584 168430080 126322560 109479552 117901056 134744064 134744064 176851584 143165568 126322560 160008576 143165568 168430080 277909632 412653696 429496704 446339712 463182720 446339712 421075200 387389184 362124672 395810688 463182720 454761216 429496704 547397760 1229539584 1313754624 1263225600 1229539584 1608507264 1204275072 1052688000 985315968 884257920 1077952512 1094795520 1204275072 1002158976 1145324544 1195853568 917943936 193694592 286331136 1936945920 1237961088 1330597632 1212696576 808464384 446339712 336860160 446339712 581083776 833728896 993737472 1044266496 993737472 892679424 757935360 783199872 833728896 917943936 909522432 875836416 850571904 842150400 808464384 741092352 648455808 463182720 328438656 437918208 1019001984 1237961088 1347440640 1052688000 92636544 185273088 303174144 901100928 1195853568 1153746048 1195853568 1195853568 1246382592 1204275072 1212696576 1212696576 1212696576 1212696576 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1221118080 1212696576 1195853568 1187432064 1179010560 1187432064 1187432064 1195853568 1204275072 1204275072 1195853568 1187432064 1170589056 1162167552 1162167552 1153746048 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 168430080 176851584 176851584 151587072 126322560 117901056 117901056 143165568 134744064 185273088 168430080 143165568 143165568 176851584 294752640 471604224 437918208 437918208 454761216 454761216 446339712 421075200 387389184 362124672 370546176 429496704 421075200 429496704 421075200 1061109504 1271647104 1204275072 1280068608 1608507264 1263225600 1044266496 976894464 850571904 1103217024 1094795520 1162167552 976894464 1179010560 1044266496 176851584 84215040 976894464 1659036288 993737472 1288490112 1204275072 1086374016 732670848 294752640 328438656 378967680 513711744 614769792 555819264 471604224 370546176 345281664 437918208 530554752 555819264 454761216 353703168 336860160 421075200 505290240 572662272 623191296 522133248 488447232 968472960 1237961088 1271647104 1364283648 943208448 101058048 160008576 117901056 168430080 774778368 1246382592 1237961088 1212696576 1136903040 1221118080 1212696576 1212696576 1221118080 1237961088 1237961088 1229539584 1221118080 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1221118080 1212696576 1204275072 1187432064 1187432064 1187432064 1187432064 1187432064 1204275072 1204275072 1195853568 1195853568 1179010560 1170589056 1162167552 1162167552 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 1170589056 168430080 185273088 185273088 160008576 117901056 101058048 117901056 143165568 160008576 176851584 168430080 134744064 176851584 328438656 463182720 480025728 421075200 429496704 446339712 454761216 429496704 412653696 387389184 353703168 370546176 404232192 437918208 362124672 437918208 858993408 1313754624 1044266496 1347440640 1650614784 1372705152 951629952 884257920 833728896 1136903040 968472960 1069531008 1044266496 850571904 218959104 101058048 75793536 1364283648 1473763200 749513856 1322176128 1204275072 1195853568 1010580480 597926784 572662272 530554752 505290240 480025728 261066624 210537600 176851584 193694592 193694592 202116096 202116096 193694592 151587072 185273088 362124672 606348288 724249344 724249344 631612800 901100928 1221118080 1170589056 1339019136 1347440640 985315968 143165568 75793536 126322560 126322560 151587072 698984832 1212696576 1237961088 1313754624 1229539584 1237961088 1246382592 1229539584 1229539584 1237961088 1212696576 1195853568 1221118080 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1221118080 1221118080 1212696576 1204275072 1195853568 1187432064 1187432064 1187432064 1204275072 1204275072 1204275072 1195853568 1187432064 1179010560 1179010560 1170589056 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 168430080 176851584 168430080 151587072 117901056 101058048 109479552 134744064 151587072 143165568 210537600 269488128 286331136 412653696 471604224 370546176 395810688 429496704 454761216 463182720 446339712 404232192 370546176 353703168 362124672 412653696 437918208 395810688 463182720 648455808 1322176128 934786944 1389548160 1659036288 1448498688 867414912 816885888 774778368 1111638528 774778368 1002158976 412653696 109479552 160008576 117901056 109479552 1600085760 1515870720 530554752 1381126656 1254804096 1136903040 1052688000 858993408 783199872 783199872 724249344 665298816 404232192 328438656 252645120 227380608 160008576 109479552 126322560 202116096 286331136 387389184 597926784 850571904 892679424 808464384 791621376 993737472 1120060032 1237961088 1221118080 1389548160 1170589056 58950528 176851584 75793536 109479552 126322560 50529024 437918208 1094795520 1229539584 1187432064 1229539584 1263225600 1254804096 1229539584 1221118080 1195853568 1179010560 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1212696576 1229539584 1229539584 1229539584 1221118080 1212696576 1204275072 1187432064 1187432064 1204275072 1204275072 1204275072 1204275072 1187432064 1187432064 1187432064 1187432064 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 1179010560 185273088 185273088 168430080 143165568 101058048 84215040 109479552 134744064 160008576 235802112 496868736 623191296 471604224 429496704 488447232 454761216 395810688 421075200 471604224 480025728 446339712 395810688 353703168 336860160 336860160 437918208 378967680 488447232 404232192 480025728 1254804096 917943936 1397969664 1616928768 1456920192 850571904 800042880 707406336 1052688000 640034304 160008576 126322560 92636544 84215040 143165568 50529024 1692722304 1760094336 454761216 1347440640 1263225600 1153746048 1120060032 960051456 749513856 901100928 867414912 867414912 623191296 480025728 277909632 227380608 202116096 244223616 218959104 294752640 387389184 513711744 724249344 892679424 875836416 774778368 884257920 1179010560 1136903040 1237961088 1254804096 1760094336 1035844992 109479552 101058048 151587072 126322560 109479552 126322560 92636544 218959104 589505280 1077952512 1170589056 1254804096 1254804096 1229539584 1229539584 1229539584 1237961088 1212696576 1212696576 1212696576 1212696576 1221118080 1212696576 1221118080 1212696576 1246382592 1237961088 1237961088 1237961088 1229539584 1212696576 1195853568 1187432064 1195853568 1195853568 1204275072 1204275072 1195853568 1195853568 1195853568 1195853568 1187432064 1187432064 1187432064 1187432064 1179010560 1179010560 1179010560 1187432064 176851584 202116096 210537600 75793536 134744064 101058048 109479552 101058048 244223616 926365440 1423234176 1170589056 446339712 505290240 480025728 412653696 429496704 454761216 480025728 480025728 437918208 395810688 345281664 336860160 370546176 412653696 378967680 395810688 471604224 471604224 1162167552 943208448 1339019136 1600085760 1389548160 850571904 547397760 336860160 143165568 126322560 101058048 117901056 92636544 75793536 117901056 134744064 1760094336 1861152384 564240768 1170589056 1288490112 1162167552 1111638528 943208448 867414912 884257920 909522432 867414912 715827840 564240768 496868736 437918208 345281664 294752640 311595648 362124672 463182720 581083776 842150400 943208448 783199872 808464384 993737472 1204275072 1094795520 1288490112 1524292224 1903259904 993737472 117901056 101058048 109479552 126322560 117901056 117901056 109479552 126322560 126322560 84215040 336860160 791621376 1195853568 1305333120 1221118080 1187432064 1271647104 1229539584 1212696576 1187432064 1221118080 1237961088 1229539584 1204275072 1187432064 1221118080 1237961088 1237961088 1229539584 1204275072 1204275072 1212696576 1212696576 1212696576 1204275072 1204275072 1204275072 1204275072 1204275072 1204275072 1212696576 1179010560 1170589056 1170589056 1170589056 1179010560 1187432064 1187432064 1187432064 176851584 151587072 176851584 126322560 176851584 117901056 75793536 328438656 1128481536 1490606208 1414812672 1136903040 757935360 480025728 480025728 421075200 353703168 395810688 454761216 480025728 471604224 421075200 370546176 336860160 303174144 421075200 437918208 404232192 378967680 412653696 1103217024 1061109504 1027423488 968472960 581083776 176851584 92636544 92636544 58950528 101058048 92636544 109479552 109479552 101058048 151587072 134744064 1751672832 1886416896 564240768 1002158976 1364283648 1136903040 1027423488 1019001984 951629952 833728896 909522432 842150400 690563328 640034304 564240768 496868736 437918208 488447232 572662272 564240768 631612800 774778368 917943936 875836416 749513856 901100928 1111638528 1103217024 1246382592 1296911616 1936945920 1936945920 825307392 109479552 101058048 109479552 109479552 109479552 101058048 101058048 117901056 109479552 134744064 168430080 143165568 227380608 648455808 1153746048 1305333120 1162167552 1229539584 1229539584 1221118080 1212696576 1204275072 1212696576 1246382592 1288490112 1246382592 1246382592 1246382592 1237961088 1229539584 1204275072 1204275072 1204275072 1212696576 1204275072 1221118080 1221118080 1221118080 1221118080 1204275072 1212696576 1195853568 1195853568 1187432064 1179010560 1179010560 1187432064 1179010560 1187432064 160008576 126322560 193694592 151587072 117901056 84215040 176851584 917943936 1448498688 1600085760 1364283648 1170589056 1195853568 648455808 463182720 454761216 404232192 437918208 463182720 463182720 429496704 378967680 328438656 294752640 378967680 395810688 370546176 421075200 488447232 471604224 631612800 412653696 126322560 143165568 84215040 58950528 109479552 151587072 117901056 109479552 117901056 117901056 109479552 117901056 151587072 92636544 1709565312 1920102912 353703168 808464384 1263225600 1313754624 1120060032 993737472 875836416 968472960 917943936 816885888 673720320 707406336 614769792 547397760 522133248 690563328 715827840 656877312 707406336 850571904 943208448 867414912 808464384 993737472 1061109504 1170589056 1271647104 1616928768 1995896448 1920102912 698984832 101058048 84215040 92636544 101058048 101058048 92636544 92636544 101058048 109479552 134744064 67372032 126322560 235802112 160008576 117901056 505290240 1044266496 1246382592 1221118080 1204275072 1254804096 1280068608 1263225600 1221118080 1195853568 1229539584 1204275072 1204275072 1229539584 1229539584 1221118080 1229539584 1254804096 1195853568 1204275072 1221118080 1229539584 1229539584 1221118080 1212696576 1195853568 1212696576 1212696576 1195853568 1179010560 1179010560 1195853568 1179010560 1170589056 193694592 143165568 176851584 143165568 75793536 109479552 261066624 1389548160 1482184704 1490606208 1364283648 1179010560 1423234176 1002158976 597926784 513711744 395810688 421075200 446339712 463182720 437918208 404232192 353703168 328438656 277909632 404232192 454761216 378967680 218959104 143165568 151587072 117901056 109479552 117901056 117901056 92636544 58950528 75793536 109479552 126322560 126322560 109479552 101058048 109479552 134744064 75793536 1616928768 1979053440 530554752 623191296 1305333120 1288490112 1094795520 1103217024 993737472 1002158976 951629952 858993408 707406336 749513856 656877312 614769792 614769792 825307392 816885888 783199872 783199872 892679424 985315968 968472960 951629952 1061109504 1103217024 1162167552 1389548160 1962210432 1877995392 1911681408 471604224 109479552 84215040 92636544 101058048 101058048 84215040 84215040 92636544 101058048 143165568 168430080 168430080 143165568 134744064 168430080 193694592 193694592 395810688 850571904 1212696576 1204275072 1145324544 1221118080 1280068608 1229539584 1288490112 1246382592 1246382592 1263225600 1237961088 1187432064 1179010560 1204275072 1204275072 1204275072 1212696576 1229539584 1221118080 1212696576 1204275072 1195853568 1212696576 1195853568 1187432064 1179010560 1179010560 1187432064 1179010560 1179010560 210537600 143165568 126322560 134744064 126322560 185273088 244223616 1397969664 1524292224 1541135232 1414812672 1271647104 1507449216 1355862144 901100928 429496704 412653696 437918208 463182720 463182720 412653696 353703168 261066624 218959104 244223616 210537600 160008576 117901056 117901056 151587072 84215040 58950528 75793536 84215040 126322560 143165568 126322560 143165568 143165568 84215040 109479552 84215040 92636544 134744064 143165568 101058048 1431655680 1970631936 1566399744 395810688 1069531008 1305333120 1170589056 1027423488 1027423488 1069531008 1019001984 943208448 808464384 791621376 724249344 707406336 749513856 909522432 909522432 858993408 858993408 943208448 985315968 943208448 976894464 1077952512 1204275072 1044266496 1726408320 1995896448 1953788928 1886416896 160008576 143165568 101058048 109479552 101058048 101058048 84215040 84215040 101058048 109479552 134744064 92636544 117901056 185273088 210537600 176851584 134744064 151587072 202116096 75793536 235802112 783199872 1212696576 1296911616 1237961088 1229539584 1212696576 1204275072 1229539584 1271647104 1254804096 1221118080 1204275072 1229539584 1212696576 1212696576 1212696576 1204275072 1204275072 1204275072 1204275072 1212696576 1195853568 1195853568 1170589056 1170589056 1187432064 1187432064 1187432064 1187432064 160008576 160008576 151587072 134744064 134744064 168430080 252645120 1381126656 1423234176 1591664256 1423234176 1423234176 1541135232 1591664256 1440077184 623191296 446339712 421075200 353703168 286331136 227380608 168430080 109479552 75793536 92636544 75793536 92636544 84215040 92636544 126322560 92636544 109479552 126322560 117901056 117901056 92636544 67372032 109479552 134744064 67372032 84215040 92636544 109479552 143165568 134744064 75793536 1069531008 1827466368 2004317952 1044266496 732670848 1187432064 1136903040 1052688000 1094795520 993737472 1061109504 968472960 867414912 783199872 791621376 766356864 842150400 960051456 875836416 825307392 858993408 1027423488 1010580480 858993408 960051456 1128481536 985315968 1355862144 1945367424 1911681408 1995896448 1583242752 67372032 143165568 109479552 101058048 101058048 92636544 84215040 84215040 101058048 109479552 117901056 143165568 168430080 168430080 151587072 143165568 168430080 210537600 160008576 193694592 185273088 143165568 218959104 513711744 901100928 1179010560 1254804096 1263225600 1271647104 1254804096 1212696576 1195853568 1229539584 1246382592 1229539584 1221118080 1221118080 1204275072 1204275072 1195853568 1195853568 1204275072 1187432064 1179010560 1179010560 1170589056 1179010560 1187432064 1179010560 1179010560 134744064 168430080 168430080 117901056 101058048 92636544 303174144 1440077184 1482184704 1591664256 1482184704 1465341696 1557978240 1701143808 1726408320 833728896 261066624 227380608 160008576 117901056 92636544 109479552 117901056 117901056 151587072 92636544 101058048 75793536 42107520 50529024 109479552 109479552 25264512 84215040 143165568 143165568 126322560 126322560 126322560 126322560 101058048 109479552 92636544 126322560 92636544 75793536 800042880 1743251328 2004317952 1776937344 597926784 1010580480 1212696576 1019001984 985315968 1069531008 1077952512 951629952 867414912 766356864 842150400 774778368 875836416 968472960 884257920 867414912 901100928 1077952512 1035844992 892679424 976894464 1094795520 1035844992 1835887872 1945367424 1936945920 1936945920 1010580480 134744064 117901056 109479552 101058048 109479552 101058048 84215040 84215040 101058048 109479552 109479552 117901056 151587072 193694592 193694592 168430080 160008576 168430080 151587072 176851584 176851584 168430080 143165568 160008576 202116096 235802112 412653696 640034304 943208448 1145324544 1246382592 1271647104 1246382592 1204275072 1229539584 1221118080 1229539584 1221118080 1204275072 1195853568 1195853568 1187432064 1204275072 1187432064 1170589056 1162167552 1179010560 1179010560 1170589056 1170589056 160008576 151587072 134744064 109479552 143165568 92636544 311595648 1364283648 1566399744 1490606208 1574821248 1499027712 1633771776 1701143808 1414812672 429496704 126322560 117901056 109479552 126322560 134744064 126322560 109479552 84215040 134744064 75793536 117901056 134744064 151587072 101058048 168430080 67372032 134744064 126322560 84215040 84215040 117901056 92636544 75793536 109479552 109479552 109479552 92636544 109479552 101058048 168430080 749513856 1844309376 1953788928 2038003968 1010580480 589505280 1136903040 1195853568 1044266496 1010580480 1103217024 934786944 867414912 766356864 901100928 783199872 892679424 976894464 926365440 943208448 926365440 1019001984 968472960 850571904 892679424 842150400 1549556736 1962210432 1962210432 1953788928 1962210432 564240768 92636544 117901056 109479552 109479552 101058048 92636544 75793536 75793536 84215040 101058048 117901056 168430080 176851584 143165568 160008576 210537600 202116096 143165568 193694592 185273088 160008576 151587072 193694592 218959104 193694592 151587072 193694592 218959104 210537600 202116096 345281664 682141824 1061109504 1271647104 1229539584 1229539584 1237961088 1229539584 1229539584 1212696576 1187432064 1170589056 1212696576 1204275072 1179010560 1170589056 1179010560 1170589056 1170589056 1162167552 185273088 134744064 160008576 126322560 134744064 92636544 294752640 1339019136 1549556736 1557978240 1566399744 1499027712 1381126656 1103217024 261066624 143165568 117901056 117901056 109479552 117901056 109479552 109479552 109479552 101058048 109479552 109479552 117901056 117901056 109479552 101058048 101058048 101058048 134744064 117901056 109479552 101058048 101058048 101058048 101058048 84215040 143165568 109479552 109479552 92636544 126322560 92636544 648455808 1877995392 1877995392 2071689984 1877995392 547397760 901100928 1120060032 1145324544 993737472 1061109504 1052688000 858993408 808464384 791621376 597926784 943208448 884257920 867414912 816885888 951629952 1035844992 884257920 842150400 631612800 1271647104 1911681408 2046425472 1962210432 1936945920 1894838400 193694592 126322560 84215040 92636544 92636544 101058048 101058048 84215040 84215040 92636544 109479552 101058048 117901056 143165568 168430080 176851584 185273088 193694592 193694592 185273088 185273088 193694592 193694592 185273088 176851584 185273088 176851584 202116096 202116096 218959104 202116096 151587072 134744064 218959104 336860160 875836416 1237961088 1237961088 1195853568 1204275072 1246382592 1162167552 1221118080 1187432064 1187432064 1187432064 1187432064 1170589056 1179010560 1179010560 1170589056 160008576 160008576 160008576 160008576 151587072 75793536 218959104 1355862144 1473763200 1633771776 1364283648 244223616 151587072 160008576 16843008 176851584 117901056 117901056 126322560 126322560 117901056 117901056 109479552 109479552 117901056 109479552 117901056 117901056 109479552 101058048 109479552 101058048 101058048 101058048 92636544 92636544 117901056 109479552 109479552 109479552 92636544 84215040 134744064 134744064 134744064 126322560 471604224 1928524416 1894838400 2004317952 2063268480 1768515840 766356864 1044266496 1069531008 1111638528 1069531008 1120060032 892679424 757935360 842150400 572662272 707406336 749513856 724249344 800042880 816885888 1086374016 892679424 581083776 1010580480 1920102912 2021160960 2004317952 2071689984 1936945920 1246382592 126322560 75793536 109479552 92636544 101058048 109479552 101058048 84215040 84215040 109479552 117901056 126322560 143165568 151587072 168430080 168430080 176851584 176851584 185273088 185273088 202116096 202116096 193694592 185273088 193694592 193694592 193694592 227380608 193694592 176851584 210537600 202116096 176851584 185273088 202116096 202116096 294752640 875836416 1254804096 1204275072 1187432064 1212696576 1162167552 1195853568 1187432064 1195853568 1187432064 1179010560 1162167552 1170589056 1170589056 143165568 176851584 117901056 151587072 160008576 101058048 176851584 1406391168 1650614784 1456920192 252645120 176851584 92636544 117901056 160008576 117901056 126322560 126322560 134744064 134744064 117901056 117901056 126322560 117901056 109479552 117901056 117901056 109479552 117901056 101058048 101058048 92636544 92636544 101058048 101058048 92636544 109479552 117901056 117901056 117901056 126322560 126322560 134744064 143165568 92636544 143165568 277909632 1877995392 1987474944 2004317952 2130640512 2029582464 1852730880 875836416 1136903040 1187432064 1145324544 1103217024 943208448 825307392 842150400 564240768 715827840 833728896 707406336 631612800 993737472 976894464 766356864 842150400 1928524416 1987474944 2113797504 2012739456 2046425472 1920102912 513711744 75793536 75793536 109479552 101058048 109479552 109479552 109479552 92636544 92636544 109479552 117901056 143165568 151587072 143165568 160008576 160008576 168430080 176851584 185273088 176851584 185273088 193694592 193694592 185273088 185273088 185273088 193694592 227380608 176851584 168430080 210537600 227380608 193694592 160008576 143165568 160008576 185273088 261066624 530554752 1120060032 1237961088 1204275072 1195853568 1187432064 1195853568 1195853568 1187432064 1170589056 1153746048 1170589056 1170589056 168430080 176851584 101058048 134744064 143165568 134744064 143165568 1381126656 1549556736 656877312 109479552 193694592 58950528 109479552 101058048 101058048 126322560 134744064 126322560 134744064 126322560 126322560 117901056 117901056 101058048 101058048 109479552 117901056 101058048 101058048 109479552 92636544 109479552 101058048 101058048 109479552 109479552 109479552 101058048 101058048 126322560 126322560 126322560 126322560 84215040 134744064 168430080 1406391168 1886416896 2088532992 2071689984 2130640512 2096954496 1667457792 833728896 1212696576 1364283648 1170589056 1044266496 960051456 791621376 555819264 842150400 783199872 707406336 757935360 1086374016 985315968 707406336 1903259904 2029582464 2105376000 2122219008 2088532992 1987474944 1675879296 160008576 84215040 101058048 101058048 117901056 109479552 117901056 109479552 109479552 109479552 126322560 134744064 117901056 134744064 151587072 160008576 168430080 176851584 185273088 168430080 176851584 185273088 185273088 185273088 176851584 176851584 185273088 193694592 218959104 202116096 202116096 193694592 185273088 168430080 176851584 210537600 227380608 168430080 151587072 193694592 176851584 412653696 1052688000 1212696576 1179010560 1187432064 1187432064 1170589056 1170589056 1153746048 1162167552 1162167552 185273088 168430080 126322560 134744064 109479552 126322560 117901056 1330597632 1448498688 126322560 252645120 42107520 67372032 202116096 126322560 134744064 126322560 126322560 143165568 143165568 134744064 134744064 126322560 117901056 101058048 101058048 109479552 101058048 109479552 109479552 92636544 101058048 109479552 109479552 109479552 101058048 109479552 109479552 109479552 109479552 75793536 101058048 134744064 134744064 143165568 117901056 117901056 665298816 1844309376 1911681408 2139062016 2122219008 2096954496 2088532992 1406391168 909522432 1288490112 1263225600 1212696576 1111638528 909522432 732670848 1027423488 774778368 707406336 1145324544 1027423488 707406336 1920102912 2105376000 2088532992 2130640512 2105376000 2139062016 2046425472 1061109504 134744064 126322560 126322560 117901056 126322560 117901056 109479552 117901056 109479552 117901056 134744064 134744064 117901056 134744064 160008576 168430080 176851584 176851584 176851584 160008576 168430080 176851584 185273088 185273088 185273088 176851584 176851584 185273088 185273088 193694592 193694592 185273088 176851584 168430080 193694592 227380608 210537600 252645120 160008576 160008576 160008576 176851584 496868736 1237961088 1179010560 1187432064 1187432064 1179010560 1170589056 1145324544 1145324544 1162167552 353703168 143165568 151587072 176851584 92636544 117901056 143165568 1280068608 783199872 109479552 50529024 202116096 134744064 84215040 126322560 160008576 126322560 134744064 126322560 134744064 126322560 134744064 117901056 117901056 109479552 109479552 109479552 101058048 101058048 109479552 101058048 92636544 92636544 92636544 101058048 101058048 109479552 109479552 117901056 126322560 109479552 117901056 126322560 117901056 160008576 126322560 168430080 210537600 1566399744 1877995392 2021160960 2113797504 2139062016 2113797504 2088532992 1254804096 1044266496 1305333120 1414812672 1271647104 1153746048 993737472 1187432064 985315968 1069531008 1120060032 867414912 1936945920 2113797504 2071689984 2130640512 2130640512 2122219008 2130640512 1979053440 395810688 168430080 143165568 117901056 143165568 134744064 134744064 109479552 117901056 117901056 126322560 134744064 134744064 160008576 176851584 176851584 193694592 193694592 176851584 176851584 168430080 185273088 185273088 193694592 193694592 176851584 185273088 193694592 193694592 193694592 176851584 176851584 185273088 185273088 176851584 168430080 160008576 134744064 126322560 252645120 193694592 143165568 151587072 134744064 1019001984 1187432064 1195853568 1187432064 1179010560 1162167552 1145324544 1145324544 1162167552 867414912 244223616 143165568 168430080 109479552 109479552 143165568 1136903040 362124672 151587072 126322560 67372032 143165568 151587072 151587072 75793536 117901056 126322560 117901056 126322560 117901056 117901056 109479552 109479552 109479552 109479552 101058048 101058048 101058048 101058048 92636544 92636544 92636544 109479552 117901056 109479552 109479552 101058048 109479552 109479552 143165568 143165568 117901056 92636544 134744064 117901056 193694592 143165568 1019001984 1903259904 2021160960 2139062016 2113797504 2139062016 2096954496 2046425472 1204275072 1111638528 1305333120 1254804096 1229539584 1128481536 1162167552 1094795520 1120060032 1254804096 1928524416 2080111488 2080111488 2139062016 2139062016 2096954496 2139062016 2096954496 1423234176 117901056 160008576 143165568 151587072 143165568 160008576 143165568 117901056 117901056 134744064 134744064 151587072 151587072 185273088 185273088 168430080 168430080 176851584 168430080 176851584 168430080 185273088 193694592 193694592 185273088 185273088 185273088 185273088 193694592 168430080 168430080 168430080 168430080 185273088 176851584 151587072 126322560 227380608 126322560 244223616 134744064 109479552 193694592 160008576 581083776 1187432064 1187432064 1187432064 1187432064 1162167552 1153746048 1153746048 1153746048 1431655680 421075200 126322560 143165568 117901056 109479552 101058048 943208448 109479552 58950528 151587072 160008576 126322560 117901056 134744064 151587072 117901056 117901056 117901056 126322560 117901056 117901056 109479552 109479552 109479552 109479552 109479552 109479552 109479552 92636544 101058048 92636544 117901056 117901056 117901056 109479552 92636544 92636544 92636544 101058048 67372032 101058048 101058048 101058048 126322560 109479552 143165568 193694592 682141824 1928524416 1928524416 2139062016 2130640512 2096954496 2130640512 2105376000 1979053440 1179010560 1347440640 1557978240 1709565312 1751672832 1709565312 1642193280 1583242752 1305333120 2004317952 2122219008 2130640512 2113797504 2113797504 2139062016 2139062016 2080111488 757935360 168430080 160008576 117901056 193694592 134744064 160008576 143165568 117901056 126322560 134744064 143165568 143165568 151587072 168430080 160008576 143165568 143165568 143165568 160008576 176851584 185273088 176851584 185273088 193694592 176851584 176851584 168430080 176851584 176851584 160008576 176851584 168430080 160008576 143165568 151587072 160008576 176851584 151587072 185273088 151587072 151587072 252645120 101058048 176851584 252645120 1187432064 1187432064 1187432064 1179010560 1170589056 1162167552 1145324544 1153746048 1566399744 1187432064 160008576 143165568 117901056 117901056 176851584 446339712 117901056 126322560 134744064 143165568 143165568 134744064 117901056 117901056 143165568 126322560 126322560 117901056 109479552 109479552 109479552 117901056 101058048 101058048 109479552 109479552 109479552 109479552 92636544 84215040 101058048 109479552 117901056 117901056 117901056 109479552 101058048 101058048 101058048 101058048 101058048 117901056 117901056 126322560 151587072 160008576 311595648 1802201856 1953788928 2063268480 2113797504 2122219008 2139062016 2122219008 2096954496 2054846976 2004317952 1928524416 1953788928 1869573888 1549556736 1347440640 412653696 193694592 505290240 1886416896 2122219008 2139062016 2139062016 2113797504 2071689984 1793780352 193694592 185273088 193694592 160008576 109479552 168430080 143165568 151587072 151587072 151587072 151587072 151587072 160008576 160008576 185273088 185273088 185273088 176851584 168430080 160008576 160008576 160008576 176851584 176851584 168430080 176851584 185273088 185273088 168430080 151587072 160008576 151587072 151587072 151587072 160008576 151587072 151587072 143165568 126322560 151587072 160008576 160008576 151587072 134744064 109479552 117901056 1077952512 1162167552 1162167552 1212696576 1153746048 1195853568 1136903040 1179010560 1541135232 1406391168 597926784 92636544 126322560 109479552 160008576 252645120 117901056 117901056 126322560 134744064 134744064 126322560 126322560 117901056 126322560 126322560 126322560 117901056 117901056 117901056 117901056 117901056 109479552 109479552 109479552 109479552 109479552 109479552 101058048 101058048 101058048 109479552 117901056 126322560 109479552 101058048 101058048 101058048 109479552 109479552 117901056 109479552 109479552 109479552 126322560 134744064 210537600 1431655680 1995896448 2038003968 2063268480 2130640512 2096954496 2130640512 2096954496 1145324544 665298816 614769792 421075200 286331136 244223616 202116096 202116096 210537600 126322560 320017152 1726408320 2096954496 2139062016 2113797504 2139062016 976894464 185273088 126322560 143165568 160008576 143165568 168430080 160008576 160008576 160008576 160008576 168430080 176851584 168430080 168430080 168430080 168430080 168430080 176851584 176851584 176851584 185273088 185273088 185273088 176851584 176851584 185273088 185273088 185273088 168430080 160008576 193694592 185273088 176851584 168430080 160008576 151587072 143165568 134744064 126322560 134744064 160008576 160008576 151587072 126322560 117901056 117901056 707406336 1136903040 1221118080 1145324544 1179010560 1170589056 1153746048 1204275072 1490606208 1499027712 1120060032 395810688 117901056 151587072 202116096 134744064 117901056 109479552 117901056 126322560 126322560 117901056 109479552 117901056 117901056 126322560 117901056 117901056 117901056 109479552 109479552 109479552 126322560 126322560 117901056 109479552 109479552 109479552 101058048 101058048 92636544 101058048 117901056 117901056 109479552 101058048 109479552 109479552 101058048 109479552 117901056 109479552 109479552 109479552 109479552 117901056 185273088 993737472 1894838400 2046425472 2130640512 2080111488 2139062016 2096954496 934786944 193694592 58950528 244223616 151587072 143165568 202116096 151587072 134744064 168430080 261066624 151587072 362124672 1819044864 2130640512 2054846976 1894838400 328438656 202116096 151587072 143165568 185273088 168430080 168430080 168430080 168430080 168430080 168430080 176851584 176851584 168430080 168430080 176851584 176851584 185273088 185273088 185273088 185273088 193694592 185273088 202116096 193694592 193694592 202116096 202116096 202116096 193694592 185273088 210537600 202116096 185273088 168430080 160008576 143165568 126322560 117901056 126322560 143165568 151587072 151587072 143165568 126322560 126322560 134744064 353703168 1229539584 1229539584 1145324544 1187432064 1145324544 1187432064 1179010560 1482184704 1414812672 1448498688 1002158976 151587072 185273088 185273088 134744064 117901056 109479552 117901056 126322560 126322560 126322560 109479552 117901056 117901056 126322560 126322560 126322560 117901056 117901056 117901056 109479552 134744064 134744064 126322560 109479552 109479552 109479552 109479552 109479552 101058048 109479552 117901056 117901056 101058048 101058048 101058048 109479552 84215040 92636544 109479552 109479552 109479552 109479552 117901056 117901056 151587072 690563328 1886416896 2113797504 2130640512 2105376000 2088532992 875836416 160008576 126322560 218959104 227380608 193694592 227380608 168430080 126322560 227380608 117901056 84215040 92636544 252645120 404232192 1911681408 2096954496 1145324544 202116096 176851584 202116096 168430080 176851584 168430080 160008576 168430080 168430080 168430080 168430080 176851584 168430080 160008576 160008576 202116096 202116096 202116096 193694592 185273088 176851584 176851584 176851584 193694592 193694592 193694592 202116096 202116096 202116096 193694592 185273088 185273088 176851584 168430080 160008576 151587072 143165568 134744064 126322560 134744064 143165568 143165568 143165568 134744064 117901056 126322560 126322560 185273088 1179010560 1136903040 1204275072 1170589056 1153746048 1229539584 1145324544 1524292224 1372705152 1549556736 1339019136 378967680 168430080 117901056 143165568 126322560 126322560 117901056 126322560 126322560 126322560 117901056 126322560 117901056 126322560 126322560 126322560 126322560 126322560 117901056 117901056 143165568 134744064 126322560 117901056 109479552 109479552 109479552 109479552 109479552 109479552 117901056 117901056 101058048 92636544 92636544 101058048 84215040 92636544 101058048 109479552 109479552 109479552 117901056 117901056 168430080 303174144 1692722304 1995896448 2088532992 2139062016 833728896 109479552 134744064 193694592 176851584 92636544 134744064 176851584 134744064 227380608 168430080 168430080 193694592 176851584 160008576 126322560 698984832 1928524416 404232192 176851584 151587072 176851584 160008576 143165568 176851584 143165568 176851584 176851584 176851584 168430080 176851584 176851584 168430080 168430080 210537600 210537600 202116096 202116096 193694592 176851584 176851584 168430080 168430080 176851584 176851584 176851584 176851584 176851584 176851584 176851584 176851584 168430080 160008576 151587072 160008576 151587072 143165568 134744064 143165568 134744064 143165568 134744064 126322560 109479552 117901056 117901056 117901056 757935360 1162167552 1204275072 1145324544 1179010560 1221118080 1170589056 1507449216 1397969664 1473763200 1263225600 715827840 193694592 67372032 134744064 126322560 126322560 117901056 117901056 126322560 126322560 117901056 126322560 109479552 126322560 126322560 134744064 134744064 126322560 126322560 117901056 134744064 126322560 126322560 117901056 109479552 109479552 109479552 109479552 109479552 117901056 117901056 109479552 92636544 84215040 92636544 92636544 92636544 101058048 109479552 109479552 101058048 101058048 109479552 109479552 117901056 227380608 1052688000 2021160960 2139062016 816885888 168430080 185273088 160008576 92636544 126322560 126322560 117901056 143165568 126322560 160008576 134744064 143165568 117901056 134744064 84215040 277909632 109479552 564240768 193694592 109479552 227380608 160008576 168430080 151587072 193694592 151587072 185273088 185273088 176851584 176851584 185273088 185273088 176851584 176851584 193694592 193694592 193694592 202116096 193694592 185273088 176851584 176851584 168430080 176851584 185273088 185273088 176851584 176851584 185273088 185273088 185273088 176851584 168430080 168430080 160008576 160008576 151587072 143165568 134744064 134744064 143165568 134744064 126322560 109479552 117901056 117901056 126322560 294752640 1229539584 1179010560 1187432064 1212696576 1153746048 1237961088 1482184704 1406391168 1406391168 1229539584 968472960 185273088 126322560 92636544 126322560 126322560 117901056 126322560 117901056 117901056 117901056 126322560 109479552 117901056 126322560 126322560 134744064 126322560 117901056 117901056 117901056 117901056 117901056 117901056 117901056 109479552 109479552 109479552 101058048 109479552 109479552 109479552 92636544 92636544 92636544 101058048 101058048 101058048 109479552 101058048 101058048 101058048 117901056 126322560 92636544 235802112 564240768 2004317952 985315968 151587072 92636544 92636544 126322560 84215040 176851584 160008576 75793536 126322560 143165568 109479552 151587072 168430080 185273088 134744064 252645120 75793536 168430080 202116096 227380608 126322560 261066624 185273088 168430080 185273088 176851584 160008576 176851584 176851584 176851584 176851584 185273088 185273088 176851584 176851584 185273088 193694592 193694592 193694592 185273088 176851584 168430080 160008576 176851584 185273088 193694592 185273088 176851584 176851584 193694592 202116096 185273088 176851584 168430080 160008576 168430080 160008576 151587072 143165568 117901056 126322560 143165568 126322560 126322560 109479552 117901056 109479552 143165568 126322560 1002158976 1187432064 1204275072 1195853568 1153746048 1246382592 1507449216 1406391168 1397969664 1355862144 1019001984 160008576 185273088 50529024 117901056 109479552 109479552 117901056 109479552 109479552 109479552 117901056 101058048 109479552 117901056 126322560 126322560 126322560 117901056 109479552 109479552 109479552 117901056 117901056 117901056 117901056 109479552 101058048 92636544 101058048 109479552 101058048 92636544 92636544 101058048 109479552 84215040 92636544 92636544 101058048 101058048 117901056 134744064 151587072 176851584 84215040 269488128 884257920 126322560 160008576 151587072 84215040 117901056 101058048 143165568 117901056 92636544 109479552 101058048 160008576 134744064 134744064 176851584 160008576 101058048 252645120 168430080 193694592 151587072 185273088 168430080 176851584 117901056 193694592 134744064 168430080 160008576 160008576 168430080 168430080 176851584 176851584 176851584 176851584 202116096 202116096 202116096 193694592 185273088 160008576 151587072 143165568 143165568 160008576 168430080 168430080 151587072 151587072 168430080 176851584 160008576 151587072 151587072 151587072 160008576 160008576 160008576 151587072 109479552 117901056 134744064 134744064 126322560 109479552 109479552 109479552 84215040 143165568 597926784 1204275072 1187432064 1162167552 1229539584 1204275072 1515870720 1381126656 1431655680 1305333120 1061109504 252645120 101058048 126322560 109479552 101058048 92636544 109479552 101058048 117901056 126322560 143165568 109479552 109479552 109479552 109479552 109479552 117901056 117901056 126322560 126322560 117901056 109479552 109479552 117901056 117901056 109479552 101058048 109479552 109479552 101058048 101058048 92636544 92636544 101058048 101058048 117901056 117901056 109479552 101058048 101058048 109479552 117901056 134744064 134744064 134744064 235802112 126322560 134744064 210537600 84215040 134744064 193694592 151587072 168430080 134744064 193694592 92636544 176851584 328438656 244223616 286331136 370546176 176851584 160008576 151587072 160008576 193694592 176851584 168430080 160008576 168430080 185273088 185273088 176851584 168430080 176851584 176851584 176851584 176851584 185273088 193694592 185273088 193694592 193694592 185273088 176851584 185273088 193694592 193694592 193694592 185273088 160008576 160008576 151587072 134744064 134744064 143165568 168430080 185273088 176851584 160008576 151587072 143165568 143165568 151587072 151587072 151587072 117901056 117901056 117901056 126322560 126322560 126322560 126322560 134744064 143165568 126322560 286331136 1212696576 1204275072 1179010560 1229539584 1195853568 1532713728 1414812672 1423234176 1305333120 1069531008 218959104 84215040 117901056 109479552 101058048 109479552 117901056 109479552 109479552 109479552 117901056 109479552 117901056 117901056 109479552 117901056 117901056 126322560 126322560 117901056 109479552 109479552 109479552 117901056 117901056 109479552 101058048 109479552 109479552 109479552 101058048 92636544 101058048 101058048 101058048 109479552 109479552 109479552 101058048 92636544 92636544 109479552 126322560 143165568 134744064 210537600 143165568 92636544 109479552 67372032 151587072 101058048 126322560 109479552 1069531008 1423234176 1667457792 1802201856 1717986816 1768515840 1684300800 1549556736 1322176128 235802112 134744064 160008576 134744064 160008576 160008576 151587072 160008576 176851584 185273088 176851584 168430080 168430080 160008576 151587072 143165568 151587072 151587072 160008576 160008576 168430080 168430080 168430080 185273088 202116096 202116096 202116096 185273088 160008576 160008576 151587072 134744064 134744064 143165568 168430080 185273088 185273088 168430080 151587072 143165568 143165568 143165568 134744064 143165568 126322560 134744064 117901056 117901056 109479552 109479552 109479552 109479552 101058048 92636544 185273088 1027423488 1179010560 1204275072 1212696576 1221118080 1515870720 1431655680 1389548160 1296911616 1086374016 168430080 84215040 109479552 109479552 109479552 117901056 117901056 109479552 101058048 92636544 92636544 109479552 117901056 117901056 117901056 117901056 126322560 126322560 126322560 117901056 109479552 101058048 101058048 109479552 117901056 117901056 109479552 117901056 117901056 109479552 109479552 101058048 101058048 109479552 109479552 109479552 109479552 109479552 101058048 92636544 92636544 109479552 117901056 101058048 143165568 176851584 143165568 126322560 193694592 210537600 134744064 210537600 176851584 867414912 1709565312 2012739456 2113797504 2139062016 2139062016 2113797504 2113797504 2029582464 1869573888 757935360 210537600 143165568 126322560 143165568 143165568 151587072 160008576 168430080 176851584 185273088 176851584 168430080 160008576 143165568 126322560 126322560 134744064 134744064 143165568 151587072 160008576 168430080 193694592 202116096 202116096 193694592 176851584 160008576 160008576 151587072 134744064 134744064 143165568 160008576 176851584 185273088 168430080 151587072 143165568 134744064 134744064 126322560 117901056 143165568 143165568 126322560 126322560 117901056 109479552 101058048 101058048 84215040 92636544 84215040 741092352 1162167552 1212696576 1195853568 1237961088 1490606208 1440077184 1364283648 1296911616 1061109504 126322560 109479552 109479552 109479552 117901056 109479552 109479552 101058048 101058048 92636544 92636544 117901056 117901056 117901056 117901056 117901056 126322560 126322560 126322560 109479552 101058048 101058048 101058048 109479552 117901056 117901056 109479552 117901056 117901056 117901056 117901056 109479552 109479552 109479552 109479552 117901056 126322560 117901056 109479552 101058048 101058048 109479552 126322560 126322560 151587072 134744064 143165568 134744064 168430080 218959104 109479552 143165568 235802112 1465341696 1852730880 2139062016 2139062016 2080111488 2139062016 2096954496 2088532992 1987474944 1861152384 968472960 202116096 126322560 176851584 143165568 143165568 151587072 160008576 168430080 168430080 185273088 185273088 176851584 168430080 151587072 134744064 143165568 143165568 143165568 143165568 151587072 168430080 176851584 193694592 193694592 185273088 168430080 151587072 151587072 151587072 143165568 134744064 126322560 126322560 143165568 160008576 168430080 160008576 143165568 134744064 134744064 134744064 126322560 117901056 143165568 126322560 126322560 117901056 109479552 101058048 92636544 92636544 109479552 101058048 75793536 463182720 1204275072 1221118080 1195853568 1229539584 1490606208 1448498688 1364283648 1305333120 960051456 109479552 126322560 117901056 117901056 117901056 101058048 92636544 92636544 101058048 109479552 109479552 109479552 109479552 109479552 117901056 117901056 117901056 117901056 117901056 117901056 109479552 101058048 101058048 109479552 109479552 117901056 109479552 117901056 117901056 117901056 117901056 109479552 109479552 109479552 109479552 117901056 117901056 117901056 117901056 101058048 101058048 109479552 126322560 143165568 117901056 109479552 193694592 185273088 134744064 202116096 235802112 176851584 858993408 1692722304 2088532992 2139062016 2130640512 2139062016 2113797504 2130640512 2122219008 2004317952 1894838400 530554752 143165568 151587072 134744064 143165568 151587072 168430080 176851584 168430080 176851584 176851584 185273088 168430080 168430080 168430080 168430080 176851584 168430080 160008576 160008576 176851584 185273088 193694592 193694592 176851584 151587072 134744064 126322560 151587072 151587072 143165568 126322560 117901056 117901056 134744064 143165568 160008576 143165568 134744064 134744064 134744064 134744064 126322560 117901056 117901056 126322560 109479552 109479552 101058048 109479552 101058048 101058048 126322560 101058048 117901056 261066624 1212696576 1212696576 1204275072 1212696576 1499027712 1431655680 1381126656 1313754624 800042880 101058048 117901056 109479552 109479552 117901056 101058048 92636544 92636544 101058048 117901056 126322560 109479552 109479552 109479552 117901056 117901056 117901056 117901056 117901056 143165568 126322560 109479552 101058048 109479552 109479552 109479552 109479552 117901056 117901056 117901056 117901056 109479552 109479552 109479552 109479552 101058048 109479552 109479552 109479552 101058048 101058048 101058048 117901056 101058048 134744064 143165568 151587072 218959104 210537600 160008576 160008576 437918208 1372705152 1861152384 2130640512 2122219008 2096954496 2139062016 2130640512 2088532992 2012739456 1936945920 1440077184 176851584 151587072 218959104 109479552 160008576 168430080 185273088 185273088 176851584 176851584 176851584 185273088 168430080 168430080 176851584 185273088 193694592 185273088 176851584 168430080 202116096 202116096 193694592 176851584 151587072 126322560 117901056 117901056 151587072 151587072 143165568 134744064 117901056 117901056 134744064 143165568 143165568 134744064 134744064 134744064 134744064 134744064 126322560 126322560 117901056 117901056 109479552 101058048 101058048 109479552 101058048 109479552 117901056 84215040 126322560 134744064 1128481536 1221118080 1221118080 1212696576 1490606208 1406391168 1389548160 1305333120 640034304 109479552 101058048 109479552 109479552 109479552 117901056 117901056 101058048 109479552 117901056 117901056 109479552 109479552 117901056 117901056 126322560 117901056 117901056 117901056 160008576 143165568 126322560 109479552 109479552 109479552 101058048 101058048 109479552 109479552 117901056 117901056 109479552 109479552 101058048 101058048 101058048 101058048 109479552 109479552 101058048 101058048 109479552 117901056 117901056 168430080 176851584 109479552 160008576 160008576 134744064 353703168 1237961088 1734829824 2088532992 2113797504 2139062016 2139062016 2139062016 2105376000 2139062016 1979053440 1760094336 631612800 168430080 176851584 193694592 176851584 176851584 185273088 202116096 193694592 176851584 168430080 168430080 176851584 185273088 185273088 185273088 185273088 193694592 193694592 185273088 185273088 202116096 202116096 185273088 160008576 126322560 117901056 126322560 134744064 168430080 160008576 160008576 143165568 134744064 126322560 134744064 143165568 143165568 143165568 134744064 126322560 126322560 126322560 117901056 109479552 109479552 117901056 109479552 101058048 101058048 101058048 109479552 109479552 109479552 101058048 109479552 117901056 960051456 1229539584 1221118080 1229539584 1473763200 1372705152 1389548160 1305333120 530554752 117901056 117901056 126322560 117901056 109479552 117901056 117901056 117901056 109479552 101058048 92636544 109479552 117901056 117901056 126322560 126322560 126322560 126322560 117901056 168430080 151587072 126322560 117901056 109479552 101058048 101058048 92636544 109479552 109479552 117901056 117901056 109479552 109479552 101058048 101058048 101058048 109479552 117901056 117901056 109479552 109479552 117901056 126322560 143165568 75793536 168430080 218959104 227380608 126322560 387389184 1229539584 1726408320 1962210432 2122219008 2130640512 2088532992 2130640512 2122219008 2139062016 2029582464 1717986816 1465341696 176851584 210537600 235802112 134744064 210537600 185273088 202116096 210537600 202116096 176851584 176851584 176851584 185273088 210537600 210537600 202116096 193694592 202116096 193694592 193694592 202116096 193694592 193694592 176851584 143165568 117901056 109479552 126322560 143165568 176851584 185273088 168430080 151587072 151587072 143165568 151587072 160008576 160008576 151587072 143165568 126322560 126322560 117901056 109479552 101058048 109479552 109479552 109479552 109479552 92636544 101058048 101058048 92636544 126322560 126322560 92636544 134744064 833728896 1246382592 1204275072 1237961088 1414812672 1406391168 1389548160 1339019136 429496704 101058048 134744064 84215040 134744064 126322560 109479552 101058048 101058048 101058048 101058048 109479552 92636544 75793536 160008576 33686016 202116096 126322560 84215040 134744064 134744064 101058048 92636544 151587072 58950528 109479552 109479552 75793536 58950528 176851584 117901056 92636544 109479552 117901056 151587072 101058048 134744064 134744064 126322560 117901056 109479552 109479552 117901056 126322560 160008576 92636544 210537600 193694592 202116096 176851584 1288490112 1616928768 1920102912 2113797504 2096954496 2130640512 2130640512 2130640512 2113797504 2088532992 1776937344 1591664256 513711744 218959104 227380608 193694592 151587072 210537600 227380608 210537600 193694592 193694592 168430080 143165568 143165568 168430080 202116096 126322560 202116096 176851584 160008576 202116096 168430080 160008576 185273088 143165568 160008576 92636544 185273088 109479552 160008576 160008576 168430080 109479552 168430080 117901056 168430080 185273088 160008576 151587072 160008576 134744064 143165568 134744064 134744064 134744064 92636544 109479552 126322560 126322560 126322560 117901056 109479552 109479552 109479552 109479552 143165568 101058048 109479552 151587072 673720320 1237961088 1271647104 1229539584 1431655680 1406391168 1372705152 1339019136 328438656 84215040 134744064 101058048 126322560 117901056 109479552 109479552 101058048 109479552 101058048 117901056 185273088 75793536 101058048 218959104 92636544 92636544 261066624 101058048 143165568 134744064 134744064 185273088 84215040 126322560 134744064 134744064 84215040 58950528 92636544 109479552 185273088 193694592 33686016 202116096 126322560 126322560 126322560 109479552 101058048 101058048 109479552 117901056 117901056 160008576 151587072 143165568 202116096 277909632 1069531008 1642193280 1869573888 2130640512 2130640512 2122219008 2130640512 2130640512 2046425472 1810623360 1330597632 951629952 294752640 168430080 185273088 218959104 168430080 193694592 210537600 202116096 176851584 185273088 176851584 151587072 151587072 168430080 193694592 143165568 185273088 235802112 218959104 193694592 218959104 218959104 176851584 168430080 134744064 117901056 67372032 126322560 160008576 160008576 210537600 117901056 235802112 84215040 117901056 109479552 143165568 160008576 143165568 109479552 109479552 126322560 143165568 143165568 126322560 134744064 117901056 126322560 117901056 117901056 101058048 117901056 109479552 117901056 126322560 109479552 126322560 134744064 564240768 1254804096 1271647104 1246382592 1465341696 1372705152 1347440640 1330597632 210537600 75793536 134744064 126322560 117901056 101058048 101058048 109479552 101058048 109479552 101058048 101058048 58950528 117901056 1103217024 1162167552 1179010560 1027423488 934786944 774778368 707406336 606348288 446339712 345281664 168430080 151587072 109479552 84215040 160008576 126322560 151587072 117901056 67372032 176851584 75793536 117901056 126322560 126322560 117901056 109479552 101058048 92636544 101058048 109479552 92636544 202116096 92636544 134744064 168430080 252645120 640034304 1541135232 1827466368 2038003968 2096954496 2130640512 2130640512 2080111488 1760094336 1263225600 951629952 395810688 176851584 193694592 185273088 244223616 185273088 185273088 202116096 185273088 185273088 193694592 193694592 168430080 160008576 176851584 160008576 218959104 160008576 168430080 160008576 168430080 168430080 117901056 143165568 185273088 185273088 210537600 101058048 185273088 176851584 160008576 101058048 176851584 151587072 160008576 202116096 185273088 109479552 117901056 151587072 134744064 126322560 134744064 126322560 92636544 84215040 101058048 101058048 109479552 109479552 109479552 101058048 117901056 109479552 117901056 126322560 134744064 134744064 134744064 421075200 1280068608 1263225600 1280068608 1456920192 1364283648 1339019136 1288490112 126322560 92636544 126322560 126322560 101058048 101058048 109479552 117901056 109479552 109479552 101058048 101058048 244223616 67372032 1120060032 1566399744 2130640512 2130640512 2063268480 1212696576 1237961088 1296911616 1355862144 1499027712 1532713728 1557978240 1423234176 1322176128 1128481536 1077952512 842150400 648455808 126322560 25264512 210537600 143165568 126322560 126322560 117901056 109479552 101058048 101058048 101058048 109479552 109479552 160008576 92636544 185273088 168430080 168430080 261066624 1271647104 1625350272 1979053440 2122219008 2096954496 2021160960 1835887872 1313754624 858993408 707406336 210537600 210537600 227380608 202116096 210537600 193694592 176851584 176851584 185273088 193694592 193694592 193694592 176851584 176851584 176851584 117901056 227380608 193694592 185273088 202116096 185273088 218959104 631612800 488447232 538976256 572662272 572662272 564240768 555819264 555819264 572662272 606348288 943208448 168430080 143165568 126322560 151587072 84215040 168430080 109479552 117901056 101058048 151587072 143165568 92636544 117901056 134744064 92636544 101058048 109479552 101058048 109479552 117901056 109479552 126322560 117901056 143165568 134744064 109479552 294752640 1263225600 1246382592 1263225600 1423234176 1355862144 1364283648 1170589056 109479552 109479552 109479552 109479552 92636544 101058048 109479552 117901056 109479552 109479552 101058048 101058048 84215040 269488128 1195853568 1650614784 2096954496 2113797504 1760094336 1027423488 1229539584 1271647104 1263225600 1347440640 1397969664 1524292224 1532713728 1557978240 1499027712 1507449216 1423234176 1440077184 808464384 151587072 50529024 75793536 126322560 126322560 126322560 117901056 109479552 109479552 126322560 126322560 134744064 109479552 151587072 210537600 202116096 193694592 160008576 842150400 1515870720 1835887872 2063268480 1979053440 1793780352 1296911616 892679424 1019001984 412653696 168430080 202116096 193694592 202116096 134744064 176851584 185273088 168430080 185273088 193694592 202116096 193694592 185273088 185273088 168430080 261066624 151587072 117901056 168430080 244223616 134744064 143165568 1179010560 707406336 749513856 698984832 698984832 757935360 749513856 732670848 833728896 749513856 1490606208 252645120 143165568 160008576 168430080 151587072 151587072 168430080 151587072 92636544 143165568 134744064 67372032 101058048 84215040 101058048 109479552 109479552 109479552 117901056 117901056 126322560 126322560 109479552 134744064 109479552 92636544 202116096 1145324544 1221118080 1237961088 1414812672 1355862144 1381126656 960051456 117901056 134744064 101058048 109479552 109479552 101058048 109479552 109479552 101058048 109479552 101058048 101058048 58950528 353703168 1414812672 1566399744 1793780352 1903259904 1701143808 1355862144 1204275072 1389548160 1473763200 1541135232 1507449216 1532713728 1499027712 1541135232 1532713728 1456920192 1423234176 1473763200 1288490112 656877312 151587072 117901056 117901056 126322560 134744064 126322560 117901056 117901056 134744064 143165568 160008576 109479552 168430080 151587072 185273088 227380608 185273088 362124672 1499027712 1633771776 1877995392 1844309376 1414812672 1094795520 1179010560 1145324544 185273088 168430080 193694592 168430080 218959104 126322560 176851584 176851584 176851584 193694592 193694592 193694592 193694592 193694592 176851584 168430080 151587072 176851584 252645120 143165568 168430080 185273088 176851584 1288490112 715827840 732670848 741092352 741092352 757935360 757935360 766356864 783199872 825307392 1473763200 345281664 160008576 151587072 84215040 185273088 109479552 84215040 126322560 109479552 193694592 168430080 58950528 117901056 117901056 109479552 109479552 109479552 117901056 126322560 126322560 134744064 126322560 134744064 134744064 151587072 126322560 176851584 1002158976 1237961088 1246382592 1406391168 1389548160 1381126656 724249344 134744064 126322560 92636544 109479552 117901056 117901056 117901056 109479552 101058048 109479552 101058048 109479552 185273088 488447232 1440077184 1776937344 1734829824 1625350272 1869573888 1254804096 1170589056 1431655680 1583242752 1684300800 1675879296 1684300800 1625350272 1667457792 1659036288 1608507264 1574821248 1524292224 1600085760 1271647104 682141824 67372032 109479552 126322560 134744064 134744064 126322560 126322560 143165568 151587072 160008576 143165568 151587072 151587072 168430080 185273088 210537600 143165568 1128481536 1675879296 1827466368 1549556736 1136903040 1305333120 1633771776 665298816 160008576 176851584 193694592 168430080 193694592 176851584 176851584 176851584 185273088 210537600 210537600 193694592 176851584 185273088 176851584 160008576 202116096 160008576 151587072 227380608 774778368 1313754624 884257920 926365440 825307392 698984832 1010580480 825307392 850571904 732670848 976894464 682141824 1077952512 1179010560 766356864 1061109504 867414912 774778368 648455808 581083776 623191296 842150400 917943936 884257920 530554752 126322560 101058048 126322560 109479552 126322560 126322560 126322560 143165568 143165568 126322560 126322560 151587072 134744064 193694592 134744064 160008576 808464384 1254804096 1288490112 1406391168 1397969664 1381126656 572662272 143165568 117901056 92636544 126322560 126322560 117901056 117901056 109479552 101058048 101058048 101058048 109479552 126322560 640034304 1086374016 1465341696 1886416896 1827466368 1254804096 1027423488 1136903040 1296911616 1313754624 1355862144 1381126656 1448498688 1440077184 1507449216 1499027712 1465341696 1440077184 1406391168 1440077184 1381126656 1280068608 277909632 109479552 117901056 126322560 134744064 126322560 126322560 143165568 151587072 126322560 151587072 117901056 218959104 193694592 126322560 235802112 210537600 614769792 1650614784 1574821248 1305333120 1162167552 1170589056 1313754624 134744064 176851584 117901056 168430080 134744064 143165568 210537600 168430080 160008576 202116096 218959104 210537600 185273088 176851584 193694592 176851584 160008576 143165568 210537600 362124672 690563328 1397969664 2046425472 1473763200 901100928 1170589056 850571904 1456920192 968472960 1111638528 833728896 1389548160 825307392 1557978240 926365440 909522432 1625350272 1136903040 1077952512 741092352 816885888 682141824 1136903040 1397969664 1313754624 724249344 109479552 67372032 151587072 126322560 134744064 126322560 134744064 143165568 143165568 134744064 126322560 126322560 126322560 185273088 126322560 134744064 656877312 1237961088 1288490112 1448498688 1364283648 1389548160 328438656 117901056 143165568 101058048 101058048 101058048 101058048 109479552 109479552 101058048 92636544 101058048 109479552 134744064 446339712 783199872 943208448 926365440 926365440 1044266496 1187432064 1195853568 1237961088 1296911616 1339019136 1372705152 1397969664 1448498688 1490606208 1397969664 1423234176 1372705152 1372705152 1364283648 1322176128 1296911616 269488128 101058048 109479552 117901056 126322560 117901056 109479552 109479552 101058048 134744064 143165568 143165568 143165568 151587072 151587072 160008576 168430080 134744064 1515870720 1465341696 960051456 656877312 1204275072 353703168 117901056 168430080 143165568 117901056 126322560 151587072 176851584 176851584 185273088 235802112 185273088 151587072 176851584 202116096 176851584 168430080 193694592 185273088 395810688 656877312 875836416 1566399744 2004317952 1473763200 875836416 1153746048 842150400 1532713728 1052688000 1204275072 993737472 1414812672 901100928 1549556736 1010580480 884257920 1482184704 1187432064 1069531008 800042880 783199872 732670848 985315968 1246382592 1355862144 707406336 143165568 117901056 134744064 126322560 134744064 143165568 134744064 143165568 126322560 134744064 143165568 143165568 151587072 168430080 117901056 168430080 505290240 1237961088 1288490112 1431655680 1372705152 1313754624 261066624 92636544 134744064 101058048 117901056 117901056 117901056 126322560 117901056 117901056 109479552 126322560 126322560 75793536 109479552 134744064 101058048 58950528 84215040 176851584 269488128 328438656 395810688 488447232 597926784 715827840 825307392 934786944 993737472 1120060032 1204275072 1229539584 1263225600 1280068608 1288490112 1170589056 252645120 101058048 109479552 109479552 109479552 109479552 109479552 117901056 117901056 134744064 134744064 134744064 143165568 143165568 134744064 143165568 151587072 193694592 757935360 1195853568 589505280 488447232 800042880 101058048 160008576 168430080 151587072 143165568 134744064 151587072 160008576 160008576 176851584 160008576 151587072 176851584 202116096 168430080 143165568 160008576 210537600 429496704 732670848 867414912 825307392 749513856 993737472 732670848 774778368 993737472 1296911616 1170589056 1010580480 1052688000 1263225600 892679424 943208448 1145324544 917943936 732670848 833728896 724249344 808464384 715827840 631612800 673720320 682141824 724249344 1010580480 320017152 75793536 92636544 143165568 126322560 134744064 151587072 160008576 143165568 134744064 134744064 126322560 151587072 143165568 160008576 151587072 160008576 387389184 1263225600 1296911616 1406391168 1381126656 1162167552 176851584 84215040 134744064 92636544 126322560 101058048 109479552 109479552 109479552 101058048 101058048 117901056 117901056 126322560 109479552 101058048 109479552 117901056 117901056 117901056 109479552 134744064 134744064 126322560 109479552 92636544 84215040 101058048 109479552 134744064 117901056 160008576 269488128 294752640 370546176 446339712 126322560 101058048 101058048 101058048 92636544 101058048 109479552 134744064 143165568 134744064 134744064 126322560 126322560 134744064 126322560 126322560 134744064 151587072 218959104 690563328 496868736 522133248 277909632 101058048 143165568 134744064 126322560 134744064 143165568 151587072 160008576 176851584 185273088 193694592 176851584 176851584 168430080 160008576 202116096 336860160 488447232 1044266496 1473763200 1482184704 1305333120 656877312 656877312 682141824 1145324544 1372705152 1591664256 623191296 1229539584 1515870720 1920102912 555819264 766356864 1448498688 1271647104 968472960 741092352 732670848 724249344 690563328 682141824 707406336 656877312 690563328 1136903040 261066624 143165568 109479552 168430080 126322560 126322560 151587072 160008576 143165568 134744064 134744064 134744064 143165568 134744064 143165568 193694592 143165568 244223616 1288490112 1288490112 1381126656 1381126656 1010580480 101058048 75793536 134744064 84215040 126322560 92636544 92636544 101058048 92636544 101058048 92636544 109479552 109479552 92636544 101058048 109479552 126322560 126322560 126322560 117901056 117901056 117901056 126322560 126322560 117901056 109479552 101058048 117901056 126322560 117901056 67372032 109479552 143165568 58950528 67372032 101058048 101058048 101058048 101058048 92636544 92636544 101058048 109479552 126322560 126322560 143165568 134744064 126322560 117901056 126322560 126322560 126322560 117901056 101058048 126322560 252645120 530554752 471604224 67372032 185273088 117901056 109479552 126322560 134744064 134744064 134744064 151587072 176851584 202116096 218959104 193694592 176851584 151587072 185273088 286331136 480025728 640034304 1179010560 1532713728 1431655680 1271647104 690563328 665298816 682141824 976894464 1355862144 1616928768 825307392 1246382592 1313754624 1768515840 757935360 934786944 1406391168 1187432064 909522432 749513856 800042880 698984832 648455808 698984832 741092352 715827840 783199872 1094795520 320017152 134744064 67372032 92636544 126322560 143165568 143165568 143165568 143165568 143165568 126322560 134744064 143165568 151587072 143165568 193694592 134744064 151587072 1313754624 1271647104 1355862144 1355862144 850571904 92636544 101058048 134744064 75793536 117901056 109479552 109479552 117901056 109479552 109479552 101058048 117901056 117901056 126322560 143165568 134744064 109479552 84215040 75793536 92636544 109479552 101058048 109479552 117901056 117901056 109479552 101058048 101058048 101058048 101058048 117901056 168430080 92636544 101058048 210537600 134744064 75793536 101058048 101058048 101058048 101058048 101058048 101058048 101058048 101058048 134744064 134744064 117901056 126322560 109479552 109479552 109479552 109479552 143165568 109479552 151587072 320017152 210537600 151587072 101058048 168430080 143165568 134744064 134744064 126322560 134744064 143165568 160008576 185273088 176851584 168430080 151587072 168430080 202116096 252645120 336860160 395810688 572662272 698984832 555819264 522133248 320017152 345281664 336860160 378967680 488447232 530554752 235802112 320017152 303174144 581083776 294752640 320017152 412653696 328438656 227380608 202116096 202116096 218959104 185273088 160008576 210537600 160008576 185273088 311595648 109479552 75793536 143165568 168430080 134744064 143165568 143165568 134744064 126322560 134744064 134744064 143165568 134744064 151587072 151587072 160008576 143165568 151587072 1254804096 1263225600 1364283648 1313754624 690563328 109479552 117901056 134744064 84215040 109479552 101058048 101058048 109479552 101058048 101058048 101058048 101058048 117901056 117901056 117901056 126322560 143165568 160008576 151587072 134744064 117901056 126322560 134744064 143165568 151587072 151587072 151587072 143165568 134744064 151587072 126322560 176851584 67372032 75793536 126322560 92636544 101058048 109479552 109479552 101058048 101058048 101058048 101058048 92636544 92636544 117901056 117901056 126322560 126322560 117901056 117901056 117901056 134744064 143165568 126322560 160008576 126322560 84215040 185273088 92636544 126322560 117901056 126322560 126322560 134744064 143165568 168430080 185273088 202116096 168430080 151587072 143165568 151587072 185273088 193694592 168430080 160008576 176851584 185273088 160008576 210537600 202116096 193694592 218959104 235802112 218959104 185273088 210537600 252645120 244223616 202116096 185273088 218959104 202116096 185273088 193694592 269488128 134744064 185273088 176851584 160008576 210537600 143165568 134744064 50529024 134744064 75793536 143165568 126322560 143165568 143165568 134744064 126322560 126322560 134744064 134744064 151587072 134744064 151587072 160008576 126322560 151587072 151587072 1069531008 1271647104 1397969664 1271647104 572662272 126322560 126322560 109479552 101058048 109479552 92636544 84215040 101058048 84215040 92636544 92636544 92636544 109479552 160008576 117901056 75793536 58950528 84215040 109479552 117901056 117901056 109479552 109479552 109479552 109479552 109479552 101058048 92636544 84215040 75793536 16843008 151587072 134744064 168430080 58950528 92636544 151587072 109479552 101058048 101058048 92636544 92636544 92636544 92636544 101058048 109479552 109479552 117901056 126322560 126322560 126322560 134744064 151587072 117901056 168430080 126322560 143165568 109479552 134744064 168430080 101058048 117901056 126322560 143165568 151587072 176851584 185273088 193694592 193694592 168430080 160008576 160008576 143165568 168430080 168430080 185273088 185273088 218959104 185273088 235802112 269488128 218959104 185273088 160008576 202116096 227380608 269488128 227380608 160008576 193694592 277909632 261066624 134744064 185273088 176851584 185273088 252645120 176851584 151587072 168430080 210537600 134744064 168430080 210537600 134744064 151587072 101058048 109479552 101058048 134744064 134744064 134744064 134744064 134744064 134744064 134744064 143165568 151587072 126322560 160008576 109479552 160008576 134744064 816885888 1296911616 1423234176 1246382592 505290240 134744064 126322560 92636544 117901056 109479552 101058048 101058048 109479552 101058048 101058048 109479552 109479552 117901056 109479552 117901056 126322560 126322560 126322560 134744064 126322560 126322560 126322560 117901056 117901056 117901056 117901056 117901056 117901056 117901056 143165568 67372032 143165568 50529024 151587072 109479552 176851584 101058048 117901056 101058048 92636544 84215040 84215040 92636544 101058048 109479552 109479552 109479552 117901056 126322560 126322560 134744064 143165568 151587072 176851584 84215040 101058048 176851584 67372032 126322560 160008576 151587072 176851584 168430080 168430080 193694592 193694592 176851584 151587072 126322560 117901056 143165568 168430080 168430080 168430080 168430080 193694592 202116096 193694592 176851584 193694592 193694592 143165568 235802112 193694592 202116096 168430080 193694592 185273088 286331136 218959104 168430080 168430080 218959104 185273088 227380608 193694592 109479552 176851584 193694592 160008576 143165568 160008576 160008576 160008576 151587072 75793536 143165568 126322560 168430080 134744064 134744064 151587072 143165568 134744064 143165568 134744064 134744064 160008576 92636544 160008576 109479552 168430080 109479552 631612800 1322176128 \ No newline at end of file diff --git a/Tests/images/hopper_bigtiff.tif b/Tests/images/hopper_bigtiff.tif new file mode 100644 index 00000000000..9588a37d80b Binary files /dev/null and b/Tests/images/hopper_bigtiff.tif differ diff --git a/Tests/images/hopper_rle8.bmp b/Tests/images/hopper_rle8.bmp new file mode 100644 index 00000000000..0fff4a0d43d Binary files /dev/null and b/Tests/images/hopper_rle8.bmp differ diff --git a/Tests/images/hopper_rle8_row_overflow.bmp b/Tests/images/hopper_rle8_row_overflow.bmp new file mode 100644 index 00000000000..d606dc3e41a Binary files /dev/null and b/Tests/images/hopper_rle8_row_overflow.bmp differ diff --git a/Tests/images/imagedraw/discontiguous_corners_polygon.png b/Tests/images/imagedraw/discontiguous_corners_polygon.png new file mode 100644 index 00000000000..509c42b26e0 Binary files /dev/null and b/Tests/images/imagedraw/discontiguous_corners_polygon.png differ diff --git a/Tests/images/imagedraw_polygon_1px_high_translucent.png b/Tests/images/imagedraw_polygon_1px_high_translucent.png new file mode 100644 index 00000000000..8bbf9397c72 Binary files /dev/null and b/Tests/images/imagedraw_polygon_1px_high_translucent.png differ diff --git a/Tests/images/issue_6194.j2k b/Tests/images/issue_6194.j2k new file mode 100644 index 00000000000..b1b8851670b Binary files /dev/null and b/Tests/images/issue_6194.j2k differ diff --git a/Tests/images/multiple_comments.gif b/Tests/images/multiple_comments.gif new file mode 100644 index 00000000000..88b2af800e8 Binary files /dev/null and b/Tests/images/multiple_comments.gif differ diff --git a/Tests/images/no_palette.gif b/Tests/images/no_palette.gif new file mode 100644 index 00000000000..0432ebcb61c Binary files /dev/null and b/Tests/images/no_palette.gif differ diff --git a/Tests/images/no_palette_with_background.gif b/Tests/images/no_palette_with_background.gif new file mode 100644 index 00000000000..e49e5d461aa Binary files /dev/null and b/Tests/images/no_palette_with_background.gif differ diff --git a/Tests/images/no_palette_with_transparency.gif b/Tests/images/no_palette_with_transparency.gif new file mode 100644 index 00000000000..031bdcfce10 Binary files /dev/null and b/Tests/images/no_palette_with_transparency.gif differ diff --git a/Tests/images/second_frame_comment.gif b/Tests/images/second_frame_comment.gif new file mode 100644 index 00000000000..c8fc957911e Binary files /dev/null and b/Tests/images/second_frame_comment.gif differ diff --git a/Tests/images/tiff_wrong_bits_per_sample_3.tiff b/Tests/images/tiff_wrong_bits_per_sample_3.tiff new file mode 100644 index 00000000000..43526b157a5 Binary files /dev/null and b/Tests/images/tiff_wrong_bits_per_sample_3.tiff differ diff --git a/Tests/images/tiny.png b/Tests/images/tiny.png new file mode 100644 index 00000000000..3d9ff56e7ef Binary files /dev/null and b/Tests/images/tiny.png differ diff --git a/Tests/images/zero_height.j2k b/Tests/images/zero_height.j2k new file mode 100644 index 00000000000..21bdd8f7667 Binary files /dev/null and b/Tests/images/zero_height.j2k differ diff --git a/Tests/test_bmp_reference.py b/Tests/test_bmp_reference.py index 440bc325b45..b17aad2ea50 100644 --- a/Tests/test_bmp_reference.py +++ b/Tests/test_bmp_reference.py @@ -40,6 +40,7 @@ def test_questionable(): "rgb32fakealpha.bmp", "rgb24largepal.bmp", "pal8os2sp.bmp", + "pal8rletrns.bmp", "rgb32bf-xbgr.bmp", ] for f in get_files("q"): diff --git a/Tests/test_box_blur.py b/Tests/test_box_blur.py index 94f504e0b55..3bdd5177d3f 100644 --- a/Tests/test_box_blur.py +++ b/Tests/test_box_blur.py @@ -25,7 +25,7 @@ def box_blur(image, radius=1, n=1): return image._new(image.im.box_blur(radius, n)) -def assertImage(im, data, delta=0): +def assert_image(im, data, delta=0): it = iter(im.getdata()) for data_row in data: im_row = [next(it) for _ in range(im.size[0])] @@ -35,12 +35,12 @@ def assertImage(im, data, delta=0): next(it) -def assertBlur(im, radius, data, passes=1, delta=0): +def assert_blur(im, radius, data, passes=1, delta=0): # check grayscale image - assertImage(box_blur(im, radius, passes), data, delta) + assert_image(box_blur(im, radius, passes), data, delta) rgba = Image.merge("RGBA", (im, im, im, im)) for band in box_blur(rgba, radius, passes).split(): - assertImage(band, data, delta) + assert_image(band, data, delta) def test_color_modes(): @@ -64,7 +64,7 @@ def test_color_modes(): def test_radius_0(): - assertBlur( + assert_blur( sample, 0, [ @@ -80,7 +80,7 @@ def test_radius_0(): def test_radius_0_02(): - assertBlur( + assert_blur( sample, 0.02, [ @@ -97,7 +97,7 @@ def test_radius_0_02(): def test_radius_0_05(): - assertBlur( + assert_blur( sample, 0.05, [ @@ -114,7 +114,7 @@ def test_radius_0_05(): def test_radius_0_1(): - assertBlur( + assert_blur( sample, 0.1, [ @@ -131,7 +131,7 @@ def test_radius_0_1(): def test_radius_0_5(): - assertBlur( + assert_blur( sample, 0.5, [ @@ -148,7 +148,7 @@ def test_radius_0_5(): def test_radius_1(): - assertBlur( + assert_blur( sample, 1, [ @@ -165,7 +165,7 @@ def test_radius_1(): def test_radius_1_5(): - assertBlur( + assert_blur( sample, 1.5, [ @@ -182,7 +182,7 @@ def test_radius_1_5(): def test_radius_bigger_then_half(): - assertBlur( + assert_blur( sample, 3, [ @@ -199,7 +199,7 @@ def test_radius_bigger_then_half(): def test_radius_bigger_then_width(): - assertBlur( + assert_blur( sample, 10, [ @@ -214,7 +214,7 @@ def test_radius_bigger_then_width(): def test_extreme_large_radius(): - assertBlur( + assert_blur( sample, 600, [ @@ -229,7 +229,7 @@ def test_extreme_large_radius(): def test_two_passes(): - assertBlur( + assert_blur( sample, 1, [ @@ -247,7 +247,7 @@ def test_two_passes(): def test_three_passes(): - assertBlur( + assert_blur( sample, 1, [ diff --git a/Tests/test_color_lut.py b/Tests/test_color_lut.py index 120ff777e77..6d9a6057029 100644 --- a/Tests/test_color_lut.py +++ b/Tests/test_color_lut.py @@ -15,27 +15,27 @@ class TestColorLut3DCoreAPI: def generate_identity_table(self, channels, size): if isinstance(size, tuple): - size1D, size2D, size3D = size + size_1d, size_2d, size_3d = size else: - size1D, size2D, size3D = (size, size, size) + size_1d, size_2d, size_3d = (size, size, size) table = [ [ - r / (size1D - 1) if size1D != 1 else 0, - g / (size2D - 1) if size2D != 1 else 0, - b / (size3D - 1) if size3D != 1 else 0, - r / (size1D - 1) if size1D != 1 else 0, - g / (size2D - 1) if size2D != 1 else 0, + r / (size_1d - 1) if size_1d != 1 else 0, + g / (size_2d - 1) if size_2d != 1 else 0, + b / (size_3d - 1) if size_3d != 1 else 0, + r / (size_1d - 1) if size_1d != 1 else 0, + g / (size_2d - 1) if size_2d != 1 else 0, ][:channels] - for b in range(size3D) - for g in range(size2D) - for r in range(size1D) + for b in range(size_3d) + for g in range(size_2d) + for r in range(size_1d) ] return ( channels, - size1D, - size2D, - size3D, + size_1d, + size_2d, + size_3d, [item for sublist in table for item in sublist], ) @@ -567,7 +567,7 @@ def test_3_to_3_channels(self): assert tuple(lut.size) == tuple(source.size) assert len(lut.table) == len(source.table) assert lut.table != source.table - assert lut.table[0:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0] + assert lut.table[:10] == [0.0, 0.0, 0.0, 0.25, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0] def test_3_to_4_channels(self): source = ImageFilter.Color3DLUT.generate((6, 5, 4), lambda r, g, b: (r, g, b)) @@ -576,7 +576,7 @@ def test_3_to_4_channels(self): assert len(lut.table) != len(source.table) assert lut.table != source.table # fmt: off - assert lut.table[0:16] == [ + assert lut.table[:16] == [ 0.0, 0.0, 0.0, 1, 0.2**2, 0.0, 0.0, 1, 0.4**2, 0.0, 0.0, 1, 0.6**2, 0.0, 0.0, 1] # fmt: on @@ -592,7 +592,7 @@ def test_4_to_3_channels(self): assert len(lut.table) != len(source.table) assert lut.table != source.table # fmt: off - assert lut.table[0:18] == [ + assert lut.table[:18] == [ 1.0, 1.0, 1.0, 0.75, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.96, 1.0, 0.75, 0.96, 1.0, 0.0, 0.96, 1.0] # fmt: on @@ -606,7 +606,7 @@ def test_4_to_4_channels(self): assert len(lut.table) == len(source.table) assert lut.table != source.table # fmt: off - assert lut.table[0:16] == [ + assert lut.table[:16] == [ 0.0, 0.0, 0.0, 0.5, 0.2**2, 0.0, 0.0, 0.5, 0.4**2, 0.0, 0.0, 0.5, 0.6**2, 0.0, 0.0, 0.5] # fmt: on @@ -622,7 +622,7 @@ def test_with_normals_3_channels(self): assert len(lut.table) == len(source.table) assert lut.table != source.table # fmt: off - assert lut.table[0:18] == [ + assert lut.table[:18] == [ 0.0, 0.0, 0.0, 0.16, 0.0, 0.0, 0.24, 0.0, 0.0, 0.24, 0.0, 0.0, 0.8 - (0.8**2), 0, 0, 0, 0, 0] # fmt: on @@ -639,7 +639,7 @@ def test_with_normals_4_channels(self): assert len(lut.table) == len(source.table) assert lut.table != source.table # fmt: off - assert lut.table[0:16] == [ + assert lut.table[:16] == [ 0.0, 0.0, 0.0, 0.5, 0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 0.0, 0.16, 0.0, 0.5] # fmt: on diff --git a/Tests/test_decompression_bomb.py b/Tests/test_decompression_bomb.py index 1778491ab64..d85d1f3c266 100644 --- a/Tests/test_decompression_bomb.py +++ b/Tests/test_decompression_bomb.py @@ -51,7 +51,6 @@ def test_exception(self): with Image.open(TEST_FILE): pass - @pytest.mark.xfail(reason="different exception") def test_exception_ico(self): with pytest.raises(Image.DecompressionBombError): with Image.open("Tests/images/decompression_bomb.ico"): @@ -70,15 +69,15 @@ def test_exception_bmp(self): class TestDecompressionCrop: @classmethod - def setup_class(self): + def setup_class(cls): width, height = 128, 128 Image.MAX_IMAGE_PIXELS = height * width * 4 - 1 @classmethod - def teardown_class(self): + def teardown_class(cls): Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT - def testEnlargeCrop(self): + def test_enlarge_crop(self): # Crops can extend the extents, therefore we should have the # same decompression bomb warnings on them. with hopper() as src: diff --git a/Tests/test_deprecate.py b/Tests/test_deprecate.py new file mode 100644 index 00000000000..30ed4a8081d --- /dev/null +++ b/Tests/test_deprecate.py @@ -0,0 +1,91 @@ +import pytest + +from PIL import _deprecate + + +@pytest.mark.parametrize( + "version, expected", + [ + ( + 10, + "Old thing is deprecated and will be removed in Pillow 10 " + r"\(2023-07-01\)\. Use new thing instead\.", + ), + ( + None, + r"Old thing is deprecated and will be removed in a future version\. " + r"Use new thing instead\.", + ), + ], +) +def test_version(version, expected): + with pytest.warns(DeprecationWarning, match=expected): + _deprecate.deprecate("Old thing", version, "new thing") + + +def test_unknown_version(): + expected = r"Unknown removal version, update PIL\._deprecate\?" + with pytest.raises(ValueError, match=expected): + _deprecate.deprecate("Old thing", 12345, "new thing") + + +@pytest.mark.parametrize( + "deprecated, plural, expected", + [ + ( + "Old thing", + False, + r"Old thing is deprecated and should be removed\.", + ), + ( + "Old things", + True, + r"Old things are deprecated and should be removed\.", + ), + ], +) +def test_old_version(deprecated, plural, expected): + expected = r"" + with pytest.raises(RuntimeError, match=expected): + _deprecate.deprecate(deprecated, 1, plural=plural) + + +def test_plural(): + expected = ( + r"Old things are deprecated and will be removed in Pillow 10 \(2023-07-01\)\. " + r"Use new thing instead\." + ) + with pytest.warns(DeprecationWarning, match=expected): + _deprecate.deprecate("Old things", 10, "new thing", plural=True) + + +def test_replacement_and_action(): + expected = "Use only one of 'replacement' and 'action'" + with pytest.raises(ValueError, match=expected): + _deprecate.deprecate( + "Old thing", 10, replacement="new thing", action="Upgrade to new thing" + ) + + +@pytest.mark.parametrize( + "action", + [ + "Upgrade to new thing", + "Upgrade to new thing.", + ], +) +def test_action(action): + expected = ( + r"Old thing is deprecated and will be removed in Pillow 10 \(2023-07-01\)\. " + r"Upgrade to new thing\." + ) + with pytest.warns(DeprecationWarning, match=expected): + _deprecate.deprecate("Old thing", 10, action=action) + + +def test_no_replacement_or_action(): + expected = ( + r"Old thing is deprecated and will be removed in Pillow 10 \(2023-07-01\)" + ) + with pytest.warns(DeprecationWarning, match=expected): + _deprecate.deprecate("Old thing", 10) diff --git a/Tests/test_deprecated_imageqt.py b/Tests/test_deprecated_imageqt.py new file mode 100644 index 00000000000..2528ff3f7d4 --- /dev/null +++ b/Tests/test_deprecated_imageqt.py @@ -0,0 +1,18 @@ +import warnings + +with warnings.catch_warnings(record=True) as w: + # Arrange: cause all warnings to always be triggered + warnings.simplefilter("always") + + # Act: trigger a warning with Qt5 + from PIL import ImageQt + + +def test_deprecated(): + # Assert + if ImageQt.qt_version in ("5", "side2"): + assert len(w) == 1 + assert issubclass(w[0].category, DeprecationWarning) + assert "deprecated" in str(w[0].message) + else: + assert len(w) == 0 diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index d1d5c85c1ae..ad61a07ccc5 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -637,6 +637,15 @@ def test_apng_save_blend(tmp_path): assert im.getpixel((0, 0)) == (0, 255, 0, 255) +def test_seek_after_close(): + im = Image.open("Tests/images/apng/delay.png") + im.seek(1) + im.close() + + with pytest.raises(ValueError): + im.seek(0) + + def test_constants_deprecation(): for enum, prefix in { PngImagePlugin.Disposal: "APNG_DISPOSE_", diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index 47fc97df055..f214fd6bda1 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -4,7 +4,12 @@ from PIL import BmpImagePlugin, Image -from .helper import assert_image_equal, assert_image_equal_tofile, hopper +from .helper import ( + assert_image_equal, + assert_image_equal_tofile, + assert_image_similar_tofile, + hopper, +) def test_sanity(tmp_path): @@ -125,6 +130,42 @@ def test_rgba_bitfields(): assert_image_equal_tofile(im, "Tests/images/bmp/q/rgb32bf-xbgr.bmp") +def test_rle8(): + with Image.open("Tests/images/hopper_rle8.bmp") as im: + assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12) + + # This test image has been manually hexedited + # to have rows with too much data + with Image.open("Tests/images/hopper_rle8_row_overflow.bmp") as im: + assert_image_similar_tofile(im.convert("RGB"), "Tests/images/hopper.bmp", 12) + + # Signal end of bitmap before the image is finished + with open("Tests/images/bmp/g/pal8rle.bmp", "rb") as fp: + data = fp.read(1063) + b"\x01" + with Image.open(io.BytesIO(data)) as im: + with pytest.raises(ValueError): + im.load() + + +@pytest.mark.parametrize( + "file_name,length", + ( + # EOF immediately after the header + ("Tests/images/hopper_rle8.bmp", 1078), + # EOF during delta + ("Tests/images/bmp/q/pal8rletrns.bmp", 3670), + # EOF when reading data in absolute mode + ("Tests/images/bmp/g/pal8rle.bmp", 1064), + ), +) +def test_rle8_eof(file_name, length): + with open(file_name, "rb") as fp: + data = fp.read(length) + with Image.open(io.BytesIO(data)) as im: + with pytest.raises(ValueError): + im.load() + + def test_offset(): # This image has been hexedited # to exclude the palette size from the pixel data offset diff --git a/Tests/test_file_fli.py b/Tests/test_file_fli.py index c1ad4a7f0f9..a7d43d2e922 100644 --- a/Tests/test_file_fli.py +++ b/Tests/test_file_fli.py @@ -46,6 +46,15 @@ def test_closed_file(): im.close() +def test_seek_after_close(): + im = Image.open(animated_test_file) + im.seek(1) + im.close() + + with pytest.raises(ValueError): + im.seek(0) + + def test_context_manager(): with warnings.catch_warnings(): with Image.open(static_test_file) as im: diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 011d982f097..c261cfb97bb 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -3,7 +3,7 @@ import pytest -from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, features +from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette, ImageSequence, features from .helper import ( assert_image_equal, @@ -46,6 +46,19 @@ def test_closed_file(): im.close() +def test_seek_after_close(): + im = Image.open("Tests/images/iss634.gif") + im.load() + im.close() + + with pytest.raises(ValueError): + im.is_animated + with pytest.raises(ValueError): + im.n_frames + with pytest.raises(ValueError): + im.seek(1) + + def test_context_manager(): with warnings.catch_warnings(): with Image.open(TEST_GIF) as im: @@ -59,6 +72,51 @@ def test_invalid_file(): GifImagePlugin.GifImageFile(invalid_file) +def test_l_mode_transparency(): + with Image.open("Tests/images/no_palette_with_transparency.gif") as im: + assert im.mode == "L" + assert im.load()[0, 0] == 128 + assert im.info["transparency"] == 255 + + im.seek(1) + assert im.mode == "L" + assert im.load()[0, 0] == 128 + + +def test_strategy(): + with Image.open("Tests/images/chi.gif") as im: + expected_zero = im.convert("RGB") + + im.seek(1) + expected_one = im.convert("RGB") + + try: + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_ALWAYS + with Image.open("Tests/images/chi.gif") as im: + assert im.mode == "RGB" + assert_image_equal(im, expected_zero) + + GifImagePlugin.LOADING_STRATEGY = ( + GifImagePlugin.LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY + ) + # Stay in P mode with only a global palette + with Image.open("Tests/images/chi.gif") as im: + assert im.mode == "P" + + im.seek(1) + assert im.mode == "P" + assert_image_equal(im.convert("RGB"), expected_one) + + # Change to RGB mode when a frame has an individual palette + with Image.open("Tests/images/iss634.gif") as im: + assert im.mode == "P" + + im.seek(1) + assert im.mode == "RGB" + finally: + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST + + def test_optimize(): def test_grayscale(optimize): im = Image.new("L", (1, 1), 0) @@ -296,16 +354,23 @@ def test_seek_rewind(): assert_image_equal(im, expected) -def test_n_frames(): - for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]: - # Test is_animated before n_frames - with Image.open(path) as im: - assert im.is_animated == (n_frames != 1) +@pytest.mark.parametrize( + "path, n_frames", + ( + (TEST_GIF, 1), + ("Tests/images/comment_after_last_frame.gif", 2), + ("Tests/images/iss634.gif", 42), + ), +) +def test_n_frames(path, n_frames): + # Test is_animated before n_frames + with Image.open(path) as im: + assert im.is_animated == (n_frames != 1) - # Test is_animated after n_frames - with Image.open(path) as im: - assert im.n_frames == n_frames - assert im.is_animated == (n_frames != 1) + # Test is_animated after n_frames + with Image.open(path) as im: + assert im.n_frames == n_frames + assert im.is_animated == (n_frames != 1) def test_no_change(): @@ -383,18 +448,38 @@ def test_dispose_background_transparency(): assert px[35, 30][3] == 0 -def test_transparent_dispose(): - expected_colors = [ - (2, 1, 2), - ((0, 255, 24, 255), (0, 0, 255, 255), (0, 255, 24, 255)), - ((0, 0, 0, 0), (0, 0, 255, 255), (0, 0, 0, 0)), - ] - with Image.open("Tests/images/transparent_dispose.gif") as img: - for frame in range(3): - img.seek(frame) - for x in range(3): - color = img.getpixel((x, 0)) - assert color == expected_colors[frame][x] +@pytest.mark.parametrize( + "loading_strategy, expected_colors", + ( + ( + GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST, + ( + (2, 1, 2), + ((0, 255, 24, 255), (0, 0, 255, 255), (0, 255, 24, 255)), + ((0, 0, 0, 0), (0, 0, 255, 255), (0, 0, 0, 0)), + ), + ), + ( + GifImagePlugin.LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY, + ( + (2, 1, 2), + (0, 1, 0), + (2, 1, 2), + ), + ), + ), +) +def test_transparent_dispose(loading_strategy, expected_colors): + GifImagePlugin.LOADING_STRATEGY = loading_strategy + try: + with Image.open("Tests/images/transparent_dispose.gif") as img: + for frame in range(3): + img.seek(frame) + for x in range(3): + color = img.getpixel((x, 0)) + assert color == expected_colors[frame][x] + finally: + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST def test_dispose_previous(): @@ -554,7 +639,8 @@ def test_dispose2_background(tmp_path): assert im.getpixel((0, 0)) == (255, 0, 0) -def test_transparency_in_second_frame(): +def test_transparency_in_second_frame(tmp_path): + out = str(tmp_path / "temp.gif") with Image.open("Tests/images/different_transparency.gif") as im: assert im.info["transparency"] == 0 @@ -564,6 +650,14 @@ def test_transparency_in_second_frame(): assert_image_equal_tofile(im, "Tests/images/different_transparency_merged.png") + im.save(out, save_all=True) + + with Image.open(out) as reread: + reread.seek(reread.tell() + 1) + assert_image_equal_tofile( + reread, "Tests/images/different_transparency_merged.png" + ) + def test_no_transparency_in_second_frame(): with Image.open("Tests/images/iss634.gif") as img: @@ -575,6 +669,22 @@ def test_no_transparency_in_second_frame(): assert img.histogram()[255] == 0 +def test_remapped_transparency(tmp_path): + out = str(tmp_path / "temp.gif") + + im = Image.new("P", (1, 2)) + im2 = im.copy() + + # Add transparency at a higher index + # so that it will be optimized to a lower index + im.putpixel((0, 1), 5) + im.info["transparency"] = 5 + im.save(out, save_all=True, append_images=[im2]) + + with Image.open(out) as reloaded: + assert reloaded.info["transparency"] == reloaded.getpixel((0, 1)) + + def test_duration(tmp_path): duration = 1000 @@ -626,6 +736,23 @@ def test_multiple_duration(tmp_path): pass +def test_roundtrip_info_duration(tmp_path): + duration_list = [100, 500, 500] + + out = str(tmp_path / "temp.gif") + with Image.open("Tests/images/transparent_dispose.gif") as im: + assert [ + frame.info["duration"] for frame in ImageSequence.Iterator(im) + ] == duration_list + + im.save(out, save_all=True) + + with Image.open(out) as reloaded: + assert [ + frame.info["duration"] for frame in ImageSequence.Iterator(reloaded) + ] == duration_list + + def test_identical_frames(tmp_path): duration_list = [1000, 1500, 2000, 4000] @@ -677,9 +804,16 @@ def test_number_of_loops(tmp_path): im = Image.new("L", (100, 100), "#000") im.save(out, loop=number_of_loops) with Image.open(out) as reread: - assert reread.info["loop"] == number_of_loops + # Check that even if a subsequent GIF frame has the number of loops specified, + # only the value from the first frame is used + with Image.open("Tests/images/duplicate_number_of_loops.gif") as im: + assert im.info["loop"] == 2 + + im.seek(1) + assert im.info["loop"] == 2 + def test_background(tmp_path): out = str(tmp_path / "temp.gif") @@ -712,6 +846,9 @@ def test_comment(tmp_path): with Image.open(out) as reread: assert reread.info["comment"] == im.info["comment"].encode() + # Test that GIF89a is used for comments + assert reread.info["version"] == b"GIF89a" + def test_comment_over_255(tmp_path): out = str(tmp_path / "temp.gif") @@ -722,43 +859,95 @@ def test_comment_over_255(tmp_path): im.info["comment"] = comment im.save(out) with Image.open(out) as reread: - assert reread.info["comment"] == comment + # Test that GIF89a is used for comments + assert reread.info["version"] == b"GIF89a" + def test_zero_comment_subblocks(): with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im: assert_image_equal_tofile(im, TEST_GIF) +def test_read_multiple_comment_blocks(): + with Image.open("Tests/images/multiple_comments.gif") as im: + # Multiple comment blocks in a frame are separated not concatenated + assert im.info["comment"] == b"Test comment 1\nTest comment 2" + + +def test_empty_string_comment(tmp_path): + out = str(tmp_path / "temp.gif") + with Image.open("Tests/images/chi.gif") as im: + assert "comment" in im.info + + # Empty string comment should suppress existing comment + im.save(out, save_all=True, comment="") + + with Image.open(out) as reread: + for frame in ImageSequence.Iterator(reread): + assert "comment" not in frame.info + + +def test_retain_comment_in_subsequent_frames(tmp_path): + # Test that a comment block at the beginning is kept + with Image.open("Tests/images/chi.gif") as im: + for frame in ImageSequence.Iterator(im): + assert frame.info["comment"] == b"Created with GIMP" + + with Image.open("Tests/images/second_frame_comment.gif") as im: + assert "comment" not in im.info + + # Test that a comment in the middle is read + im.seek(1) + assert im.info["comment"] == b"Comment in the second frame" + + # Test that it is still present in a later frame + im.seek(2) + assert im.info["comment"] == b"Comment in the second frame" + + # Test that rewinding removes the comment + im.seek(0) + assert "comment" not in im.info + + # Test that a saved image keeps the comment + out = str(tmp_path / "temp.gif") + with Image.open("Tests/images/dispose_prev.gif") as im: + im.save(out, save_all=True, comment="Test") + + with Image.open(out) as reread: + for frame in ImageSequence.Iterator(reread): + assert frame.info["comment"] == b"Test" + + def test_version(tmp_path): out = str(tmp_path / "temp.gif") - def assertVersionAfterSave(im, version): + def assert_version_after_save(im, version): im.save(out) with Image.open(out) as reread: assert reread.info["version"] == version # Test that GIF87a is used by default im = Image.new("L", (100, 100), "#000") - assertVersionAfterSave(im, b"GIF87a") + assert_version_after_save(im, b"GIF87a") # Test setting the version to 89a im = Image.new("L", (100, 100), "#000") im.info["version"] = b"89a" - assertVersionAfterSave(im, b"GIF89a") + assert_version_after_save(im, b"GIF89a") # Test that adding a GIF89a feature changes the version im.info["transparency"] = 1 - assertVersionAfterSave(im, b"GIF89a") + assert_version_after_save(im, b"GIF89a") # Test that a GIF87a image is also saved in that format with Image.open("Tests/images/test.colors.gif") as im: - assertVersionAfterSave(im, b"GIF87a") + assert_version_after_save(im, b"GIF87a") # Test that a GIF89a image is also saved in that format im.info["version"] = b"GIF89a" - assertVersionAfterSave(im, b"GIF87a") + assert_version_after_save(im, b"GIF87a") def test_append_images(tmp_path): @@ -773,10 +962,10 @@ def test_append_images(tmp_path): assert reread.n_frames == 3 # Tests appending using a generator - def imGenerator(ims): + def im_generator(ims): yield from ims - im.save(out, save_all=True, append_images=imGenerator(ims)) + im.save(out, save_all=True, append_images=im_generator(ims)) with Image.open(out) as reread: assert reread.n_frames == 3 @@ -831,6 +1020,17 @@ def test_rgb_transparency(tmp_path): assert "transparency" not in reloaded.info +def test_rgba_transparency(tmp_path): + out = str(tmp_path / "temp.gif") + + im = hopper("P") + im.save(out, save_all=True, append_images=[Image.new("RGBA", im.size)]) + + with Image.open(out) as reloaded: + reloaded.seek(1) + assert_image_equal(hopper("P").convert("RGB"), reloaded) + + def test_bbox(tmp_path): out = str(tmp_path / "temp.gif") @@ -960,6 +1160,11 @@ def test_lzw_bits(): def test_extents(): with Image.open("Tests/images/test_extents.gif") as im: assert im.size == (100, 100) + + # Check that n_frames does not change the size + assert im.n_frames == 2 + assert im.size == (100, 100) + im.seek(1) assert im.size == (150, 150) diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 7d8f89184b1..55632909c6b 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -4,15 +4,13 @@ import pytest -from PIL import IcnsImagePlugin, Image, _binary, features +from PIL import IcnsImagePlugin, Image, _binary -from .helper import assert_image_equal, assert_image_similar_tofile +from .helper import assert_image_equal, assert_image_similar_tofile, skip_unless_feature # sample icon file TEST_FILE = "Tests/images/pillow.icns" -ENABLE_JPEG2K = features.check_codec("jpg_2000") - def test_sanity(): # Loading this icon by default should result in the largest size @@ -111,14 +109,12 @@ def test_older_icon(): assert im2.size == (wr, hr) +@skip_unless_feature("jpg_2000") def test_jp2_icon(): # This icon uses JPEG 2000 images instead of the PNG images. # The advantage of doing this is that OS X 10.5 supports JPEG 2000 # but not PNG; some commercial software therefore does just this. - if not ENABLE_JPEG2K: - return - with Image.open("Tests/images/pillow3.icns") as im: for w, h, r in im.info["sizes"]: wr = w * r @@ -149,6 +145,7 @@ def test_not_an_icns_file(): IcnsImagePlugin.IcnsFile(fp) +@skip_unless_feature("jpg_2000") def test_icns_decompression_bomb(): with Image.open( "Tests/images/oom-8ed3316a4109213ca96fb8a256a0bfefdece1461.icns" diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py index 12b80fbde27..3fcd5c61f0d 100644 --- a/Tests/test_file_ico.py +++ b/Tests/test_file_ico.py @@ -1,4 +1,5 @@ import io +import os import pytest @@ -70,6 +71,53 @@ def test_save_to_bytes(): ) +def test_no_duplicates(tmp_path): + temp_file = str(tmp_path / "temp.ico") + temp_file2 = str(tmp_path / "temp2.ico") + + im = hopper() + sizes = [(32, 32), (64, 64)] + im.save(temp_file, "ico", sizes=sizes) + + sizes.append(sizes[-1]) + im.save(temp_file2, "ico", sizes=sizes) + + assert os.path.getsize(temp_file) == os.path.getsize(temp_file2) + + +def test_different_bit_depths(tmp_path): + temp_file = str(tmp_path / "temp.ico") + temp_file2 = str(tmp_path / "temp2.ico") + + im = hopper() + im.save(temp_file, "ico", bitmap_format="bmp", sizes=[(128, 128)]) + + hopper("1").save( + temp_file2, + "ico", + bitmap_format="bmp", + sizes=[(128, 128)], + append_images=[im], + ) + + assert os.path.getsize(temp_file) != os.path.getsize(temp_file2) + + # Test that only matching sizes of different bit depths are saved + temp_file3 = str(tmp_path / "temp3.ico") + temp_file4 = str(tmp_path / "temp4.ico") + + im.save(temp_file3, "ico", bitmap_format="bmp", sizes=[(128, 128)]) + im.save( + temp_file4, + "ico", + bitmap_format="bmp", + sizes=[(128, 128)], + append_images=[Image.new("P", (64, 64))], + ) + + assert os.path.getsize(temp_file3) == os.path.getsize(temp_file4) + + @pytest.mark.parametrize("mode", ("1", "L", "P", "RGB", "RGBA")) def test_save_to_bytes_bmp(mode): output = io.BytesIO() diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index e5e8c85f4ed..12edd75828e 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -68,6 +68,13 @@ def test_sanity(self): assert im.format == "JPEG" assert im.get_format_mimetype() == "image/jpeg" + @pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0))) + def test_zero(self, size, tmp_path): + f = str(tmp_path / "temp.jpg") + im = Image.new("RGB", size) + with pytest.raises(ValueError): + im.save(f) + def test_app(self): # Test APP/COM reader (@PIL135) with Image.open(TEST_FILE) as im: @@ -736,7 +743,7 @@ def test_no_dpi_in_exif(self): # Act / Assert # "When the image resolution is unknown, 72 [dpi] is designated." - # http://www.exiv2.org/tags.html + # https://exiv2.org/tags.html assert im.info.get("dpi") == (72, 72) def test_invalid_exif(self): diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index b5ea6d0a026..7942d6b9afd 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -209,6 +209,49 @@ def test_layers(): assert_image_similar(im, test_card, 0.4) +@pytest.mark.parametrize( + "name, args, offset, data", + ( + ("foo.j2k", {}, 0, b"\xff\x4f"), + ("foo.jp2", {}, 4, b"jP"), + (None, {"no_jp2": True}, 0, b"\xff\x4f"), + ("foo.j2k", {"no_jp2": True}, 0, b"\xff\x4f"), + ("foo.jp2", {"no_jp2": True}, 0, b"\xff\x4f"), + ("foo.j2k", {"no_jp2": False}, 0, b"\xff\x4f"), + ("foo.jp2", {"no_jp2": False}, 4, b"jP"), + ("foo.jp2", {"no_jp2": False}, 4, b"jP"), + ), +) +def test_no_jp2(name, args, offset, data): + out = BytesIO() + if name: + out.name = name + test_card.save(out, "JPEG2000", **args) + out.seek(offset) + assert out.read(2) == data + + +def test_mct(): + # Three component + for val in (0, 1): + out = BytesIO() + test_card.save(out, "JPEG2000", mct=val, no_jp2=True) + + assert out.getvalue()[59] == val + with Image.open(out) as im: + assert_image_similar(im, test_card, 1.0e-3) + + # Single component should have MCT disabled + for val in (0, 1): + out = BytesIO() + with Image.open("Tests/images/16bit.cropped.jp2") as jp2: + jp2.save(out, "JPEG2000", mct=val, no_jp2=True) + + assert out.getvalue()[53] == 0 + with Image.open(out) as im: + assert_image_similar(im, jp2, 1.0e-3) + + def test_rgba(): # Arrange with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k: @@ -255,6 +298,11 @@ def test_16bit_jp2_roundtrips(): assert_image_equal(im, jp2) +def test_issue_6194(): + with Image.open("Tests/images/issue_6194.j2k") as im: + assert im.getpixel((5, 5)) == 31 + + def test_unbound_local(): # prepatch, a malformed jp2 file could cause an UnboundLocalError exception. with pytest.raises(OSError): diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index a9337f4fc65..a43548ae0f3 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -4,7 +4,6 @@ import os import re from collections import namedtuple -from ctypes import c_float import pytest @@ -168,14 +167,11 @@ def test_write_metadata(self, tmp_path): val = original[tag] if tag.endswith("Resolution"): if legacy_api: - assert ( - c_float(val[0][0] / val[0][1]).value - == c_float(value[0][0] / value[0][1]).value + assert val[0][0] / val[0][1] == ( + 4294967295 / 113653537 ), f"{tag} didn't roundtrip" else: - assert ( - c_float(val).value == c_float(value).value - ), f"{tag} didn't roundtrip" + assert val == 37.79000115940079, f"{tag} didn't roundtrip" else: assert val == value, f"{tag} didn't roundtrip" @@ -501,8 +497,8 @@ def test_cmyk_save(self, tmp_path): im.save(out, compression="tiff_adobe_deflate") assert_image_equal_tofile(im, out) - def test_palette_save(self, tmp_path): - im = hopper("P") + @pytest.mark.parametrize("im", (hopper("P"), Image.new("P", (1, 1), "#000"))) + def test_palette_save(self, im, tmp_path): out = str(tmp_path / "temp.tif") TiffImagePlugin.WRITE_LIBTIFF = True diff --git a/Tests/test_file_mpo.py b/Tests/test_file_mpo.py index 0fa3b6382ec..d093f26ccd8 100644 --- a/Tests/test_file_mpo.py +++ b/Tests/test_file_mpo.py @@ -48,6 +48,14 @@ def test_closed_file(): im.close() +def test_seek_after_close(): + im = Image.open(test_files[0]) + im.close() + + with pytest.raises(ValueError): + im.seek(1) + + def test_context_manager(): with warnings.catch_warnings(): with Image.open(test_files[0]) as im: @@ -116,6 +124,15 @@ def test_parallax(): assert exif.get_ifd(0x927C)[0xB211] == -3.125 +def test_reload_exif_after_seek(): + with Image.open("Tests/images/sugarshack.mpo") as im: + exif = im.getexif() + del exif[296] + + im.seek(1) + assert 296 in exif + + def test_mp(): for test_file in test_files: with Image.open(test_file) as im: @@ -145,10 +162,10 @@ def test_mp_attribute(): for test_file in test_files: with Image.open(test_file) as im: mpinfo = im._getmp() - frameNumber = 0 + frame_number = 0 for mpentry in mpinfo[0xB002]: mpattr = mpentry["Attribute"] - if frameNumber: + if frame_number: assert not mpattr["RepresentativeImageFlag"] else: assert mpattr["RepresentativeImageFlag"] @@ -157,7 +174,7 @@ def test_mp_attribute(): assert mpattr["ImageDataFormat"] == "JPEG" assert mpattr["MPType"] == "Multi-Frame Image: (Disparity)" assert mpattr["Reserved"] == 0 - frameNumber += 1 + frame_number += 1 def test_seek(): diff --git a/Tests/test_file_pdf.py b/Tests/test_file_pdf.py index 10daa414b5a..c71d4f5f22b 100644 --- a/Tests/test_file_pdf.py +++ b/Tests/test_file_pdf.py @@ -131,10 +131,10 @@ def test_save_all(tmp_path): assert os.path.getsize(outfile) > 0 # Test appending using a generator - def imGenerator(ims): + def im_generator(ims): yield from ims - im.save(outfile, save_all=True, append_images=imGenerator(ims)) + im.save(outfile, save_all=True, append_images=im_generator(ims)) assert os.path.isfile(outfile) assert os.path.getsize(outfile) > 0 @@ -253,9 +253,9 @@ def test_pdf_append(tmp_path): check_pdf_pages_consistency(pdf) # append two images - mode_CMYK = hopper("CMYK") - mode_P = hopper("P") - mode_CMYK.save(pdf_filename, append=True, save_all=True, append_images=[mode_P]) + mode_cmyk = hopper("CMYK") + mode_p = hopper("P") + mode_cmyk.save(pdf_filename, append=True, save_all=True, append_images=[mode_p]) # open the PDF again, check pages and info again with PdfParser.PdfParser(pdf_filename) as pdf: diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index bb2b0d11918..2a40ab7be9d 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -635,6 +635,17 @@ def test_padded_idat(self): assert_image_equal_tofile(im, "Tests/images/bw_gradient.png") + @pytest.mark.parametrize("cid", (b"IHDR", b"pHYs", b"acTL", b"fcTL", b"fdAT")) + def test_truncated_chunks(self, cid): + fp = BytesIO() + with PngImagePlugin.PngStream(fp) as png: + with pytest.raises(ValueError): + png.call(cid, 0, 0) + + ImageFile.LOAD_TRUNCATED_IMAGES = True + png.call(cid, 0, 0) + ImageFile.LOAD_TRUNCATED_IMAGES = False + def test_specify_bits(self, tmp_path): im = hopper("P") diff --git a/Tests/test_file_ppm.py b/Tests/test_file_ppm.py index 8fe68d33e2c..627ed9d0fbf 100644 --- a/Tests/test_file_ppm.py +++ b/Tests/test_file_ppm.py @@ -13,16 +13,53 @@ def test_sanity(): with Image.open(TEST_FILE) as im: - im.load() assert im.mode == "RGB" assert im.size == (128, 128) - assert im.format, "PPM" + assert im.format == "PPM" assert im.get_format_mimetype() == "image/x-portable-pixmap" +@pytest.mark.parametrize( + "data, mode, pixels", + ( + (b"P5 3 1 4 \x00\x02\x04", "L", (0, 128, 255)), + (b"P5 3 1 257 \x00\x00\x00\x80\x01\x01", "I", (0, 32640, 65535)), + # P6 with maxval < 255 + ( + b"P6 3 1 17 \x00\x01\x02\x08\x09\x0A\x0F\x10\x11", + "RGB", + ( + (0, 15, 30), + (120, 135, 150), + (225, 240, 255), + ), + ), + # P6 with maxval > 255 + # Scale down to 255, since there is no RGB mode with more than 8-bit + ( + b"P6 3 1 257 \x00\x00\x00\x01\x00\x02" + b"\x00\x80\x00\x81\x00\x82\x01\x00\x01\x01\xFF\xFF", + "RGB", + ( + (0, 1, 2), + (127, 128, 129), + (254, 255, 255), + ), + ), + ), +) +def test_arbitrary_maxval(data, mode, pixels): + fp = BytesIO(data) + with Image.open(fp) as im: + assert im.size == (3, 1) + assert im.mode == mode + + px = im.load() + assert tuple(px[x, 0] for x in range(3)) == pixels + + def test_16bit_pgm(): with Image.open("Tests/images/16_bit_binary.pgm") as im: - im.load() assert im.mode == "I" assert im.size == (20, 100) assert im.get_format_mimetype() == "image/x-portable-graymap" @@ -32,8 +69,6 @@ def test_16bit_pgm(): def test_16bit_pgm_write(tmp_path): with Image.open("Tests/images/16_bit_binary.pgm") as im: - im.load() - f = str(tmp_path / "temp.pgm") im.save(f, "PPM") @@ -82,17 +117,6 @@ def test_16bit_plain_pgm(tmp_path): assert_image_equal_tofile(im, "Tests/images/hopper_16bit.pgm") -def test_32bit_plain_pgm(tmp_path): - # P2 with maxval 2 ** 31 - 1 - with Image.open("Tests/images/hopper_32bit_plain.pgm") as im: - assert im.mode == "I" - assert im.size == (128, 128) - assert im.get_format_mimetype() == "image/x-portable-graymap" - - # P5 with maxval 2 ** 31 - 1 - assert_image_equal_tofile(im, "Tests/images/hopper_32bit.pgm") - - def test_plain_pbm_data_with_comments(tmp_path): path1 = str(tmp_path / "temp1.ppm") path2 = str(tmp_path / "temp2.ppm") @@ -222,31 +246,39 @@ def test_header_token_too_long(tmp_path): with Image.open(path): pass - assert str(e.value) == "Token too long in file header: b'01234567890'" + assert str(e.value) == "Token too long in file header: 01234567890" -def test_too_many_colors(tmp_path): - path = str(tmp_path / "temp.ppm") - with open(path, "wb") as f: - f.write(b"P6\n1 1\n1000\n") +def test_truncated_header(tmp_path): + # Test EOF in header + path = str(tmp_path / "temp.pgm") + with open(path, "w") as f: + f.write("P6") with pytest.raises(ValueError) as e: with Image.open(path): pass - assert str(e.value) == "Too many colors for band: 1000" + assert str(e.value) == "Reached EOF while reading header" + + # Test EOF for PyDecoder + fp = BytesIO(b"P5 3 1 4") + with Image.open(fp) as im: + with pytest.raises(ValueError): + im.load() -def test_truncated_header(tmp_path): - path = str(tmp_path / "temp.pgm") +@pytest.mark.parametrize("maxval", (0, 65536)) +def test_invalid_maxval(maxval, tmp_path): + path = str(tmp_path / "temp.ppm") with open(path, "w") as f: - f.write("P6") + f.write("P6\n3 1 " + str(maxval)) with pytest.raises(ValueError) as e: with Image.open(path): pass - assert str(e.value) == "Reached EOF while reading header" + assert str(e.value) == "maxval must be greater than 0 and less than 65536" def test_neg_ppm(): diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index aeea3fb42bb..0c8c9f30485 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -101,6 +101,10 @@ def test_cross_scan_line(): with Image.open("Tests/images/cross_scan_line.tga") as im: assert_image_equal_tofile(im, "Tests/images/cross_scan_line.png") + with Image.open("Tests/images/cross_scan_line_truncated.tga") as im: + with pytest.raises(OSError): + im.load() + def test_save(tmp_path): test_file = "Tests/images/tga_id_field.tga" diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 28aeff075cb..8706cb950dd 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -70,6 +70,15 @@ def test_closed_file(self): im.load() im.close() + def test_seek_after_close(self): + im = Image.open("Tests/images/multipage.tiff") + im.close() + + with pytest.raises(ValueError): + im.n_frames + with pytest.raises(ValueError): + im.seek(1) + def test_context_manager(self): with warnings.catch_warnings(): with Image.open("Tests/images/multipage.tiff") as im: @@ -87,18 +96,38 @@ def test_mac_tiff(self): assert_image_similar_tofile(im, "Tests/images/pil136.png", 1) + def test_bigtiff(self): + with Image.open("Tests/images/hopper_bigtiff.tif") as im: + assert_image_equal_tofile(im, "Tests/images/hopper.tif") + @pytest.mark.parametrize( - "file_name,mode,size,offset", + "file_name,mode,size,tile", [ - ("tiff_wrong_bits_per_sample.tiff", "RGBA", (52, 53), 160), - ("tiff_wrong_bits_per_sample_2.tiff", "RGB", (16, 16), 8), + ( + "tiff_wrong_bits_per_sample.tiff", + "RGBA", + (52, 53), + [("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))], + ), + ( + "tiff_wrong_bits_per_sample_2.tiff", + "RGB", + (16, 16), + [("raw", (0, 0, 16, 16), 8, ("RGB", 0, 1))], + ), + ( + "tiff_wrong_bits_per_sample_3.tiff", + "RGBA", + (512, 256), + [("libtiff", (0, 0, 512, 256), 0, ("RGBA", "tiff_lzw", False, 48782))], + ), ], ) - def test_wrong_bits_per_sample(self, file_name, mode, size, offset): + def test_wrong_bits_per_sample(self, file_name, mode, size, tile): with Image.open("Tests/images/" + file_name) as im: assert im.mode == mode assert im.size == size - assert im.tile == [("raw", (0, 0) + size, offset, (mode, 0, 1))] + assert im.tile == tile im.load() def test_set_legacy_api(self): @@ -147,14 +176,14 @@ def test_int_resolution(self): assert im.info["dpi"] == (71.0, 71.0) @pytest.mark.parametrize( - "resolutionUnit, dpi", + "resolution_unit, dpi", [(None, 72.8), (2, 72.8), (3, 184.912)], ) - def test_load_float_dpi(self, resolutionUnit, dpi): + def test_load_float_dpi(self, resolution_unit, dpi): with Image.open( - "Tests/images/hopper_float_dpi_" + str(resolutionUnit) + ".tif" + "Tests/images/hopper_float_dpi_" + str(resolution_unit) + ".tif" ) as im: - assert im.tag_v2.get(RESOLUTION_UNIT) == resolutionUnit + assert im.tag_v2.get(RESOLUTION_UNIT) == resolution_unit assert im.info["dpi"] == (dpi, dpi) def test_save_float_dpi(self, tmp_path): @@ -221,6 +250,15 @@ def test_big_endian(self): assert b[0] == ord(b"\x01") assert b[1] == ord(b"\xe0") + def test_16bit_r(self): + with Image.open("Tests/images/16bit.r.tif") as im: + assert im.getpixel((0, 0)) == 480 + assert im.mode == "I;16" + + b = im.tobytes() + assert b[0] == ord(b"\xe0") + assert b[1] == ord(b"\x01") + def test_16bit_s(self): with Image.open("Tests/images/16bit.s.tif") as im: im.load() @@ -459,6 +497,26 @@ def check_exif(exif): exif = im.getexif() check_exif(exif) + def test_modify_exif(self, tmp_path): + outfile = str(tmp_path / "temp.tif") + with Image.open("Tests/images/ifd_tag_type.tiff") as im: + exif = im.getexif() + exif[256] = 100 + + im.save(outfile, exif=exif) + + with Image.open(outfile) as im: + exif = im.getexif() + assert exif[256] == 100 + + def test_reload_exif_after_seek(self): + with Image.open("Tests/images/multipage.tiff") as im: + exif = im.getexif() + del exif[256] + im.seek(1) + + assert 256 in exif + def test_exif_frames(self): # Test that EXIF data can change across frames with Image.open("Tests/images/g4-multi.tiff") as im: @@ -598,6 +656,17 @@ def test_tiled_planar_raw(self): with Image.open(infile) as im: assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + def test_planar_configuration_save(self, tmp_path): + infile = "Tests/images/tiff_tiled_planar_raw.tif" + with Image.open(infile) as im: + assert im._planar_configuration == 2 + + outfile = str(tmp_path / "temp.tif") + im.save(outfile) + + with Image.open(outfile) as reloaded: + assert_image_equal_tofile(reloaded, infile) + def test_palette(self, tmp_path): def roundtrip(mode): outfile = str(tmp_path / "temp.tif") @@ -631,11 +700,11 @@ def test_tiff_save_all(self): assert reread.n_frames == 3 # Test appending using a generator - def imGenerator(ims): + def im_generator(ims): yield from ims mp = BytesIO() - im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims)) + im.save(mp, format="TIFF", save_all=True, append_images=im_generator(ims)) mp.seek(0, os.SEEK_SET) with Image.open(mp) as reread: @@ -666,6 +735,13 @@ def test_save_icc_profile(self, tmp_path): with Image.open(outfile) as reloaded: assert reloaded.info["icc_profile"] == icc_profile + def test_save_bmp_compression(self, tmp_path): + with Image.open("Tests/images/hopper.bmp") as im: + assert im.info["compression"] == 0 + + outfile = str(tmp_path / "temp.tif") + im.save(outfile) + def test_discard_icc_profile(self, tmp_path): outfile = str(tmp_path / "temp.tif") diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 0562955169f..d7a0d93775d 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -28,26 +28,26 @@ def test_rt_metadata(tmp_path): # For text items, we still have to decode('ascii','replace') because # the tiff file format can't take 8 bit bytes in that field. - basetextdata = "This is some arbitrary metadata for a text field" - bindata = basetextdata.encode("ascii") + b" \xff" - textdata = basetextdata + " " + chr(255) - reloaded_textdata = basetextdata + " ?" - floatdata = 12.345 - doubledata = 67.89 + base_text_data = "This is some arbitrary metadata for a text field" + bin_data = base_text_data.encode("ascii") + b" \xff" + text_data = base_text_data + " " + chr(255) + reloaded_text_data = base_text_data + " ?" + float_data = 12.345 + double_data = 67.89 info = TiffImagePlugin.ImageFileDirectory() ImageJMetaData = TAG_IDS["ImageJMetaData"] ImageJMetaDataByteCounts = TAG_IDS["ImageJMetaDataByteCounts"] ImageDescription = TAG_IDS["ImageDescription"] - info[ImageJMetaDataByteCounts] = len(bindata) - info[ImageJMetaData] = bindata - info[TAG_IDS["RollAngle"]] = floatdata + info[ImageJMetaDataByteCounts] = len(bin_data) + info[ImageJMetaData] = bin_data + info[TAG_IDS["RollAngle"]] = float_data info.tagtype[TAG_IDS["RollAngle"]] = 11 - info[TAG_IDS["YawAngle"]] = doubledata + info[TAG_IDS["YawAngle"]] = double_data info.tagtype[TAG_IDS["YawAngle"]] = 12 - info[ImageDescription] = textdata + info[ImageDescription] = text_data f = str(tmp_path / "temp.tif") @@ -55,28 +55,28 @@ def test_rt_metadata(tmp_path): with Image.open(f) as loaded: - assert loaded.tag[ImageJMetaDataByteCounts] == (len(bindata),) - assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bindata),) + assert loaded.tag[ImageJMetaDataByteCounts] == (len(bin_data),) + assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bin_data),) - assert loaded.tag[ImageJMetaData] == bindata - assert loaded.tag_v2[ImageJMetaData] == bindata + assert loaded.tag[ImageJMetaData] == bin_data + assert loaded.tag_v2[ImageJMetaData] == bin_data - assert loaded.tag[ImageDescription] == (reloaded_textdata,) - assert loaded.tag_v2[ImageDescription] == reloaded_textdata + assert loaded.tag[ImageDescription] == (reloaded_text_data,) + assert loaded.tag_v2[ImageDescription] == reloaded_text_data loaded_float = loaded.tag[TAG_IDS["RollAngle"]][0] - assert round(abs(loaded_float - floatdata), 5) == 0 + assert round(abs(loaded_float - float_data), 5) == 0 loaded_double = loaded.tag[TAG_IDS["YawAngle"]][0] - assert round(abs(loaded_double - doubledata), 7) == 0 + assert round(abs(loaded_double - double_data), 7) == 0 # check with 2 element ImageJMetaDataByteCounts, issue #2006 - info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8) + info[ImageJMetaDataByteCounts] = (8, len(bin_data) - 8) img.save(f, tiffinfo=info) with Image.open(f) as loaded: - assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8) - assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8) + assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8) + assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8) def test_read_metadata(): @@ -356,7 +356,7 @@ def test_empty_values(): assert 33432 in info -def test_PhotoshopInfo(tmp_path): +def test_photoshop_info(tmp_path): with Image.open("Tests/images/issue_2278.tif") as im: assert len(im.tag_v2[34377]) == 70 assert isinstance(im.tag_v2[34377], bytes) diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 0511193782c..f1bdc59cf34 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -8,6 +8,7 @@ from PIL import Image, WebPImagePlugin, features from .helper import ( + assert_image_equal, assert_image_similar, assert_image_similar_tofile, hopper, @@ -105,6 +106,19 @@ def test_write_method(self, tmp_path): hopper().save(buffer_method, format="WEBP", method=6) assert buffer_no_args.getbuffer() != buffer_method.getbuffer() + @skip_unless_feature("webp_anim") + def test_save_all(self, tmp_path): + temp_file = str(tmp_path / "temp.webp") + im = Image.new("RGB", (1, 1)) + im2 = Image.new("RGB", (1, 1), "#f00") + im.save(temp_file, save_all=True, append_images=[im2]) + + with Image.open(temp_file) as reloaded: + assert_image_equal(im, reloaded) + + reloaded.seek(1) + assert_image_similar(im2, reloaded, 1) + def test_icc_profile(self, tmp_path): self._roundtrip(tmp_path, self.rgb_mode, 12.5, {"icc_profile": None}) if _webp.HAVE_WEBPANIM: @@ -171,9 +185,25 @@ def test_file_pointer_could_be_reused(self): Image.open(blob).load() Image.open(blob).load() - @skip_unless_feature("webp") + @pytest.mark.parametrize( + "background", + (0, (0,), (-1, 0, 1, 2), (253, 254, 255, 256)), + ) + @skip_unless_feature("webp_anim") + def test_invalid_background(self, background, tmp_path): + temp_file = str(tmp_path / "temp.webp") + im = hopper() + with pytest.raises(OSError): + im.save(temp_file, save_all=True, append_images=[im], background=background) + @skip_unless_feature("webp_anim") def test_background_from_gif(self, tmp_path): + # Save L mode GIF with background + with Image.open("Tests/images/no_palette_with_background.gif") as im: + out_webp = str(tmp_path / "temp.webp") + im.save(out_webp, save_all=True) + + # Save P mode GIF with background with Image.open("Tests/images/chi.gif") as im: original_value = im.convert("RGB").getpixel((1, 1)) @@ -191,7 +221,6 @@ def test_background_from_gif(self, tmp_path): difference = sum(abs(original_value[i] - reread_value[i]) for i in range(0, 3)) assert difference < 5 - @skip_unless_feature("webp") @skip_unless_feature("webp_anim") def test_duration(self, tmp_path): with Image.open("Tests/images/dispose_bgnd.gif") as im: diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index 25ebffe0248..c621df0d99c 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -1,6 +1,7 @@ import pytest +from packaging.version import parse as parse_version -from PIL import Image +from PIL import Image, features from .helper import ( assert_image_equal, @@ -27,7 +28,6 @@ def test_n_frames(): assert im.is_animated -@pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_write_animation_L(tmp_path): """ Convert an animated GIF to animated WebP, then compare the frame count, and first @@ -46,6 +46,11 @@ def test_write_animation_L(tmp_path): orig.load() im.load() assert_image_similar(im, orig.convert("RGBA"), 32.9) + + if is_big_endian(): + webp = parse_version(features.version_module("webp")) + if webp < parse_version("1.2.2"): + pytest.skip("Fails with libwebp earlier than 1.2.2") orig.seek(orig.n_frames - 1) im.seek(im.n_frames - 1) orig.load() @@ -53,7 +58,6 @@ def test_write_animation_L(tmp_path): assert_image_similar(im, orig.convert("RGBA"), 32.9) -@pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_write_animation_RGB(tmp_path): """ Write an animated WebP from RGB frames, and ensure the frames @@ -69,6 +73,10 @@ def check(temp_file): assert_image_equal(im, frame1.convert("RGBA")) # Compare second frame to original + if is_big_endian(): + webp = parse_version(features.version_module("webp")) + if webp < parse_version("1.2.2"): + pytest.skip("Fails with libwebp earlier than 1.2.2") im.seek(1) im.load() assert_image_equal(im, frame2.convert("RGBA")) @@ -82,14 +90,14 @@ def check(temp_file): check(temp_file1) # Tests appending using a generator - def imGenerator(ims): + def im_generator(ims): yield from ims temp_file2 = str(tmp_path / "temp_generator.webp") frame1.copy().save( temp_file2, save_all=True, - append_images=imGenerator([frame2]), + append_images=im_generator([frame2]), lossless=True, ) check(temp_file2) diff --git a/Tests/test_image.py b/Tests/test_image.py index 2cd858df16f..6dc89918f05 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -7,7 +7,7 @@ import pytest -from PIL import Image, ImageDraw, ImagePalette, UnidentifiedImageError +from PIL import Image, ImageDraw, ImagePalette, UnidentifiedImageError, features from .helper import ( assert_image_equal, @@ -161,6 +161,8 @@ def test_pathlib(self, tmp_path): assert im.size == (128, 128) for ext in (".jpg", ".jp2"): + if ext == ".jp2" and not features.check_codec("jpg_2000"): + pytest.skip("jpg_2000 not available") temp_file = str(tmp_path / ("temp." + ext)) if os.path.exists(temp_file): os.remove(temp_file) @@ -170,7 +172,7 @@ def test_fp_name(self, tmp_path): temp_file = str(tmp_path / "temp.jpg") class FP: - def write(a, b): + def write(self, b): pass fp = FP() @@ -602,11 +604,34 @@ def test_remap_palette(self): with Image.open("Tests/images/hopper.gif") as im: assert_image_equal(im, im.remap_palette(list(range(256)))) + # Test identity transform with an RGBA palette + im = Image.new("P", (256, 1)) + for x in range(256): + im.putpixel((x, 0), x) + im.putpalette(list(range(256)) * 4, "RGBA") + im_remapped = im.remap_palette(list(range(256))) + assert_image_equal(im, im_remapped) + assert im.palette.palette == im_remapped.palette.palette + # Test illegal image mode with hopper() as im: with pytest.raises(ValueError): im.remap_palette(None) + def test_remap_palette_transparency(self): + im = Image.new("P", (1, 2)) + im.putpixel((0, 1), 1) + im.info["transparency"] = 0 + + im_remapped = im.remap_palette([1, 0]) + assert im_remapped.info["transparency"] == 1 + + # Test unused transparency + im.info["transparency"] = 2 + + im_remapped = im.remap_palette([1, 0]) + assert "transparency" not in im_remapped.info + def test__new(self): im = hopper("RGB") im_p = hopper("P") @@ -652,6 +677,15 @@ def test_no_resource_warning_on_save(self, tmp_path): with warnings.catch_warnings(): im.save(temp_file) + def test_no_new_file_on_error(self, tmp_path): + temp_file = str(tmp_path / "temp.jpg") + + im = Image.new("RGB", (0, 0)) + with pytest.raises(ValueError): + im.save(temp_file) + + assert not os.path.exists(temp_file) + def test_load_on_nonexclusive_multiframe(self): with open("Tests/images/frozenpond.mpo", "rb") as fp: @@ -666,6 +700,19 @@ def act(fp): assert not fp.closed + def test_empty_exif(self): + with Image.open("Tests/images/exif.png") as im: + exif = im.getexif() + assert dict(exif) != {} + + # Test that exif data is cleared after another load + exif.load(None) + assert dict(exif) == {} + + # Test loading just the EXIF header + exif.load(b"Exif\x00\x00") + assert dict(exif) == {} + @mark_if_feature_version( pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" ) @@ -802,6 +849,35 @@ def test_zero_tobytes(self, size): im = Image.new("RGB", size) assert im.tobytes() == b"" + def test_apply_transparency(self): + im = Image.new("P", (1, 1)) + im.putpalette((0, 0, 0, 1, 1, 1)) + assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1} + + # Test that no transformation is applied without transparency + im.apply_transparency() + assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1} + + # Test that a transparency index is applied + im.info["transparency"] = 0 + im.apply_transparency() + assert "transparency" not in im.info + assert im.palette.colors == {(0, 0, 0, 0): 0, (1, 1, 1, 255): 1} + + # Test that existing transparency is kept + im = Image.new("P", (1, 1)) + im.putpalette((0, 0, 0, 255, 1, 1, 1, 128), "RGBA") + im.info["transparency"] = 0 + im.apply_transparency() + assert im.palette.colors == {(0, 0, 0, 0): 0, (1, 1, 1, 128): 1} + + # Test that transparency bytes are applied + with Image.open("Tests/images/pil123p.png") as im: + assert isinstance(im.info["transparency"], bytes) + assert im.palette.colors[(27, 35, 6)] == 24 + im.apply_transparency() + assert im.palette.colors[(27, 35, 6, 214)] == 24 + def test_categories_deprecation(self): with pytest.warns(DeprecationWarning): assert hopper().category == 0 diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 97321143d7e..617274a576d 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -1,4 +1,3 @@ -import ctypes import os import subprocess import sys @@ -154,14 +153,17 @@ def check(self, mode, c=None): # Check 0 im = Image.new(mode, (0, 0), None) - with pytest.raises(IndexError): + assert im.load() is not None + + error = ValueError if self._need_cffi_access else IndexError + with pytest.raises(error): im.putpixel((0, 0), c) - with pytest.raises(IndexError): + with pytest.raises(error): im.getpixel((0, 0)) # Check 0 negative index - with pytest.raises(IndexError): + with pytest.raises(error): im.putpixel((-1, -1), c) - with pytest.raises(IndexError): + with pytest.raises(error): im.getpixel((-1, -1)) # check initial color @@ -176,10 +178,10 @@ def check(self, mode, c=None): # Check 0 im = Image.new(mode, (0, 0), c) - with pytest.raises(IndexError): + with pytest.raises(error): im.getpixel((0, 0)) # Check 0 negative index - with pytest.raises(IndexError): + with pytest.raises(error): im.getpixel((-1, -1)) def test_basic(self): @@ -401,6 +403,8 @@ class TestEmbeddable: "not from shell", ) def test_embeddable(self): + import ctypes + with open("embed_pil.c", "w") as fh: fh.write( """ diff --git a/Tests/test_image_array.py b/Tests/test_image_array.py index 5c9cdd7e0e0..7168c4265bb 100644 --- a/Tests/test_image_array.py +++ b/Tests/test_image_array.py @@ -80,3 +80,15 @@ def test(mode): with pytest.raises(TypeError): wrapped = Wrapper(test("L"), {"shape": (100, 128)}) Image.fromarray(wrapped) + + +def test_fromarray_palette(): + # Arrange + i = im.convert("L") + a = numpy.array(i) + + # Act + out = Image.fromarray(a, "P") + + # Assert that the Python and C palettes match + assert len(out.palette.colors) == len(out.im.getpalette()) / 3 diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 1d646981976..e5639e10533 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -27,15 +27,15 @@ def convert(im, mode): "HSV", ) - for mode in modes: - im = hopper(mode) - for mode in modes: - convert(im, mode) + for input_mode in modes: + im = hopper(input_mode) + for output_mode in modes: + convert(im, output_mode) # Check 0 - im = Image.new(mode, (0, 0)) - for mode in modes: - convert(im, mode) + im = Image.new(input_mode, (0, 0)) + for output_mode in modes: + convert(im, output_mode) def test_default(): @@ -70,6 +70,11 @@ def test_16bit(): with Image.open("Tests/images/16bit.cropped.tif") as im: _test_float_conversion(im) + for color in (65535, 65536): + im = Image.new("I", (1, 1), color) + im_i16 = im.convert("I;16") + assert im_i16.getpixel((0, 0)) == 65535 + def test_16bit_workaround(): with Image.open("Tests/images/16bit.cropped.tif") as im: @@ -135,6 +140,10 @@ def test_trns_l(tmp_path): f = str(tmp_path / "temp.png") + im_la = im.convert("LA") + assert "transparency" not in im_la.info + im_la.save(f) + im_rgb = im.convert("RGB") assert im_rgb.info["transparency"] == (128, 128, 128) # undone im_rgb.save(f) @@ -213,6 +222,20 @@ def test_p_la(): assert_image_similar(alpha, comparable, 5) +def test_p2pa_alpha(): + with Image.open("Tests/images/tiny.png") as im: + assert im.mode == "P" + + im_pa = im.convert("PA") + assert im_pa.mode == "PA" + + im_a = im_pa.getchannel("A") + for x in range(4): + alpha = 255 if x > 1 else 0 + for y in range(4): + assert im_a.getpixel((x, y)) == alpha + + def test_matrix_illegal_conversion(): # Arrange im = hopper("CMYK") diff --git a/Tests/test_image_copy.py b/Tests/test_image_copy.py index ad0391dbe5e..21e438654b1 100644 --- a/Tests/test_image_copy.py +++ b/Tests/test_image_copy.py @@ -6,8 +6,8 @@ def test_copy(): - croppedCoordinates = (10, 10, 20, 20) - croppedSize = (10, 10) + cropped_coordinates = (10, 10, 20, 20) + cropped_size = (10, 10) for mode in "1", "P", "L", "RGB", "I", "F": # Internal copy method im = hopper(mode) @@ -23,15 +23,15 @@ def test_copy(): # Internal copy method on a cropped image im = hopper(mode) - out = im.crop(croppedCoordinates).copy() + out = im.crop(cropped_coordinates).copy() assert out.mode == im.mode - assert out.size == croppedSize + assert out.size == cropped_size # Python's copy method on a cropped image im = hopper(mode) - out = copy.copy(im.crop(croppedCoordinates)) + out = copy.copy(im.crop(cropped_coordinates)) assert out.mode == im.mode - assert out.size == croppedSize + assert out.size == cropped_size def test_copy_zero(): diff --git a/Tests/test_image_filter.py b/Tests/test_image_filter.py index df8c353f391..14a8da9f102 100644 --- a/Tests/test_image_filter.py +++ b/Tests/test_image_filter.py @@ -99,10 +99,10 @@ def test_rankfilter_properties(): def test_builtinfilter_p(): - builtinFilter = ImageFilter.BuiltinFilter() + builtin_filter = ImageFilter.BuiltinFilter() with pytest.raises(ValueError): - builtinFilter.filter(hopper("P")) + builtin_filter.filter(hopper("P")) def test_kernel_not_enough_coefficients(): diff --git a/Tests/test_image_fromqimage.py b/Tests/test_image_fromqimage.py index 5ad5b5c3c0a..7fe992353bc 100644 --- a/Tests/test_image_fromqimage.py +++ b/Tests/test_image_fromqimage.py @@ -1,6 +1,12 @@ +import warnings + import pytest -from PIL import Image, ImageQt +from PIL import Image + +with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt from .helper import assert_image_equal, hopper diff --git a/Tests/test_image_paste.py b/Tests/test_image_paste.py index dc3caef017b..4ea1d73ce16 100644 --- a/Tests/test_image_paste.py +++ b/Tests/test_image_paste.py @@ -1,6 +1,6 @@ from PIL import Image -from .helper import assert_image_equal, cached_property +from .helper import CachedProperty, assert_image_equal class TestImagingPaste: @@ -34,7 +34,7 @@ def assert_9points_paste(self, im, im2, mask, expected): im.paste(im2, mask) self.assert_9points_image(im, expected) - @cached_property + @CachedProperty def mask_1(self): mask = Image.new("1", (self.size, self.size)) px = mask.load() @@ -43,11 +43,11 @@ def mask_1(self): px[y, x] = (x + y) % 2 return mask - @cached_property + @CachedProperty def mask_L(self): return self.gradient_L.transpose(Image.Transpose.ROTATE_270) - @cached_property + @CachedProperty def gradient_L(self): gradient = Image.new("L", (self.size, self.size)) px = gradient.load() @@ -56,7 +56,7 @@ def gradient_L(self): px[y, x] = (x + y) % 255 return gradient - @cached_property + @CachedProperty def gradient_RGB(self): return Image.merge( "RGB", @@ -67,7 +67,17 @@ def gradient_RGB(self): ], ) - @cached_property + @CachedProperty + def gradient_LA(self): + return Image.merge( + "LA", + [ + self.gradient_L, + self.gradient_L.transpose(Image.Transpose.ROTATE_90), + ], + ) + + @CachedProperty def gradient_RGBA(self): return Image.merge( "RGBA", @@ -79,7 +89,7 @@ def gradient_RGBA(self): ], ) - @cached_property + @CachedProperty def gradient_RGBa(self): return Image.merge( "RGBa", @@ -145,6 +155,28 @@ def test_image_mask_L(self): ], ) + def test_image_mask_LA(self): + for mode in ("RGBA", "RGB", "L"): + im = Image.new(mode, (200, 200), "white") + im2 = getattr(self, "gradient_" + mode) + + self.assert_9points_paste( + im, + im2, + self.gradient_LA, + [ + (128, 191, 255, 191), + (112, 207, 206, 111), + (128, 254, 128, 1), + (208, 208, 239, 239), + (192, 191, 191, 191), + (207, 207, 112, 113), + (255, 255, 255, 255), + (239, 207, 207, 239), + (255, 191, 128, 191), + ], + ) + def test_image_mask_RGBA(self): for mode in ("RGBA", "RGB", "L"): im = Image.new(mode, (200, 200), "white") diff --git a/Tests/test_image_point.py b/Tests/test_image_point.py index 366f458544f..157ecb120f0 100644 --- a/Tests/test_image_point.py +++ b/Tests/test_image_point.py @@ -1,5 +1,7 @@ import pytest +from PIL import Image + from .helper import assert_image_equal, hopper @@ -10,17 +12,31 @@ def test_sanity(): im.point(list(range(256))) im.point(list(range(256)) * 3) im.point(lambda x: x) + im.point(lambda x: x * 1.2) im = im.convert("I") with pytest.raises(ValueError): im.point(list(range(256))) im.point(lambda x: x * 1) im.point(lambda x: x + 1) + im.point(lambda x: x - 1) im.point(lambda x: x * 1 + 1) + im.point(lambda x: 0.1 + 0.2 * x) + im.point(lambda x: -x) + im.point(lambda x: x - 0.5) + im.point(lambda x: 1 - x / 2) + im.point(lambda x: (2 + x) / 3) + im.point(lambda x: 0.5) + im.point(lambda x: x / 1) + im.point(lambda x: x + x) + with pytest.raises(TypeError): + im.point(lambda x: x * x) + with pytest.raises(TypeError): + im.point(lambda x: x / x) with pytest.raises(TypeError): - im.point(lambda x: x - 1) + im.point(lambda x: 1 / x) with pytest.raises(TypeError): - im.point(lambda x: x / 1) + im.point(lambda x: x // 2) def test_16bit_lut(): @@ -46,3 +62,8 @@ def test_f_mode(): im = hopper("F") with pytest.raises(ValueError): im.point(None) + + +def test_coerce_e_deprecation(): + with pytest.warns(DeprecationWarning): + assert Image.coerce_e(2).data == 2 diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 12542233773..6d050efccba 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -458,7 +458,7 @@ def resize_tiled(self, im, dst_size, xtiles, ytiles): def split_range(size, tiles): scale = size / tiles for i in range(tiles): - yield (int(round(scale * i)), int(round(scale * (i + 1)))) + yield int(round(scale * i)), int(round(scale * (i + 1))) tiled = Image.new(im.mode, dst_size) scale = (im.size[0] / tiled.size[0], im.size[1] / tiled.size[1]) diff --git a/Tests/test_image_resize.py b/Tests/test_image_resize.py index 04b7c8c97db..8347fabb9e5 100644 --- a/Tests/test_image_resize.py +++ b/Tests/test_image_resize.py @@ -12,6 +12,7 @@ assert_image_equal_tofile, assert_image_similar, hopper, + skip_unless_feature, ) @@ -264,6 +265,14 @@ def resize(mode, size): with pytest.raises(ValueError): im.resize((10, 10), "unknown") + @skip_unless_feature("libtiff") + def test_load_first(self): + # load() may change the size of the image + # Test that resize() is calling it before getting the size + with Image.open("Tests/images/g4_orientation_5.tif") as im: + im = im.resize((64, 64)) + assert im.size == (64, 64) + def test_default_filter(self): for mode in "L", "RGB", "I", "F": im = hopper(mode) diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index 6d4eb4cd132..20cc101ed4e 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -7,6 +7,7 @@ assert_image_similar, fromstring, hopper, + skip_unless_feature, tostring, ) @@ -88,6 +89,15 @@ def test_no_resize(): assert im.size == (64, 64) +@skip_unless_feature("libtiff") +def test_load_first(): + # load() may change the size of the image + # Test that thumbnail() is calling it before performing size calculations + with Image.open("Tests/images/g4_orientation_5.tif") as im: + im.thumbnail((64, 64)) + assert im.size == (64, 10) + + # valgrind test is failing with memory allocated in libjpeg @pytest.mark.valgrind_known_error(reason="Known Failing") def test_DCT_scaling_edges(): @@ -130,4 +140,4 @@ def test_reducing_gap_for_DCT_scaling(): with Image.open("Tests/images/hopper.jpg") as im: im.thumbnail((18, 18), Image.Resampling.BICUBIC, reducing_gap=3.0) - assert_image_equal(ref, im) + assert_image_similar(ref, im, 1.4) diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 3cd755cb4d3..69d1ac9fad3 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -655,6 +655,20 @@ def test_polygon_1px_high(): assert_image_equal_tofile(im, expected) +def test_polygon_1px_high_translucent(): + # Test drawing a translucent 1px high polygon + # Arrange + im = Image.new("RGB", (4, 3)) + draw = ImageDraw.Draw(im, "RGBA") + expected = "Tests/images/imagedraw_polygon_1px_high_translucent.png" + + # Act + draw.polygon([(1, 1), (1, 1), (3, 1), (3, 1)], (255, 0, 0, 127)) + + # Assert + assert_image_equal_tofile(im, expected) + + def test_polygon_translucent(): # Arrange im = Image.new("RGB", (W, H)) @@ -1440,3 +1454,23 @@ def test_continuous_horizontal_edges_polygon(): assert_image_equal_tofile( img, expected, "continuous horizontal edges polygon failed" ) + + +def test_discontiguous_corners_polygon(): + img, draw = create_base_image_draw((84, 68)) + draw.polygon(((1, 21), (34, 4), (71, 1), (38, 18)), BLACK) + draw.polygon(((71, 44), (38, 27), (1, 24)), BLACK) + draw.polygon( + ((38, 66), (5, 49), (77, 49), (47, 66), (82, 63), (82, 47), (1, 47), (1, 63)), + BLACK, + ) + expected = os.path.join(IMAGES_PATH, "discontiguous_corners_polygon.png") + assert_image_similar_tofile(img, expected, 1) + + +def test_polygon(): + im = Image.new("RGB", (W, H)) + draw = ImageDraw.Draw(im) + draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red") + expected = "Tests/images/imagedraw_outline_polygon_RGB.png" + assert_image_similar_tofile(im, expected, 1) diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index f3da73e3810..fc0fbfb9bbc 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -2,7 +2,15 @@ import pytest -from PIL import BmpImagePlugin, EpsImagePlugin, Image, ImageFile, _binary, features +from PIL import ( + BmpImagePlugin, + EpsImagePlugin, + Image, + ImageFile, + UnidentifiedImageError, + _binary, + features, +) from .helper import ( assert_image, @@ -35,9 +43,9 @@ def roundtrip(format): parser = ImageFile.Parser() parser.feed(data) - imOut = parser.close() + im_out = parser.close() - return im, imOut + return im, im_out assert_image_equal(*roundtrip("BMP")) im1, im2 = roundtrip("GIF") @@ -200,6 +208,9 @@ class MockPyEncoder(ImageFile.PyEncoder): def encode(self, buffer): return 1, 1, b"" + def cleanup(self): + self.cleanup_called = True + xoff, yoff, xsize, ysize = 10, 20, 100, 100 @@ -327,10 +338,12 @@ def test_negsize(self): im = MockImageFile(buf) fp = BytesIO() + self.encoder.cleanup_called = False with pytest.raises(ValueError): ImageFile._save( im, fp, [("MOCK", (xoff, yoff, -10, yoff + ysize), 0, "RGB")] ) + assert self.encoder.cleanup_called with pytest.raises(ValueError): ImageFile._save( @@ -372,3 +385,7 @@ def test_encode(self): with pytest.raises(NotImplementedError): encoder.encode_to_file(None, None) + + def test_zero_height(self): + with pytest.raises(UnidentifiedImageError): + Image.open("Tests/images/zero_height.j2k") diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index f9d0a4c4f0d..0c50303f902 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -65,9 +65,12 @@ def _font_as_bytes(self): return font_bytes def test_font_with_filelike(self): - ImageFont.truetype( + ttf = ImageFont.truetype( self._font_as_bytes(), FONT_SIZE, layout_engine=self.LAYOUT_ENGINE ) + ttf_copy = ttf.font_variant() + assert ttf_copy.font_bytes == ttf.font_bytes + self._render(self._font_as_bytes()) # Usage note: making two fonts from the same buffer fails. # shared_bytes = self._font_as_bytes() @@ -977,6 +980,14 @@ def test_colr_mask(self): assert_image_similar_tofile(im, "Tests/images/colr_bungee_mask.png", 22) + def test_fill_deprecation(self): + font = self.get_font() + with pytest.warns(DeprecationWarning): + font.getmask2("Hello world", fill=Image.core.fill) + with pytest.warns(DeprecationWarning): + with pytest.raises(TypeError): + font.getmask2("Hello world", fill=None) + @skip_unless_feature("raqm") class TestImageFont_RaqmLayout(TestImageFont): diff --git a/Tests/test_imagemorph.py b/Tests/test_imagemorph.py index 368c2bba140..6de95306836 100644 --- a/Tests/test_imagemorph.py +++ b/Tests/test_imagemorph.py @@ -48,12 +48,8 @@ def img_string_normalize(im): return img_to_string(string_to_img(im)) -def assert_img_equal(A, B): - assert img_to_string(A) == img_to_string(B) - - -def assert_img_equal_img_string(A, Bstring): - assert img_to_string(A) == img_string_normalize(Bstring) +def assert_img_equal_img_string(a, b_string): + assert img_to_string(a) == img_string_normalize(b_string) def test_str_to_img(): diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 6aa1cf35edf..87fffa7b724 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -63,6 +63,7 @@ def test_sanity(): ImageOps.grayscale(hopper("L")) ImageOps.grayscale(hopper("RGB")) + ImageOps.invert(hopper("1")) ImageOps.invert(hopper("L")) ImageOps.invert(hopper("RGB")) diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index e38a2068a4a..de3920cf5eb 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -174,7 +174,7 @@ def test_overflow_segfault(): # through to the sequence. Seeing this on 32-bit Windows. with pytest.raises((TypeError, MemoryError)): # post patch, this fails with a memory error - x = evil() + x = Evil() # This fails due to the invalid malloc above, # and segfaults @@ -182,7 +182,7 @@ def test_overflow_segfault(): x[i] = b"0" * 16 -class evil: +class Evil: def __init__(self): self.corrupt = Image.core.path(0x4000000000000000) diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index a42240d49bf..2f2b0791853 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -2,10 +2,13 @@ import pytest -from PIL import ImageQt - from .helper import assert_image_similar, hopper +with warnings.catch_warnings() as w: + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt + + pytestmark = pytest.mark.skipif( not ImageQt.qt_is_installed, reason="Qt bindings are not installed" ) diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py index 7cf237b4654..6af7e760204 100644 --- a/Tests/test_imagesequence.py +++ b/Tests/test_imagesequence.py @@ -65,21 +65,21 @@ def test_libtiff(): def test_consecutive(): with Image.open("Tests/images/multipage.tiff") as im: - firstFrame = None + first_frame = None for frame in ImageSequence.Iterator(im): - if firstFrame is None: - firstFrame = frame.copy() + if first_frame is None: + first_frame = frame.copy() for frame in ImageSequence.Iterator(im): - assert_image_equal(frame, firstFrame) + assert_image_equal(frame, first_frame) break def test_palette_mmap(): # Using mmap in ImageFile can require to reload the palette. with Image.open("Tests/images/multipage-mmap.tiff") as im: - color1 = im.getpalette()[0:3] + color1 = im.getpalette()[:3] im.seek(0) - color2 = im.getpalette()[0:3] + color2 = im.getpalette()[:3] assert color1 == color2 diff --git a/Tests/test_imagetk.py b/Tests/test_imagetk.py index 928b8cbd188..a929910b3cc 100644 --- a/Tests/test_imagetk.py +++ b/Tests/test_imagetk.py @@ -26,6 +26,8 @@ def setup_module(): # setup tk tk.Frame() # root = tk.Tk() + except RuntimeError as v: + pytest.skip(f"RuntimeError: {v}") except tk.TclError as v: pytest.skip(f"TCL Error: {v}") @@ -75,8 +77,16 @@ def test_photoimage_blank(): assert im_tk.width() == 100 assert im_tk.height() == 100 - # reloaded = ImageTk.getimage(im_tk) - # assert_image_equal(reloaded, im) + im = Image.new(mode, (100, 100)) + reloaded = ImageTk.getimage(im_tk) + assert_image_equal(reloaded.convert(mode), im) + + +def test_box_deprecation(): + im = hopper() + im_tk = ImageTk.PhotoImage(im) + with pytest.warns(DeprecationWarning): + im_tk.paste(im, (0, 0, 128, 128)) def test_bitmapimage(): diff --git a/Tests/test_imagewin_pointers.py b/Tests/test_imagewin_pointers.py index c51a66089c8..df130565575 100644 --- a/Tests/test_imagewin_pointers.py +++ b/Tests/test_imagewin_pointers.py @@ -1,4 +1,3 @@ -import ctypes from io import BytesIO from PIL import Image, ImageWin @@ -8,6 +7,7 @@ # see https://github.com/python-pillow/Pillow/pull/1431#issuecomment-144692652 if is_win32(): + import ctypes import ctypes.wintypes class BITMAPFILEHEADER(ctypes.Structure): diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index af7eae935f6..979806cae99 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -444,6 +444,8 @@ def test_RGBA(self): self.assert_unpack("RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0)) self.assert_unpack("RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) self.assert_unpack("RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) + self.assert_unpack("RGBA", "BGRA;16L", 8, (6, 4, 2, 8), (14, 12, 10, 16)) + self.assert_unpack("RGBA", "BGRA;16B", 8, (5, 3, 1, 7), (13, 11, 9, 15)) self.assert_unpack( "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12) ) diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py index 688af7113cc..6e8a2ac589f 100644 --- a/Tests/test_mode_i16.py +++ b/Tests/test_mode_i16.py @@ -26,51 +26,51 @@ def test_basic(tmp_path): def basic(mode): - imIn = original.convert(mode) - verify(imIn) + im_in = original.convert(mode) + verify(im_in) - w, h = imIn.size + w, h = im_in.size - imOut = imIn.copy() - verify(imOut) # copy + im_out = im_in.copy() + verify(im_out) # copy - imOut = imIn.transform((w, h), Image.Transform.EXTENT, (0, 0, w, h)) - verify(imOut) # transform + im_out = im_in.transform((w, h), Image.Transform.EXTENT, (0, 0, w, h)) + verify(im_out) # transform filename = str(tmp_path / "temp.im") - imIn.save(filename) + im_in.save(filename) - with Image.open(filename) as imOut: + with Image.open(filename) as im_out: - verify(imIn) - verify(imOut) + verify(im_in) + verify(im_out) - imOut = imIn.crop((0, 0, w, h)) - verify(imOut) + im_out = im_in.crop((0, 0, w, h)) + verify(im_out) - imOut = Image.new(mode, (w, h), None) - imOut.paste(imIn.crop((0, 0, w // 2, h)), (0, 0)) - imOut.paste(imIn.crop((w // 2, 0, w, h)), (w // 2, 0)) + im_out = Image.new(mode, (w, h), None) + im_out.paste(im_in.crop((0, 0, w // 2, h)), (0, 0)) + im_out.paste(im_in.crop((w // 2, 0, w, h)), (w // 2, 0)) - verify(imIn) - verify(imOut) + verify(im_in) + verify(im_out) - imIn = Image.new(mode, (1, 1), 1) - assert imIn.getpixel((0, 0)) == 1 + im_in = Image.new(mode, (1, 1), 1) + assert im_in.getpixel((0, 0)) == 1 - imIn.putpixel((0, 0), 2) - assert imIn.getpixel((0, 0)) == 2 + im_in.putpixel((0, 0), 2) + assert im_in.getpixel((0, 0)) == 2 if mode == "L": maximum = 255 else: maximum = 32767 - imIn = Image.new(mode, (1, 1), 256) - assert imIn.getpixel((0, 0)) == min(256, maximum) + im_in = Image.new(mode, (1, 1), 256) + assert im_in.getpixel((0, 0)) == min(256, maximum) - imIn.putpixel((0, 0), 512) - assert imIn.getpixel((0, 0)) == min(512, maximum) + im_in.putpixel((0, 0), 512) + assert im_in.getpixel((0, 0)) == min(512, maximum) basic("L") diff --git a/Tests/test_qt_image_qapplication.py b/Tests/test_qt_image_qapplication.py index dec790c5069..1fc8161467b 100644 --- a/Tests/test_qt_image_qapplication.py +++ b/Tests/test_qt_image_qapplication.py @@ -1,6 +1,10 @@ +import warnings + import pytest -from PIL import ImageQt +with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt from .helper import assert_image_equal, assert_image_equal_tofile, hopper diff --git a/Tests/test_qt_image_toqimage.py b/Tests/test_qt_image_toqimage.py index 2a6b29abebc..60bfaeb9b75 100644 --- a/Tests/test_qt_image_toqimage.py +++ b/Tests/test_qt_image_toqimage.py @@ -1,6 +1,10 @@ +import warnings + import pytest -from PIL import ImageQt +with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=DeprecationWarning) + from PIL import ImageQt from .helper import assert_image_equal, assert_image_equal_tofile, hopper diff --git a/Tests/test_util.py b/Tests/test_util.py index b5bfca0126f..9efbdd1f380 100644 --- a/Tests/test_util.py +++ b/Tests/test_util.py @@ -8,7 +8,7 @@ def test_is_path(): fp = "filename.ext" # Act - it_is = _util.isPath(fp) + it_is = _util.is_path(fp) # Assert assert it_is @@ -21,7 +21,7 @@ def test_path_obj_is_path(): test_path = Path("filename.ext") # Act - it_is = _util.isPath(test_path) + it_is = _util.is_path(test_path) # Assert assert it_is @@ -33,7 +33,7 @@ def test_is_not_path(tmp_path): pass # Act - it_is_not = _util.isPath(fp) + it_is_not = _util.is_path(fp) # Assert assert not it_is_not @@ -44,7 +44,7 @@ def test_is_directory(): directory = "Tests" # Act - it_is = _util.isDirectory(directory) + it_is = _util.is_directory(directory) # Assert assert it_is @@ -55,7 +55,7 @@ def test_is_not_directory(): text = "abc" # Act - it_is_not = _util.isDirectory(text) + it_is_not = _util.is_directory(text) # Assert assert not it_is_not @@ -65,7 +65,7 @@ def test_deferred_error(): # Arrange # Act - thing = _util.deferred_error(ValueError("Some error text")) + thing = _util.DeferredError(ValueError("Some error text")) # Assert with pytest.raises(ValueError): diff --git a/depends/install_openjpeg.sh b/depends/install_openjpeg.sh index 914e71e5396..4f4b81a628b 100755 --- a/depends/install_openjpeg.sh +++ b/depends/install_openjpeg.sh @@ -1,7 +1,7 @@ #!/bin/bash # install openjpeg -archive=openjpeg-2.4.0 +archive=openjpeg-2.5.0 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz diff --git a/docs/conf.py b/docs/conf.py index 7bbe8c4c96f..bc67d936893 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,8 +16,6 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) -import sphinx_rtd_theme - import PIL # -- General configuration ------------------------------------------------ @@ -70,7 +68,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = "en" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -126,13 +124,15 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "sphinx_rtd_theme" -html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +html_theme = "furo" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. -# html_theme_options = {} +html_theme_options = { + "light_logo": "pillow-logo-dark-text.png", + "dark_logo": "pillow-logo.png", +} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] @@ -146,7 +146,7 @@ # The name of an image file (relative to this directory) to place at the top # of the sidebar. -html_logo = "resources/pillow-logo.png" +# html_logo = "resources/pillow-logo.png" # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 @@ -311,10 +311,7 @@ def setup(app): - app.add_js_file("js/script.js") - app.add_css_file("css/styles.css") app.add_css_file("css/dark.css") - app.add_css_file("css/light.css") # GitHub repo for sphinx-issues diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 0b82e41851c..8c5b8a748d7 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -69,7 +69,7 @@ In effect, ``viewer.show_file("test.jpg")`` will continue to work unchanged. Constants ~~~~~~~~~ -.. deprecated:: 9.2.0 +.. deprecated:: 9.1.0 A number of constants have been deprecated and will be removed in Pillow 10.0.0 (2023-07-01). Instead, ``enum.IntEnum`` classes have been added. @@ -97,8 +97,8 @@ Deprecated Use instead ``Image.TRANSPOSE`` ``Image.Transpose.TRANSPOSE`` ``Image.TRANSVERSE`` ``Image.Transpose.TRANSVERSE`` ``Image.BOX`` ``Image.Resampling.BOX`` -``Image.BILINEAR`` ``Image.Resampling.BILNEAR`` -``Image.LINEAR`` ``Image.Resampling.BILNEAR`` +``Image.BILINEAR`` ``Image.Resampling.BILINEAR`` +``Image.LINEAR`` ``Image.Resampling.BILINEAR`` ``Image.HAMMING`` ``Image.Resampling.HAMMING`` ``Image.BICUBIC`` ``Image.Resampling.BICUBIC`` ``Image.CUBIC`` ``Image.Resampling.BICUBIC`` @@ -142,6 +142,42 @@ The stub image plugin ``FitsStubImagePlugin`` has been deprecated and will be re Pillow 10.0.0 (2023-07-01). FITS images can be read without a handler through :mod:`~PIL.FitsImagePlugin` instead. +FreeTypeFont.getmask2 fill parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` has been +deprecated and will be removed in Pillow 10 (2023-07-01). + +PhotoImage.paste box parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +The ``box`` parameter is unused. It will be removed in Pillow 10.0.0 (2023-07-01). + +PyQt5 and PySide2 +~~~~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +`Qt 5 reached end-of-life `_ on 2020-12-08 for +open-source users (and will reach EOL on 2023-12-08 for commercial licence holders). + +Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed +in Pillow 10 (2023-07-01). Upgrade to +`PyQt6 `_ or +`PySide6 `_ instead. + +Image.coerce_e +~~~~~~~~~~~~~~ + +.. deprecated:: 9.2.0 + +This undocumented method has been deprecated and will be removed in Pillow 10 +(2023-07-01). + Removed features ---------------- diff --git a/docs/example/DdsImagePlugin.py b/docs/example/DdsImagePlugin.py index 29fefba1643..ec3938b367f 100644 --- a/docs/example/DdsImagePlugin.py +++ b/docs/example/DdsImagePlugin.py @@ -253,7 +253,7 @@ def decode(self, buffer): self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize)) except struct.error as e: raise OSError("Truncated DDS file") from e - return 0, 0 + return -1, 0 class DXT5Decoder(ImageFile.PyDecoder): @@ -264,7 +264,7 @@ def decode(self, buffer): self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize)) except struct.error as e: raise OSError("Truncated DDS file") from e - return 0, 0 + return -1, 0 Image.register_decoder("DXT1", DXT1Decoder) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 17808dbc463..1826d965f7a 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -17,15 +17,13 @@ When an image is opened from a file, only that instance of the image is consider have the format. Copies of the image will contain data loaded from the file, but not the file itself, meaning that it can no longer be considered to be in the original format. So if :py:meth:`~PIL.Image.Image.copy` is called on an image, or another method -internally creates a copy of the image, the ``fp`` (file pointer), along with any -methods and attributes specific to a format. The :py:attr:`~PIL.Image.Image.format` -attribute will be ``None``. +internally creates a copy of the image, then any methods or attributes specific to the +format will no longer be present. The ``fp`` (file pointer) attribute will no longer be +present, and the :py:attr:`~PIL.Image.Image.format` attribute will be ``None``. Fully supported formats ----------------------- -.. contents:: - BLP ^^^ @@ -44,8 +42,9 @@ BMP ^^^ Pillow reads and writes Windows and OS/2 BMP files containing ``1``, ``L``, ``P``, -or ``RGB`` data. 16-colour images are read as ``P`` images. Run-length encoding -is not supported. +or ``RGB`` data. 16-colour images are read as ``P`` images. 4-bit run-length encoding +is not supported. Support for reading 8-bit run-length encoding was added in Pillow +9.1.0. The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: @@ -102,12 +101,38 @@ GIF ^^^ Pillow reads GIF87a and GIF89a versions of the GIF file format. The library -writes run-length encoded files in GIF87a by default, unless GIF89a features -are used or GIF89a is already in use. +writes files in GIF87a by default, unless GIF89a features are used or GIF89a is +already in use. Files are written with LZW encoding. GIF files are initially read as grayscale (``L``) or palette mode (``P``) -images, but seeking to later frames in an image will change the mode to either -``RGB`` or ``RGBA``, depending on whether the first frame had transparency. +images. Seeking to later frames in a ``P`` image will change the image to +``RGB`` (or ``RGBA`` if the first frame had transparency). + +``P`` mode images are changed to ``RGB`` because each frame of a GIF may contain +its own individual palette of up to 256 colors. When a new frame is placed onto a +previous frame, those colors may combine to exceed the ``P`` mode limit of 256 +colors. Instead, the image is converted to ``RGB`` handle this. + +If you would prefer the first ``P`` image frame to be ``RGB`` as well, so that +every ``P`` frame is converted to ``RGB`` or ``RGBA`` mode, there is a setting +available:: + + from PIL import GifImagePlugin + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_ALWAYS + +GIF frames do not always contain individual palettes however. If there is only +a global palette, then all of the colors can fit within ``P`` mode. If you would +prefer the frames to be kept as ``P`` in that case, there is also a setting +available:: + + from PIL import GifImagePlugin + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY + +To restore the default behavior, where ``P`` mode images are only converted to +``RGB`` or ``RGBA`` after the first frame:: + + from PIL import GifImagePlugin + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_FIRST The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: @@ -131,7 +156,8 @@ The :py:meth:`~PIL.Image.open` method sets the following it will loop forever. **comment** - May not be present. A comment about the image. + May not be present. A comment about the image. This is the last comment found + before the current frame's image. **extension** May not be present. Contains application specific information. @@ -220,17 +246,14 @@ Reading local images The GIF loader creates an image memory the same size as the GIF file’s *logical screen size*, and pastes the actual pixel data (the *local image*) into this -image. If you only want the actual pixel rectangle, you can manipulate the -:py:attr:`~PIL.Image.Image.size` and :py:attr:`~PIL.ImageFile.ImageFile.tile` -attributes before loading the file:: +image. If you only want the actual pixel rectangle, you can crop the image:: im = Image.open(...) if im.tile[0][0] == "gif": # only read the first "local image" from this GIF file - tag, (x0, y0, x1, y1), offset, extra = im.tile[0] - im.size = (x1 - x0, y1 - y0) - im.tile = [(tag, (0, 0) + im.size, offset, extra)] + box = im.tile[0][1] + im = im.crop(box) ICNS ^^^^ @@ -364,10 +387,12 @@ The :py:meth:`~PIL.Image.open` method may set the following The :py:meth:`~PIL.Image.Image.save` method supports the following options: **quality** - The image quality, on a scale from 0 (worst) to 95 (best). The default is - 75. Values above 95 should be avoided; 100 disables portions of the JPEG - compression algorithm, and results in large files with hardly any gain in - image quality. + The image quality, on a scale from 0 (worst) to 95 (best), or the string + ``keep``. The default is 75. Values above 95 should be avoided; 100 disables + portions of the JPEG compression algorithm, and results in large files with + hardly any gain in image quality. The value ``keep`` is only valid for JPEG + files and will retain the original image quality level, subsampling, and + qtables. **optimize** If present and true, indicates that the encoder should make an extra pass @@ -475,9 +500,18 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: and must be greater than the code-block size. **irreversible** - If ``True``, use the lossy Irreversible Color Transformation - followed by DWT 9-7. Defaults to ``False``, which means to use the - Reversible Color Transformation with DWT 5-3. + If ``True``, use the lossy discrete waveform transformation DWT 9-7. + Defaults to ``False``, which uses the lossless DWT 5-3. + +**mct** + If ``1`` then enable multiple component transformation when encoding, + otherwise use ``0`` for no component transformation (default). If MCT is + enabled and ``irreversible`` is ``True`` then the Irreversible Color + Transformation will be applied, otherwise encoding will use the + Reversible Color Transformation. MCT works best with a ``mode`` of + ``RGB`` and is only applicable when the image data has 3 components. + + .. versionadded:: 9.1.0 **progression** Controls the progression order; must be one of ``"LRCP"``, ``"RLCP"``, @@ -497,6 +531,13 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options: for compliant 4K files, *at least one* of the dimensions must match 4096 x 2160. +**no_jp2** + If ``True`` then don't wrap the raw codestream in the JP2 file format when + saving, otherwise the extension of the filename will be used to determine + the format (default). + + .. versionadded:: 9.1.0 + .. note:: To enable JPEG 2000 support, you need to build and install the OpenJPEG @@ -743,7 +784,7 @@ parameter must be set to ``True``. The following parameters can also be set: PPM ^^^ -Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L`` or +Pillow reads and writes PBM, PGM, PPM and PNM files containing ``1``, ``L``, ``I`` or ``RGB`` data. SGI @@ -1192,6 +1233,11 @@ PSD Pillow identifies and reads PSD files written by Adobe Photoshop 2.5 and 3.0. +SUN +^^^ + +Pillow identifies and reads Sun raster files. + WAL ^^^ @@ -1206,13 +1252,13 @@ this format. By default, a Quake2 standard palette is attached to the texture. To override the palette, use the putpalette method. -WMF -^^^ +WMF, EMF +^^^^^^^^ -Pillow can identify WMF files. +Pillow can identify WMF and EMF files. -On Windows, it can read WMF files. By default, it will load the image at 72 -dpi. To load it at another resolution: +On Windows, it can read WMF and EMF files. By default, it will load the image +at 72 dpi. To load it at another resolution: .. code-block:: python @@ -1222,7 +1268,8 @@ dpi. To load it at another resolution: im.load(dpi=144) To add other read or write support, use -:py:func:`PIL.WmfImagePlugin.register_handler` to register a WMF handler. +:py:func:`PIL.WmfImagePlugin.register_handler` to register a WMF and EMF +handler. .. code-block:: python diff --git a/docs/handbook/tutorial.rst b/docs/handbook/tutorial.rst index b0dbffda4a6..50133f15ec2 100644 --- a/docs/handbook/tutorial.rst +++ b/docs/handbook/tutorial.rst @@ -171,20 +171,37 @@ Rolling an image :: - def roll(image, delta): + def roll(im, delta): """Roll an image sideways.""" - xsize, ysize = image.size + xsize, ysize = im.size delta = delta % xsize if delta == 0: - return image + return im - part1 = image.crop((0, 0, delta, ysize)) - part2 = image.crop((delta, 0, xsize, ysize)) - image.paste(part1, (xsize - delta, 0, xsize, ysize)) - image.paste(part2, (0, 0, xsize - delta, ysize)) + part1 = im.crop((0, 0, delta, ysize)) + part2 = im.crop((delta, 0, xsize, ysize)) + im.paste(part1, (xsize - delta, 0, xsize, ysize)) + im.paste(part2, (0, 0, xsize - delta, ysize)) - return image + return im + +Or if you would like to merge two images into a wider image: + +Merging images +^^^^^^^^^^^^^^ + +:: + + def merge(im1, im2): + w = im1.size[0] + im2.size[0] + h = max(im1.size[1], im2.size[1]) + im = Image.new("RGBA", (w, h)) + + im.paste(im1) + im.paste(im2, (im1.size[0], 0)) + + return im For more advanced tricks, the paste method can also take a transparency mask as an optional argument. In this mask, the value 255 indicates that the pasted @@ -487,6 +504,17 @@ image header. In addition, seek will also be used when the image data is read tar file, you can use the :py:class:`~PIL.ContainerIO` or :py:class:`~PIL.TarIO` modules to access it. +Reading from URL +^^^^^^^^^^^^^^^^ + +:: + + from PIL import Image + from urllib.request import urlopen + url = "https://python-pillow.org/images/pillow-logo.png" + img = Image.open(urlopen(url)) + + Reading from a tar archive ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/handbook/writing-your-own-image-plugin.rst b/docs/handbook/writing-your-own-image-plugin.rst index 0c9cfe8e80d..80138742d68 100644 --- a/docs/handbook/writing-your-own-image-plugin.rst +++ b/docs/handbook/writing-your-own-image-plugin.rst @@ -123,8 +123,12 @@ The ``tile`` attribute To be able to read the file as well as just identifying it, the ``tile`` attribute must also be set. This attribute consists of a list of tile descriptors, where each descriptor specifies how data should be loaded to a -given region in the image. In most cases, only a single descriptor is used, -covering the full image. +given region in the image. + +In most cases, only a single descriptor is used, covering the full image. +:py:class:`.PsdImagePlugin.PsdImageFile` uses multiple tiles to combine +channels within a single layer, given that the channels are stored separately, +one after the other. The tile descriptor is a 4-tuple with the following contents:: @@ -324,42 +328,42 @@ The fields are used as follows: Whether the first line in the image is the top line on the screen (1), or the bottom line (-1). If omitted, the orientation defaults to 1. -.. _file-decoders: +.. _file-codecs: -Writing Your Own File Decoder in C -================================== +Writing Your Own File Codec in C +================================ -There are 3 stages in a file decoder's lifetime: +There are 3 stages in a file codec's lifetime: -1. Setup: Pillow looks for a function in the decoder registry, falling - back to a function named ``[decodername]_decoder`` on the internal - core image object. That function is called with the ``args`` tuple - from the ``tile`` setup in the ``_open`` method. +1. Setup: Pillow looks for a function in the decoder or encoder registry, + falling back to a function named ``[codecname]_decoder`` or + ``[codecname]_encoder`` on the internal core image object. That function is + called with the ``args`` tuple from the ``tile``. -2. Decoding: The decoder's decode function is repeatedly called with - chunks of image data. +2. Transforming: The codec's ``decode`` or ``encode`` function is repeatedly + called with chunks of image data. -3. Cleanup: If the decoder has registered a cleanup function, it will - be called at the end of the decoding process, even if there was an +3. Cleanup: If the codec has registered a cleanup function, it will + be called at the end of the transformation process, even if there was an exception raised. Setup ----- -The current conventions are that the decoder setup function is named -``PyImaging_[Decodername]DecoderNew`` and defined in ``decode.c``. The -python binding for it is named ``[decodername]_decoder`` and is setup -from within the ``_imaging.c`` file in the codecs section of the -function array. +The current conventions are that the codec setup function is named +``PyImaging_[codecname]DecoderNew`` or ``PyImaging_[codecname]EncoderNew`` +and defined in ``decode.c`` or ``encode.c``. The Python binding for it is +named ``[codecname]_decoder`` or ``[codecname]_encoder`` and is set up from +within the ``_imaging.c`` file in the codecs section of the function array. -The setup function needs to call ``PyImaging_DecoderNew`` and at the -very least, set the ``decode`` function pointer. The fields of -interest in this object are: +The setup function needs to call ``PyImaging_DecoderNew`` or +``PyImaging_EncoderNew`` and at the very least, set the ``decode`` or +``encode`` function pointer. The fields of interest in this object are: -**decode** - Function pointer to the decode function, which has access to - ``im``, ``state``, and the buffer of data to be added to the image. +**decode**/**encode** + Function pointer to the decode or encode function, which has access to + ``im``, ``state``, and the buffer of data to be transformed. **cleanup** Function pointer to the cleanup function, has access to ``state``. @@ -369,36 +373,34 @@ interest in this object are: **state** An ImagingCodecStateInstance, will be set by Pillow. The ``context`` - member is an opaque struct that can be used by the decoder to store + member is an opaque struct that can be used by the codec to store any format specific state or options. -**pulls_fd** - **EXPERIMENTAL** -- **WARNING**, interface may change. If set to 1, - ``state->fd`` will be a pointer to the Python file like object. The - decoder may use the functions in ``codec_fd.c`` to read directly - from the file like object rather than have the data pushed through a - buffer. Note that this implementation may be refactored until this - warning is removed. +**pulls_fd**/**pushes_fd** + If the decoder has ``pulls_fd`` or the encoder has ``pushes_fd`` set to 1, + ``state->fd`` will be a pointer to the Python file like object. The codec may + use the functions in ``codec_fd.c`` to read or write directly with the file + like object rather than have the data pushed through a buffer. .. versionadded:: 3.3.0 -Decoding --------- +Transforming +------------ -The decode function is called with the target (core) image, the -decoder state structure, and a buffer of data to be decoded. +The decode or encode function is called with the target (core) image, the codec +state structure, and a buffer of data to be transformed. -**Experimental** -- If ``pulls_fd`` is set, then the decode function -is called once, with an empty buffer. It is the decoder's -responsibility to decode the entire tile in that one call. The rest of -this section only applies if ``pulls_fd`` is not set. +It is the codec's responsibility to pull as much data as possible out of the +buffer and return the number of bytes consumed. The next call to the codec will +include the previous unconsumed tail. The codec function will be called +multiple times as the data processed. -It is the decoder's responsibility to pull as much data as possible -out of the buffer and return the number of bytes consumed. The next -call to the decoder will include the previous unconsumed tail. The -decoder function will be called multiple times as the data is read -from the file like object. +Alternatively, if ``pulls_fd`` or ``pushes_fd`` is set, then the decode or +encode function is called once, with an empty buffer. It is the codec's +responsibility to transform the entire tile in that one call. Using this will +provide a codec with more freedom, but that freedom may mean increased memory +usage if the entire tile is held in memory at once by the codec. If an error occurs, set ``state->errcode`` and return -1. @@ -407,10 +409,9 @@ Return -1 on success, without setting the errcode. Cleanup ------- -The cleanup function is called after the decoder returns a negative -value, or if there is a read error from the file. This function should -free any allocated memory and release any resources from external -libraries. +The cleanup function is called after the codec returns a negative +value, or if there is an error. This function should free any allocated +memory and release any resources from external libraries. .. _file-codecs-py: @@ -425,11 +426,32 @@ They should be registered using :py:meth:`PIL.Image.register_decoder` and the file codecs, there are three stages in the lifetime of a Python-based file codec: -1. Setup: Pillow looks for the decoder in the registry, then +1. Setup: Pillow looks for the codec in the decoder or encoder registry, then instantiates the class. 2. Transforming: The instance's ``decode`` method is repeatedly called with a buffer of data to be interpreted, or the ``encode`` method is repeatedly called with the size of data to be output. -3. Cleanup: The instance's ``cleanup`` method is called. + Alternatively, if the decoder's ``_pulls_fd`` property (or the encoder's + ``_pushes_fd`` property) is set to ``True``, then ``decode`` and ``encode`` + will only be called once. In the decoder, ``self.fd`` can be used to access + the file-like object. Using this will provide a codec with more freedom, but + that freedom may mean increased memory usage if entire file is held in + memory at once by the codec. + + In ``decode``, once the data has been interpreted, ``set_as_raw`` can be + used to populate the image. + +3. Cleanup: The instance's ``cleanup`` method is called once the transformation + is complete. This can be used to clean up any resources used by the codec. + + If you set ``_pulls_fd`` or ``_pushes_fd`` to ``True`` however, then you + probably chose to perform any cleanup tasks at the end of ``decode`` or + ``encode``. + +For an example :py:class:`PIL.ImageFile.PyDecoder`, see `DdsImagePlugin +`_. +For a plugin that uses both :py:class:`PIL.ImageFile.PyDecoder` and +:py:class:`PIL.ImageFile.PyEncoder`, see `BlpImagePlugin +`_ diff --git a/docs/index.rst b/docs/index.rst index f1a721c6ac1..5e886c2e82a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,6 +29,10 @@ Pillow for enterprise is available via the Tidelift Subscription. `Learn more `_ on 2020-12-08 for +open-source users (and will reach EOL on 2023-12-08 for commercial licence holders). + +Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed +in Pillow 10 (2023-07-01). Upgrade to +`PyQt6 `_ or +`PySide6 `_ instead. + .. versionadded:: 1.1.6 .. py:class:: ImageQt(image) diff --git a/docs/reference/ImageSequence.rst b/docs/reference/ImageSequence.rst index 1bfb554b653..f2e7d9edd28 100644 --- a/docs/reference/ImageSequence.rst +++ b/docs/reference/ImageSequence.rst @@ -25,3 +25,8 @@ The :py:class:`~PIL.ImageSequence.Iterator` class .. autoclass:: PIL.ImageSequence.Iterator :members: + +Functions +--------- + +.. autofunction:: PIL.ImageSequence.all_frames diff --git a/docs/reference/PixelAccess.rst b/docs/reference/PixelAccess.rst index 173a0bcc0e6..d2e80fb8cb7 100644 --- a/docs/reference/PixelAccess.rst +++ b/docs/reference/PixelAccess.rst @@ -6,7 +6,13 @@ The PixelAccess class provides read and write access to :py:class:`PIL.Image` data at a pixel level. -.. note:: Accessing individual pixels is fairly slow. If you are looping over all of the pixels in an image, there is likely a faster way using other parts of the Pillow API. +.. note:: Accessing individual pixels is fairly slow. If you are + looping over all of the pixels in an image, there is likely + a faster way using other parts of the Pillow API. + + :mod:`~PIL.Image`, :mod:`~PIL.ImageChops` and :mod:`~PIL.ImageOps` + have methods for many standard operations. If you wish to perform + a custom mapping, check out :py:meth:`~PIL.Image.Image.point`. Example ------- @@ -39,7 +45,7 @@ Access using negative indexes is also possible. :py:class:`PixelAccess` Class ------------------------------------ +----------------------------- .. class:: PixelAccess diff --git a/docs/reference/PyAccess.rst b/docs/reference/PyAccess.rst index e77944d2001..f9eb9b52418 100644 --- a/docs/reference/PyAccess.rst +++ b/docs/reference/PyAccess.rst @@ -7,8 +7,12 @@ The :py:mod:`~PIL.PyAccess` module provides a CFFI/Python implementation of the :ref:`PixelAccess`. This implementation is far faster on PyPy than the PixelAccess version. .. note:: Accessing individual pixels is fairly slow. If you are - looping over all of the pixels in an image, there is likely - a faster way using other parts of the Pillow API. + looping over all of the pixels in an image, there is likely + a faster way using other parts of the Pillow API. + + :mod:`~PIL.Image`, :mod:`~PIL.ImageChops` and :mod:`~PIL.ImageOps` + have methods for many standard operations. If you wish to perform + a custom mapping, check out :py:meth:`~PIL.Image.Image.point`. Example ------- diff --git a/docs/reference/TiffTags.rst b/docs/reference/TiffTags.rst index 1441185dd14..7cb7d16ae47 100644 --- a/docs/reference/TiffTags.rst +++ b/docs/reference/TiffTags.rst @@ -10,6 +10,10 @@ metadata tag numbers, names, and type information. .. method:: lookup(tag) :param tag: Integer tag number + :param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in + + .. versionadded:: 8.3.0 + :returns: Taginfo namedtuple, From the :py:data:`~PIL.TiffTags.TAGS_V2` info if possible, otherwise just populating the value and name from :py:data:`~PIL.TiffTags.TAGS`. If the tag is not recognized, "unknown" is returned for the name @@ -42,6 +46,16 @@ metadata tag numbers, names, and type information. .. versionadded:: 3.0.0 +.. py:data:: PIL.TiffTags.TAGS_V2_GROUPS + :type: dict + + :py:data:`~PIL.TiffTags.TAGS_V2` is one dimensional and + doesn't account for the fact that tags actually exist in + `different groups `_. + This dictionary is used when the tag in question is part of a group. + +.. versionadded:: 8.3.0 + .. py:data:: PIL.TiffTags.TAGS :type: dict diff --git a/docs/reference/internal_modules.rst b/docs/reference/internal_modules.rst index 1105ff76e1f..363a67d9b02 100644 --- a/docs/reference/internal_modules.rst +++ b/docs/reference/internal_modules.rst @@ -9,6 +9,14 @@ Internal Modules :undoc-members: :show-inheritance: +:mod:`~PIL._deprecate` Module +----------------------------- + +.. automodule:: PIL._deprecate + :members: + :undoc-members: + :show-inheritance: + :mod:`~PIL._tkinter_finder` Module ---------------------------------- diff --git a/docs/releasenotes/8.0.0.rst b/docs/releasenotes/8.0.0.rst index 2ff9b3799ba..fe26580474d 100644 --- a/docs/releasenotes/8.0.0.rst +++ b/docs/releasenotes/8.0.0.rst @@ -174,7 +174,7 @@ Previously, if a BMP file was too large, an ``OSError`` would be raised. Now, Dark theme for docs ^^^^^^^^^^^^^^^^^^^ -The https://pillow.readthedocs.io documentation will use a dark theme if the the user has requested the system use one. Uses the ``prefers-color-scheme`` CSS media query. +The https://pillow.readthedocs.io documentation will use a dark theme if the user has requested the system use one. Uses the ``prefers-color-scheme`` CSS media query. diff --git a/docs/releasenotes/9.0.0.rst b/docs/releasenotes/9.0.0.rst index 947ccd849e3..dd993d39eb4 100644 --- a/docs/releasenotes/9.0.0.rst +++ b/docs/releasenotes/9.0.0.rst @@ -149,6 +149,9 @@ Switched to libjpeg-turbo in macOS and Linux wheels The Pillow wheels from PyPI for macOS and Linux have switched from libjpeg to libjpeg-turbo. It is a fork of libjpeg, popular for its speed. +Because different JPEG decoders load images differently, JPEG pixels may be +altered slightly with this change. + Added support for pickling TrueType fonts ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/releasenotes/9.1.0.rst b/docs/releasenotes/9.1.0.rst index 22b185e95ac..57646e5588a 100644 --- a/docs/releasenotes/9.1.0.rst +++ b/docs/releasenotes/9.1.0.rst @@ -76,8 +76,8 @@ Deprecated Use instead ``Image.TRANSPOSE`` ``Image.Transpose.TRANSPOSE`` ``Image.TRANSVERSE`` ``Image.Transpose.TRANSVERSE`` ``Image.BOX`` ``Image.Resampling.BOX`` -``Image.BILINEAR`` ``Image.Resampling.BILNEAR`` -``Image.LINEAR`` ``Image.Resampling.BILNEAR`` +``Image.BILINEAR`` ``Image.Resampling.BILINEAR`` +``Image.LINEAR`` ``Image.Resampling.BILINEAR`` ``Image.HAMMING`` ``Image.Resampling.HAMMING`` ``Image.BICUBIC`` ``Image.Resampling.BICUBIC`` ``Image.CUBIC`` ``Image.Resampling.BICUBIC`` @@ -146,12 +146,24 @@ At present, the information within each block is merely returned as a dictionary "data" entry. This will allow more useful information to be added in the future without breaking backwards compatibility. -Added rawmode argument to Image.getpalette() -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Added mct and no_jp2 options for saving JPEG 2000 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, :py:meth:`~PIL.Image.Image.getpalette` returns RGB data from the palette. -A ``rawmode`` argument has been added, to allow the mode to be chosen instead. ``None`` -can be used to return data in the current mode of the palette. +The :py:meth:`PIL.Image.Image.save` method now supports the following options for +JPEG 2000: + +**mct** + If ``1`` then enable multiple component transformation when encoding, + otherwise use ``0`` for no component transformation (default). If MCT is + enabled and ``irreversible`` is ``True`` then the Irreversible Color + Transformation will be applied, otherwise encoding will use the + Reversible Color Transformation. MCT works best with a ``mode`` of + ``RGB`` and is only applicable when the image data has 3 components. + +**no_jp2** + If ``True`` then don't wrap the raw codestream in the JP2 file format when + saving, otherwise the extension of the filename will be used to determine + the format (default). Added PyEncoder ^^^^^^^^^^^^^^^ @@ -160,9 +172,35 @@ Added PyEncoder written in Python. See :ref:`Writing Your Own File Codec in Python` for more information. +GifImagePlugin loading strategy +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Pillow 9.0.0 introduced the conversion of subsequent GIF frames to ``RGB`` or ``RGBA``. This +behaviour can now be changed so that the first ``P`` frame is converted to ``RGB`` as +well. + +.. code-block:: python + + from PIL import GifImagePlugin + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_ALWAYS + +Or subsequent frames can be kept in ``P`` mode as long as there is only a single +palette. + +.. code-block:: python + + from PIL import GifImagePlugin + GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY + Other Changes ============= +musllinux wheels +^^^^^^^^^^^^^^^^ + +Pillow now builds binary wheels for musllinux, suitable for Linux distributions based on the musl C standard library such as Alpine +(rather than the glibc library used by manylinux wheels). See :pep:`656`. + ImageShow temporary files on Unix ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,6 +215,11 @@ Image._repr_pretty_ identity of the object. This allows Jupyter to describe an image and have that description stay the same on subsequent executions of the same code. +Added BigTIFF reading +^^^^^^^^^^^^^^^^^^^^^ + +Support has been added for reading BigTIFF images. + Added BLP saving ^^^^^^^^^^^^^^^^ diff --git a/docs/releasenotes/9.1.1.rst b/docs/releasenotes/9.1.1.rst new file mode 100644 index 00000000000..f8b155f3d6a --- /dev/null +++ b/docs/releasenotes/9.1.1.rst @@ -0,0 +1,16 @@ +9.1.1 +----- + +Security +======== + +This release addresses several security problems. + +:cve:`CVE-2022-30595`: When reading a TGA file with RLE packets that cross scan lines, +Pillow reads the information past the end of the first line without deducting that +from the length of the remaining file data. This vulnerability was introduced in Pillow +9.1.0, and can cause a heap buffer overflow. + +Opening an image with a zero or negative height has been found to bypass a +decompression bomb check. This will now raise a :py:exc:`SyntaxError` instead, in turn +raising a ``PIL.UnidentifiedImageError``. diff --git a/docs/releasenotes/9.2.0.rst b/docs/releasenotes/9.2.0.rst new file mode 100644 index 00000000000..424fd487a29 --- /dev/null +++ b/docs/releasenotes/9.2.0.rst @@ -0,0 +1,82 @@ +9.2.0 +----- + +Backwards Incompatible Changes +============================== + +TODO +^^^^ + +Deprecations +============ + +PyQt5 and PySide2 +^^^^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +`Qt 5 reached end-of-life `_ on 2020-12-08 for +open-source users (and will reach EOL on 2023-12-08 for commercial licence holders). + +Support for PyQt5 and PySide2 has been deprecated from ``ImageQt`` and will be removed +in Pillow 10 (2023-07-01). Upgrade to +`PyQt6 `_ or +`PySide6 `_ instead. + +FreeTypeFont.getmask2 fill parameter +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +The undocumented ``fill`` parameter of :py:meth:`.FreeTypeFont.getmask2` +has been deprecated and will be removed in Pillow 10 (2023-07-01). + +PhotoImage.paste box parameter +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +The ``box`` parameter is unused. It will be removed in Pillow 10.0.0 (2023-07-01). + +Image.coerce_e +^^^^^^^^^^^^^^ + +.. deprecated:: 9.2.0 + +This undocumented method has been deprecated and will be removed in Pillow 10 +(2023-07-01). + +API Changes +=========== + +TODO +^^^^ + +TODO + +API Additions +============= + +Image.apply_transparency +^^^^^^^^^^^^^^^^^^^^^^^^ + +Added :py:meth:`~PIL.Image.Image.apply_transparency`, a method to take a P mode image +with "transparency" in ``im.info``, and apply the transparency to the palette instead. +The image's palette mode will become "RGBA", and "transparency" will be removed from +``im.info``. + +Security +======== + +TODO +^^^^ + +TODO + +Other Changes +============= + +TODO +^^^^ + +TODO diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index 656acef95d2..597c804f861 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -14,6 +14,8 @@ expected to be backported to earlier versions. .. toctree:: :maxdepth: 2 + 9.2.0 + 9.1.1 9.1.0 9.0.1 9.0.0 diff --git a/docs/resources/css/dark.css b/docs/resources/css/dark.css index 8866c07eabd..1571cbc4e91 100644 --- a/docs/resources/css/dark.css +++ b/docs/resources/css/dark.css @@ -1,1996 +1,9 @@ +/* For black-on-white/transparent images at handbook/text-anchors.html */ +body[data-theme="dark"] #text-anchors img { + filter: invert(1) brightness(0.85) hue-rotate(-60deg); +} @media (prefers-color-scheme: dark) { - html { - background-color: #181a1b !important; - } - - html, body, input, textarea, select, button { - background-color: #181a1b; - } - - html, body, input, textarea, select, button { - border-color: #736b5e; - color: #e8e6e3; - } - - a { - color: #3391ff; - } - - table { - border-color: #545b5e; - } - - ::placeholder { - color: #b2aba1; - } - - input:-webkit-autofill, - textarea:-webkit-autofill, - select:-webkit-autofill { - background-color: #555b00 !important; - color: #e8e6e3 !important; - } - - ::selection { - background-color: #004daa !important; - color: #e8e6e3 !important; - } - - ::-moz-selection { - background-color: #004daa !important; - color: #e8e6e3 !important; - } - - /* Invert Style */ - .jfk-bubble.gtx-bubble, embed[type="application/pdf"] { - filter: invert(100%) hue-rotate(180deg) contrast(90%) !important; - } - - /* Override Style */ - .vimvixen-hint { - background-color: #7b5300 !important; - border-color: #d8b013 !important; - color: #f3e8c8 !important; - } - - ::placeholder { - opacity: 0.5 !important; - } - - /* Variables Style */ - :root { - --darkreader-neutral-background: #181a1b; - --darkreader-neutral-text: #e8e6e3; - --darkreader-selection-background: #004daa; - --darkreader-selection-text: #e8e6e3; - } - - /* Modified CSS */ - a:hover, - a:active { - outline-color: initial; - } - - abbr[title] { - border-bottom-color: initial; - } - - ins { - background-image: initial; - background-color: rgb(112, 112, 0); - color: rgb(232, 230, 227); - text-decoration-color: initial; - } - - mark { - background-image: initial; - background-color: rgb(204, 204, 0); - color: rgb(232, 230, 227); - } - - ul, - ol, - dl { - list-style-image: none; - } - - li { - list-style-image: initial; - } - - img { - border-color: initial; - } - - fieldset { - border-color: initial; - } - - legend { - border-color: initial; - } - - .chromeframe { - background-image: initial; - background-color: rgb(53, 57, 59); - color: rgb(232, 230, 227); - } - - .ir { - border-color: initial; - background-color: transparent; - } - - .visuallyhidden { - border-color: initial; - } - - .fa-border { - border-color: rgb(53, 57, 59); - } - - .fa-inverse { - color: rgb(232, 230, 227); - } - - .sr-only { - border-color: initial; - } - - .fa::before, - .wy-menu-vertical li span.toctree-expand::before, - .wy-menu-vertical li.on a span.toctree-expand::before, - .wy-menu-vertical li.current > a span.toctree-expand::before, - .rst-content .admonition-title::before, - .rst-content h1 .headerlink::before, - .rst-content h2 .headerlink::before, - .rst-content h3 .headerlink::before, - .rst-content h4 .headerlink::before, - .rst-content h5 .headerlink::before, - .rst-content h6 .headerlink::before, - .rst-content dl dt .headerlink::before, - .rst-content p.caption .headerlink::before, - .rst-content table > caption .headerlink::before, - .rst-content .code-block-caption .headerlink::before, - .rst-content tt.download span:first-child::before, - .rst-content code.download span:first-child::before, - .icon::before, - .wy-dropdown .caret::before, - .wy-inline-validate.wy-inline-validate-success .wy-input-context::before, - .wy-inline-validate.wy-inline-validate-danger .wy-input-context::before, - .wy-inline-validate.wy-inline-validate-warning .wy-input-context::before, - .wy-inline-validate.wy-inline-validate-info .wy-input-context::before { - text-decoration-color: inherit; - } - - a .fa, - a .wy-menu-vertical li span.toctree-expand, - .wy-menu-vertical li a span.toctree-expand, - .wy-menu-vertical li.on a span.toctree-expand, - .wy-menu-vertical li.current > a span.toctree-expand, - a .rst-content .admonition-title, - .rst-content a .admonition-title, - a .rst-content h1 .headerlink, - .rst-content h1 a .headerlink, - a .rst-content h2 .headerlink, - .rst-content h2 a .headerlink, - a .rst-content h3 .headerlink, - .rst-content h3 a .headerlink, - a .rst-content h4 .headerlink, - .rst-content h4 a .headerlink, - a .rst-content h5 .headerlink, - .rst-content h5 a .headerlink, - a .rst-content h6 .headerlink, - .rst-content h6 a .headerlink, - a .rst-content dl dt .headerlink, - .rst-content dl dt a .headerlink, - a .rst-content p.caption .headerlink, - .rst-content p.caption a .headerlink, - a .rst-content table > caption .headerlink, - .rst-content table > caption a .headerlink, - a .rst-content .code-block-caption .headerlink, - .rst-content .code-block-caption a .headerlink, - a .rst-content tt.download span:first-child, - .rst-content tt.download a span:first-child, - a .rst-content code.download span:first-child, - .rst-content code.download a span:first-child, - a .icon { - text-decoration-color: inherit; - } - - .wy-alert, - .rst-content .note, - .rst-content .attention, - .rst-content .caution, - .rst-content .danger, - .rst-content .error, - .rst-content .hint, - .rst-content .important, - .rst-content .tip, - .rst-content .warning, - .rst-content .seealso, - .rst-content .admonition-todo, - .rst-content .admonition { - background-image: initial; - background-color: rgb(32, 35, 36); - } - - .wy-alert-title, - .rst-content .admonition-title { - color: rgb(232, 230, 227); - background-image: initial; - background-color: rgb(29, 91, 131); - } - - .wy-alert.wy-alert-danger, - .rst-content .wy-alert-danger.note, - .rst-content .wy-alert-danger.attention, - .rst-content .wy-alert-danger.caution, - .rst-content .danger, - .rst-content .error, - .rst-content .wy-alert-danger.hint, - .rst-content .wy-alert-danger.important, - .rst-content .wy-alert-danger.tip, - .rst-content .wy-alert-danger.warning, - .rst-content .wy-alert-danger.seealso, - .rst-content .wy-alert-danger.admonition-todo, - .rst-content .wy-alert-danger.admonition { - background-image: initial; - background-color: rgb(52, 12, 8); - } - - .wy-alert.wy-alert-danger .wy-alert-title, - .rst-content .wy-alert-danger.note .wy-alert-title, - .rst-content .wy-alert-danger.attention .wy-alert-title, - .rst-content .wy-alert-danger.caution .wy-alert-title, - .rst-content .danger .wy-alert-title, - .rst-content .error .wy-alert-title, - .rst-content .wy-alert-danger.hint .wy-alert-title, - .rst-content .wy-alert-danger.important .wy-alert-title, - .rst-content .wy-alert-danger.tip .wy-alert-title, - .rst-content .wy-alert-danger.warning .wy-alert-title, - .rst-content .wy-alert-danger.seealso .wy-alert-title, - .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, - .rst-content .wy-alert-danger.admonition .wy-alert-title, - .wy-alert.wy-alert-danger .rst-content .admonition-title, - .rst-content .wy-alert.wy-alert-danger .admonition-title, - .rst-content .wy-alert-danger.note .admonition-title, - .rst-content .wy-alert-danger.attention .admonition-title, - .rst-content .wy-alert-danger.caution .admonition-title, - .rst-content .danger .admonition-title, - .rst-content .error .admonition-title, - .rst-content .wy-alert-danger.hint .admonition-title, - .rst-content .wy-alert-danger.important .admonition-title, - .rst-content .wy-alert-danger.tip .admonition-title, - .rst-content .wy-alert-danger.warning .admonition-title, - .rst-content .wy-alert-danger.seealso .admonition-title, - .rst-content .wy-alert-danger.admonition-todo .admonition-title, - .rst-content .wy-alert-danger.admonition .admonition-title { - background-image: initial; - background-color: rgb(108, 22, 13); - } - - .wy-alert.wy-alert-warning, - .rst-content .wy-alert-warning.note, - .rst-content .attention, - .rst-content .caution, - .rst-content .wy-alert-warning.danger, - .rst-content .wy-alert-warning.error, - .rst-content .wy-alert-warning.hint, - .rst-content .wy-alert-warning.important, - .rst-content .wy-alert-warning.tip, - .rst-content .warning, - .rst-content .wy-alert-warning.seealso, - .rst-content .admonition-todo, - .rst-content .wy-alert-warning.admonition { - background-image: initial; - background-color: rgb(82, 53, 0); - } - - .wy-alert.wy-alert-warning .wy-alert-title, - .rst-content .wy-alert-warning.note .wy-alert-title, - .rst-content .attention .wy-alert-title, - .rst-content .caution .wy-alert-title, - .rst-content .wy-alert-warning.danger .wy-alert-title, - .rst-content .wy-alert-warning.error .wy-alert-title, - .rst-content .wy-alert-warning.hint .wy-alert-title, - .rst-content .wy-alert-warning.important .wy-alert-title, - .rst-content .wy-alert-warning.tip .wy-alert-title, - .rst-content .warning .wy-alert-title, - .rst-content .wy-alert-warning.seealso .wy-alert-title, - .rst-content .admonition-todo .wy-alert-title, - .rst-content .wy-alert-warning.admonition .wy-alert-title, - .wy-alert.wy-alert-warning .rst-content .admonition-title, - .rst-content .wy-alert.wy-alert-warning .admonition-title, - .rst-content .wy-alert-warning.note .admonition-title, - .rst-content .attention .admonition-title, - .rst-content .caution .admonition-title, - .rst-content .wy-alert-warning.danger .admonition-title, - .rst-content .wy-alert-warning.error .admonition-title, - .rst-content .wy-alert-warning.hint .admonition-title, - .rst-content .wy-alert-warning.important .admonition-title, - .rst-content .wy-alert-warning.tip .admonition-title, - .rst-content .warning .admonition-title, - .rst-content .wy-alert-warning.seealso .admonition-title, - .rst-content .admonition-todo .admonition-title, - .rst-content .wy-alert-warning.admonition .admonition-title { - background-image: initial; - background-color: rgb(123, 65, 14); - } - - .wy-alert.wy-alert-info, - .rst-content .note, - .rst-content .wy-alert-info.attention, - .rst-content .wy-alert-info.caution, - .rst-content .wy-alert-info.danger, - .rst-content .wy-alert-info.error, - .rst-content .wy-alert-info.hint, - .rst-content .wy-alert-info.important, - .rst-content .wy-alert-info.tip, - .rst-content .wy-alert-info.warning, - .rst-content .seealso, - .rst-content .wy-alert-info.admonition-todo, - .rst-content .wy-alert-info.admonition { - background-image: initial; - background-color: rgb(32, 35, 36); - } - - .wy-alert.wy-alert-info .wy-alert-title, - .rst-content .note .wy-alert-title, - .rst-content .wy-alert-info.attention .wy-alert-title, - .rst-content .wy-alert-info.caution .wy-alert-title, - .rst-content .wy-alert-info.danger .wy-alert-title, - .rst-content .wy-alert-info.error .wy-alert-title, - .rst-content .wy-alert-info.hint .wy-alert-title, - .rst-content .wy-alert-info.important .wy-alert-title, - .rst-content .wy-alert-info.tip .wy-alert-title, - .rst-content .wy-alert-info.warning .wy-alert-title, - .rst-content .seealso .wy-alert-title, - .rst-content .wy-alert-info.admonition-todo .wy-alert-title, - .rst-content .wy-alert-info.admonition .wy-alert-title, - .wy-alert.wy-alert-info .rst-content .admonition-title, - .rst-content .wy-alert.wy-alert-info .admonition-title, - .rst-content .note .admonition-title, - .rst-content .wy-alert-info.attention .admonition-title, - .rst-content .wy-alert-info.caution .admonition-title, - .rst-content .wy-alert-info.danger .admonition-title, - .rst-content .wy-alert-info.error .admonition-title, - .rst-content .wy-alert-info.hint .admonition-title, - .rst-content .wy-alert-info.important .admonition-title, - .rst-content .wy-alert-info.tip .admonition-title, - .rst-content .wy-alert-info.warning .admonition-title, - .rst-content .seealso .admonition-title, - .rst-content .wy-alert-info.admonition-todo .admonition-title, - .rst-content .wy-alert-info.admonition .admonition-title { - background-image: initial; - background-color: rgb(29, 91, 131); - } - - .wy-alert.wy-alert-success, - .rst-content .wy-alert-success.note, - .rst-content .wy-alert-success.attention, - .rst-content .wy-alert-success.caution, - .rst-content .wy-alert-success.danger, - .rst-content .wy-alert-success.error, - .rst-content .hint, - .rst-content .important, - .rst-content .tip, - .rst-content .wy-alert-success.warning, - .rst-content .wy-alert-success.seealso, - .rst-content .wy-alert-success.admonition-todo, - .rst-content .wy-alert-success.admonition { - background-image: initial; - background-color: rgb(9, 66, 58); - } - - .wy-alert.wy-alert-success .wy-alert-title, - .rst-content .wy-alert-success.note .wy-alert-title, - .rst-content .wy-alert-success.attention .wy-alert-title, - .rst-content .wy-alert-success.caution .wy-alert-title, - .rst-content .wy-alert-success.danger .wy-alert-title, - .rst-content .wy-alert-success.error .wy-alert-title, - .rst-content .hint .wy-alert-title, - .rst-content .important .wy-alert-title, - .rst-content .tip .wy-alert-title, - .rst-content .wy-alert-success.warning .wy-alert-title, - .rst-content .wy-alert-success.seealso .wy-alert-title, - .rst-content .wy-alert-success.admonition-todo .wy-alert-title, - .rst-content .wy-alert-success.admonition .wy-alert-title, - .wy-alert.wy-alert-success .rst-content .admonition-title, - .rst-content .wy-alert.wy-alert-success .admonition-title, - .rst-content .wy-alert-success.note .admonition-title, - .rst-content .wy-alert-success.attention .admonition-title, - .rst-content .wy-alert-success.caution .admonition-title, - .rst-content .wy-alert-success.danger .admonition-title, - .rst-content .wy-alert-success.error .admonition-title, - .rst-content .hint .admonition-title, - .rst-content .important .admonition-title, - .rst-content .tip .admonition-title, - .rst-content .wy-alert-success.warning .admonition-title, - .rst-content .wy-alert-success.seealso .admonition-title, - .rst-content .wy-alert-success.admonition-todo .admonition-title, - .rst-content .wy-alert-success.admonition .admonition-title { - background-image: initial; - background-color: rgb(21, 150, 125); - } - - .wy-alert.wy-alert-neutral, - .rst-content .wy-alert-neutral.note, - .rst-content .wy-alert-neutral.attention, - .rst-content .wy-alert-neutral.caution, - .rst-content .wy-alert-neutral.danger, - .rst-content .wy-alert-neutral.error, - .rst-content .wy-alert-neutral.hint, - .rst-content .wy-alert-neutral.important, - .rst-content .wy-alert-neutral.tip, - .rst-content .wy-alert-neutral.warning, - .rst-content .wy-alert-neutral.seealso, - .rst-content .wy-alert-neutral.admonition-todo, - .rst-content .wy-alert-neutral.admonition { - background-image: initial; - background-color: rgb(27, 36, 36); - } - - .wy-alert.wy-alert-neutral .wy-alert-title, - .rst-content .wy-alert-neutral.note .wy-alert-title, - .rst-content .wy-alert-neutral.attention .wy-alert-title, - .rst-content .wy-alert-neutral.caution .wy-alert-title, - .rst-content .wy-alert-neutral.danger .wy-alert-title, - .rst-content .wy-alert-neutral.error .wy-alert-title, - .rst-content .wy-alert-neutral.hint .wy-alert-title, - .rst-content .wy-alert-neutral.important .wy-alert-title, - .rst-content .wy-alert-neutral.tip .wy-alert-title, - .rst-content .wy-alert-neutral.warning .wy-alert-title, - .rst-content .wy-alert-neutral.seealso .wy-alert-title, - .rst-content .wy-alert-neutral.admonition-todo .wy-alert-title, - .rst-content .wy-alert-neutral.admonition .wy-alert-title, - .wy-alert.wy-alert-neutral .rst-content .admonition-title, - .rst-content .wy-alert.wy-alert-neutral .admonition-title, - .rst-content .wy-alert-neutral.note .admonition-title, - .rst-content .wy-alert-neutral.attention .admonition-title, - .rst-content .wy-alert-neutral.caution .admonition-title, - .rst-content .wy-alert-neutral.danger .admonition-title, - .rst-content .wy-alert-neutral.error .admonition-title, - .rst-content .wy-alert-neutral.hint .admonition-title, - .rst-content .wy-alert-neutral.important .admonition-title, - .rst-content .wy-alert-neutral.tip .admonition-title, - .rst-content .wy-alert-neutral.warning .admonition-title, - .rst-content .wy-alert-neutral.seealso .admonition-title, - .rst-content .wy-alert-neutral.admonition-todo .admonition-title, - .rst-content .wy-alert-neutral.admonition .admonition-title { - color: rgb(192, 186, 178); - background-image: initial; - background-color: rgb(40, 43, 45); - } - - .wy-alert.wy-alert-neutral a, - .rst-content .wy-alert-neutral.note a, - .rst-content .wy-alert-neutral.attention a, - .rst-content .wy-alert-neutral.caution a, - .rst-content .wy-alert-neutral.danger a, - .rst-content .wy-alert-neutral.error a, - .rst-content .wy-alert-neutral.hint a, - .rst-content .wy-alert-neutral.important a, - .rst-content .wy-alert-neutral.tip a, - .rst-content .wy-alert-neutral.warning a, - .rst-content .wy-alert-neutral.seealso a, - .rst-content .wy-alert-neutral.admonition-todo a, - .rst-content .wy-alert-neutral.admonition a { - color: rgb(84, 164, 217); - } - - .wy-tray-container li { - background-image: initial; - background-color: transparent; - color: rgb(232, 230, 227); - box-shadow: rgba(0, 0, 0, 0.1) 0px 5px 5px 0px; - } - - .wy-tray-container li.wy-tray-item-success { - background-image: initial; - background-color: rgb(31, 139, 77); - } - - .wy-tray-container li.wy-tray-item-info { - background-image: initial; - background-color: rgb(33, 102, 148); - } - - .wy-tray-container li.wy-tray-item-warning { - background-image: initial; - background-color: rgb(178, 94, 20); - } - - .wy-tray-container li.wy-tray-item-danger { - background-image: initial; - background-color: rgb(162, 33, 20); - } - - .btn { - color: rgb(232, 230, 227); - border-color: rgba(140, 130, 115, 0.1); - background-color: rgb(31, 139, 77); - text-decoration-color: initial; - box-shadow: rgba(24, 26, 27, 0.5) 0px 1px 2px -1px inset, - rgba(0, 0, 0, 0.1) 0px -2px 0px 0px inset; - } - - .btn-hover { - background-image: initial; - background-color: rgb(37, 114, 165); - color: rgb(232, 230, 227); - } - - .btn:hover { - background-image: initial; - background-color: rgb(35, 156, 86); - color: rgb(232, 230, 227); - } - - .btn:focus { - background-image: initial; - background-color: rgb(35, 156, 86); - outline-color: initial; - } - - .btn:active { - box-shadow: rgba(0, 0, 0, 0.05) 0px -1px 0px 0px inset, - rgba(0, 0, 0, 0.1) 0px 2px 0px 0px inset; - } - - .btn:visited { - color: rgb(232, 230, 227); - } - - .btn:disabled { - background-image: none; - box-shadow: none; - } - - .btn-disabled { - background-image: none; - box-shadow: none; - } - - .btn-disabled:hover, - .btn-disabled:focus, - .btn-disabled:active { - background-image: none; - box-shadow: none; - } - - .btn-info { - background-color: rgb(33, 102, 148) !important; - } - - .btn-info:hover { - background-color: rgb(37, 114, 165) !important; - } - - .btn-neutral { - background-color: rgb(27, 36, 36) !important; - color: rgb(192, 186, 178) !important; - } - - .btn-neutral:hover { - color: rgb(192, 186, 178); - background-color: rgb(34, 44, 44) !important; - } - - .btn-neutral:visited { - color: rgb(192, 186, 178) !important; - } - - .btn-success { - background-color: rgb(31, 139, 77) !important; - } - - .btn-success:hover { - background-color: rgb(27, 122, 68) !important; - } - - .btn-danger { - background-color: rgb(162, 33, 20) !important; - } - - .btn-danger:hover { - background-color: rgb(149, 30, 18) !important; - } - - .btn-warning { - background-color: rgb(178, 94, 20) !important; - } - - .btn-warning:hover { - background-color: rgb(165, 87, 18) !important; - } - - .btn-invert { - background-color: rgb(26, 28, 29); - } - - .btn-invert:hover { - background-color: rgb(35, 38, 40) !important; - } - - .btn-link { - color: rgb(84, 164, 217); - box-shadow: none; - background-color: transparent !important; - border-color: transparent !important; - } - - .btn-link:hover { - box-shadow: none; - background-color: transparent !important; - color: rgb(79, 162, 216) !important; - } - - .btn-link:active { - box-shadow: none; - background-color: transparent !important; - color: rgb(79, 162, 216) !important; - } - - .btn-link:visited { - color: rgb(164, 103, 188); - } - - .wy-dropdown-menu { - background-image: initial; - background-color: rgb(26, 28, 29); - border-color: rgb(60, 65, 67); - box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 2px 0px; - } - - .wy-dropdown-menu > dd > a { - color: rgb(192, 186, 178); - } - - .wy-dropdown-menu > dd > a:hover { - background-image: initial; - background-color: rgb(33, 102, 148); - color: rgb(232, 230, 227); - } - - .wy-dropdown-menu > dd.divider { - border-top-color: rgb(60, 65, 67); - } - - .wy-dropdown-menu > dd.call-to-action { - background-image: initial; - background-color: rgb(40, 43, 45); - } - - .wy-dropdown-menu > dd.call-to-action:hover { - background-image: initial; - background-color: rgb(40, 43, 45); - } - - .wy-dropdown-menu > dd.call-to-action .btn { - color: rgb(232, 230, 227); - } - - .wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu { - background-image: initial; - background-color: rgb(26, 28, 29); - } - - .wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover { - background-image: initial; - background-color: rgb(33, 102, 148); - color: rgb(232, 230, 227); - } - - .wy-dropdown-arrow::before { - border-bottom-color: rgb(51, 55, 57); - border-left-color: transparent; - border-right-color: transparent; - } - - fieldset { - border-color: initial; - } - - legend { - border-color: initial; - } - - label { - color: rgb(200, 195, 188); - } - - .wy-control-group.wy-control-group-required > label::after { - color: rgb(233, 88, 73); - } - - .wy-form-message-inline { - color: rgb(168, 160, 149); - } - - .wy-form-message { - color: rgb(168, 160, 149); - } - - input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"] { - border-color: rgb(62, 68, 70); - box-shadow: rgb(43, 47, 49) 0px 1px 3px inset; - } - - input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus { - outline-color: initial; - border-color: rgb(123, 114, 101); - } - - input.no-focus:focus { - border-color: rgb(62, 68, 70) !important; - } - - input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { - outline-color: rgb(13, 113, 167); - } - - input[type="text"][disabled], input[type="password"][disabled], input[type="email"][disabled], input[type="url"][disabled], input[type="date"][disabled], input[type="month"][disabled], input[type="time"][disabled], input[type="datetime"][disabled], input[type="datetime-local"][disabled], input[type="week"][disabled], input[type="number"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="color"][disabled] { - background-color: rgb(27, 29, 30); - } - - input:focus:invalid, - textarea:focus:invalid, - select:focus:invalid { - color: rgb(233, 88, 73); - border-color: rgb(149, 31, 18); - } - - input:focus:invalid:focus, - textarea:focus:invalid:focus, - select:focus:invalid:focus { - border-color: rgb(149, 31, 18); - } - - input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus, input[type="checkbox"]:focus:invalid:focus { - outline-color: rgb(149, 31, 18); - } - - select, - textarea { - border-color: rgb(62, 68, 70); - box-shadow: rgb(43, 47, 49) 0px 1px 3px inset; - } - - select { - border-color: rgb(62, 68, 70); - background-color: rgb(24, 26, 27); - } - - select:focus, - textarea:focus { - outline-color: initial; - } - - select[disabled], - textarea[disabled], - input[readonly], - select[readonly], - textarea[readonly] { - background-color: rgb(27, 29, 30); - } - - .wy-checkbox, - .wy-radio { - color: rgb(192, 186, 178); - } - - .wy-input-prefix .wy-input-context, - .wy-input-suffix .wy-input-context { - background-color: rgb(27, 36, 36); - border-color: rgb(62, 68, 70); - color: rgb(168, 160, 149); - } - - .wy-input-suffix .wy-input-context { - border-left-color: initial; - } - - .wy-input-prefix .wy-input-context { - border-right-color: initial; - } - - .wy-switch::before { - background-image: initial; - background-color: rgb(53, 57, 59); - } - - .wy-switch::after { - background-image: initial; - background-color: rgb(82, 88, 92); - } - - .wy-switch span { - color: rgb(200, 195, 188); - } - - .wy-switch.active::before { - background-image: initial; - background-color: rgb(24, 106, 58); - } - - .wy-switch.active::after { - background-image: initial; - background-color: rgb(31, 139, 77); - } - - .wy-control-group.wy-control-group-error .wy-form-message, - .wy-control-group.wy-control-group-error > label { - color: rgb(233, 88, 73); - } - - .wy-control-group.wy-control-group-error input[type="text"], .wy-control-group.wy-control-group-error input[type="password"], .wy-control-group.wy-control-group-error input[type="email"], .wy-control-group.wy-control-group-error input[type="url"], .wy-control-group.wy-control-group-error input[type="date"], .wy-control-group.wy-control-group-error input[type="month"], .wy-control-group.wy-control-group-error input[type="time"], .wy-control-group.wy-control-group-error input[type="datetime"], .wy-control-group.wy-control-group-error input[type="datetime-local"], .wy-control-group.wy-control-group-error input[type="week"], .wy-control-group.wy-control-group-error input[type="number"], .wy-control-group.wy-control-group-error input[type="search"], .wy-control-group.wy-control-group-error input[type="tel"], .wy-control-group.wy-control-group-error input[type="color"] { - border-color: rgb(149, 31, 18); - } - - .wy-control-group.wy-control-group-error textarea { - border-color: rgb(149, 31, 18); - } - - .wy-inline-validate.wy-inline-validate-success .wy-input-context { - color: rgb(92, 218, 145); - } - - .wy-inline-validate.wy-inline-validate-danger .wy-input-context { - color: rgb(233, 88, 73); - } - - .wy-inline-validate.wy-inline-validate-warning .wy-input-context { - color: rgb(232, 138, 54); - } - - .wy-inline-validate.wy-inline-validate-info .wy-input-context { - color: rgb(84, 164, 217); - } - - .wy-table caption, - .rst-content table.docutils caption, - .rst-content table.field-list caption { - color: rgb(232, 230, 227); - } - - .wy-table thead, - .rst-content table.docutils thead, - .rst-content table.field-list thead { - color: rgb(232, 230, 227); - } - - .wy-table thead th, - .rst-content table.docutils thead th, - .rst-content table.field-list thead th { - border-bottom-color: rgb(56, 61, 63); - } - - .wy-table td, - .rst-content table.docutils td, - .rst-content table.field-list td { - background-color: transparent; - } - - .wy-table-secondary { - color: rgb(152, 143, 129); - } - - .wy-table-tertiary { - color: rgb(152, 143, 129); - } - - .wy-table-odd td, - .wy-table-striped tr:nth-child(2n-1) td, - .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { - background-color: rgb(27, 36, 36); - } - - .wy-table-backed { - background-color: rgb(27, 36, 36); - } - - .wy-table-bordered-all, - .rst-content table.docutils { - border-color: rgb(56, 61, 63); - } - - .wy-table-bordered-all td, - .rst-content table.docutils td { - border-bottom-color: rgb(56, 61, 63); - border-left-color: rgb(56, 61, 63); - } - - .wy-table-bordered { - border-color: rgb(56, 61, 63); - } - - .wy-table-bordered-rows td { - border-bottom-color: rgb(56, 61, 63); - } - - .wy-table-horizontal td, - .wy-table-horizontal th { - border-bottom-color: rgb(56, 61, 63); - } - - a { - color: rgb(84, 164, 217); - text-decoration-color: initial; - } - - a:hover { - color: rgb(68, 156, 214); - } - - a:visited { - color: rgb(164, 103, 188); - } - - body { - color: rgb(192, 186, 178); - background-image: initial; - background-color: rgb(33, 35, 37); - } - - .wy-text-strike { - text-decoration-color: initial; - } - - .wy-text-warning { - color: rgb(232, 138, 54) !important; - } - - a.wy-text-warning:hover { - color: rgb(236, 157, 87) !important; - } - - .wy-text-info { - color: rgb(84, 164, 217) !important; - } - - a.wy-text-info:hover { - color: rgb(79, 162, 216) !important; - } - - .wy-text-success { - color: rgb(92, 218, 145) !important; - } - - a.wy-text-success:hover { - color: rgb(73, 214, 133) !important; - } - - .wy-text-danger { - color: rgb(233, 88, 73) !important; - } - - a.wy-text-danger:hover { - color: rgb(237, 118, 104) !important; - } - - .wy-text-neutral { - color: rgb(192, 186, 178) !important; - } - - a.wy-text-neutral:hover { - color: rgb(176, 169, 159) !important; - } - - hr { - border-right-color: initial; - border-bottom-color: initial; - border-left-color: initial; - border-top-color: rgb(56, 61, 63); - } - - code, - .rst-content tt, - .rst-content code { - background-image: initial; - background-color: rgb(24, 26, 27); - border-color: rgb(56, 61, 63); - color: rgb(233, 88, 73); - } - - .wy-plain-list-disc, - .rst-content .section ul, - .rst-content .toctree-wrapper ul, - article ul { - list-style-image: initial; - } - - .wy-plain-list-disc li, - .rst-content .section ul li, - .rst-content .toctree-wrapper ul li, - article ul li { - list-style-image: initial; - } - - .wy-plain-list-disc li li, - .rst-content .section ul li li, - .rst-content .toctree-wrapper ul li li, - article ul li li { - list-style-image: initial; - } - - .wy-plain-list-disc li li li, - .rst-content .section ul li li li, - .rst-content .toctree-wrapper ul li li li, - article ul li li li { - list-style-image: initial; - } - - .wy-plain-list-disc li ol li, - .rst-content .section ul li ol li, - .rst-content .toctree-wrapper ul li ol li, - article ul li ol li { - list-style-image: initial; - } - - .wy-plain-list-decimal, - .rst-content .section ol, - .rst-content ol.arabic, - article ol { - list-style-image: initial; - } - - .wy-plain-list-decimal li, - .rst-content .section ol li, - .rst-content ol.arabic li, - article ol li { - list-style-image: initial; - } - - .wy-plain-list-decimal li ul li, - .rst-content .section ol li ul li, - .rst-content ol.arabic li ul li, - article ol li ul li { - list-style-image: initial; - } - - .wy-breadcrumbs li code, - .wy-breadcrumbs li .rst-content tt, - .rst-content .wy-breadcrumbs li tt { - border-color: initial; - background-image: none; - background-color: initial; - } - - .wy-breadcrumbs li code.literal, - .wy-breadcrumbs li .rst-content tt.literal, - .rst-content .wy-breadcrumbs li tt.literal { - color: rgb(192, 186, 178); - } - - .wy-breadcrumbs-extra { - color: rgb(184, 178, 169); - } - - .wy-menu a:hover { - text-decoration-color: initial; - } - - .wy-menu-horiz li:hover { - background-image: initial; - background-color: rgba(24, 26, 27, 0.1); - } - - .wy-menu-horiz li.divide-left { - border-left-color: rgb(119, 110, 98); - } - - .wy-menu-horiz li.divide-right { - border-right-color: rgb(119, 110, 98); - } - - .wy-menu-vertical header, - .wy-menu-vertical p.caption { - color: rgb(99, 161, 201); - } - - .wy-menu-vertical li.divide-top { - border-top-color: rgb(119, 110, 98); - } - - .wy-menu-vertical li.divide-bottom { - border-bottom-color: rgb(119, 110, 98); - } - - .wy-menu-vertical li.current { - background-image: initial; - background-color: rgb(40, 43, 45); - } - - .wy-menu-vertical li.current a { - color: rgb(152, 143, 129); - border-right-color: rgb(63, 69, 71); - } - - .wy-menu-vertical li.current a:hover { - background-image: initial; - background-color: rgb(47, 51, 53); - } - - .wy-menu-vertical li code, - .wy-menu-vertical li .rst-content tt, - .rst-content .wy-menu-vertical li tt { - border-color: initial; - background-image: inherit; - background-color: inherit; - color: inherit; - } - - .wy-menu-vertical li span.toctree-expand { - color: rgb(183, 177, 168); - } - - .wy-menu-vertical li.on a, - .wy-menu-vertical li.current > a { - color: rgb(192, 186, 178); - background-image: initial; - background-color: rgb(26, 28, 29); - border-color: initial; - } - - .wy-menu-vertical li.on a:hover, - .wy-menu-vertical li.current > a:hover { - background-image: initial; - background-color: rgb(26, 28, 29); - } - - .wy-menu-vertical li.on a:hover span.toctree-expand, - .wy-menu-vertical li.current > a:hover span.toctree-expand { - color: rgb(152, 143, 129); - } - - .wy-menu-vertical li.on a span.toctree-expand, - .wy-menu-vertical li.current > a span.toctree-expand { - color: rgb(200, 195, 188); - } - - .wy-menu-vertical li.toctree-l1.current > a { - border-bottom-color: rgb(63, 69, 71); - border-top-color: rgb(63, 69, 71); - } - - .wy-menu-vertical li.toctree-l2 a, - .wy-menu-vertical li.toctree-l3 a, - .wy-menu-vertical li.toctree-l4 a { - color: rgb(192, 186, 178); - } - - .wy-menu-vertical li.toctree-l2.current > a { - background-image: initial; - background-color: rgb(54, 59, 61); - } - - .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a { - background-image: initial; - background-color: rgb(54, 59, 61); - } - - .wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand { - color: rgb(152, 143, 129); - } - - .wy-menu-vertical li.toctree-l2 span.toctree-expand { - color: rgb(174, 167, 156); - } - - .wy-menu-vertical li.toctree-l3.current > a { - background-image: initial; - background-color: rgb(61, 66, 69); - } - - .wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a { - background-image: initial; - background-color: rgb(61, 66, 69); - } - - .wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand { - color: rgb(152, 143, 129); - } - - .wy-menu-vertical li.toctree-l3 span.toctree-expand { - color: rgb(166, 158, 146); - } - - .wy-menu-vertical li.toctree-l2.current a, - .wy-menu-vertical li.toctree-l3.current a { - background-color: #363636; - } - - .wy-menu-vertical li ul li a { - color: rgb(208, 204, 198); - } - - .wy-menu-vertical a { - color: rgb(208, 204, 198); - } - - .wy-menu-vertical a:hover { - background-color: rgb(57, 62, 64); - } - - .wy-menu-vertical a:hover span.toctree-expand { - color: rgb(208, 204, 198); - } - - .wy-menu-vertical a:active { - background-color: rgb(33, 102, 148); - color: rgb(232, 230, 227); - } - - .wy-menu-vertical a:active span.toctree-expand { - color: rgb(232, 230, 227); - } - - .wy-side-nav-search { - background-color: rgb(33, 102, 148); - color: rgb(230, 228, 225); - } - - .wy-side-nav-search input[type="text"] { - border-color: rgb(35, 111, 160); - } - - .wy-side-nav-search img { - background-color: rgb(33, 102, 148); - } - - .wy-side-nav-search > a, - .wy-side-nav-search .wy-dropdown > a { - color: rgb(230, 228, 225); - } - - .wy-side-nav-search > a:hover, - .wy-side-nav-search .wy-dropdown > a:hover { - background-image: initial; - background-color: rgba(24, 26, 27, 0.1); - } - - .wy-side-nav-search > a img.logo, - .wy-side-nav-search .wy-dropdown > a img.logo { - background-image: initial; - background-color: transparent; - } - - .wy-side-nav-search > div.version { - color: rgba(232, 230, 227, 0.3); - } - - .wy-nav .wy-menu-vertical header { - color: rgb(84, 164, 217); - } - - .wy-nav .wy-menu-vertical a { - color: rgb(184, 178, 169); - } - - .wy-nav .wy-menu-vertical a:hover { - background-color: rgb(33, 102, 148); - color: rgb(232, 230, 227); - } - - .wy-body-for-nav { - background-image: initial; - background-color: rgb(24, 26, 27); - } - - .wy-nav-side { - color: rgb(169, 161, 150); - background-image: initial; - background-color: rgb(38, 41, 43); - } - - .wy-nav-top { - background-image: initial; - background-color: rgb(33, 102, 148); - color: rgb(232, 230, 227); - } - - .wy-nav-top a { - color: rgb(232, 230, 227); - } - - .wy-nav-top img { - background-color: rgb(33, 102, 148); - } - - .wy-nav-content-wrap { - background-image: initial; - background-color: rgb(26, 28, 29); - } - - .wy-body-mask { - background-image: initial; - background-color: rgba(0, 0, 0, 0.2); - } - - footer { - color: rgb(152, 143, 129); - } - - footer span.commit code, - footer span.commit .rst-content tt, - .rst-content footer span.commit tt { - background-image: none; - background-color: initial; - border-color: initial; - color: rgb(152, 143, 129); - } - - #search-results .search li { - border-bottom-color: rgb(56, 61, 63); - } - - #search-results .search li:first-child { - border-top-color: rgb(56, 61, 63); - } - - #search-results .context { - color: rgb(152, 143, 129); - } - - @media screen and (min-width: 1100px) { - .wy-nav-content-wrap { - background-image: initial; - background-color: rgba(0, 0, 0, 0.05); - } - - .wy-nav-content { - background-image: initial; - background-color: rgb(26, 28, 29); - } - } - .rst-versions { - color: rgb(230, 228, 225); - background-image: initial; - background-color: rgb(23, 24, 25); - } - - .rst-versions a { - color: rgb(84, 164, 217); - text-decoration-color: initial; - } - - .rst-versions .rst-current-version { - background-color: rgb(29, 31, 32); - color: rgb(92, 218, 145); - } - - .rst-versions .rst-current-version .fa, - .rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand, - .wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand, - .rst-versions .rst-current-version .rst-content .admonition-title, - .rst-content .rst-versions .rst-current-version .admonition-title, - .rst-versions .rst-current-version .rst-content h1 .headerlink, - .rst-content h1 .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content h2 .headerlink, - .rst-content h2 .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content h3 .headerlink, - .rst-content h3 .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content h4 .headerlink, - .rst-content h4 .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content h5 .headerlink, - .rst-content h5 .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content h6 .headerlink, - .rst-content h6 .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content dl dt .headerlink, - .rst-content dl dt .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content p.caption .headerlink, - .rst-content p.caption .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content table > caption .headerlink, - .rst-content table > caption .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content .code-block-caption .headerlink, - .rst-content .code-block-caption .rst-versions .rst-current-version .headerlink, - .rst-versions .rst-current-version .rst-content tt.download span:first-child, - .rst-content tt.download .rst-versions .rst-current-version span:first-child, - .rst-versions .rst-current-version .rst-content code.download span:first-child, - .rst-content code.download .rst-versions .rst-current-version span:first-child, - .rst-versions .rst-current-version .icon { - color: rgb(230, 228, 225); - } - - .rst-versions .rst-current-version.rst-out-of-date { - background-color: rgb(162, 33, 20); - color: rgb(232, 230, 227); - } - - .rst-versions .rst-current-version.rst-active-old-version { - background-color: rgb(192, 156, 11); - color: rgb(232, 230, 227); - } - - .rst-versions .rst-other-versions { - color: rgb(152, 143, 129); - } - - .rst-versions .rst-other-versions hr { - border-right-color: initial; - border-bottom-color: initial; - border-left-color: initial; - border-top-color: rgb(119, 111, 98); - } - - .rst-versions .rst-other-versions dd a { - color: rgb(230, 228, 225); - } - - .rst-versions.rst-badge { - border-color: initial; - } - - .rst-content abbr[title] { - text-decoration-color: initial; - } - - .rst-content.style-external-links a.reference.external::after { - color: rgb(184, 178, 169); - } - - .rst-content pre.literal-block, .rst-content div[class^="highlight"] { - border-color: rgb(56, 61, 63); - } - - .rst-content pre.literal-block div[class^="highlight"], .rst-content div[class^="highlight"] div[class^="highlight"] { - border-color: initial; - } - - .rst-content .linenodiv pre { - border-right-color: rgb(54, 59, 61); - } - - .rst-content .admonition table { - border-color: rgba(140, 130, 115, 0.1); - } - - .rst-content .admonition table td, - .rst-content .admonition table th { - background-image: initial !important; - background-color: transparent !important; - border-color: rgba(140, 130, 115, 0.1) !important; - } - - .rst-content .section ol.loweralpha, - .rst-content .section ol.loweralpha li { - list-style-image: initial; - } - - .rst-content .section ol.upperalpha, - .rst-content .section ol.upperalpha li { - list-style-image: initial; - } - - .rst-content .toc-backref { - color: rgb(192, 186, 178); - } - - .rst-content .sidebar { - background-image: initial; - background-color: rgb(27, 36, 36); - border-color: rgb(56, 61, 63); - } - - .rst-content .sidebar .sidebar-title { - background-image: initial; - background-color: rgb(40, 43, 45); - } - - .rst-content .highlighted { - background-image: initial; - background-color: rgb(192, 156, 11); - } - - .rst-content table.docutils.citation, - .rst-content table.docutils.footnote { - background-image: none; - background-color: initial; - border-color: initial; - color: rgb(152, 143, 129); - } - - .rst-content table.docutils.citation td, - .rst-content table.docutils.citation tr, - .rst-content table.docutils.footnote td, - .rst-content table.docutils.footnote tr { - border-color: initial; - background-color: transparent !important; - } - - .rst-content table.docutils.citation tt, - .rst-content table.docutils.citation code, - .rst-content table.docutils.footnote tt, - .rst-content table.docutils.footnote code { - color: rgb(178, 172, 162); - } - - .rst-content table.docutils th { - border-color: rgb(56, 61, 63); - } - - .rst-content table.field-list { - border-color: initial; - } - - .rst-content table.field-list td { - border-color: initial; - } - - .rst-content tt, - .rst-content tt, - .rst-content code { - color: rgb(232, 230, 227); - } - - .rst-content tt.literal, - .rst-content tt.literal, - .rst-content code.literal { - color: rgb(233, 88, 73); - } - - .rst-content tt.xref, - a .rst-content tt, - .rst-content tt.xref, - .rst-content code.xref, - a .rst-content tt, - a .rst-content code { - color: rgb(192, 186, 178); - } - - .rst-content a tt, - .rst-content a tt, - .rst-content a code { - color: rgb(84, 164, 217); - } - - .rst-content dl:not(.docutils) dt { - background-image: initial; - background-color: rgb(32, 35, 36); - color: rgb(84, 164, 217); - border-top-color: rgb(28, 89, 128); - } - - .rst-content dl:not(.docutils) dt::before { - color: rgb(109, 178, 223); - } - - .rst-content dl:not(.docutils) dt .headerlink { - color: rgb(192, 186, 178); - } - - .rst-content dl:not(.docutils) dl dt { - border-top-color: initial; - border-right-color: initial; - border-bottom-color: initial; - border-left-color: rgb(62, 68, 70); - background-image: initial; - background-color: rgb(32, 35, 37); - color: rgb(178, 172, 162); - } - - .rst-content dl:not(.docutils) dl dt .headerlink { - color: rgb(192, 186, 178); - } - - .rst-content dl:not(.docutils) tt.descname, - .rst-content dl:not(.docutils) tt.descclassname, - .rst-content dl:not(.docutils) tt.descname, - .rst-content dl:not(.docutils) code.descname, - .rst-content dl:not(.docutils) tt.descclassname, - .rst-content dl:not(.docutils) code.descclassname { - background-color: transparent; - border-color: initial; - } - - .rst-content dl:not(.docutils) .optional { - color: rgb(232, 230, 227); - } - - .rst-content .viewcode-link, - .rst-content .viewcode-back { - color: rgb(92, 218, 145); - } - - .rst-content tt.download, - .rst-content code.download { - background-image: inherit; - background-color: inherit; - color: inherit; - border-color: inherit; - } - - .rst-content .guilabel { - border-color: rgb(27, 84, 122); - background-image: initial; - background-color: rgb(32, 35, 36); - } - - span[id*="MathJax-Span"] { - color: rgb(192, 186, 178); - } - - .highlight .hll { - background-color: rgb(82, 82, 0); - } - - .highlight { - background-image: initial; - background-color: rgb(61, 82, 0); - } - - .highlight .c { - color: rgb(119, 179, 195); - } - - .highlight .err { - border-color: rgb(179, 0, 0); - } - - .highlight .k { - color: rgb(126, 255, 163); - } - - .highlight .o { - color: rgb(168, 160, 149); - } - - .highlight .ch { - color: rgb(119, 179, 195); - } - - .highlight .cm { - color: rgb(119, 179, 195); - } - - .highlight .cp { - color: rgb(126, 255, 163); - } - - .highlight .cpf { - color: rgb(119, 179, 195); - } - - .highlight .c1 { - color: rgb(119, 179, 195); - } - - .highlight .cs { - color: rgb(119, 179, 195); - background-color: rgb(60, 0, 0); - } - - .highlight .gd { - color: rgb(255, 92, 92); - } - - .highlight .gr { - color: rgb(255, 26, 26); - } - - .highlight .gh { - color: rgb(127, 174, 255); - } - - .highlight .gi { - color: rgb(92, 255, 92); - } - - .highlight .go { - color: rgb(200, 195, 188); - } - - .highlight .gp { - color: rgb(246, 147, 68); - } - - .highlight .gu { - color: rgb(255, 114, 255); - } - - .highlight .gt { - color: rgb(71, 160, 255); - } - - .highlight .kc { - color: rgb(126, 255, 163); - } - - .highlight .kd { - color: rgb(126, 255, 163); - } - - .highlight .kn { - color: rgb(126, 255, 163); - } - - .highlight .kp { - color: rgb(126, 255, 163); - } - - .highlight .kr { - color: rgb(126, 255, 163); - } - - .highlight .kt { - color: rgb(255, 137, 103); - } - - .highlight .m { - color: rgb(125, 222, 174); - } - - .highlight .s { - color: rgb(123, 166, 202); - } - - .highlight .na { - color: rgb(123, 166, 202); - } - - .highlight .nb { - color: rgb(126, 255, 163); - } - - .highlight .nc { - color: rgb(81, 194, 242); - } - - .highlight .no { - color: rgb(103, 177, 215); - } - - .highlight .nd { - color: rgb(178, 172, 162); - } - - .highlight .ni { - color: rgb(217, 100, 73); - } - - .highlight .ne { - color: rgb(126, 255, 163); - } - - .highlight .nf { - color: rgb(131, 186, 249); - } - - .highlight .nl { - color: rgb(137, 193, 255); - } - - .highlight .nn { - color: rgb(81, 194, 242); - } - - .highlight .nt { - color: rgb(138, 191, 249); - } - - .highlight .nv { - color: rgb(190, 103, 215); - } - - .highlight .ow { - color: rgb(126, 255, 163); - } - - .highlight .w { - color: rgb(189, 183, 175); - } - - .highlight .mb { - color: rgb(125, 222, 174); - } - - .highlight .mf { - color: rgb(125, 222, 174); - } - - .highlight .mh { - color: rgb(125, 222, 174); - } - - .highlight .mi { - color: rgb(125, 222, 174); - } - - .highlight .mo { - color: rgb(125, 222, 174); - } - - .highlight .sa { - color: rgb(123, 166, 202); - } - - .highlight .sb { - color: rgb(123, 166, 202); - } - - .highlight .sc { - color: rgb(123, 166, 202); - } - - .highlight .dl { - color: rgb(123, 166, 202); - } - - .highlight .sd { - color: rgb(123, 166, 202); - } - - .highlight .s2 { - color: rgb(123, 166, 202); - } - - .highlight .se { - color: rgb(123, 166, 202); - } - - .highlight .sh { - color: rgb(123, 166, 202); - } - - .highlight .si { - color: rgb(117, 168, 209); - } - - .highlight .sx { - color: rgb(246, 147, 68); - } - - .highlight .sr { - color: rgb(133, 182, 224); - } - - .highlight .s1 { - color: rgb(123, 166, 202); - } - - .highlight .ss { - color: rgb(188, 230, 128); - } - - .highlight .bp { - color: rgb(126, 255, 163); - } - - .highlight .fm { - color: rgb(131, 186, 249); - } - - .highlight .vc { - color: rgb(190, 103, 215); - } - - .highlight .vg { - color: rgb(190, 103, 215); - } - - .highlight .vi { - color: rgb(190, 103, 215); - } - - .highlight .vm { - color: rgb(190, 103, 215); - } - - .highlight .il { - color: rgb(125, 222, 174); - } - - .rst-other-versions a { - border-color: initial; - } - - .ethical-sidebar .ethical-image-link, - .ethical-footer .ethical-image-link { - border-color: initial; - } - - .ethical-sidebar, - .ethical-footer { - background-color: rgb(34, 36, 38); - border-color: rgb(62, 68, 70); - color: rgb(226, 223, 219); - } - - .ethical-sidebar ul { - list-style-image: initial; - } - - .ethical-sidebar ul li { - background-color: rgb(5, 77, 121); - color: rgb(232, 230, 227); - } - - .ethical-sidebar a, - .ethical-sidebar a:visited, - .ethical-sidebar a:hover, - .ethical-sidebar a:active, - .ethical-footer a, - .ethical-footer a:visited, - .ethical-footer a:hover, - .ethical-footer a:active { - color: rgb(226, 223, 219); - text-decoration-color: initial !important; - border-bottom-color: initial !important; - } - - .ethical-callout a { - color: rgb(161, 153, 141) !important; - text-decoration-color: initial !important; - } - - .ethical-fixedfooter { - background-color: rgb(34, 36, 38); - border-top-color: rgb(66, 72, 74); - color: rgb(192, 186, 178); - } - - .ethical-fixedfooter .ethical-text::before { - background-color: rgb(61, 140, 64); - color: rgb(232, 230, 227); - } - - .ethical-fixedfooter .ethical-callout { - color: rgb(168, 160, 149); - } - - .ethical-fixedfooter a, - .ethical-fixedfooter a:hover, - .ethical-fixedfooter a:active, - .ethical-fixedfooter a:visited { - color: rgb(192, 186, 178); - text-decoration-color: initial; - } - - .ethical-rtd .ethical-sidebar { - color: rgb(184, 178, 169); - } - - .ethical-alabaster a.ethical-image-link { - border-color: initial !important; - } - - .ethical-dark-theme .ethical-sidebar { - background-color: rgb(58, 62, 65); - border-color: rgb(75, 81, 84); - color: rgb(193, 188, 180) !important; - } - - .ethical-dark-theme a, - .ethical-dark-theme a:visited { - color: rgb(216, 213, 208) !important; - border-bottom-color: initial !important; - } - - .ethical-dark-theme .ethical-callout a { - color: rgb(184, 178, 169) !important; - } - - .keep-us-sustainable { - border-color: rgb(87, 133, 38); - } - - .keep-us-sustainable a, - .keep-us-sustainable a:hover, - .keep-us-sustainable a:visited { - text-decoration-color: initial; - } - - .wy-body-for-nav .keep-us-sustainable { - color: rgb(184, 178, 169); - } - - .wy-body-for-nav .keep-us-sustainable a { - color: rgb(222, 219, 215); - } - - /* For black-on-white/transparent images at handbook/text-anchors.html */ - #text-anchors img { + body[data-theme="auto"] #text-anchors img { filter: invert(1) brightness(0.85) hue-rotate(-60deg); } } diff --git a/docs/resources/css/light.css b/docs/resources/css/light.css deleted file mode 100644 index 04edd7b16b9..00000000000 --- a/docs/resources/css/light.css +++ /dev/null @@ -1,8 +0,0 @@ -@media (prefers-color-scheme: light) { - - .wy-menu-vertical li.toctree-l2.current a, - .wy-menu-vertical li.toctree-l3.current a { - background-color: #c9c9c9; - } - -} diff --git a/docs/resources/css/styles.css b/docs/resources/css/styles.css deleted file mode 100644 index 111f84085b7..00000000000 --- a/docs/resources/css/styles.css +++ /dev/null @@ -1,8 +0,0 @@ -th p { - margin-bottom: 0; -} - -.rst-content tr .line-block { - font-size: 1rem; - margin-bottom: 0; -} diff --git a/docs/resources/js/script.js b/docs/resources/js/script.js deleted file mode 100644 index 5cb6494ea59..00000000000 --- a/docs/resources/js/script.js +++ /dev/null @@ -1,58 +0,0 @@ -jQuery(document).ready(function ($) { - setTimeout(function () { - var sectionID = 'base'; - var search = function ($section, $sidebarItem) { - $section.children('.section, .function, .method').each(function () { - if ($(this).hasClass('section')) { - sectionID = $(this).attr('id'); - search($(this), $sidebarItem.parent().find('[href="#'+sectionID+'"]')); - } else { - var $dt = $(this).children('dt'); - var id = $dt.attr('id'); - if (id === undefined) { - return; - } - - var $functionsUL = $sidebarItem.siblings('[data-sectionID='+sectionID+']'); - if (!$functionsUL.length) { - $functionsUL = $('