Merge branch 'master' into gitignore-review
|
@ -18,9 +18,13 @@ environment:
|
|||
PIP_DIR: bin
|
||||
VENV: YES
|
||||
- PYTHON: C:/Python27-x64
|
||||
- PYTHON: C:/Python34
|
||||
- PYTHON: C:/Python37
|
||||
- PYTHON: C:/Python27
|
||||
- PYTHON: C:/Python34-x64
|
||||
- PYTHON: C:/Python37-x64
|
||||
- PYTHON: C:/Python36
|
||||
- PYTHON: C:/Python36-x64
|
||||
- PYTHON: C:/Python35
|
||||
- PYTHON: C:/Python35-x64
|
||||
- PYTHON: C:/msys64/mingw32
|
||||
EXECUTABLE: bin/python3
|
||||
PIP_DIR: bin
|
||||
|
|
1
.gitattributes
vendored
|
@ -1,2 +1,3 @@
|
|||
*.eps binary
|
||||
*.ppm binary
|
||||
*.container binary
|
||||
|
|
3
.gitignore
vendored
|
@ -62,6 +62,9 @@ pip-delete-this-directory.txt
|
|||
*.log
|
||||
*.pot
|
||||
|
||||
# viewdoc output
|
||||
.long-description.html
|
||||
|
||||
# Vim cruft
|
||||
.*.swp
|
||||
|
||||
|
|
2
.readthedocs.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
python:
|
||||
pip_install: true
|
84
.travis.yml
|
@ -1,74 +1,102 @@
|
|||
dist: xenial
|
||||
sudo: required
|
||||
language: python
|
||||
cache: pip
|
||||
|
||||
notifications:
|
||||
irc: "chat.freenode.net#pil"
|
||||
|
||||
# Run slow PyPy* first, to give them a headstart and reduce waiting time.
|
||||
# Run fast lint first to get fast feedback.
|
||||
# Run slow PyPy* next, to give them a headstart and reduce waiting time.
|
||||
# Run latest 3.x and 2.x next, to get quick compatibility results.
|
||||
# Then run the remainder, with fastest Docker jobs last.
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- python: "pypy"
|
||||
dist: trusty
|
||||
- python: "pypy3"
|
||||
dist: trusty
|
||||
- python: "3.6"
|
||||
name: "Lint"
|
||||
env: LINT="true"
|
||||
- python: "pypy2.7-6.0"
|
||||
name: "PyPy2 Xenial"
|
||||
dist: xenial
|
||||
- python: "pypy3.5-6.0"
|
||||
name: "PyPy3 Xenial"
|
||||
dist: xenial
|
||||
- python: '3.7'
|
||||
name: "3.7 Xenial"
|
||||
- python: '2.7'
|
||||
name: "2.7 Xenial"
|
||||
- python: '2.7'
|
||||
name: "2.7 Trusty"
|
||||
dist: trusty
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
name: "2.7_with_system_site_packages Xenial"
|
||||
services: xvfb
|
||||
- python: "2.7_with_system_site_packages" # For PyQt4
|
||||
name: "2.7_with_system_site_packages Trusty"
|
||||
dist: trusty
|
||||
- python: '3.6'
|
||||
name: "3.6 Xenial"
|
||||
- python: '3.6'
|
||||
name: "3.6 Trusty PYTHONOPTIMIZE=1"
|
||||
dist: trusty
|
||||
env: PYTHONOPTIMIZE=1
|
||||
- python: '3.5'
|
||||
name: "3.5 Xenial"
|
||||
- python: '3.5'
|
||||
name: "3.5 Trusty PYTHONOPTIMIZE=2"
|
||||
dist: trusty
|
||||
env: PYTHONOPTIMIZE=2
|
||||
- python: '3.4'
|
||||
dist: trusty
|
||||
- env: DOCKER="alpine" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="arch" DOCKER_TAG="pytest" # contains PyQt5
|
||||
- env: DOCKER="ubuntu-trusty-x86" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="ubuntu-xenial-amd64" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="debian-stretch-x86" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="centos-6-amd64" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="centos-7-amd64" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="amazon-1-amd64" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="amazon-2-amd64" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="fedora-26-amd64" DOCKER_TAG="pytest"
|
||||
- env: DOCKER="fedora-27-amd64" DOCKER_TAG="pytest"
|
||||
- python: "3.8-dev"
|
||||
name: "3.8-dev Xenial"
|
||||
- env: DOCKER="alpine" DOCKER_TAG="master"
|
||||
- env: DOCKER="arch" DOCKER_TAG="master" # contains PyQt5
|
||||
- env: DOCKER="ubuntu-trusty-x86" DOCKER_TAG="master"
|
||||
- env: DOCKER="ubuntu-xenial-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="debian-stretch-x86" DOCKER_TAG="master"
|
||||
- env: DOCKER="centos-6-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="centos-7-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="amazon-1-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="amazon-2-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-28-amd64" DOCKER_TAG="master"
|
||||
- env: DOCKER="fedora-29-amd64" DOCKER_TAG="master"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
install:
|
||||
- if [ "$DOCKER" == "" ]; then .travis/install.sh; fi
|
||||
|
||||
before_install:
|
||||
- if [ "$DOCKER" ]; then travis_retry docker pull pythonpillow/$DOCKER:$DOCKER_TAG; fi
|
||||
|
||||
install:
|
||||
- |
|
||||
if [ "$LINT" == "true" ]; then
|
||||
pip install tox
|
||||
elif [ "$DOCKER" == "" ]; then
|
||||
.travis/install.sh;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
# Qt needs a display for some of the tests, and it's only run on the system site packages install
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
- |
|
||||
if [ "$TRAVIS_JOB_NAME" == "2.7_with_system_site_packages Trusty" ]; then
|
||||
export DISPLAY=:99.0
|
||||
sh -e /etc/init.d/xvfb start
|
||||
fi
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ "$DOCKER" == "" ]; then
|
||||
- |
|
||||
if [ "$LINT" == "true" ]; then
|
||||
tox -e lint
|
||||
elif [ "$DOCKER" == "" ]; then
|
||||
.travis/script.sh
|
||||
else
|
||||
elif [ "$DOCKER" ]; then
|
||||
# the Pillow user in the docker container is UID 1000
|
||||
sudo chown -R 1000 $TRAVIS_BUILD_DIR
|
||||
docker run -v $TRAVIS_BUILD_DIR:/Pillow pythonpillow/$DOCKER:$DOCKER_TAG
|
||||
fi
|
||||
|
||||
after_success:
|
||||
- .travis/after_success.sh
|
||||
- |
|
||||
if [ "$LINT" == "" ]; then
|
||||
.travis/after_success.sh
|
||||
fi
|
||||
|
|
|
@ -15,15 +15,6 @@ pip install coveralls-merge
|
|||
coveralls-merge coverage.c.json
|
||||
codecov
|
||||
|
||||
if [ "$DOCKER" == "" ]; then
|
||||
pip install pyflakes pycodestyle
|
||||
pyflakes *.py | tee >(wc -l)
|
||||
pyflakes src/PIL/*.py | tee >(wc -l)
|
||||
pyflakes Tests/*.py | tee >(wc -l)
|
||||
pycodestyle --statistics --count src/PIL/*.py
|
||||
pycodestyle --statistics --count Tests/*.py
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ] && [ "$DOCKER" == "" ]; then
|
||||
# Coverage and quality reports on just the latest diff.
|
||||
# (Installation is very slow on Py3, so just do it for Py2.)
|
||||
|
|
196
CHANGES.rst
|
@ -2,9 +2,201 @@
|
|||
Changelog (Pillow)
|
||||
==================
|
||||
|
||||
5.3.0 (unreleased)
|
||||
6.0.0 (unreleased)
|
||||
------------------
|
||||
|
||||
- Remove unnecessary unittest.main() boilerplate from test files #3631
|
||||
[jdufresne]
|
||||
|
||||
- Exif: Seek to IFD offset #3584
|
||||
[radarhere]
|
||||
|
||||
- Deprecate PIL.*ImagePlugin.__version__ attributes #3628
|
||||
[jdufresne]
|
||||
|
||||
- Docs: Add note about ImageDraw operations that exceed image bounds #3620
|
||||
[radarhere]
|
||||
|
||||
- Allow for unknown PNG chunks after image data #3558
|
||||
[radarhere]
|
||||
|
||||
- Changed EPS subprocess stdin from devnull to None #3611
|
||||
[radarhere]
|
||||
|
||||
- Fix possible integer overflow #3609
|
||||
[cgohlke]
|
||||
|
||||
- Catch BaseException for resource cleanup handlers #3574
|
||||
[jdufresne]
|
||||
|
||||
- Improve pytest configuration to allow specific tests as CLI args #3579
|
||||
[jdufresne]
|
||||
|
||||
- Drop support for Python 3.4 #3596
|
||||
[hugovk]
|
||||
|
||||
- Remove deprecated PIL.OleFileIO #3598
|
||||
[hugovk]
|
||||
|
||||
- Remove deprecated ImageOps undocumented functions #3599
|
||||
[hugovk]
|
||||
|
||||
- Depends: Update libwebp to 1.0.2 #3602
|
||||
[radarhere]
|
||||
|
||||
- Detect MIME types #3525
|
||||
[radarhere]
|
||||
|
||||
5.4.1 (2019-01-06)
|
||||
------------------
|
||||
|
||||
- File closing: Only close __fp if not fp #3540
|
||||
[radarhere]
|
||||
|
||||
- Fix build for Termux #3529
|
||||
[pslacerda]
|
||||
|
||||
- PNG: Detect MIME types #3525
|
||||
[radarhere]
|
||||
|
||||
- PNG: Handle IDAT chunks after image end #3532
|
||||
[radarhere]
|
||||
|
||||
5.4.0 (2019-01-01)
|
||||
------------------
|
||||
|
||||
- Docs: Improved ImageChops documentation #3522
|
||||
[radarhere]
|
||||
|
||||
- Allow RGB and RGBA values for P image putpixel #3519
|
||||
[radarhere]
|
||||
|
||||
- Add APNG extension to PNG plugin #3501
|
||||
[pirate486743186, radarhere]
|
||||
|
||||
- Lookup ld.so.cache instead of hardcoding search paths #3245
|
||||
[pslacerda]
|
||||
|
||||
- Added custom string TIFF tags #3513
|
||||
[radarhere]
|
||||
|
||||
- Improve setup.py configuration #3395
|
||||
[diorcety]
|
||||
|
||||
- Read textual chunks located after IDAT chunks for PNG #3506
|
||||
[radarhere]
|
||||
|
||||
- Performance: Don't try to hash value if enum is empty #3503
|
||||
[Glandos]
|
||||
|
||||
- Added custom int and float TIFF tags #3350
|
||||
[radarhere]
|
||||
|
||||
- Fixes for issues reported by static code analysis #3393
|
||||
[frenzymadness]
|
||||
|
||||
- GIF: Wait until mode is normalized to copy im.info into encoderinfo #3187
|
||||
[radarhere]
|
||||
|
||||
- Docs: Add page of deprecations and removals #3486
|
||||
[hugovk]
|
||||
|
||||
- Travis CI: Upgrade PyPy from 5.8.0 to 6.0 #3488
|
||||
[hugovk]
|
||||
|
||||
- Travis CI: Allow lint job to fail #3467
|
||||
[hugovk]
|
||||
|
||||
- Resolve __fp when closing and deleting #3261
|
||||
[radarhere]
|
||||
|
||||
- Close exclusive fp before discarding #3461
|
||||
[radarhere]
|
||||
|
||||
- Updated open files documentation #3490
|
||||
[radarhere]
|
||||
|
||||
- Added libjpeg_turbo to check_feature #3493
|
||||
[radarhere]
|
||||
|
||||
- Change color table index background to tuple when saving as WebP #3471
|
||||
[radarhere]
|
||||
|
||||
- Allow arbitrary number of comment extension subblocks #3479
|
||||
[radarhere]
|
||||
|
||||
- Ensure previous FLI frame is loaded before seeking to the next #3478
|
||||
[radarhere]
|
||||
|
||||
- ImageShow improvements #3450
|
||||
[radarhere]
|
||||
|
||||
- Depends: Update libimagequant to 2.12.2 #3442, libtiff to 4.0.10 #3458, libwebp to 1.0.1 #3468, Tk Tcl to 8.6.9 #3465
|
||||
[radarhere]
|
||||
|
||||
- Check quality_layers type #3464
|
||||
[radarhere]
|
||||
|
||||
- Add context manager, __del__ and close methods to TarIO #3455
|
||||
[radarhere]
|
||||
|
||||
- Test: Do not play sound when running screencapture command #3454
|
||||
[radarhere]
|
||||
|
||||
- Close exclusive fp on open exception #3456
|
||||
[radarhere]
|
||||
|
||||
- Only close existing fp in WebP if fp is exclusive #3418
|
||||
[radarhere]
|
||||
|
||||
- Docs: Re-add the downloads badge #3443
|
||||
[hugovk]
|
||||
|
||||
- Added negative index to PixelAccess #3406
|
||||
[Nazime]
|
||||
|
||||
- Change tuple background to global color table index when saving as GIF #3385
|
||||
[radarhere]
|
||||
|
||||
- Test: Improved ImageGrab tests #3424
|
||||
[radarhere]
|
||||
|
||||
- Flake8 fixes #3422, #3440
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Only ask for YCbCr->RGB libtiff conversion for jpeg-compressed tiffs #3417
|
||||
[kkopachev]
|
||||
|
||||
- Optimise ImageOps.fit by combining resize and crop #3409
|
||||
[homm]
|
||||
|
||||
5.3.0 (2018-10-01)
|
||||
------------------
|
||||
|
||||
- Changed Image size property to be read-only by default #3203
|
||||
[radarhere]
|
||||
|
||||
- Add warnings if image file identification fails due to lack of WebP support #3169
|
||||
[radarhere, hugovk]
|
||||
|
||||
- Hide the Ghostscript progress dialog popup on Windows #3378
|
||||
[hugovk]
|
||||
|
||||
- Adding support to reading tiled and YcbCr jpeg tiffs through libtiff #3227
|
||||
[kkopachev]
|
||||
|
||||
- Fixed None as TIFF compression argument #3310
|
||||
[radarhere]
|
||||
|
||||
- Changed GIF seek to remove previous info items #3324
|
||||
[radarhere]
|
||||
|
||||
- Improved PDF document info #3274
|
||||
[radarhere]
|
||||
|
||||
- Add line width parameter to rectangle and ellipse-based shapes #3094
|
||||
[hugovk, radarhere]
|
||||
|
||||
- Fixed decompression bomb check in _crop #3313
|
||||
[dinkolubina, hugovk]
|
||||
|
||||
|
@ -3850,7 +4042,7 @@ Pre-fork
|
|||
(1.1.3 final released)
|
||||
|
||||
+ Made setup.py look for old versions of zlib. For some back-
|
||||
ground, see: http://www.gzip.org/zlib/advisory-2002-03-11.txt
|
||||
ground, see: https://zlib.net/advisory-2002-03-11.txt
|
||||
|
||||
(1.1.3c2 released)
|
||||
|
||||
|
|
2
LICENSE
|
@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is
|
|||
|
||||
Pillow is the friendly PIL fork. It is
|
||||
|
||||
Copyright © 2010-2018 by Alex Clark and contributors
|
||||
Copyright © 2010-2019 by Alex Clark and contributors
|
||||
|
||||
Like PIL, Pillow is licensed under the open source PIL Software License:
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ exclude .coveragerc
|
|||
exclude .codecov.yml
|
||||
exclude .editorconfig
|
||||
exclude .landscape.yaml
|
||||
exclude .readthedocs.yml
|
||||
exclude .travis
|
||||
exclude .travis/*
|
||||
exclude tox.ini
|
||||
|
|
11
README.rst
|
@ -16,7 +16,7 @@ Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.
|
|||
* - tests
|
||||
- |linux| |macos| |windows| |coverage|
|
||||
* - package
|
||||
- |zenodo| |version|
|
||||
- |zenodo| |tidelift| |version| |downloads|
|
||||
* - social
|
||||
- |gitter| |twitter|
|
||||
|
||||
|
@ -28,7 +28,7 @@ Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.
|
|||
:target: https://travis-ci.org/python-pillow/Pillow
|
||||
:alt: Travis CI build status (Linux)
|
||||
|
||||
.. |macos| image:: https://img.shields.io/travis/python-pillow/pillow-wheels/latest.svg?label=macOS%20build
|
||||
.. |macos| image:: https://img.shields.io/travis/python-pillow/pillow-wheels/master.svg?label=macOS%20build
|
||||
:target: https://travis-ci.org/python-pillow/pillow-wheels
|
||||
:alt: Travis CI build status (macOS)
|
||||
|
||||
|
@ -43,10 +43,17 @@ Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.
|
|||
.. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg
|
||||
:target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow
|
||||
|
||||
.. |tidelift| image:: https://tidelift.com/badges/github/python-pillow/Pillow?style=flat
|
||||
:target: https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=referral&utm_campaign=readme
|
||||
|
||||
.. |version| image:: https://img.shields.io/pypi/v/pillow.svg
|
||||
:target: https://pypi.org/project/Pillow/
|
||||
:alt: Latest PyPI version
|
||||
|
||||
.. |downloads| image:: https://img.shields.io/pypi/dm/pillow.svg
|
||||
:target: https://pypi.org/project/Pillow/
|
||||
:alt: Number of PyPI downloads
|
||||
|
||||
.. |gitter| image:: https://badges.gitter.im/python-pillow/Pillow.svg
|
||||
:target: https://gitter.im/python-pillow/Pillow?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||
:alt: Join the chat at https://gitter.im/python-pillow/Pillow
|
||||
|
|
101
RELEASING.md
|
@ -5,52 +5,52 @@
|
|||
Released quarterly on the first day of January, April, July, October.
|
||||
|
||||
* [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/3154
|
||||
* [ ] Develop and prepare release in ``master`` branch.
|
||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) and [AppVeyor CI](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in ``master`` branch.
|
||||
* [ ] Develop and prepare release in `master` branch.
|
||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) and [AppVeyor CI](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in `master` branch.
|
||||
* [ ] Check that all of the wheel builds [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels) pass the tests in Travis CI.
|
||||
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py`
|
||||
* [ ] Update `CHANGES.rst`.
|
||||
* [ ] Run pre-release check via `make release-test` in a freshly cloned repo.
|
||||
* [ ] Create branch and tag for release e.g.:
|
||||
```
|
||||
$ git branch 5.2.x
|
||||
$ git tag 5.2.0
|
||||
$ git push --all
|
||||
$ git push --tags
|
||||
```
|
||||
```bash
|
||||
git branch 5.2.x
|
||||
git tag 5.2.0
|
||||
git push --all
|
||||
git push --tags
|
||||
```
|
||||
* [ ] Create source distributions e.g.:
|
||||
```
|
||||
$ make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](#binary-distributions)
|
||||
* [ ] Upload all binaries and source distributions e.g. ``twine upload dist/Pillow-5.2.0-*``
|
||||
```bash
|
||||
make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
|
||||
* [ ] Upload all binaries and source distributions e.g. `twine upload dist/Pillow-5.2.0*`
|
||||
* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
|
||||
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), append `.dev0` to version identifier in `src/PIL/_version.py`
|
||||
* [ ] 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`
|
||||
|
||||
## Point Release
|
||||
|
||||
Released as needed for security, installation or critical bug fixes.
|
||||
|
||||
* [ ] Make necessary changes in ``master`` branch.
|
||||
* [ ] Make necessary changes in `master` branch.
|
||||
* [ ] Update `CHANGES.rst`.
|
||||
* [ ] Cherry pick individual commits from ``master`` branch to release branch e.g. ``5.2.x``.
|
||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in release branch e.g. ``5.2.x``.
|
||||
* [ ] Check out release branch e.g.:
|
||||
```
|
||||
```bash
|
||||
git checkout -t remotes/origin/5.2.x
|
||||
```
|
||||
```
|
||||
* [ ] Cherry pick individual commits from `master` branch to release branch e.g. `5.2.x`.
|
||||
* [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) to confirm passing tests in release branch e.g. `5.2.x`.
|
||||
* [ ] In compliance with [PEP 440](https://www.python.org/dev/peps/pep-0440/), update version identifier in `src/PIL/_version.py`
|
||||
* [ ] Run pre-release check via `make release-test`.
|
||||
* [ ] Create tag for release e.g.:
|
||||
```
|
||||
$ git tag 5.2.1
|
||||
$ git push --tags
|
||||
```
|
||||
```bash
|
||||
git tag 5.2.1
|
||||
git push --tags
|
||||
```
|
||||
* [ ] Create source distributions e.g.:
|
||||
```
|
||||
$ make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](#binary-distributions)
|
||||
```bash
|
||||
make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
|
||||
* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
|
||||
|
||||
## Embargoed Release
|
||||
|
@ -64,41 +64,44 @@ Released as needed privately to individual vendors for critical security-related
|
|||
* [ ] Run pre-release check via `make release-test`
|
||||
* [ ] Amend any commits with the CVE #
|
||||
* [ ] On release date, tag and push to GitHub.
|
||||
```
|
||||
```bash
|
||||
git checkout 2.5.x
|
||||
git tag 2.5.3
|
||||
git push origin 2.5.x
|
||||
git push origin --tags
|
||||
```
|
||||
```
|
||||
* [ ] Create source distributions e.g.:
|
||||
```
|
||||
$ make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](#binary-distributions)
|
||||
```bash
|
||||
make sdist
|
||||
```
|
||||
* [ ] Create [binary distributions](https://github.com/python-pillow/Pillow/blob/master/RELEASING.md#binary-distributions)
|
||||
* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
|
||||
|
||||
## Binary Distributions
|
||||
|
||||
### Windows
|
||||
* [ ] Contact @cgohlke for Windows binaries via release ticket e.g. https://github.com/python-pillow/Pillow/issues/1174.
|
||||
* [ ] Download and extract tarball from @cgohlke and ``twine upload *``.
|
||||
* [ ] Contact `@cgohlke` for Windows binaries via release ticket e.g. https://github.com/python-pillow/Pillow/issues/1174.
|
||||
* [ ] Download and extract tarball from `@cgohlke` and `twine upload *`.
|
||||
|
||||
### Mac and Linux
|
||||
* [ ] Use the [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels):
|
||||
```
|
||||
$ git clone https://github.com/python-pillow/pillow-wheels
|
||||
$ cd pillow-wheels
|
||||
$ git submodule init
|
||||
$ git submodule update Pillow
|
||||
$ cd Pillow
|
||||
$ git fetch --all
|
||||
$ git checkout [[release tag]]
|
||||
$ cd ..
|
||||
$ git commit -m "Pillow -> 5.2.0" Pillow
|
||||
$ git push
|
||||
```
|
||||
```bash
|
||||
git clone https://github.com/python-pillow/pillow-wheels
|
||||
cd pillow-wheels
|
||||
git submodule init
|
||||
git submodule update Pillow
|
||||
cd Pillow
|
||||
git fetch --all
|
||||
git checkout [[release tag]]
|
||||
cd ..
|
||||
git commit -m "Pillow -> 5.2.0" Pillow
|
||||
git push
|
||||
```
|
||||
* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).
|
||||
|
||||
```bash
|
||||
wget -m -A 'Pillow-<VERSION>*' \
|
||||
http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
|
||||
```
|
||||
|
||||
## Publicize Release
|
||||
|
||||
|
@ -106,4 +109,4 @@ Released as needed privately to individual vendors for critical security-related
|
|||
|
||||
## Documentation
|
||||
|
||||
* [ ] Make sure the default version for Read the Docs is the latest release version, i.e. ``5.2.0`` rather than ``latest`` e.g. https://pillow.readthedocs.io/en/5.2.x/
|
||||
* [ ] Make sure the default version for Read the Docs is the latest tagged release e.g. `d2d43879` (5.4.0)
|
||||
|
|
|
@ -13,28 +13,20 @@ Install::
|
|||
Execution
|
||||
---------
|
||||
|
||||
**If Pillow has been built in-place**
|
||||
|
||||
To run an individual test::
|
||||
|
||||
python Tests/test_image.py
|
||||
pytest Tests/test_image.py
|
||||
|
||||
Run all the tests from the root of the Pillow source distribution::
|
||||
Or::
|
||||
|
||||
pytest -vx Tests
|
||||
|
||||
Or with coverage::
|
||||
|
||||
pytest -vx --cov PIL --cov-report term Tests
|
||||
coverage html
|
||||
open htmlcov/index.html
|
||||
|
||||
**If Pillow has been installed**
|
||||
|
||||
To run an individual test::
|
||||
|
||||
pytest -k Tests/test_image.py
|
||||
pytest -k test_image.py
|
||||
|
||||
Run all the tests from the root of the Pillow source distribution::
|
||||
|
||||
pytest
|
||||
|
||||
Or with coverage::
|
||||
|
||||
pytest --cov PIL --cov-report term
|
||||
coverage html
|
||||
open htmlcov/index.html
|
||||
|
|
0
Tests/__init__.py
Normal file
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
|
||||
# Not running this test by default. No DOS against Travis CI.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import helper
|
||||
from . import helper
|
||||
import timeit
|
||||
|
||||
import sys
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
TEST_FILE = "Tests/images/fli_overflow.fli"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import division
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
import sys
|
||||
from PIL import Image
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
import sys
|
||||
from PIL import Image
|
||||
from io import BytesIO
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from PIL import Image
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
|
||||
class TestJ2kEncodeOverflow(PillowTestCase):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
from io import BytesIO
|
||||
import sys
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import sys
|
||||
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
# This test is not run automatically.
|
||||
#
|
||||
|
@ -21,7 +21,7 @@ class LargeMemoryTest(PillowTestCase):
|
|||
|
||||
def _write_png(self, xdim, ydim):
|
||||
f = self.tempfile('temp.png')
|
||||
im = Image.new('L', (xdim, ydim), (0))
|
||||
im = Image.new('L', (xdim, ydim), 0)
|
||||
im.save(f)
|
||||
|
||||
def test_large(self):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import sys
|
||||
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
# This test is not run automatically.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
TEST_FILE = "Tests/images/libtiff_segfault.tif"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image, PngImagePlugin, ImageFile
|
||||
from io import BytesIO
|
||||
import zlib
|
||||
|
@ -36,7 +36,7 @@ class TestPngDos(PillowTestCase):
|
|||
|
||||
def test_dos_total_memory(self):
|
||||
im = Image.new('L', (1, 1))
|
||||
compressed_data = zlib.compress('a'*1024*1023)
|
||||
compressed_data = zlib.compress(b'a'*1024*1023)
|
||||
|
||||
info = PngImagePlugin.PngInfo()
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
from __future__ import print_function
|
||||
import base64
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
# create font data chunk for embedding
|
||||
|
@ -10,7 +9,9 @@ if __name__ == "__main__":
|
|||
print(" f._load_pilfont_data(")
|
||||
print(" # %s" % os.path.basename(font))
|
||||
print(" BytesIO(base64.decodestring(b'''")
|
||||
base64.encode(open(font + ".pil", "rb"), sys.stdout)
|
||||
with open(font + ".pil", "rb") as fp:
|
||||
print(base64.b64encode(fp.read()).decode())
|
||||
print("''')), Image.open(BytesIO(base64.decodestring(b'''")
|
||||
base64.encode(open(font + ".pbm", "rb"), sys.stdout)
|
||||
with open(font + ".pbm", "rb") as fp:
|
||||
print(base64.b64encode(fp.read()).decode())
|
||||
print("'''))))")
|
||||
|
|
|
@ -53,10 +53,6 @@ class PillowTestCase(unittest.TestCase):
|
|||
# holds last result object passed to run method:
|
||||
self.currentResult = None
|
||||
|
||||
# Nicer output for --verbose
|
||||
def __str__(self):
|
||||
return self.__class__.__name__ + "." + self._testMethodName
|
||||
|
||||
def run(self, result=None):
|
||||
self.currentResult = result # remember result for use later
|
||||
unittest.TestCase.run(self, result) # call superclass run method
|
||||
|
@ -84,7 +80,7 @@ class PillowTestCase(unittest.TestCase):
|
|||
self.assertTrue(
|
||||
all(x == y for x, y in zip(a, b)),
|
||||
msg or "got %s, expected %s" % (a, b))
|
||||
except:
|
||||
except Exception:
|
||||
self.assertEqual(a, b, msg)
|
||||
|
||||
def assert_image(self, im, mode, size, msg=None):
|
||||
|
@ -110,7 +106,7 @@ class PillowTestCase(unittest.TestCase):
|
|||
try:
|
||||
url = test_image_results.upload(a, b)
|
||||
logger.error("Url for test images: %s" % url)
|
||||
except Exception as msg:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.fail(msg or "got different content")
|
||||
|
@ -149,7 +145,7 @@ class PillowTestCase(unittest.TestCase):
|
|||
try:
|
||||
url = test_image_results.upload(a, b)
|
||||
logger.error("Url for test images: %s" % url)
|
||||
except:
|
||||
except Exception:
|
||||
pass
|
||||
raise e
|
||||
|
||||
|
@ -163,7 +159,6 @@ class PillowTestCase(unittest.TestCase):
|
|||
def assert_warning(self, warn_class, func, *args, **kwargs):
|
||||
import warnings
|
||||
|
||||
result = None
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
# Cause all warnings to always be triggered.
|
||||
warnings.simplefilter("always")
|
||||
|
@ -175,7 +170,7 @@ class PillowTestCase(unittest.TestCase):
|
|||
if warn_class is None:
|
||||
self.assertEqual(len(w), 0,
|
||||
"Expected no warnings, got %s" %
|
||||
list(v.category for v in w))
|
||||
[v.category for v in w])
|
||||
else:
|
||||
self.assertGreaterEqual(len(w), 1)
|
||||
found = False
|
||||
|
@ -187,10 +182,10 @@ class PillowTestCase(unittest.TestCase):
|
|||
return result
|
||||
|
||||
def assert_all_same(self, items, msg=None):
|
||||
self.assertTrue(items.count(items[0]) == len(items), msg)
|
||||
self.assertEqual(items.count(items[0]), len(items), msg)
|
||||
|
||||
def assert_not_all_same(self, items, msg=None):
|
||||
self.assertFalse(items.count(items[0]) == len(items), msg)
|
||||
self.assertNotEqual(items.count(items[0]), len(items), msg)
|
||||
|
||||
def assert_tuple_approx_equal(self, actuals, targets, threshold, msg):
|
||||
"""Tests if actuals has values within threshold from targets"""
|
||||
|
|
BIN
Tests/images/a_fli.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Tests/images/balloon.jpf
Normal file
BIN
Tests/images/exif-ifd-offset.jpg
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
Tests/images/hopper_idat_after_image_end.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
Tests/images/hopper_unknown_pixel_mode.tif
Normal file
BIN
Tests/images/hopper_zero_comment_subblocks.gif
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
Tests/images/imagedraw_arc_width.png
Normal file
After Width: | Height: | Size: 439 B |
BIN
Tests/images/imagedraw_arc_width_fill.png
Normal file
After Width: | Height: | Size: 438 B |
BIN
Tests/images/imagedraw_chord_width.png
Normal file
After Width: | Height: | Size: 488 B |
BIN
Tests/images/imagedraw_chord_width_fill.png
Normal file
After Width: | Height: | Size: 507 B |
BIN
Tests/images/imagedraw_ellipse_width.png
Normal file
After Width: | Height: | Size: 452 B |
BIN
Tests/images/imagedraw_ellipse_width_fill.png
Normal file
After Width: | Height: | Size: 477 B |
BIN
Tests/images/imagedraw_pieslice_width.png
Normal file
After Width: | Height: | Size: 496 B |
BIN
Tests/images/imagedraw_pieslice_width_fill.png
Normal file
After Width: | Height: | Size: 523 B |
BIN
Tests/images/imagedraw_rectangle_width.png
Normal file
After Width: | Height: | Size: 228 B |
BIN
Tests/images/imagedraw_rectangle_width_fill.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
Tests/images/iss634.apng
Normal file
After Width: | Height: | Size: 342 KiB |
BIN
Tests/images/sugarshack_ifd_offset.mpo
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
Tests/images/tiff_strip_cmyk_jpeg.tif
Normal file
BIN
Tests/images/tiff_strip_planar_raw.tif
Normal file
BIN
Tests/images/tiff_strip_planar_raw_with_overviews.tif
Normal file
BIN
Tests/images/tiff_strip_raw.tif
Normal file
BIN
Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif
Normal file
BIN
Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif
Normal file
BIN
Tests/images/tiff_tiled_cmyk_jpeg.tif
Normal file
BIN
Tests/images/tiff_tiled_planar_raw.tif
Normal file
BIN
Tests/images/tiff_tiled_raw.tif
Normal file
BIN
Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif
Normal file
BIN
Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif
Normal file
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
import PIL
|
||||
import PIL.Image
|
||||
|
@ -9,7 +9,7 @@ class TestSanity(PillowTestCase):
|
|||
def test_sanity(self):
|
||||
|
||||
# Make sure we have the binary extension
|
||||
im = PIL.Image.core.new("L", (100, 100))
|
||||
PIL.Image.core.new("L", (100, 100))
|
||||
|
||||
self.assertEqual(PIL.Image.VERSION[:3], '1.1')
|
||||
|
||||
|
@ -19,12 +19,8 @@ class TestSanity(PillowTestCase):
|
|||
self.assertEqual(len(im.tobytes()), 1300)
|
||||
|
||||
# Create images in all remaining major modes.
|
||||
im = PIL.Image.new("L", (100, 100))
|
||||
im = PIL.Image.new("P", (100, 100))
|
||||
im = PIL.Image.new("RGB", (100, 100))
|
||||
im = PIL.Image.new("I", (100, 100))
|
||||
im = PIL.Image.new("F", (100, 100))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
PIL.Image.new("L", (100, 100))
|
||||
PIL.Image.new("P", (100, 100))
|
||||
PIL.Image.new("RGB", (100, 100))
|
||||
PIL.Image.new("I", (100, 100))
|
||||
PIL.Image.new("F", (100, 100))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import _binary
|
||||
|
||||
|
@ -22,7 +22,3 @@ class TestBinary(PillowTestCase):
|
|||
|
||||
self.assertEqual(_binary.o16be(65535), b'\xff\xff')
|
||||
self.assertEqual(_binary.o32be(65535), b'\x00\x00\xff\xff')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from __future__ import print_function
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image
|
||||
import os
|
||||
|
@ -17,12 +17,16 @@ class TestBmpReference(PillowTestCase):
|
|||
""" These shouldn't crash/dos, but they shouldn't return anything
|
||||
either """
|
||||
for f in self.get_files('b'):
|
||||
def open(f):
|
||||
try:
|
||||
im = Image.open(f)
|
||||
im.load()
|
||||
except Exception: # as msg:
|
||||
pass
|
||||
|
||||
# Assert that there is no unclosed file warning
|
||||
self.assert_warning(None, open, f)
|
||||
|
||||
def test_questionable(self):
|
||||
""" These shouldn't crash/dos, but it's not well defined that these
|
||||
are in spec """
|
||||
|
@ -99,7 +103,3 @@ class TestBmpReference(PillowTestCase):
|
|||
os.path.join(base, 'g', 'pal4rle.bmp'))
|
||||
if f not in unsupported:
|
||||
self.fail("Unsupported Image %s: %s" % (f, msg))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image, ImageFilter
|
||||
|
||||
|
@ -215,7 +215,3 @@ class TestBoxBlur(PillowTestCase):
|
|||
passes=3,
|
||||
delta=1,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import division
|
|||
from array import array
|
||||
|
||||
from PIL import Image, ImageFilter
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
try:
|
||||
import numpy
|
||||
|
@ -294,6 +294,8 @@ class TestColorLut3DFilter(PillowTestCase):
|
|||
|
||||
lut = ImageFilter.Color3DLUT((2, 2, 2), [(0, 1, 2, 3)] * 8,
|
||||
channels=4)
|
||||
self.assertEqual(tuple(lut.size), (2, 2, 2))
|
||||
self.assertEqual(lut.table, list(range(4)) * 8)
|
||||
|
||||
@unittest.skipIf(numpy is None, "Numpy is not installed")
|
||||
def test_numpy_sources(self):
|
||||
|
@ -517,7 +519,3 @@ class TestTransformColorLut3D(PillowTestCase):
|
|||
self.assertEqual(lut.table[0: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])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -2,7 +2,7 @@ from __future__ import division, print_function
|
|||
|
||||
import sys
|
||||
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
@ -83,7 +83,3 @@ class TestDecompressionCrop(PillowTestCase):
|
|||
for value in error_values:
|
||||
with self.assertRaises(Image.DecompressionBombError):
|
||||
im.crop(value)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
from PIL import features
|
||||
|
||||
try:
|
||||
from PIL import _webp
|
||||
HAVE_WEBP = True
|
||||
except:
|
||||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
|
||||
|
@ -23,20 +23,20 @@ class TestFeatures(PillowTestCase):
|
|||
self.assertEqual(features.check_feature(feature),
|
||||
features.check(feature))
|
||||
|
||||
@unittest.skipUnless(HAVE_WEBP, True)
|
||||
def check_webp_transparency(self):
|
||||
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
||||
def test_webp_transparency(self):
|
||||
self.assertEqual(features.check('transp_webp'),
|
||||
not _webp.WebPDecoderBuggyAlpha())
|
||||
self.assertEqual(features.check('transp_webp'),
|
||||
_webp.HAVE_TRANSPARENCY)
|
||||
|
||||
@unittest.skipUnless(HAVE_WEBP, True)
|
||||
def check_webp_mux(self):
|
||||
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
||||
def test_webp_mux(self):
|
||||
self.assertEqual(features.check('webp_mux'),
|
||||
_webp.HAVE_WEBPMUX)
|
||||
|
||||
@unittest.skipUnless(HAVE_WEBP, True)
|
||||
def check_webp_anim(self):
|
||||
@unittest.skipUnless(HAVE_WEBP, "WebP not available")
|
||||
def test_webp_anim(self):
|
||||
self.assertEqual(features.check('webp_anim'),
|
||||
_webp.HAVE_WEBPANIM)
|
||||
|
||||
|
@ -63,7 +63,3 @@ class TestFeatures(PillowTestCase):
|
|||
module = "unsupported_module"
|
||||
# Act / Assert
|
||||
self.assertRaises(ValueError, features.check_module, module)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from PIL import Image
|
||||
|
||||
from helper import PillowTestCase, unittest
|
||||
from .helper import PillowTestCase
|
||||
|
||||
|
||||
class TestFileBlp(PillowTestCase):
|
||||
|
@ -18,7 +18,3 @@ class TestFileBlp(PillowTestCase):
|
|||
im = Image.open("Tests/images/blp/blp2_dxt1a.blp")
|
||||
target = Image.open("Tests/images/blp/blp2_dxt1a.png")
|
||||
self.assert_image_equal(im, target)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, BmpImagePlugin
|
||||
import io
|
||||
|
@ -75,7 +75,3 @@ class TestFileBmp(PillowTestCase):
|
|||
im = BmpImagePlugin.DibImageFile('Tests/images/clipboard.dib')
|
||||
target = Image.open('Tests/images/clipboard_target.png')
|
||||
self.assert_image_equal(im, target)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import BufrStubImagePlugin, Image
|
||||
|
||||
|
@ -40,7 +40,3 @@ class TestFileBufrStub(PillowTestCase):
|
|||
|
||||
# Act / Assert: stub cannot save without an implemented handler
|
||||
self.assertRaises(IOError, im.save, tmpfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ContainerIO
|
||||
|
@ -123,7 +123,3 @@ class TestFileContainer(PillowTestCase):
|
|||
# Assert
|
||||
|
||||
self.assertEqual(data, expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image, CurImagePlugin
|
||||
|
||||
|
@ -26,9 +26,6 @@ class TestFileCur(PillowTestCase):
|
|||
no_cursors_file = "Tests/images/no_cursors.cur"
|
||||
|
||||
cur = CurImagePlugin.CurImageFile(TEST_FILE)
|
||||
cur.fp.close()
|
||||
with open(no_cursors_file, "rb") as cur.fp:
|
||||
self.assertRaises(TypeError, cur._open)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, DcxImagePlugin
|
||||
|
||||
|
@ -20,6 +20,12 @@ class TestFileDcx(PillowTestCase):
|
|||
orig = hopper()
|
||||
self.assert_image_equal(im, orig)
|
||||
|
||||
def test_unclosed_file(self):
|
||||
def open():
|
||||
im = Image.open(TEST_FILE)
|
||||
im.load()
|
||||
self.assert_warning(None, open)
|
||||
|
||||
def test_invalid_file(self):
|
||||
with open("Tests/images/flower.jpg", "rb") as fp:
|
||||
self.assertRaises(SyntaxError,
|
||||
|
@ -58,7 +64,3 @@ class TestFileDcx(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(EOFError, im.seek, frame)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from io import BytesIO
|
||||
|
||||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
from PIL import Image, DdsImagePlugin
|
||||
|
||||
TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
|
||||
|
@ -110,7 +110,3 @@ class TestFileDds(PillowTestCase):
|
|||
im.load()
|
||||
|
||||
self.assertRaises(IOError, short_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, EpsImagePlugin
|
||||
import io
|
||||
|
||||
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
|
||||
|
||||
# Our two EPS test files (they are identical except for their bounding boxes)
|
||||
file1 = "Tests/images/zero_bb.eps"
|
||||
file2 = "Tests/images/non_zero_bb.eps"
|
||||
|
@ -20,10 +22,7 @@ file3 = "Tests/images/binary_preview_map.eps"
|
|||
|
||||
class TestFileEps(PillowTestCase):
|
||||
|
||||
def setUp(self):
|
||||
if not EpsImagePlugin.has_ghostscript():
|
||||
self.skipTest("Ghostscript not available")
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_sanity(self):
|
||||
# Regular scale
|
||||
image1 = Image.open(file1)
|
||||
|
@ -57,6 +56,7 @@ class TestFileEps(PillowTestCase):
|
|||
self.assertRaises(SyntaxError,
|
||||
EpsImagePlugin.EpsImageFile, invalid_file)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_cmyk(self):
|
||||
cmyk_image = Image.open("Tests/images/pil_sample_cmyk.eps")
|
||||
|
||||
|
@ -71,6 +71,7 @@ class TestFileEps(PillowTestCase):
|
|||
target = Image.open('Tests/images/pil_sample_rgb.jpg')
|
||||
self.assert_image_similar(cmyk_image, target, 10)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_showpage(self):
|
||||
# See https://github.com/python-pillow/Pillow/issues/2615
|
||||
plot_image = Image.open("Tests/images/reqd_showpage.eps")
|
||||
|
@ -81,18 +82,21 @@ class TestFileEps(PillowTestCase):
|
|||
# fonts could be slightly different
|
||||
self.assert_image_similar(plot_image, target, 6)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_file_object(self):
|
||||
# issue 479
|
||||
image1 = Image.open(file1)
|
||||
with open(self.tempfile('temp_file.eps'), 'wb') as fh:
|
||||
image1.save(fh, 'EPS')
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_iobase_object(self):
|
||||
# issue 479
|
||||
image1 = Image.open(file1)
|
||||
with io.open(self.tempfile('temp_iobase.eps'), 'wb') as fh:
|
||||
image1.save(fh, 'EPS')
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_bytesio_object(self):
|
||||
with open(file1, 'rb') as f:
|
||||
img_bytes = io.BytesIO(f.read())
|
||||
|
@ -109,6 +113,7 @@ class TestFileEps(PillowTestCase):
|
|||
tmpfile = self.tempfile('temp.eps')
|
||||
self.assertRaises(ValueError, im.save, tmpfile)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_render_scale1(self):
|
||||
# We need png support for these render test
|
||||
codecs = dir(Image.core)
|
||||
|
@ -129,6 +134,7 @@ class TestFileEps(PillowTestCase):
|
|||
image2_scale1_compare.load()
|
||||
self.assert_image_similar(image2_scale1, image2_scale1_compare, 10)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_render_scale2(self):
|
||||
# We need png support for these render test
|
||||
codecs = dir(Image.core)
|
||||
|
@ -149,6 +155,7 @@ class TestFileEps(PillowTestCase):
|
|||
image2_scale2_compare.load()
|
||||
self.assert_image_similar(image2_scale2, image2_scale2_compare, 10)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_resize(self):
|
||||
# Arrange
|
||||
image1 = Image.open(file1)
|
||||
|
@ -166,6 +173,7 @@ class TestFileEps(PillowTestCase):
|
|||
self.assertEqual(image2.size, new_size)
|
||||
self.assertEqual(image3.size, new_size)
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_thumbnail(self):
|
||||
# Issue #619
|
||||
# Arrange
|
||||
|
@ -228,13 +236,12 @@ class TestFileEps(PillowTestCase):
|
|||
"Tests/images/illuCS6_no_preview.eps",
|
||||
"Tests/images/illuCS6_preview.eps"]
|
||||
|
||||
# Act
|
||||
# Act / Assert
|
||||
for filename in FILES:
|
||||
img = Image.open(filename)
|
||||
|
||||
# Assert
|
||||
self.assertEqual(img.mode, "RGB")
|
||||
|
||||
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
|
||||
def test_emptyline(self):
|
||||
# Test file includes an empty line in the header data
|
||||
emptyline_file = "Tests/images/zero_bb_emptyline.eps"
|
||||
|
@ -244,7 +251,3 @@ class TestFileEps(PillowTestCase):
|
|||
self.assertEqual(image.mode, "RGB")
|
||||
self.assertEqual(image.size, (460, 352))
|
||||
self.assertEqual(image.format, "EPS")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import FitsStubImagePlugin, Image
|
||||
|
||||
|
@ -44,7 +44,3 @@ class TestFileFitsStub(PillowTestCase):
|
|||
self.assertRaises(
|
||||
IOError,
|
||||
FitsStubImagePlugin._save, im, dummy_fp, dummy_filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image, FliImagePlugin
|
||||
|
||||
|
@ -27,6 +27,12 @@ class TestFileFli(PillowTestCase):
|
|||
self.assertEqual(im.info["duration"], 71)
|
||||
self.assertTrue(im.is_animated)
|
||||
|
||||
def test_unclosed_file(self):
|
||||
def open():
|
||||
im = Image.open(static_test_file)
|
||||
im.load()
|
||||
self.assert_warning(None, open)
|
||||
|
||||
def test_tell(self):
|
||||
# Arrange
|
||||
im = Image.open(static_test_file)
|
||||
|
@ -85,6 +91,9 @@ class TestFileFli(PillowTestCase):
|
|||
layer_number = im.tell()
|
||||
self.assertEqual(layer_number, 1)
|
||||
|
||||
def test_seek(self):
|
||||
im = Image.open(animated_test_file)
|
||||
im.seek(50)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
expected = Image.open("Tests/images/a_fli.png")
|
||||
self.assert_image_equal(im, expected)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
try:
|
||||
from PIL import FpxImagePlugin
|
||||
|
@ -21,7 +21,3 @@ class TestFileFpx(PillowTestCase):
|
|||
ole_file = "Tests/images/test-ole-file.doc"
|
||||
self.assertRaises(SyntaxError,
|
||||
FpxImagePlugin.FpxImageFile, ole_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
|
||||
|
@ -14,7 +14,3 @@ class TestFileFtex(PillowTestCase):
|
|||
im = Image.open('Tests/images/ftex_dxt1.ftc')
|
||||
target = Image.open('Tests/images/ftex_dxt1.png')
|
||||
self.assert_image_similar(im, target.convert('RGBA'), 15)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image, GbrImagePlugin
|
||||
|
||||
|
@ -17,7 +17,3 @@ class TestFileGbr(PillowTestCase):
|
|||
target = Image.open('Tests/images/gbr.png')
|
||||
|
||||
self.assert_image_equal(target, im)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import GdImageFile
|
||||
|
||||
|
@ -20,7 +20,3 @@ class TestFileGd(PillowTestCase):
|
|||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
self.assertRaises(IOError, GdImageFile.open, invalid_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
from helper import unittest, PillowTestCase, hopper, netpbm_available
|
||||
from .helper import unittest, PillowTestCase, hopper, netpbm_available
|
||||
|
||||
from PIL import Image, ImagePalette, GifImagePlugin
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
try:
|
||||
from PIL import _webp
|
||||
HAVE_WEBP = True
|
||||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
codecs = dir(Image.core)
|
||||
|
||||
# sample gif stream
|
||||
|
@ -27,6 +33,12 @@ class TestFileGif(PillowTestCase):
|
|||
self.assertEqual(im.format, "GIF")
|
||||
self.assertEqual(im.info["version"], b"GIF89a")
|
||||
|
||||
def test_unclosed_file(self):
|
||||
def open():
|
||||
im = Image.open(TEST_GIF)
|
||||
im.load()
|
||||
self.assert_warning(None, open)
|
||||
|
||||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
||||
|
@ -134,13 +146,15 @@ class TestFileGif(PillowTestCase):
|
|||
# Multiframe image
|
||||
im = Image.open("Tests/images/dispose_bgnd.gif")
|
||||
|
||||
info = im.info.copy()
|
||||
|
||||
out = self.tempfile('temp.gif')
|
||||
im.save(out, save_all=True)
|
||||
reread = Image.open(out)
|
||||
|
||||
for header in important_headers:
|
||||
self.assertEqual(
|
||||
im.info[header],
|
||||
info[header],
|
||||
reread.info[header]
|
||||
)
|
||||
|
||||
|
@ -207,6 +221,15 @@ class TestFileGif(PillowTestCase):
|
|||
except EOFError:
|
||||
self.assertEqual(framecount, 5)
|
||||
|
||||
def test_seek_info(self):
|
||||
im = Image.open("Tests/images/iss634.gif")
|
||||
info = im.info.copy()
|
||||
|
||||
im.seek(1)
|
||||
im.seek(0)
|
||||
|
||||
self.assertEqual(im.info, info)
|
||||
|
||||
def test_n_frames(self):
|
||||
for path, n_frames in [
|
||||
[TEST_GIF, 1],
|
||||
|
@ -400,6 +423,11 @@ class TestFileGif(PillowTestCase):
|
|||
|
||||
self.assertEqual(reread.info['background'], im.info['background'])
|
||||
|
||||
if HAVE_WEBP and _webp.HAVE_WEBPANIM:
|
||||
im = Image.open("Tests/images/hopper.webp")
|
||||
self.assertIsInstance(im.info['background'], tuple)
|
||||
im.save(out)
|
||||
|
||||
def test_comment(self):
|
||||
im = Image.open(TEST_GIF)
|
||||
self.assertEqual(im.info['comment'],
|
||||
|
@ -413,6 +441,23 @@ class TestFileGif(PillowTestCase):
|
|||
|
||||
self.assertEqual(reread.info['comment'], im.info['comment'])
|
||||
|
||||
def test_comment_over_255(self):
|
||||
out = self.tempfile('temp.gif')
|
||||
im = Image.new('L', (100, 100), '#000')
|
||||
comment = b"Test comment text"
|
||||
while len(comment) < 256:
|
||||
comment += comment
|
||||
im.info['comment'] = comment
|
||||
im.save(out)
|
||||
reread = Image.open(out)
|
||||
|
||||
self.assertEqual(reread.info['comment'], comment)
|
||||
|
||||
def test_zero_comment_subblocks(self):
|
||||
im = Image.open('Tests/images/hopper_zero_comment_subblocks.gif')
|
||||
expected = Image.open(TEST_GIF)
|
||||
self.assert_image_equal(im, expected)
|
||||
|
||||
def test_version(self):
|
||||
out = self.tempfile('temp.gif')
|
||||
|
||||
|
@ -491,6 +536,27 @@ class TestFileGif(PillowTestCase):
|
|||
|
||||
self.assertEqual(reloaded.info['transparency'], 253)
|
||||
|
||||
def test_rgb_transparency(self):
|
||||
out = self.tempfile('temp.gif')
|
||||
|
||||
# Single frame
|
||||
im = Image.new('RGB', (1, 1))
|
||||
im.info['transparency'] = (255, 0, 0)
|
||||
self.assert_warning(UserWarning, im.save, out)
|
||||
|
||||
reloaded = Image.open(out)
|
||||
self.assertNotIn('transparency', reloaded.info)
|
||||
|
||||
# Multiple frames
|
||||
im = Image.new('RGB', (1, 1))
|
||||
im.info['transparency'] = b""
|
||||
ims = [Image.new('RGB', (1, 1))]
|
||||
self.assert_warning(UserWarning,
|
||||
im.save, out, save_all=True, append_images=ims)
|
||||
|
||||
reloaded = Image.open(out)
|
||||
self.assertNotIn('transparency', reloaded.info)
|
||||
|
||||
def test_bbox(self):
|
||||
out = self.tempfile('temp.gif')
|
||||
|
||||
|
@ -588,7 +654,3 @@ class TestFileGif(PillowTestCase):
|
|||
self.assertEqual(im.tile[0][3][0], 11) # LZW bits
|
||||
# codec error prepatch
|
||||
im.load()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import GimpGradientFile
|
||||
|
||||
|
@ -119,7 +119,3 @@ class TestImage(PillowTestCase):
|
|||
# load returns raw palette information
|
||||
self.assertEqual(len(palette[0]), 1024)
|
||||
self.assertEqual(palette[1], "RGBA")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL.GimpPaletteFile import GimpPaletteFile
|
||||
|
||||
|
@ -28,7 +28,3 @@ class TestImage(PillowTestCase):
|
|||
|
||||
# Assert
|
||||
self.assertEqual(mode, "RGB")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import GribStubImagePlugin, Image
|
||||
|
||||
|
@ -40,7 +40,3 @@ class TestFileGribStub(PillowTestCase):
|
|||
|
||||
# Act / Assert: stub cannot save without an implemented handler
|
||||
self.assertRaises(IOError, im.save, tmpfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Hdf5StubImagePlugin, Image
|
||||
|
||||
|
@ -44,7 +44,3 @@ class TestFileHdf5Stub(PillowTestCase):
|
|||
self.assertRaises(
|
||||
IOError,
|
||||
Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import unittest, PillowTestCase
|
||||
|
||||
from PIL import Image, IcnsImagePlugin
|
||||
|
||||
|
@ -17,7 +17,10 @@ class TestFileIcns(PillowTestCase):
|
|||
# Loading this icon by default should result in the largest size
|
||||
# (512x512@2x) being loaded
|
||||
im = Image.open(TEST_FILE)
|
||||
im.load()
|
||||
|
||||
# Assert that there is no unclosed file warning
|
||||
self.assert_warning(None, im.load)
|
||||
|
||||
self.assertEqual(im.mode, "RGBA")
|
||||
self.assertEqual(im.size, (1024, 1024))
|
||||
self.assertEqual(im.format, "ICNS")
|
||||
|
@ -64,6 +67,10 @@ class TestFileIcns(PillowTestCase):
|
|||
self.assertEqual(im2.mode, 'RGBA')
|
||||
self.assertEqual(im2.size, (wr, hr))
|
||||
|
||||
# Check that we cannot load an incorrect size
|
||||
with self.assertRaises(ValueError):
|
||||
im.size = (1, 1)
|
||||
|
||||
def test_older_icon(self):
|
||||
# This icon was made with Icon Composer rather than iconutil; it still
|
||||
# uses PNG rather than JP2, however (since it was made on 10.9).
|
||||
|
@ -114,7 +121,3 @@ class TestFileIcns(PillowTestCase):
|
|||
with io.BytesIO(b'invalid\n') as fp:
|
||||
self.assertRaises(SyntaxError,
|
||||
IcnsImagePlugin.IcnsFile, fp)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
import io
|
||||
from PIL import Image, IcoImagePlugin
|
||||
|
@ -28,7 +28,7 @@ class TestFileIco(PillowTestCase):
|
|||
# the default image
|
||||
output.seek(0)
|
||||
reloaded = Image.open(output)
|
||||
self.assertEqual(reloaded.info['sizes'], set([(32, 32), (64, 64)]))
|
||||
self.assertEqual(reloaded.info['sizes'], {(32, 32), (64, 64)})
|
||||
|
||||
self.assertEqual(im.mode, reloaded.mode)
|
||||
self.assertEqual((64, 64), reloaded.size)
|
||||
|
@ -47,6 +47,11 @@ class TestFileIco(PillowTestCase):
|
|||
self.assert_image_equal(reloaded,
|
||||
hopper().resize((32, 32), Image.LANCZOS))
|
||||
|
||||
def test_incorrect_size(self):
|
||||
im = Image.open(TEST_ICO_FILE)
|
||||
with self.assertRaises(ValueError):
|
||||
im.size = (1, 1)
|
||||
|
||||
def test_save_256x256(self):
|
||||
"""Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
|
||||
# Arrange
|
||||
|
@ -76,8 +81,4 @@ class TestFileIco(PillowTestCase):
|
|||
# Assert
|
||||
self.assertEqual(
|
||||
im_saved.info['sizes'],
|
||||
set([(16, 16), (24, 24), (32, 32), (48, 48)]))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
{(16, 16), (24, 24), (32, 32), (48, 48)})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, ImImagePlugin
|
||||
|
||||
|
@ -15,6 +15,12 @@ class TestFileIm(PillowTestCase):
|
|||
self.assertEqual(im.size, (128, 128))
|
||||
self.assertEqual(im.format, "IM")
|
||||
|
||||
def test_unclosed_file(self):
|
||||
def open():
|
||||
im = Image.open(TEST_IM)
|
||||
im.load()
|
||||
self.assert_warning(None, open)
|
||||
|
||||
def test_tell(self):
|
||||
# Arrange
|
||||
im = Image.open(TEST_IM)
|
||||
|
@ -63,7 +69,3 @@ class TestFileIm(PillowTestCase):
|
|||
|
||||
def test_number(self):
|
||||
self.assertEqual(1.2, ImImagePlugin.number("1.2"))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, IptcImagePlugin
|
||||
|
||||
|
@ -69,7 +69,3 @@ class TestFileIptc(PillowTestCase):
|
|||
|
||||
# Assert
|
||||
self.assertEqual(mystdout.getvalue(), "61 62 63 \n")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from helper import djpeg_available, cjpeg_available
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
from .helper import djpeg_available, cjpeg_available
|
||||
|
||||
from io import BytesIO
|
||||
import os
|
||||
|
@ -581,6 +581,15 @@ class TestFileJpeg(PillowTestCase):
|
|||
# OSError for unidentified image.
|
||||
self.assertEqual(im.info.get("dpi"), (72, 72))
|
||||
|
||||
def test_ifd_offset_exif(self):
|
||||
# Arrange
|
||||
# This image has been manually hexedited to have an IFD offset of 10,
|
||||
# in contrast to normal 8
|
||||
im = Image.open("Tests/images/exif-ifd-offset.jpg")
|
||||
|
||||
# Act / Assert
|
||||
self.assertEqual(im._getexif()[306], '2017:03:13 23:03:09')
|
||||
|
||||
|
||||
@unittest.skipUnless(sys.platform.startswith('win32'), "Windows only")
|
||||
class TestFileCloseW32(PillowTestCase):
|
||||
|
@ -602,7 +611,3 @@ class TestFileCloseW32(PillowTestCase):
|
|||
self.assertTrue(fp.closed)
|
||||
# this should not fail, as load should have closed the file.
|
||||
os.remove(tmpfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image, Jpeg2KImagePlugin
|
||||
from io import BytesIO
|
||||
|
@ -39,6 +39,12 @@ class TestFileJpeg2k(PillowTestCase):
|
|||
self.assertEqual(im.mode, 'RGB')
|
||||
self.assertEqual(im.size, (640, 480))
|
||||
self.assertEqual(im.format, 'JPEG2000')
|
||||
self.assertEqual(im.get_format_mimetype(), 'image/jp2')
|
||||
|
||||
def test_jpf(self):
|
||||
im = Image.open('Tests/images/balloon.jpf')
|
||||
self.assertEqual(im.format, 'JPEG2000')
|
||||
self.assertEqual(im.get_format_mimetype(), 'image/jpx')
|
||||
|
||||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
@ -105,6 +111,22 @@ class TestFileJpeg2k(PillowTestCase):
|
|||
im.load()
|
||||
self.assertEqual(im.size, (160, 120))
|
||||
|
||||
def test_layers_type(self):
|
||||
outfile = self.tempfile('temp_layers.jp2')
|
||||
for quality_layers in [
|
||||
[100, 50, 10],
|
||||
(100, 50, 10),
|
||||
None
|
||||
]:
|
||||
test_card.save(outfile, quality_layers=quality_layers)
|
||||
|
||||
for quality_layers in [
|
||||
'quality_layers',
|
||||
('100', '50', '10')
|
||||
]:
|
||||
self.assertRaises(ValueError, test_card.save, outfile,
|
||||
quality_layers=quality_layers)
|
||||
|
||||
def test_layers(self):
|
||||
out = BytesIO()
|
||||
test_card.save(out, 'JPEG2000', quality_layers=[100, 50, 10],
|
||||
|
@ -188,7 +210,3 @@ class TestFileJpeg2k(PillowTestCase):
|
|||
|
||||
# Assert
|
||||
self.assertEqual(p.image.size, (640, 480))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from __future__ import print_function
|
||||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
from PIL import features
|
||||
from PIL._util import py3
|
||||
|
||||
|
@ -8,6 +8,7 @@ import io
|
|||
import logging
|
||||
import itertools
|
||||
import os
|
||||
import distutils.version
|
||||
|
||||
from PIL import Image, TiffImagePlugin, TiffTags
|
||||
|
||||
|
@ -194,7 +195,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
im = Image.open('Tests/images/hopper_g4.tif')
|
||||
for tag in im.tag_v2:
|
||||
try:
|
||||
del(core_items[tag])
|
||||
del core_items[tag]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
@ -204,7 +205,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
# 4: "long",
|
||||
# 5: "rational",
|
||||
# 12: "double",
|
||||
# type: dummy value
|
||||
# Type: dummy value
|
||||
values = {2: 'test',
|
||||
3: 1,
|
||||
4: 2**20,
|
||||
|
@ -222,7 +223,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
for _ in range(info.length))
|
||||
|
||||
# Extra samples really doesn't make sense in this application.
|
||||
del(new_ifd[338])
|
||||
del new_ifd[338]
|
||||
|
||||
out = self.tempfile("temp.tif")
|
||||
TiffImagePlugin.WRITE_LIBTIFF = True
|
||||
|
@ -231,6 +232,37 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
def test_custom_metadata(self):
|
||||
custom = {
|
||||
37000: 4,
|
||||
37001: 4.2,
|
||||
37002: 'custom tag value',
|
||||
37003: u'custom tag value',
|
||||
37004: b'custom tag value'
|
||||
}
|
||||
|
||||
libtiff_version = TiffImagePlugin._libtiff_version()
|
||||
|
||||
libtiffs = [False]
|
||||
if distutils.version.StrictVersion(libtiff_version) >= \
|
||||
distutils.version.StrictVersion("4.0"):
|
||||
libtiffs.append(True)
|
||||
|
||||
for libtiff in libtiffs:
|
||||
TiffImagePlugin.WRITE_LIBTIFF = libtiff
|
||||
|
||||
im = hopper()
|
||||
|
||||
out = self.tempfile("temp.tif")
|
||||
im.save(out, tiffinfo=custom)
|
||||
TiffImagePlugin.WRITE_LIBTIFF = False
|
||||
|
||||
reloaded = Image.open(out)
|
||||
for tag, value in custom.items():
|
||||
if libtiff and isinstance(value, bytes):
|
||||
value = value.decode()
|
||||
self.assertEqual(reloaded.tag_v2[tag], value)
|
||||
|
||||
def test_int_dpi(self):
|
||||
# issue #1765
|
||||
im = hopper('RGB')
|
||||
|
@ -415,7 +447,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
im = Image.open('Tests/images/multipage.tiff')
|
||||
frames = im.n_frames
|
||||
self.assertEqual(frames, 3)
|
||||
for idx in range(frames):
|
||||
for _ in range(frames):
|
||||
im.seek(0)
|
||||
# Should not raise ValueError: I/O operation on closed file
|
||||
im.load()
|
||||
|
@ -496,7 +528,7 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
pilim_load = Image.open(buffer_io)
|
||||
self.assert_image_similar(pilim, pilim_load, 0)
|
||||
|
||||
# save_bytesio()
|
||||
save_bytesio()
|
||||
save_bytesio('raw')
|
||||
save_bytesio("packbits")
|
||||
save_bytesio("tiff_lzw")
|
||||
|
@ -545,11 +577,11 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
def test_read_icc(self):
|
||||
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||
icc = img.info.get('icc_profile')
|
||||
self.assertNotEqual(icc, None)
|
||||
self.assertIsNotNone(icc)
|
||||
TiffImagePlugin.READ_LIBTIFF = True
|
||||
with Image.open("Tests/images/hopper.iccprofile.tif") as img:
|
||||
icc_libtiff = img.info.get('icc_profile')
|
||||
self.assertNotEqual(icc_libtiff, None)
|
||||
self.assertIsNotNone(icc_libtiff)
|
||||
TiffImagePlugin.READ_LIBTIFF = False
|
||||
self.assertEqual(icc, icc_libtiff)
|
||||
|
||||
|
@ -633,6 +665,38 @@ class TestFileLibTiff(LibTiffTestCase):
|
|||
im2 = hopper()
|
||||
self.assert_image_similar(im, im2, 5)
|
||||
|
||||
def test_strip_cmyk_jpeg(self):
|
||||
infile = "Tests/images/tiff_strip_cmyk_jpeg.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
|
||||
|
||||
def test_strip_ycbcr_jpeg_2x2_sampling(self):
|
||||
infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
|
||||
|
||||
def test_strip_ycbcr_jpeg_1x1_sampling(self):
|
||||
infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_equal_tofile(im, "Tests/images/flower2.jpg")
|
||||
|
||||
def test_tiled_cmyk_jpeg(self):
|
||||
infile = "Tests/images/tiff_tiled_cmyk_jpeg.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
|
||||
|
||||
def test_tiled_ycbcr_jpeg_1x1_sampling(self):
|
||||
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_equal_tofile(im, "Tests/images/flower2.jpg")
|
||||
|
||||
def test_tiled_ycbcr_jpeg_2x2_sampling(self):
|
||||
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif"
|
||||
im = Image.open(infile)
|
||||
|
||||
self.assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
from helper import unittest
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from test_file_libtiff import LibTiffTestCase
|
||||
from .test_file_libtiff import LibTiffTestCase
|
||||
|
||||
|
||||
class TestFileLibTiffSmall(LibTiffTestCase):
|
||||
|
@ -46,7 +44,3 @@ class TestFileLibTiffSmall(LibTiffTestCase):
|
|||
|
||||
self.assertEqual(im.size, (128, 128))
|
||||
self._assert_noerr(im)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
|
||||
from PIL import Image, McIdasImagePlugin
|
||||
|
||||
|
@ -28,7 +28,3 @@ class TestFileMcIdas(PillowTestCase):
|
|||
self.assertEqual(im.size, (1800, 400))
|
||||
im2 = Image.open(saved_file)
|
||||
self.assert_image_equal(im, im2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, ImagePalette, features
|
||||
|
||||
|
@ -64,7 +64,3 @@ class TestFileMic(PillowTestCase):
|
|||
ole_file = "Tests/images/test-ole-file.doc"
|
||||
self.assertRaises(SyntaxError,
|
||||
MicImagePlugin.MicImageFile, ole_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
|
@ -31,6 +31,12 @@ class TestFileMpo(PillowTestCase):
|
|||
self.assertEqual(im.size, (640, 480))
|
||||
self.assertEqual(im.format, "MPO")
|
||||
|
||||
def test_unclosed_file(self):
|
||||
def open():
|
||||
im = Image.open(test_files[0])
|
||||
im.load()
|
||||
self.assert_warning(None, open)
|
||||
|
||||
def test_app(self):
|
||||
for test_file in test_files:
|
||||
# Test APP/COM reader (@PIL135)
|
||||
|
@ -56,6 +62,14 @@ class TestFileMpo(PillowTestCase):
|
|||
self.assertEqual(mpinfo[45056], b'0100')
|
||||
self.assertEqual(mpinfo[45057], 2)
|
||||
|
||||
def test_mp_offset(self):
|
||||
# This image has been manually hexedited to have an IFD offset of 10
|
||||
# in APP2 data, in contrast to normal 8
|
||||
im = Image.open("Tests/images/sugarshack_ifd_offset.mpo")
|
||||
mpinfo = im._getmp()
|
||||
self.assertEqual(mpinfo[45056], b'0100')
|
||||
self.assertEqual(mpinfo[45057], 2)
|
||||
|
||||
def test_mp_attribute(self):
|
||||
for test_file in test_files:
|
||||
im = Image.open(test_file)
|
||||
|
@ -136,7 +150,3 @@ class TestFileMpo(PillowTestCase):
|
|||
self.assertEqual(im.tell(), 1)
|
||||
jpg1 = self.frame_roundtrip(im)
|
||||
self.assert_image_similar(im, jpg1, 30)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import unittest, PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, MspImagePlugin
|
||||
|
||||
|
@ -78,7 +78,3 @@ class TestFileMsp(PillowTestCase):
|
|||
|
||||
# Act/Assert
|
||||
self.assertRaises(IOError, im.save, filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper, imagemagick_available
|
||||
from .helper import PillowTestCase, hopper, imagemagick_available
|
||||
|
||||
import os.path
|
||||
|
||||
|
@ -52,7 +52,3 @@ class TestFilePalm(PillowTestCase):
|
|||
|
||||
# Act / Assert
|
||||
self.assertRaises(IOError, self.helper_save_as_palm, mode)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase
|
||||
from .helper import PillowTestCase
|
||||
from PIL import Image
|
||||
|
||||
|
||||
|
@ -16,7 +16,3 @@ class TestFilePcd(PillowTestCase):
|
|||
|
||||
# target = hopper().resize((768,512))
|
||||
# self.assert_image_similar(im, target, 10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
|
||||
from PIL import Image, ImageFile, PcxImagePlugin
|
||||
|
||||
|
@ -128,7 +128,3 @@ class TestFilePcx(PillowTestCase):
|
|||
for x in range(5):
|
||||
px[x, 3] = 0
|
||||
self._test_buffer_overflow(im)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from helper import unittest, PillowTestCase, hopper
|
||||
from .helper import PillowTestCase, hopper
|
||||
from PIL import Image, PdfParser
|
||||
import io
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
|
||||
class TestFilePdf(PillowTestCase):
|
||||
|
@ -187,8 +188,13 @@ class TestFilePdf(PillowTestCase):
|
|||
# open it, check pages and info
|
||||
with PdfParser.PdfParser(pdf_filename, mode="r+b") as pdf:
|
||||
self.assertEqual(len(pdf.pages), 1)
|
||||
self.assertEqual(len(pdf.info), 1)
|
||||
self.assertEqual(len(pdf.info), 4)
|
||||
self.assertEqual(pdf.info.Title, os.path.splitext(
|
||||
os.path.basename(pdf_filename)
|
||||
)[0])
|
||||
self.assertEqual(pdf.info.Producer, "PdfParser")
|
||||
self.assertIn(b"CreationDate", pdf.info)
|
||||
self.assertIn(b"ModDate", pdf.info)
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
|
||||
# append some info
|
||||
|
@ -203,8 +209,10 @@ class TestFilePdf(PillowTestCase):
|
|||
# open it again, check pages and info again
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
self.assertEqual(len(pdf.pages), 1)
|
||||
self.assertEqual(len(pdf.info), 6)
|
||||
self.assertEqual(len(pdf.info), 8)
|
||||
self.assertEqual(pdf.info.Title, "abc")
|
||||
self.assertIn(b"CreationDate", pdf.info)
|
||||
self.assertIn(b"ModDate", pdf.info)
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
|
||||
# append two images
|
||||
|
@ -216,29 +224,36 @@ class TestFilePdf(PillowTestCase):
|
|||
# open the PDF again, check pages and info again
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
self.assertEqual(len(pdf.pages), 3)
|
||||
self.assertEqual(len(pdf.info), 6)
|
||||
self.assertEqual(len(pdf.info), 8)
|
||||
self.assertEqual(PdfParser.decode_text(pdf.info[b"Title"]), "abc")
|
||||
self.assertEqual(pdf.info.Title, "abc")
|
||||
self.assertEqual(pdf.info.Producer, "PdfParser")
|
||||
self.assertEqual(pdf.info.Keywords, "qw)e\\r(ty")
|
||||
self.assertEqual(pdf.info.Subject, u"ghi\uABCD")
|
||||
self.assertIn(b"CreationDate", pdf.info)
|
||||
self.assertIn(b"ModDate", pdf.info)
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
|
||||
def test_pdf_info(self):
|
||||
# make a PDF file
|
||||
pdf_filename = self.helper_save_as_pdf(
|
||||
"RGB", title="title", author="author", subject="subject",
|
||||
keywords="keywords", creator="creator", producer="producer")
|
||||
keywords="keywords", creator="creator", producer="producer",
|
||||
creationDate=time.strptime("2000", "%Y"),
|
||||
modDate=time.strptime("2001", "%Y"))
|
||||
|
||||
# open it, check pages and info
|
||||
with PdfParser.PdfParser(pdf_filename) as pdf:
|
||||
self.assertEqual(len(pdf.info), 6)
|
||||
self.assertEqual(len(pdf.info), 8)
|
||||
self.assertEqual(pdf.info.Title, "title")
|
||||
self.assertEqual(pdf.info.Author, "author")
|
||||
self.assertEqual(pdf.info.Subject, "subject")
|
||||
self.assertEqual(pdf.info.Keywords, "keywords")
|
||||
self.assertEqual(pdf.info.Creator, "creator")
|
||||
self.assertEqual(pdf.info.Producer, "producer")
|
||||
self.assertEqual(pdf.info.CreationDate,
|
||||
time.strptime("2000", "%Y"))
|
||||
self.assertEqual(pdf.info.ModDate, time.strptime("2001", "%Y"))
|
||||
self.check_pdf_pages_consistency(pdf)
|
||||
|
||||
def test_pdf_append_to_bytesio(self):
|
||||
|
@ -251,7 +266,3 @@ class TestFilePdf(PillowTestCase):
|
|||
f = io.BytesIO(f.getvalue())
|
||||
im.save(f, format="PDF", append=True)
|
||||
self.assertGreater(len(f.getvalue()), initial_size)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import hopper, unittest, PillowTestCase
|
||||
from .helper import hopper, PillowTestCase
|
||||
|
||||
from PIL import Image, PixarImagePlugin
|
||||
|
||||
|
@ -24,7 +24,3 @@ class TestFilePixar(PillowTestCase):
|
|||
self.assertRaises(
|
||||
SyntaxError,
|
||||
PixarImagePlugin.PixarImageFile, invalid_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from helper import unittest, PillowTestCase, PillowLeakTestCase, hopper
|
||||
from .helper import unittest, PillowTestCase, PillowLeakTestCase, hopper
|
||||
from PIL import Image, ImageFile, PngImagePlugin
|
||||
from PIL._util import py3
|
||||
|
||||
|
@ -6,6 +6,12 @@ from io import BytesIO
|
|||
import zlib
|
||||
import sys
|
||||
|
||||
try:
|
||||
from PIL import _webp
|
||||
HAVE_WEBP = True
|
||||
except ImportError:
|
||||
HAVE_WEBP = False
|
||||
|
||||
codecs = dir(Image.core)
|
||||
|
||||
|
||||
|
@ -80,21 +86,22 @@ class TestFilePng(PillowTestCase):
|
|||
self.assertEqual(im.mode, "RGB")
|
||||
self.assertEqual(im.size, (128, 128))
|
||||
self.assertEqual(im.format, "PNG")
|
||||
self.assertEqual(im.get_format_mimetype(), 'image/png')
|
||||
|
||||
hopper("1").save(test_file)
|
||||
im = Image.open(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("L").save(test_file)
|
||||
im = Image.open(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("P").save(test_file)
|
||||
im = Image.open(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("RGB").save(test_file)
|
||||
im = Image.open(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
hopper("I").save(test_file)
|
||||
im = Image.open(test_file)
|
||||
Image.open(test_file)
|
||||
|
||||
def test_invalid_file(self):
|
||||
invalid_file = "Tests/images/flower.jpg"
|
||||
|
@ -327,7 +334,9 @@ class TestFilePng(PillowTestCase):
|
|||
# Check open/load/verify exception (@PIL150)
|
||||
|
||||
im = Image.open(TEST_PNG_FILE)
|
||||
im.verify()
|
||||
|
||||
# Assert that there is no unclosed file warning
|
||||
self.assert_warning(None, im.verify)
|
||||
|
||||
im = Image.open(TEST_PNG_FILE)
|
||||
im.load()
|
||||
|
@ -555,6 +564,42 @@ class TestFilePng(PillowTestCase):
|
|||
chunks = PngImagePlugin.getchunks(im)
|
||||
self.assertEqual(len(chunks), 3)
|
||||
|
||||
def test_textual_chunks_after_idat(self):
|
||||
im = Image.open("Tests/images/hopper.png")
|
||||
self.assertIn('comment', im.text.keys())
|
||||
for k, v in {
|
||||
'date:create': '2014-09-04T09:37:08+03:00',
|
||||
'date:modify': '2014-09-04T09:37:08+03:00',
|
||||
}.items():
|
||||
self.assertEqual(im.text[k], v)
|
||||
|
||||
# Raises a SyntaxError in load_end
|
||||
im = Image.open("Tests/images/broken_data_stream.png")
|
||||
with self.assertRaises(IOError):
|
||||
self.assertIsInstance(im.text, dict)
|
||||
|
||||
# Raises a UnicodeDecodeError in load_end
|
||||
im = Image.open("Tests/images/truncated_image.png")
|
||||
# The file is truncated
|
||||
self.assertRaises(IOError, lambda: im.text)
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
self.assertIsInstance(im.text, dict)
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||
|
||||
# Raises an EOFError in load_end
|
||||
im = Image.open("Tests/images/hopper_idat_after_image_end.png")
|
||||
self.assertEqual(im.text, {'TXT': 'VALUE', 'ZIP': 'VALUE'})
|
||||
|
||||
@unittest.skipUnless(HAVE_WEBP and _webp.HAVE_WEBPANIM,
|
||||
"WebP support not installed with animation")
|
||||
def test_apng(self):
|
||||
im = Image.open("Tests/images/iss634.apng")
|
||||
self.assertEqual(im.get_format_mimetype(), 'image/apng')
|
||||
|
||||
# This also tests reading unknown PNG chunks (fcTL and fdAT) in load_end
|
||||
expected = Image.open("Tests/images/iss634.webp")
|
||||
self.assert_image_similar(im, expected, 0.23)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
|
||||
class TestTruncatedPngPLeaks(PillowLeakTestCase):
|
||||
|
@ -581,7 +626,3 @@ class TestTruncatedPngPLeaks(PillowLeakTestCase):
|
|||
self._test_leak(core)
|
||||
finally:
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|