Merge branch 'master' into reduce

This commit is contained in:
Alexander 2019-12-05 14:23:28 +03:00
commit 5283141417
302 changed files with 5771 additions and 6008 deletions

View File

@ -13,16 +13,8 @@ environment:
TEST_OPTIONS:
DEPLOY: YES
matrix:
- PYTHON: C:/vp/pypy2
EXECUTABLE: bin/pypy.exe
PIP_DIR: bin
VENV: YES
- PYTHON: C:/Python27-x64
- PYTHON: C:/Python37
- PYTHON: C:/Python27
- PYTHON: C:/Python37-x64
- PYTHON: C:/Python36
- PYTHON: C:/Python36-x64
- PYTHON: C:/Python38
- PYTHON: C:/Python38-x64
- PYTHON: C:/Python35
- PYTHON: C:/Python35-x64
- PYTHON: C:/msys64/mingw32
@ -44,11 +36,6 @@ install:
- xcopy c:\pillow-depends\*.tar.gz c:\pillow\winbuild\
- xcopy /s c:\pillow-depends\test_images\* c:\pillow\tests\images
- cd c:\pillow\winbuild\
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy2")
{
c:\pillow\winbuild\appveyor_install_pypy2.cmd
}
- ps: |
if ($env:PYTHON -eq "c:/vp/pypy3")
{
@ -65,6 +52,9 @@ install:
c:\pillow\winbuild\build_deps.cmd
$host.SetShouldExit(0)
}
- curl -fsSL -o gs950.exe https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs950/gs950w32.exe
- gs950.exe /S
- path %path%;C:\Program Files (x86)\gs\gs9.50\bin
build_script:
- ps: |
@ -85,7 +75,8 @@ build_script:
test_script:
- cd c:\pillow
- '%PYTHON%\%PIP_DIR%\pip.exe install pytest pytest-cov'
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov-report term --cov-report xml Tests'
- c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\%EXECUTABLE%
- '%PYTHON%\%EXECUTABLE% -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests'
#- '%PYTHON%\%EXECUTABLE% test-installed.py -v -s %TEST_OPTIONS%' TODO TEST_OPTIONS with pytest?
after_test:

View File

@ -6,4 +6,13 @@ codecov:
# https://docs.codecov.io/v4.3.6/docs/comparing-commits
allow_coverage_offsets: true
token: 6dafc396-e7f5-4221-a38a-8b07a49fbdae
comment: off
# Matches 'omit:' in .coveragerc
ignore:
- "Tests/32bit_segfault_check.py"
- "Tests/bench_cffi_access.py"
- "Tests/check_*.py"
- "Tests/createfontdatachunk.py"

View File

@ -12,3 +12,10 @@ exclude_lines =
# Don't complain about debug code
if Image.DEBUG:
if DEBUG:
[run]
omit =
Tests/32bit_segfault_check.py
Tests/bench_cffi_access.py
Tests/check_*.py
Tests/createfontdatachunk.py

View File

@ -9,14 +9,14 @@ Please send a pull request to the master branch. Please include [documentation](
- Fork the Pillow repository.
- Create a branch from master.
- Develop bug fixes, features, tests, etc.
- Run the test suite on Python 2.7 and 3.x. You can enable [Travis CI](https://travis-ci.org/profile/) and [AppVeyor](https://ci.appveyor.com/projects/new) on your repo to catch test failures prior to the pull request, and [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
- Run the test suite. You can enable [Travis CI](https://travis-ci.org/profile/) and [AppVeyor](https://ci.appveyor.com/projects/new) on your repo to catch test failures prior to the pull request, and [Codecov](https://codecov.io/gh) to see if the changed code is covered by tests.
- Create a pull request to pull the changes from your branch to the Pillow master.
### Guidelines
- Separate code commits from reformatting commits.
- Provide tests for any newly added code.
- Follow PEP8.
- Follow PEP 8.
- When committing only documentation changes please include [ci skip] in the commit message to avoid running tests on Travis-CI and AppVeyor.
## Reporting Issues

2
.github/FUNDING.yml vendored
View File

@ -1 +1 @@
tidelift: pypi/pillow
tidelift: "pypi/Pillow"

View File

@ -8,17 +8,17 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python: [3.7]
python-version: ["3.8"]
name: Python ${{ matrix.python }}
name: Python ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python }}
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python }}
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |

17
.github/workflows/macos-install.sh vendored Executable file
View File

@ -0,0 +1,17 @@
#!/bin/bash
set -e
brew install libtiff libjpeg openjpeg libimagequant webp little-cms2 freetype
PYTHONOPTIMIZE=0 pip install cffi
pip install coverage
pip install olefile
pip install -U pytest
pip install -U pytest-cov
pip install pyroma
pip install test-image-results
pip install numpy
# extra test images
pushd depends && ./install_extra_test_images.sh && popd

40
.github/workflows/test-docker.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Test Docker
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
docker: [
alpine,
arch,
ubuntu-16.04-xenial-amd64,
ubuntu-18.04-bionic-amd64,
debian-9-stretch-x86,
debian-10-buster-x86,
centos-6-amd64,
centos-7-amd64,
amazon-1-amd64,
amazon-2-amd64,
fedora-30-amd64,
fedora-31-amd64,
]
dockerTag: [master]
name: ${{ matrix.docker }}
steps:
- uses: actions/checkout@v1
- name: Docker pull
run: |
docker pull pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}
- name: Docker build
run: |
# The Pillow user in the docker container is UID 1000
sudo chown -R 1000 $GITHUB_WORKSPACE
docker run -v $GITHUB_WORKSPACE:/Pillow pythonpillow/${{ matrix.docker }}:${{ matrix.dockerTag }}

392
.github/workflows/test-windows.yml vendored Normal file
View File

@ -0,0 +1,392 @@
name: Test Windows
on: [push, pull_request]
jobs:
build:
runs-on: windows-2019
strategy:
fail-fast: false
matrix:
python-version: ["3.5", "3.6", "3.7", "3.8", "pypy3.6"]
architecture: ["x86", "x64"]
include:
- architecture: "x86"
platform-vcvars: "x86"
platform-msbuild: "Win32"
- architecture: "x64"
platform-vcvars: "x86_amd64"
platform-msbuild: "x64"
- python-version: "pypy3.6"
pypy-version: "pypy3.6-v7.2.0-win32"
pypy-url: "https://bitbucket.org/pypy/pypy/downloads/pypy3.6-v7.2.0-win32.zip"
exclude:
- python-version: "pypy3.6"
architecture: "x64"
timeout-minutes: 30
name: Python ${{ matrix.python-version }} ${{ matrix.architecture }}
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v1
with:
repository: python-pillow/pillow-depends
ref: master
- name: Cache
uses: actions/cache@v1
with:
path: ~\AppData\Local\pip\Cache
key:
${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.architecture }}-${{ hashFiles('**/.github/workflows/test-windows.yml') }}
restore-keys: |
${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.architecture }}-
${{ runner.os }}-${{ matrix.python-version }}-
- name: Install PyPy
if: "contains(matrix.python-version, 'pypy')"
run: |
curl -fsSL -o pypy3.zip "${{ matrix.pypy-url }}"
7z x pypy3.zip "-o$env:RUNNER_WORKSPACE\"
mv "$env:RUNNER_WORKSPACE\${{ matrix.pypy-version }}" "$env:RUNNER_WORKSPACE\${{ matrix.python-version }}"
$env:PYTHON="$env:RUNNER_WORKSPACE\${{ matrix.python-version }}"
# set env: pythonLocation
Write-Host "`#`#[set-env name=pythonLocation;]$env:PYTHON" # old syntax https://github.com/actions/toolkit/issues/61
Write-Host "::set-env name=pythonLocation::$env:PYTHON" # new syntax https://github.com/actions/toolkit/blob/5bb77ec03fea98332e41f9347c8fbb1ce1e48f4a/docs/commands.md
New-Item -ItemType SymbolicLink -Path "$env:PYTHON\python.exe" -Target "$env:PYTHON\pypy3.exe"
curl -fsSL -o get-pip.py https://bootstrap.pypa.io/get-pip.py
$env:PATH = "$env:PYTHON\bin;$env:PATH"
& $env:PYTHON\python.exe get-pip.py
shell: pwsh
# sets env: pythonLocation
- name: Set up Python
if: "!contains(matrix.python-version, 'pypy')"
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
architecture: ${{ matrix.architecture }}
- name: pip install wheel pytest pytest-cov
run: |
"%pythonLocation%\python.exe" -m pip install wheel pytest pytest-cov
shell: cmd
- name: Fetch dependencies
run: |
7z x ..\pillow-depends\nasm-2.14.02-win64.zip "-o$env:RUNNER_WORKSPACE\"
Write-Host "`#`#[add-path]$env:RUNNER_WORKSPACE\nasm-2.14.02"
Write-Host "::add-path::$env:RUNNER_WORKSPACE\nasm-2.14.02"
..\pillow-depends\gs950w32.exe /S
Write-Host "`#`#[add-path]C:\Program Files (x86)\gs\gs9.50\bin"
Write-Host "::add-path::C:\Program Files (x86)\gs\gs9.50\bin"
$env:PYTHON=$env:pythonLocation
xcopy ..\pillow-depends\*.zip $env:GITHUB_WORKSPACE\winbuild\
xcopy ..\pillow-depends\*.tar.gz $env:GITHUB_WORKSPACE\winbuild\
xcopy /s ..\pillow-depends\test_images\* $env:GITHUB_WORKSPACE\tests\images\
cd $env:GITHUB_WORKSPACE/winbuild/
python.exe $env:GITHUB_WORKSPACE\winbuild\build_dep.py
env:
EXECUTABLE: bin\python.exe
shell: pwsh
- name: Build dependencies / libjpeg
if: false
run: |
REM FIXME uses /MT not /MD, see makefile.vc and win32.mak for more info
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\jpeg-9c
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
nmake -nologo -f makefile.vc setup-vc6
nmake -nologo -f makefile.vc clean
nmake -nologo -f makefile.vc nodebug=1 libjpeg.lib cjpeg.exe djpeg.exe
copy /Y /B j*.h %INCLIB%
copy /Y /B *.lib %INCLIB%
copy /Y /B *.exe %INCLIB%
shell: cmd
- name: Build dependencies / libjpeg-turbo
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\libjpeg-turbo-2.0.3
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
set CMAKE=%CMAKE% -DENABLE_SHARED:BOOL=OFF -DWITH_JPEG8:BOOL=TRUE -DWITH_CRT_DLL:BOOL=TRUE -DCMAKE_BUILD_TYPE=Release
%CMAKE% -G "NMake Makefiles" .
nmake -nologo -f Makefile clean
nmake -nologo -f Makefile jpeg-static cjpeg-static djpeg-static
copy /Y /B j*.h %INCLIB%
copy /Y /B jpeg-static.lib %INCLIB%\libjpeg.lib
copy /Y /B cjpeg-static.exe %INCLIB%\cjpeg.exe
copy /Y /B djpeg-static.exe %INCLIB%\djpeg.exe
shell: cmd
- name: Build dependencies / zlib
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\zlib-1.2.11
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
nmake -nologo -f win32\Makefile.msc clean
nmake -nologo -f win32\Makefile.msc zlib.lib
copy /Y /B z*.h %INCLIB%
copy /Y /B *.lib %INCLIB%
copy /Y /B zlib.lib %INCLIB%\z.lib
shell: cmd
- name: Build dependencies / LibTIFF
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\tiff-4.1.0
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
copy %GITHUB_WORKSPACE%\winbuild\tiff.opt nmake.opt
nmake -nologo -f makefile.vc clean
nmake -nologo -f makefile.vc lib
copy /Y /B libtiff\tiff*.h %INCLIB%
copy /Y /B libtiff\*.dll %INCLIB%
copy /Y /B libtiff\*.lib %INCLIB%
shell: cmd
- name: Build dependencies / WebP
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\libwebp-1.0.3
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
rmdir /S /Q output\release-static
nmake -nologo -f Makefile.vc CFG=release-static OBJDIR=output ARCH=${{ matrix.architecture }} all
mkdir %INCLIB%\webp
copy /Y /B src\webp\*.h %INCLIB%\webp
copy /Y /B output\release-static\${{ matrix.architecture }}\lib\* %INCLIB%
shell: cmd
- name: Build dependencies / FreeType
run: |
REM Toolkit v100 not available; missing VCTargetsPath; Clean fails
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\freetype-2.10.1
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
rmdir /S /Q objs
set DefaultPlatformToolset=v142
set VCTargetsPath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\
set MSBUILD="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
powershell -Command "(gc builds\windows\vc2010\freetype.vcxproj) -replace 'MultiThreaded<', 'MultiThreadedDLL<' | Out-File -encoding ASCII builds\windows\vc2010\freetype.vcxproj"
%MSBUILD% builds\windows\vc2010\freetype.sln /t:Build /p:Configuration="Release Static" /p:Platform=${{ matrix.platform-msbuild }} /m
xcopy /Y /E /Q include %INCLIB%
copy /Y /B "objs\${{ matrix.platform-msbuild }}\Release Static\freetype.lib" %INCLIB%
shell: cmd
- name: Build dependencies / LCMS2
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\lcms2-2.8
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
rmdir /S /Q Lib
rmdir /S /Q Projects\VC2015\Release
set VCTargetsPath=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\
set MSBUILD="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
powershell %GITHUB_WORKSPACE%\winbuild\lcms2_patch.ps1
%MSBUILD% Projects\VC2015\lcms2.sln /t:Clean;lcms2_static /p:Configuration="Release" /p:Platform=${{ matrix.platform-msbuild }} /m
xcopy /Y /E /Q include %INCLIB%
copy /Y /B Lib\MS\*.lib %INCLIB%
shell: cmd
- name: Build dependencies / OpenJPEG
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\openjpeg-2.3.1msvcr10-x32
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
set CMAKE=%CMAKE% -DBUILD_THIRDPARTY:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
%CMAKE% -G "NMake Makefiles" .
nmake -nologo -f Makefile clean
nmake -nologo -f Makefile
mkdir %INCLIB%\openjpeg-2.3.1
copy /Y /B src\lib\openjp2\*.h %INCLIB%\openjpeg-2.3.1
copy /Y /B bin\*.lib %INCLIB%
shell: cmd
# GPL licensed; skip if building wheels
- name: Build dependencies / libimagequant
if: "github.event_name != 'push' || contains(matrix.python-version, 'pypy')"
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
rem ba653c8: Merge tag '2.12.5' into msvc
cd /D %BUILD%\libimagequant-ba653c8ccb34dde4e21c6076d85a72d21ed9d971
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
echo (gc CMakeLists.txt) -replace 'add_library', "add_compile_options(-openmp-)`r`nadd_library" ^| Out-File -encoding ASCII CMakeLists.txt > patch.ps1
echo (gc CMakeLists.txt) -replace ' SHARED', ' STATIC' ^| Out-File -encoding ASCII CMakeLists.txt >> patch.ps1
powershell .\patch.ps1
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
%CMAKE% -G "NMake Makefiles" .
nmake -nologo -f Makefile clean
nmake -nologo -f Makefile
copy /Y /B *.h %INCLIB%
copy /Y /B *.lib %INCLIB%
shell: cmd
# for Raqm
- name: Build dependencies / HarfBuzz
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
set INCLUDE=%INCLUDE%;%INCLIB%
set LIB=%LIB%;%INCLIB%
cd /D %BUILD%\harfbuzz-2.6.1
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
set CMAKE=%CMAKE% -DHB_HAVE_FREETYPE:BOOL=ON -DCMAKE_BUILD_TYPE=Release
%CMAKE% -G "NMake Makefiles" .
nmake -nologo -f Makefile clean
nmake -nologo -f Makefile harfbuzz
copy /Y /B src\*.h %INCLIB%
copy /Y /B *.lib %INCLIB%
shell: cmd
# for Raqm
- name: Build dependencies / FriBidi
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
cd /D %BUILD%\fribidi-1.0.7
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
copy /Y /B %GITHUB_WORKSPACE%\winbuild\fribidi.cmake CMakeLists.txt
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
%CMAKE% -G "NMake Makefiles" .
nmake -nologo -f Makefile clean
nmake -nologo -f Makefile fribidi
copy /Y /B lib\*.h %INCLIB%
copy /Y /B *.lib %INCLIB%
shell: cmd
- name: Build dependencies / Raqm
run: |
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
set BUILD=%GITHUB_WORKSPACE%\winbuild\build
set INCLUDE=%INCLUDE%;%INCLIB%
set LIB=%LIB%;%INCLIB%
cd /D %BUILD%\libraqm-0.7.0
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
echo on
copy /Y /B %GITHUB_WORKSPACE%\winbuild\raqm.cmake CMakeLists.txt
set CMAKE=cmake.exe -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_RULE_MESSAGES:BOOL=OFF
set CMAKE=%CMAKE% -DCMAKE_BUILD_TYPE=Release
%CMAKE% -G "NMake Makefiles" .
nmake -nologo -f Makefile clean
nmake -nologo -f Makefile libraqm
copy /Y /B src\*.h %INCLIB%
copy /Y /B libraqm.dll %INCLIB%
shell: cmd
- name: Build Pillow
run: |
set PYTHON=%pythonLocation%
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set MPLSRC=%GITHUB_WORKSPACE%
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
cd /D %GITHUB_WORKSPACE%
set LIB=%INCLIB%;%PYTHON%\tcl
set INCLUDE=%INCLIB%;%GITHUB_WORKSPACE%\depends\tcl86\include;%INCLUDE%
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
set MSSdk=1
set DISTUTILS_USE_SDK=1
set py_vcruntime_redist=true
%PYTHON%\python.exe setup.py build_ext install
rem Add libraqm.dll (copied to INCLIB) to PATH.
path %INCLIB%;%PATH%
%PYTHON%\python.exe selftest.py --installed
shell: cmd
# failing with PyPy3
- name: Enable heap verification
if: "!contains(matrix.python-version, 'pypy')"
run: |
c:\"Program Files (x86)"\"Windows Kits"\10\Debuggers\x86\gflags.exe /p /enable %PYTHON%\python.exe
shell: cmd
- name: Test Pillow
run: |
set PYTHON=%pythonLocation%
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
rem Add libraqm.dll (copied to INCLIB) to PATH.
path %INCLIB%;%PATH%
cd /D %GITHUB_WORKSPACE%
%PYTHON%\python.exe -m pytest -vx --cov PIL --cov Tests --cov-report term --cov-report xml Tests
shell: cmd
- name: Upload errors
uses: actions/upload-artifact@v1
if: failure()
with:
name: errors
path: Tests/errors
- name: Upload coverage
if: success()
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
name: ${{ runner.os }} Python ${{ matrix.python-version }}
- name: Build wheel
id: wheel
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
run: |
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ##[set-output name=dist;]dist-%%a
for /f "tokens=3 delims=/" %%a in ("${{ github.ref }}") do echo ::set-output name=dist::dist-%%a
set PYTHON=%pythonLocation%
set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\V7.1A\Include
set MPLSRC=%GITHUB_WORKSPACE%
set INCLIB=%GITHUB_WORKSPACE%\winbuild\depends\msvcr10-x32
cd /D %GITHUB_WORKSPACE%
set LIB=%INCLIB%;%PYTHON%\tcl
set INCLUDE=%INCLIB%;%GITHUB_WORKSPACE%\depends\tcl86\include;%INCLUDE%
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.platform-vcvars }}
%PYTHON%\python.exe setup.py bdist_wheel
shell: cmd
- uses: actions/upload-artifact@v1
if: "github.event_name == 'push' && !contains(matrix.python-version, 'pypy')"
with:
name: ${{ steps.wheel.outputs.dist }}
path: dist

103
.github/workflows/test.yml vendored Normal file
View File

@ -0,0 +1,103 @@
name: Test
on: [push, pull_request]
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [
"ubuntu-latest",
"macOS-latest",
]
python-version: [
"pypy3",
"3.8",
"3.7",
"3.6",
"3.5",
]
include:
- python-version: "3.5"
env: PYTHONOPTIMIZE=2
- python-version: "3.6"
env: PYTHONOPTIMIZE=1
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} Python ${{ matrix.python-version }}
steps:
- uses: actions/checkout@v1
- name: Ubuntu cache
uses: actions/cache@v1
if: startsWith(matrix.os, 'ubuntu')
with:
path: ~/.cache/pip
key:
${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.travis/*.sh') }}
restore-keys: |
${{ matrix.os }}-${{ matrix.python-version }}-
- name: macOS cache
uses: actions/cache@v1
if: startsWith(matrix.os, 'macOS')
with:
path: ~/Library/Caches/pip
key:
${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.travis/*.sh') }}
restore-keys: |
${{ matrix.os }}-${{ matrix.python-version }}-
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install Linux dependencies
if: startsWith(matrix.os, 'ubuntu')
run: |
.travis/install.sh
- name: Install macOS dependencies
if: startsWith(matrix.os, 'macOS')
run: |
.github/workflows/macos-install.sh
- name: Build
run: |
.travis/build.sh
- name: Test
run: |
.travis/test.sh
- name: Upload errors
uses: actions/upload-artifact@v1
if: failure()
with:
name: errors
path: Tests/errors
- name: Docs
if: matrix.python-version == 3.8
run: |
pip install sphinx-rtd-theme
make doccheck
- name: After success
if: success()
run: |
.travis/after_success.sh
env:
MATRIX_OS: ${{ matrix.os }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
- name: Upload coverage
if: success()
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
name: ${{ matrix.os }} Python ${{ matrix.python-version }}

View File

@ -6,8 +6,8 @@ notifications:
irc: "chat.freenode.net#pil"
# 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.
# Run slow PyPy next, to give it a headstart and reduce waiting time.
# Run latest 3.x next, to get quick compatibility results.
# Then run the remainder, with fastest Docker jobs last.
matrix:
@ -16,25 +16,22 @@ matrix:
- python: "3.6"
name: "Lint"
env: LINT="true"
- python: "pypy"
name: "PyPy2 Xenial"
- python: "pypy3"
name: "PyPy3 Xenial"
- python: "3.8"
name: "3.8 Xenial"
services: xvfb
- python: '3.7'
name: "3.7 Xenial"
- python: '2.7'
name: "2.7 Xenial"
- python: "2.7_with_system_site_packages" # For PyQt4
name: "2.7_with_system_site_packages Xenial"
services: xvfb
- python: '3.6'
name: "3.6 Xenial PYTHONOPTIMIZE=1"
env: PYTHONOPTIMIZE=1
services: xvfb
- python: '3.5'
name: "3.5 Xenial PYTHONOPTIMIZE=2"
env: PYTHONOPTIMIZE=2
- python: "3.8-dev"
name: "3.8-dev Xenial"
services: xvfb
- env: DOCKER="alpine" DOCKER_TAG="master"
- env: DOCKER="arch" DOCKER_TAG="master" # contains PyQt5
- env: DOCKER="ubuntu-16.04-xenial-amd64" DOCKER_TAG="master"
@ -45,8 +42,8 @@ matrix:
- 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-29-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-30-amd64" DOCKER_TAG="master"
- env: DOCKER="fedora-31-amd64" DOCKER_TAG="master"
services:
- docker
@ -67,7 +64,8 @@ script:
if [ "$LINT" == "true" ]; then
tox -e lint
elif [ "$DOCKER" == "" ]; then
.travis/script.sh
.travis/build.sh
.travis/test.sh
elif [ "$DOCKER" ]; then
# the Pillow user in the docker container is UID 1000
sudo chown -R 1000 $TRAVIS_BUILD_DIR

View File

@ -1,7 +1,12 @@
#!/bin/bash
# gather the coverage data
sudo apt-get -qq install lcov
if [[ "$MATRIX_OS" == "macOS-latest" ]]; then
brew install lcov
else
sudo apt-get -qq install lcov
fi
lcov --capture --directory . -b . --output-file coverage.info
# filter to remove system headers
lcov --remove coverage.info '/usr/*' -o coverage.filtered.info
@ -11,16 +16,14 @@ coveralls-lcov -v -n coverage.filtered.info > coverage.c.json
coverage report
pip install codecov
if [[ $TRAVIS_PYTHON_VERSION != "2.7_with_system_site_packages" ]]; then
# Not working here. Just skip it, it's being removed soon.
pip install coveralls-merge
coveralls-merge coverage.c.json
pip install coveralls-merge
coveralls-merge coverage.c.json
if [[ $TRAVIS ]]; then
codecov
fi
codecov
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ] && [ "$DOCKER" == "" ]; then
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ] && [ "$DOCKER" == "" ]; then
# Coverage and quality reports on just the latest diff.
# (Installation is very slow on Py3, so just do it for Py2.)
depends/diffcover-install.sh
depends/diffcover-run.sh
fi

10
.travis/build.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
set -e
coverage erase
if [ $(uname) == "Darwin" ]; then
export CPPFLAGS="-I/usr/local/miniconda/include";
fi
make clean
make install-coverage

View File

@ -3,7 +3,7 @@
set -e
sudo apt-get update
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk python-qt4\
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\
ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\
cmake imagemagick libharfbuzz-dev libfribidi-dev
@ -15,9 +15,13 @@ pip install -U pytest-cov
pip install pyroma
pip install test-image-results
pip install numpy
if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then
sudo apt-get -qq install pyqt5-dev-tools
pip install pyqt5
fi
# docs only on Python 2.7
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then pip install -r requirements.txt ; fi
# docs only on Python 3.7
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then pip install -r requirements.txt ; fi
# webp
pushd depends && ./install_webp.sh && popd

View File

@ -1,12 +0,0 @@
#!/bin/bash
set -e
coverage erase
make clean
make install-coverage
python -m pytest -v -x --cov PIL --cov-report term Tests
# Docs
if [ "$TRAVIS_PYTHON_VERSION" == "2.7" ]; then make doccheck; fi

8
.travis/test.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/bash
set -e
python -m pytest -v -x --cov PIL --cov Tests --cov-report term Tests
# Docs
if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then make doccheck; fi

View File

@ -2,11 +2,71 @@
Changelog (Pillow)
==================
6.2.0 (2019-10-01)
7.0.0 (unreleased)
------------------
- Handle broken Photoshop data #4239
[radarhere]
- Raise a specific exception if no data is found for an MPO frame #4240
[radarhere]
- Fix Unicode support for PyPy #4145
[nulano]
- Drop support for EOL Python 2.7 #4109
[hugovk, radarhere, jdufresne]
- Added UnidentifiedImageError #4182
[radarhere, hugovk]
- Remove deprecated __version__ from plugins #4197
[hugovk, radarhere]
- Fixed freeing unallocated pointer when resizing with height too large #4116
[radarhere]
- Copy info in Image.transform #4128
[radarhere]
- Corrected DdsImagePlugin setting info gamma #4171
[radarhere]
- Depends: Update libtiff to 4.1.0 #4195, Tk Tcl to 8.6.10 #4229
[radarhere]
- Improve handling of file resources #3577
[jdufresne]
- Removed CI testing of Fedora 29 #4165
[hugovk]
- Added pypy3 to tox envlist #4137
[jdufresne]
- Drop support for EOL PyQt4 and PySide #4108
[hugovk, radarhere]
- Removed deprecated setting of TIFF image sizes #4114
[radarhere]
- Removed deprecated PILLOW_VERSION #4107
[hugovk]
- Changed default frombuffer raw decoder args #1730
[radarhere]
6.2.1 (2019-10-21)
------------------
- This is the last Pillow release to support Python 2.7 #3642
- Add support for Python 3.8 #4141
[hugovk]
6.2.0 (2019-10-01)
------------------
- Catch buffer overruns #4104
[radarhere]

View File

@ -3,7 +3,7 @@
.DEFAULT_GOAL := release-test
clean:
python setup.py clean
python3 setup.py clean
rm src/PIL/*.so || true
rm -r build || true
find . -name __pycache__ | xargs rm -r || true
@ -15,8 +15,8 @@ co:
done
coverage:
python selftest.py
python setup.py test
python3 selftest.py
python3 setup.py test
rm -r htmlcov || true
coverage report
@ -30,7 +30,7 @@ doccheck:
$(MAKE) -C docs linkcheck || true
docserve:
cd docs/_build/html && python -mSimpleHTTPServer 2> /dev/null&
cd docs/_build/html && python3 -mSimpleHTTPServer 2> /dev/null&
help:
@echo "Welcome to Pillow development. Please use \`make <target>\` where <target> is one of"
@ -50,22 +50,22 @@ help:
@echo " upload-test build and upload sdists to test.pythonpackages.com"
inplace: clean
python setup.py develop build_ext --inplace
python3 setup.py develop build_ext --inplace
install:
python setup.py install
python selftest.py
python3 setup.py install
python3 selftest.py
install-coverage:
CFLAGS="-coverage" python setup.py build_ext install
python selftest.py
CFLAGS="-coverage" python3 setup.py build_ext install
python3 selftest.py
debug:
# make a debug version if we don't have a -dbg python. Leaves in symbols
# for our stuff, kills optimization, and redirects to dev null so we
# see any build failures.
make clean > /dev/null
CFLAGS='-g -O0' python setup.py build_ext install > /dev/null
CFLAGS='-g -O0' python3 setup.py build_ext install > /dev/null
install-req:
pip install -r requirements.txt
@ -76,17 +76,17 @@ install-venv:
release-test:
$(MAKE) install-req
python setup.py develop
python selftest.py
python -m pytest Tests
python setup.py install
python -m pytest -qq
python3 setup.py develop
python3 selftest.py
python3 -m pytest Tests
python3 setup.py install
python3 -m pytest -qq
check-manifest
pyroma .
viewdoc
sdist:
python setup.py sdist --format=gztar
python3 setup.py sdist --format=gztar
test:
pytest -qq
@ -97,10 +97,10 @@ upload-test:
# username:
# password:
# repository = http://test.pythonpackages.com
python setup.py sdist --format=gztar upload -r test
python3 setup.py sdist --format=gztar upload -r test
upload:
python setup.py sdist --format=gztar upload
python3 setup.py sdist --format=gztar upload
readme:
viewdoc

View File

@ -14,7 +14,7 @@ Pillow is the friendly PIL fork by `Alex Clark and Contributors <https://github.
* - docs
- |docs|
* - tests
- |linux| |macos| |windows| |coverage|
- |linux| |macos| |windows| |gha_lint| |gha| |gha_windows| |gha_docker| |coverage|
* - package
- |zenodo| |tidelift| |version| |downloads|
* - social
@ -60,6 +60,18 @@ To report a security vulnerability, please follow the procedure described in the
:target: https://ci.appveyor.com/project/python-pillow/Pillow
:alt: AppVeyor CI build status (Windows)
.. |gha_lint| image:: https://github.com/python-pillow/Pillow/workflows/Lint/badge.svg
:alt: GitHub Actions build status (Lint)
.. |gha_docker| image:: https://github.com/python-pillow/Pillow/workflows/Test%20Docker/badge.svg
:alt: GitHub Actions build status (Test Docker)
.. |gha| image:: https://github.com/python-pillow/Pillow/workflows/Test/badge.svg
:alt: GitHub Actions build status (Test Linux and macOS)
.. |gha_windows| image:: https://github.com/python-pillow/Pillow/workflows/Test%20Windows/badge.svg
:alt: GitHub Actions build status (Test Windows)
.. |coverage| image:: https://codecov.io/gh/python-pillow/Pillow/branch/master/graph/badge.svg
:target: https://codecov.io/gh/python-pillow/Pillow
:alt: Code coverage

View File

@ -51,6 +51,7 @@ Released as needed for security, installation or critical bug fixes.
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.1*`
* [ ] Create a [new release on GitHub](https://github.com/python-pillow/Pillow/releases/new)
## Embargoed Release
@ -92,7 +93,7 @@ Released as needed privately to individual vendors for critical security-related
```
* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/).
```bash
wget -m -A 'Pillow-<VERSION>*' \
wget -m -A 'Pillow-<VERSION>-*' \
http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com
```

View File

@ -27,6 +27,6 @@ Run all the tests from the root of the Pillow source distribution::
Or with coverage::
pytest --cov PIL --cov-report term
pytest --cov PIL --cov Tests --cov-report term
coverage html
open htmlcov/index.html

View File

@ -1,8 +1,9 @@
import time
import unittest
from PIL import PyAccess
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
# Not running this test by default. No DOS against Travis CI.

View File

@ -1,23 +0,0 @@
import sys
import timeit
from . import helper
sys.path.insert(0, ".")
def bench(mode):
im = helper.hopper(mode)
get = im.im.getpixel
xy = 50, 50 # position shouldn't really matter
t0 = timeit.default_timer()
for _ in range(1000000):
get(xy)
print(mode, timeit.default_timer() - t0, "us")
bench("L")
bench("I")
bench("I;16")
bench("F")
bench("RGB")

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
TEST_FILE = "Tests/images/fli_overflow.fli"
@ -9,8 +11,8 @@ class TestFliOverflow(PillowTestCase):
def test_fli_overflow(self):
# this should not crash with a malloc error or access violation
im = Image.open(TEST_FILE)
im.load()
with Image.open(TEST_FILE) as im:
im.load()
if __name__ == "__main__":

View File

@ -4,9 +4,5 @@
from io import BytesIO
from PIL import Image
from PIL._util import py3
if py3:
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00", "latin-1")))
else:
Image.open(BytesIO(bytes("icns\x00\x00\x00\x10hang\x00\x00\x00\x00")))
Image.open(BytesIO(b"icns\x00\x00\x00\x10hang\x00\x00\x00\x00"))

View File

@ -1,18 +1,15 @@
#!/usr/bin/env python
from __future__ import division
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase, is_win32
min_iterations = 100
max_iterations = 10000
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestImagingLeaks(PillowTestCase):
def _get_mem_usage(self):
from resource import getpagesize, getrusage, RUSAGE_SELF

View File

@ -4,19 +4,5 @@
from io import BytesIO
from PIL import Image
from PIL._util import py3
if py3:
Image.open(
BytesIO(
bytes(
"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang",
"latin-1",
)
)
)
else:
Image.open(
BytesIO(bytes("\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang"))
)
Image.open(BytesIO(b"\x00\x00\x00\x0cjP\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x00hang"))

View File

@ -1,9 +1,9 @@
import sys
import unittest
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase, is_win32
# Limits for testing the leak
mem_limit = 1024 * 1048576
@ -13,7 +13,7 @@ codecs = dir(Image.core)
test_file = "Tests/images/rgb_trns_ycbc.jp2"
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestJpegLeaks(PillowTestCase):
def setUp(self):
if "jpeg2k_encoder" not in codecs or "jpeg2k_decoder" not in codecs:

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
class TestJ2kEncodeOverflow(PillowTestCase):

View File

@ -1,7 +1,7 @@
import sys
import unittest
from io import BytesIO
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper, is_win32
iterations = 5000
@ -15,7 +15,7 @@ valgrind --tool=massif python test-installed.py -s -v Tests/check_jpeg_leaks.py
"""
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestJpegLeaks(PillowTestCase):
"""

View File

@ -1,8 +1,9 @@
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
# This test is not run automatically.
#

View File

@ -1,8 +1,9 @@
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
# This test is not run automatically.
#

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
TEST_FILE = "Tests/images/libtiff_segfault.tif"
@ -12,8 +14,8 @@ class TestLibtiffSegfault(PillowTestCase):
"""
with self.assertRaises(IOError):
im = Image.open(TEST_FILE)
im.load()
with Image.open(TEST_FILE) as im:
im.load()
if __name__ == "__main__":

View File

@ -1,9 +1,10 @@
import unittest
import zlib
from io import BytesIO
from PIL import Image, ImageFile, PngImagePlugin
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
TEST_FILE = "Tests/images/png_decompression_dos.png"

11
Tests/conftest.py Normal file
View File

@ -0,0 +1,11 @@
def pytest_report_header(config):
import io
try:
from PIL import features
with io.StringIO() as out:
features.pilinfo(out=out, supported_formats=False)
return out.getvalue()
except Exception as e:
return "pytest_report_header failed: %s" % str(e)

View File

@ -1,6 +1,4 @@
#!/usr/bin/env python
from __future__ import print_function
import base64
import os

View File

@ -1,16 +1,16 @@
"""
Helper functions.
"""
from __future__ import print_function
import logging
import os
import subprocess
import sys
import tempfile
import unittest
from io import BytesIO
from PIL import Image, ImageMath
from PIL._util import py3
logger = logging.getLogger(__name__)
@ -22,12 +22,26 @@ if os.environ.get("SHOW_ERRORS", None):
HAS_UPLOADER = True
class test_image_results:
@classmethod
def upload(self, a, b):
@staticmethod
def upload(a, b):
a.show()
b.show()
elif "GITHUB_ACTIONS" in os.environ:
HAS_UPLOADER = True
class test_image_results:
@staticmethod
def upload(a, b):
dir_errors = os.path.join(os.path.dirname(__file__), "errors")
os.makedirs(dir_errors, exist_ok=True)
tmpdir = tempfile.mkdtemp(dir=dir_errors)
a.save(os.path.join(tmpdir, "a.png"))
b.save(os.path.join(tmpdir, "b.png"))
return tmpdir
else:
try:
import test_image_results
@ -51,37 +65,22 @@ def convert_to_comparable(a, b):
class PillowTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
# holds last result object passed to run method:
self.currentResult = None
def run(self, result=None):
self.currentResult = result # remember result for use later
unittest.TestCase.run(self, result) # call superclass run method
def delete_tempfile(self, path):
try:
ok = self.currentResult.wasSuccessful()
except AttributeError: # for pytest
ok = True
if ok:
# only clean out tempfiles if test passed
try:
os.remove(path)
except OSError:
pass # report?
else:
print("=== orphaned temp file: %s" % path)
os.remove(path)
except OSError:
pass # report?
def assert_deep_equal(self, a, b, msg=None):
try:
self.assertEqual(
len(a), len(b), msg or "got length %s, expected %s" % (len(a), len(b))
len(a),
len(b),
msg or "got length {}, expected {}".format(len(a), len(b)),
)
self.assertTrue(
all(x == y for x, y in zip(a, b)), msg or "got %s, expected %s" % (a, b)
all(x == y for x, y in zip(a, b)),
msg or "got {}, expected {}".format(a, b),
)
except Exception:
self.assertEqual(a, b, msg)
@ -89,20 +88,24 @@ class PillowTestCase(unittest.TestCase):
def assert_image(self, im, mode, size, msg=None):
if mode is not None:
self.assertEqual(
im.mode, mode, msg or "got mode %r, expected %r" % (im.mode, mode)
im.mode,
mode,
msg or "got mode {!r}, expected {!r}".format(im.mode, mode),
)
if size is not None:
self.assertEqual(
im.size, size, msg or "got size %r, expected %r" % (im.size, size)
im.size,
size,
msg or "got size {!r}, expected {!r}".format(im.size, size),
)
def assert_image_equal(self, a, b, msg=None):
self.assertEqual(
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
a.mode, b.mode, msg or "got mode {!r}, expected {!r}".format(a.mode, b.mode)
)
self.assertEqual(
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
)
if a.tobytes() != b.tobytes():
if HAS_UPLOADER:
@ -123,10 +126,10 @@ class PillowTestCase(unittest.TestCase):
def assert_image_similar(self, a, b, epsilon, msg=None):
epsilon = float(epsilon)
self.assertEqual(
a.mode, b.mode, msg or "got mode %r, expected %r" % (a.mode, b.mode)
a.mode, b.mode, msg or "got mode {!r}, expected {!r}".format(a.mode, b.mode)
)
self.assertEqual(
a.size, b.size, msg or "got size %r, expected %r" % (a.size, b.size)
a.size, b.size, msg or "got size {!r}, expected {!r}".format(a.size, b.size)
)
a, b = convert_to_comparable(a, b)
@ -200,24 +203,13 @@ class PillowTestCase(unittest.TestCase):
self.assertTrue(value, msg + ": " + repr(actuals) + " != " + repr(targets))
def skipKnownBadTest(self, msg=None, platform=None, travis=None, interpreter=None):
# Skip if platform/travis matches, and
# PILLOW_RUN_KNOWN_BAD is not true in the environment.
def skipKnownBadTest(self, msg=None):
# Skip if PILLOW_RUN_KNOWN_BAD is not true in the environment.
if os.environ.get("PILLOW_RUN_KNOWN_BAD", False):
print(os.environ.get("PILLOW_RUN_KNOWN_BAD", False))
return
skip = True
if platform is not None:
skip = sys.platform.startswith(platform)
if travis is not None:
skip = skip and (travis == bool(os.environ.get("TRAVIS", False)))
if interpreter is not None:
skip = skip and (
interpreter == "pypy" and hasattr(sys, "pypy_version_info")
)
if skip:
self.skipTest(msg or "Known Bad Test")
self.skipTest(msg or "Known Bad Test")
def tempfile(self, template):
assert template[:5] in ("temp.", "temp_")
@ -229,12 +221,12 @@ class PillowTestCase(unittest.TestCase):
def open_withImagemagick(self, f):
if not imagemagick_available():
raise IOError()
raise OSError()
outfile = self.tempfile("temp.png")
if command_succeeds([IMCONVERT, f, outfile]):
return Image.open(outfile)
raise IOError()
raise OSError()
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@ -277,21 +269,12 @@ class PillowLeakTestCase(PillowTestCase):
# helpers
if not py3:
# Remove DeprecationWarning in Python 3
PillowTestCase.assertRaisesRegex = PillowTestCase.assertRaisesRegexp
PillowTestCase.assertRegex = PillowTestCase.assertRegexpMatches
def fromstring(data):
from io import BytesIO
return Image.open(BytesIO(data))
def tostring(im, string_format, **options):
from io import BytesIO
out = BytesIO()
im.save(out, string_format, **options)
return out.getvalue()
@ -323,13 +306,10 @@ def command_succeeds(cmd):
Runs the command, which must be a list of strings. Returns True if the
command succeeds, or False if an OSError was raised by subprocess.Popen.
"""
import subprocess
with open(os.devnull, "wb") as f:
try:
subprocess.call(cmd, stdout=f, stderr=subprocess.STDOUT)
except OSError:
return False
try:
subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
except OSError:
return False
return True
@ -355,10 +335,25 @@ def on_appveyor():
return "APPVEYOR" in os.environ
def on_github_actions():
return "GITHUB_ACTIONS" in os.environ
def on_ci():
# Travis and AppVeyor have "CI"
# Azure Pipelines has "TF_BUILD"
return "CI" in os.environ or "TF_BUILD" in os.environ
# GitHub Actions has "GITHUB_ACTIONS"
return (
"CI" in os.environ or "TF_BUILD" in os.environ or "GITHUB_ACTIONS" in os.environ
)
def is_win32():
return sys.platform.startswith("win32")
def is_pypy():
return hasattr(sys, "pypy_translation_info")
if sys.platform == "win32":
@ -377,7 +372,7 @@ def distro():
return line.strip().split("=")[1]
class cached_property(object):
class cached_property:
def __init__(self, func):
self.func = func

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@ -1,16 +0,0 @@
from __future__ import print_function
import glob
import os
import sys
import traceback
sys.path.insert(0, ".")
for file in glob.glob("src/PIL/*.py"):
module = os.path.basename(file)[:-3]
try:
exec("from PIL import " + module)
except (ImportError, SyntaxError):
print("===", "failed to import", module)
traceback.print_exc()

View File

@ -1,68 +0,0 @@
# brute-force search for access descriptor hash table
from __future__ import print_function
modes = [
"1",
"L",
"LA",
"La",
"I",
"I;16",
"I;16L",
"I;16B",
"I;32L",
"I;32B",
"F",
"P",
"PA",
"RGB",
"RGBA",
"RGBa",
"RGBX",
"CMYK",
"YCbCr",
"LAB",
"HSV",
]
def hash(s, i):
# djb2 hash: multiply by 33 and xor character
for c in s:
i = (((i << 5) + i) ^ ord(c)) & 0xFFFFFFFF
return i
def check(size, i0):
h = [None] * size
for m in modes:
i = hash(m, i0)
i = i % size
if h[i]:
return 0
h[i] = m
return h
min_start = 0
# 1) find the smallest table size with no collisions
for min_size in range(len(modes), 16384):
if check(min_size, 0):
print(len(modes), "modes fit in", min_size, "slots")
break
# 2) see if we can do better with a different initial value
for i0 in range(65556):
for size in range(1, min_size):
if check(size, i0):
if size < min_size:
print(len(modes), "modes fit in", size, "slots with start", i0)
min_size = size
min_start = i0
print()
print("#define ACCESS_TABLE_SIZE", min_size)
print("#define ACCESS_TABLE_HASH", min_start)

View File

@ -1,5 +1,3 @@
from __future__ import print_function
import os
from PIL import Image
@ -24,8 +22,8 @@ class TestBmpReference(PillowTestCase):
def open(f):
try:
im = Image.open(f)
im.load()
with Image.open(f) as im:
im.load()
except Exception: # as msg:
pass
@ -48,8 +46,8 @@ class TestBmpReference(PillowTestCase):
]
for f in self.get_files("q"):
try:
im = Image.open(f)
im.load()
with Image.open(f) as im:
im.load()
if os.path.basename(f) not in supported:
print("Please add %s to the partially supported bmp specs." % f)
except Exception: # as msg:
@ -89,17 +87,17 @@ class TestBmpReference(PillowTestCase):
for f in self.get_files("g"):
try:
im = Image.open(f)
im.load()
compare = Image.open(get_compare(f))
compare.load()
if im.mode == "P":
# assert image similar doesn't really work
# with paletized image, since the palette might
# be differently ordered for an equivalent image.
im = im.convert("RGBA")
compare = im.convert("RGBA")
self.assert_image_similar(im, compare, 5)
with Image.open(f) as im:
im.load()
with Image.open(get_compare(f)) as compare:
compare.load()
if im.mode == "P":
# assert image similar doesn't really work
# with paletized image, since the palette might
# be differently ordered for an equivalent image.
im = im.convert("RGBA")
compare = im.convert("RGBA")
self.assert_image_similar(im, compare, 5)
except Exception as msg:
# there are three here that are unsupported:
@ -109,4 +107,4 @@ class TestBmpReference(PillowTestCase):
os.path.join(base, "g", "pal4rle.bmp"),
)
if f not in unsupported:
self.fail("Unsupported Image %s: %s" % (f, msg))
self.fail("Unsupported Image {}: {}".format(f, msg))

View File

@ -1,10 +1,9 @@
from __future__ import division
import unittest
from array import array
from PIL import Image, ImageFilter
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
try:
import numpy

View File

@ -1,12 +1,9 @@
from __future__ import division, print_function
import sys
import unittest
from PIL import Image
from .helper import PillowTestCase, unittest
is_pypy = hasattr(sys, "pypy_version_info")
from .helper import PillowTestCase, is_pypy
class TestCoreStats(PillowTestCase):
@ -87,7 +84,7 @@ class TestCoreMemory(PillowTestCase):
stats = Image.core.get_stats()
self.assertGreaterEqual(stats["new_count"], 1)
self.assertGreaterEqual(stats["allocated_blocks"], 64)
if not is_pypy:
if not is_pypy():
self.assertGreaterEqual(stats["freed_blocks"], 64)
def test_get_blocks_max(self):
@ -108,7 +105,7 @@ class TestCoreMemory(PillowTestCase):
if sys.maxsize < 2 ** 32:
self.assertRaises(ValueError, Image.core.set_blocks_max, 2 ** 29)
@unittest.skipIf(is_pypy, "images are not collected")
@unittest.skipIf(is_pypy(), "images are not collected")
def test_set_blocks_max_stats(self):
Image.core.reset_stats()
Image.core.set_blocks_max(128)
@ -123,7 +120,7 @@ class TestCoreMemory(PillowTestCase):
self.assertEqual(stats["freed_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 64)
@unittest.skipIf(is_pypy, "images are not collected")
@unittest.skipIf(is_pypy(), "images are not collected")
def test_clear_cache_stats(self):
Image.core.reset_stats()
Image.core.clear_cache()
@ -153,7 +150,7 @@ class TestCoreMemory(PillowTestCase):
self.assertGreaterEqual(stats["allocated_blocks"], 16)
self.assertGreaterEqual(stats["reused_blocks"], 0)
self.assertEqual(stats["blocks_cached"], 0)
if not is_pypy:
if not is_pypy():
self.assertGreaterEqual(stats["freed_blocks"], 16)

View File

@ -14,8 +14,8 @@ class TestDecompressionBomb(PillowTestCase):
def test_no_warning_small_file(self):
# Implicit assert: no warning.
# A warning would cause a failure.
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
Image.open(TEST_FILE)
with Image.open(TEST_FILE):
pass
def test_no_warning_no_limit(self):
# Arrange
@ -26,21 +26,28 @@ class TestDecompressionBomb(PillowTestCase):
# Act / Assert
# Implicit assert: no warning.
# A warning would cause a failure.
Image.open(TEST_FILE)
with Image.open(TEST_FILE):
pass
def test_warning(self):
# Set limit to trigger warning on the test file
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
self.assertEqual(Image.MAX_IMAGE_PIXELS, 128 * 128 - 1)
self.assert_warning(Image.DecompressionBombWarning, Image.open, TEST_FILE)
def open():
with Image.open(TEST_FILE):
pass
self.assert_warning(Image.DecompressionBombWarning, open)
def test_exception(self):
# Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
self.assertEqual(Image.MAX_IMAGE_PIXELS, 64 * 128 - 1)
self.assertRaises(Image.DecompressionBombError, lambda: Image.open(TEST_FILE))
with self.assertRaises(Image.DecompressionBombError):
with Image.open(TEST_FILE):
pass
def test_exception_ico(self):
with self.assertRaises(Image.DecompressionBombError):
@ -54,6 +61,7 @@ class TestDecompressionBomb(PillowTestCase):
class TestDecompressionCrop(PillowTestCase):
def setUp(self):
self.src = hopper()
self.addCleanup(self.src.close)
Image.MAX_IMAGE_PIXELS = self.src.height * self.src.width * 4 - 1
def tearDown(self):

View File

@ -1,10 +1,9 @@
from __future__ import unicode_literals
import io
import unittest
from PIL import features
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
try:
from PIL import _webp
@ -70,11 +69,14 @@ class TestFeatures(PillowTestCase):
lines = out.splitlines()
self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Pillow "))
self.assertEqual(lines[2], "-" * 68)
self.assertTrue(lines[3].startswith("Python modules loaded from "))
self.assertTrue(lines[4].startswith("Binary modules loaded from "))
self.assertEqual(lines[5], "-" * 68)
self.assertTrue(lines[6].startswith("Python "))
self.assertTrue(lines[2].startswith("Python "))
lines = lines[3:]
while lines[0].startswith(" "):
lines = lines[1:]
self.assertEqual(lines[0], "-" * 68)
self.assertTrue(lines[1].startswith("Python modules loaded from "))
self.assertTrue(lines[2].startswith("Binary modules loaded from "))
self.assertEqual(lines[3], "-" * 68)
jpeg = (
"\n"
+ "-" * 68

View File

@ -5,16 +5,16 @@ from .helper import PillowTestCase
class TestFileBlp(PillowTestCase):
def test_load_blp2_raw(self):
im = Image.open("Tests/images/blp/blp2_raw.blp")
target = Image.open("Tests/images/blp/blp2_raw.png")
self.assert_image_equal(im, target)
with Image.open("Tests/images/blp/blp2_raw.blp") as im:
with Image.open("Tests/images/blp/blp2_raw.png") as target:
self.assert_image_equal(im, target)
def test_load_blp2_dxt1(self):
im = Image.open("Tests/images/blp/blp2_dxt1.blp")
target = Image.open("Tests/images/blp/blp2_dxt1.png")
self.assert_image_equal(im, target)
with Image.open("Tests/images/blp/blp2_dxt1.blp") as im:
with Image.open("Tests/images/blp/blp2_dxt1.png") as target:
self.assert_image_equal(im, target)
def test_load_blp2_dxt1a(self):
im = Image.open("Tests/images/blp/blp2_dxt1a.blp")
target = Image.open("Tests/images/blp/blp2_dxt1a.png")
self.assert_image_equal(im, target)
with Image.open("Tests/images/blp/blp2_dxt1a.blp") as im:
with Image.open("Tests/images/blp/blp2_dxt1a.png") as target:
self.assert_image_equal(im, target)

View File

@ -11,12 +11,12 @@ class TestFileBmp(PillowTestCase):
im.save(outfile, "BMP")
reloaded = Image.open(outfile)
reloaded.load()
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "BMP")
self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
with Image.open(outfile) as reloaded:
reloaded.load()
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "BMP")
self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
def test_sanity(self):
self.roundtrip(hopper())
@ -36,89 +36,86 @@ class TestFileBmp(PillowTestCase):
im.save(output, "BMP")
output.seek(0)
reloaded = Image.open(output)
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "BMP")
with Image.open(output) as reloaded:
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "BMP")
def test_dpi(self):
dpi = (72, 72)
output = io.BytesIO()
im = hopper()
im.save(output, "BMP", dpi=dpi)
with hopper() as im:
im.save(output, "BMP", dpi=dpi)
output.seek(0)
reloaded = Image.open(output)
self.assertEqual(reloaded.info["dpi"], dpi)
with Image.open(output) as reloaded:
self.assertEqual(reloaded.info["dpi"], dpi)
def test_save_bmp_with_dpi(self):
# Test for #1301
# Arrange
outfile = self.tempfile("temp.jpg")
im = Image.open("Tests/images/hopper.bmp")
with Image.open("Tests/images/hopper.bmp") as im:
# Act
im.save(outfile, "JPEG", dpi=im.info["dpi"])
# Act
im.save(outfile, "JPEG", dpi=im.info["dpi"])
# Assert
reloaded = Image.open(outfile)
reloaded.load()
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "JPEG")
# Assert
with Image.open(outfile) as reloaded:
reloaded.load()
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
self.assertEqual(im.size, reloaded.size)
self.assertEqual(reloaded.format, "JPEG")
def test_load_dpi_rounding(self):
# Round up
im = Image.open("Tests/images/hopper.bmp")
self.assertEqual(im.info["dpi"], (96, 96))
with Image.open("Tests/images/hopper.bmp") as im:
self.assertEqual(im.info["dpi"], (96, 96))
# Round down
im = Image.open("Tests/images/hopper_roundDown.bmp")
self.assertEqual(im.info["dpi"], (72, 72))
with Image.open("Tests/images/hopper_roundDown.bmp") as im:
self.assertEqual(im.info["dpi"], (72, 72))
def test_save_dpi_rounding(self):
outfile = self.tempfile("temp.bmp")
im = Image.open("Tests/images/hopper.bmp")
with Image.open("Tests/images/hopper.bmp") as im:
im.save(outfile, dpi=(72.2, 72.2))
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (72, 72))
im.save(outfile, dpi=(72.2, 72.2))
reloaded = Image.open(outfile)
self.assertEqual(reloaded.info["dpi"], (72, 72))
im.save(outfile, dpi=(72.8, 72.8))
reloaded = Image.open(outfile)
self.assertEqual(reloaded.info["dpi"], (73, 73))
im.save(outfile, dpi=(72.8, 72.8))
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (73, 73))
def test_load_dib(self):
# test for #1293, Imagegrab returning Unsupported Bitfields Format
im = Image.open("Tests/images/clipboard.dib")
self.assertEqual(im.format, "DIB")
self.assertEqual(im.get_format_mimetype(), "image/bmp")
with Image.open("Tests/images/clipboard.dib") as im:
self.assertEqual(im.format, "DIB")
self.assertEqual(im.get_format_mimetype(), "image/bmp")
target = Image.open("Tests/images/clipboard_target.png")
self.assert_image_equal(im, target)
with Image.open("Tests/images/clipboard_target.png") as target:
self.assert_image_equal(im, target)
def test_save_dib(self):
outfile = self.tempfile("temp.dib")
im = Image.open("Tests/images/clipboard.dib")
im.save(outfile)
with Image.open("Tests/images/clipboard.dib") as im:
im.save(outfile)
reloaded = Image.open(outfile)
self.assertEqual(reloaded.format, "DIB")
self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
self.assert_image_equal(im, reloaded)
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.format, "DIB")
self.assertEqual(reloaded.get_format_mimetype(), "image/bmp")
self.assert_image_equal(im, reloaded)
def test_rgba_bitfields(self):
# This test image has been manually hexedited
# to change the bitfield compression in the header from XBGR to RGBA
im = Image.open("Tests/images/rgb32bf-rgba.bmp")
with Image.open("Tests/images/rgb32bf-rgba.bmp") as im:
# So before the comparing the image, swap the channels
b, g, r = im.split()[1:]
im = Image.merge("RGB", (r, g, b))
# So before the comparing the image, swap the channels
b, g, r = im.split()[1:]
im = Image.merge("RGB", (r, g, b))
target = Image.open("Tests/images/bmp/q/rgb32bf-xbgr.bmp")
self.assert_image_equal(im, target)
with Image.open("Tests/images/bmp/q/rgb32bf-xbgr.bmp") as target:
self.assert_image_equal(im, target)

View File

@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
class TestFileBufrStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "BUFR")
# Assert
self.assertEqual(im.format, "BUFR")
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
def test_invalid_file(self):
# Arrange
@ -28,10 +28,10 @@ class TestFileBufrStub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
def test_save(self):
# Arrange

View File

@ -11,8 +11,8 @@ class TestFileContainer(PillowTestCase):
dir(ContainerIO)
def test_isatty(self):
im = hopper()
container = ContainerIO.ContainerIO(im, 0, 0)
with hopper() as im:
container = ContainerIO.ContainerIO(im, 0, 0)
self.assertFalse(container.isatty())

View File

@ -7,14 +7,13 @@ TEST_FILE = "Tests/images/deerstalker.cur"
class TestFileCur(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
self.assertEqual(im.size, (32, 32))
self.assertIsInstance(im, CurImagePlugin.CurImageFile)
# Check some pixel colors to ensure image is loaded properly
self.assertEqual(im.getpixel((10, 1)), (0, 0, 0, 0))
self.assertEqual(im.getpixel((11, 1)), (253, 254, 254, 1))
self.assertEqual(im.getpixel((16, 16)), (84, 87, 86, 255))
with Image.open(TEST_FILE) as im:
self.assertEqual(im.size, (32, 32))
self.assertIsInstance(im, CurImagePlugin.CurImageFile)
# Check some pixel colors to ensure image is loaded properly
self.assertEqual(im.getpixel((10, 1)), (0, 0, 0, 0))
self.assertEqual(im.getpixel((11, 1)), (253, 254, 254, 1))
self.assertEqual(im.getpixel((16, 16)), (84, 87, 86, 255))
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"

View File

@ -1,6 +1,8 @@
import unittest
from PIL import DcxImagePlugin, Image
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
# Created with ImageMagick: convert hopper.ppm hopper.dcx
TEST_FILE = "Tests/images/hopper.dcx"
@ -11,19 +13,35 @@ class TestFileDcx(PillowTestCase):
# Arrange
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.size, (128, 128))
self.assertIsInstance(im, DcxImagePlugin.DcxImageFile)
orig = hopper()
self.assert_image_equal(im, orig)
# Assert
self.assertEqual(im.size, (128, 128))
self.assertIsInstance(im, DcxImagePlugin.DcxImageFile)
orig = hopper()
self.assert_image_equal(im, orig)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_FILE) as im:
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
@ -32,34 +50,34 @@ class TestFileDcx(PillowTestCase):
def test_tell(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act
frame = im.tell()
# Act
frame = im.tell()
# Assert
self.assertEqual(frame, 0)
# Assert
self.assertEqual(frame, 0)
def test_n_frames(self):
im = Image.open(TEST_FILE)
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
def test_eoferror(self):
im = Image.open(TEST_FILE)
n_frames = im.n_frames
with Image.open(TEST_FILE) as im:
n_frames = im.n_frames
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_seek_too_far(self):
# Arrange
im = Image.open(TEST_FILE)
frame = 999 # too big on purpose
with Image.open(TEST_FILE) as im:
frame = 999 # too big on purpose
# Act / Assert
self.assertRaises(EOFError, im.seek, frame)

View File

@ -8,6 +8,7 @@ TEST_FILE_DXT1 = "Tests/images/dxt1-rgb-4bbp-noalpha_MipMaps-1.dds"
TEST_FILE_DXT3 = "Tests/images/dxt3-argb-8bbp-explicitalpha_MipMaps-1.dds"
TEST_FILE_DXT5 = "Tests/images/dxt5-argb-8bbp-interpolatedalpha_MipMaps-1.dds"
TEST_FILE_DX10_BC7 = "Tests/images/bc7-argb-8bpp_MipMaps-1.dds"
TEST_FILE_DX10_BC7_UNORM_SRGB = "Tests/images/DXGI_FORMAT_BC7_UNORM_SRGB.dds"
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/uncompressed_rgb.dds"
@ -16,58 +17,71 @@ class TestFileDds(PillowTestCase):
def test_sanity_dxt1(self):
"""Check DXT1 images can be opened"""
target = Image.open(TEST_FILE_DXT1.replace(".dds", ".png"))
with Image.open(TEST_FILE_DXT1.replace(".dds", ".png")) as target:
target = target.convert("RGBA")
with Image.open(TEST_FILE_DXT1) as im:
im.load()
im = Image.open(TEST_FILE_DXT1)
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
self.assert_image_equal(target.convert("RGBA"), im)
self.assert_image_equal(im, target)
def test_sanity_dxt5(self):
"""Check DXT5 images can be opened"""
target = Image.open(TEST_FILE_DXT5.replace(".dds", ".png"))
im = Image.open(TEST_FILE_DXT5)
im.load()
with Image.open(TEST_FILE_DXT5) as im:
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
self.assert_image_equal(target, im)
with Image.open(TEST_FILE_DXT5.replace(".dds", ".png")) as target:
self.assert_image_equal(target, im)
def test_sanity_dxt3(self):
"""Check DXT3 images can be opened"""
target = Image.open(TEST_FILE_DXT3.replace(".dds", ".png"))
with Image.open(TEST_FILE_DXT3.replace(".dds", ".png")) as target:
with Image.open(TEST_FILE_DXT3) as im:
im.load()
im = Image.open(TEST_FILE_DXT3)
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
self.assert_image_equal(target, im)
self.assert_image_equal(target, im)
def test_dx10_bc7(self):
"""Check DX10 images can be opened"""
target = Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png"))
with Image.open(TEST_FILE_DX10_BC7) as im:
im.load()
im = Image.open(TEST_FILE_DX10_BC7)
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (256, 256))
with Image.open(TEST_FILE_DX10_BC7.replace(".dds", ".png")) as target:
self.assert_image_equal(target, im)
self.assert_image_equal(target, im)
def test_dx10_bc7_unorm_srgb(self):
"""Check DX10 unsigned normalized integer images can be opened"""
with Image.open(TEST_FILE_DX10_BC7_UNORM_SRGB) as im:
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (16, 16))
self.assertEqual(im.info["gamma"], 1 / 2.2)
with Image.open(
TEST_FILE_DX10_BC7_UNORM_SRGB.replace(".dds", ".png")
) as target:
self.assert_image_equal(target, im)
def test_unimplemented_dxgi_format(self):
self.assertRaises(
@ -79,16 +93,17 @@ class TestFileDds(PillowTestCase):
def test_uncompressed_rgb(self):
"""Check uncompressed RGB images can be opened"""
target = Image.open(TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png"))
with Image.open(TEST_FILE_UNCOMPRESSED_RGB) as im:
im.load()
im = Image.open(TEST_FILE_UNCOMPRESSED_RGB)
im.load()
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (800, 600))
self.assertEqual(im.format, "DDS")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (800, 600))
self.assert_image_equal(target, im)
with Image.open(
TEST_FILE_UNCOMPRESSED_RGB.replace(".dds", ".png")
) as target:
self.assert_image_equal(target, im)
def test__validate_true(self):
"""Check valid prefix"""
@ -129,8 +144,8 @@ class TestFileDds(PillowTestCase):
img_file = f.read()
def short_file():
im = Image.open(BytesIO(img_file[:-100]))
im.load()
with Image.open(BytesIO(img_file[:-100])) as im:
im.load()
self.assertRaises(IOError, short_file)

View File

@ -1,8 +1,9 @@
import io
import unittest
from PIL import EpsImagePlugin, Image
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
HAS_GHOSTSCRIPT = EpsImagePlugin.has_ghostscript()
@ -25,30 +26,30 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_sanity(self):
# Regular scale
image1 = Image.open(file1)
image1.load()
self.assertEqual(image1.mode, "RGB")
self.assertEqual(image1.size, (460, 352))
self.assertEqual(image1.format, "EPS")
with Image.open(file1) as image1:
image1.load()
self.assertEqual(image1.mode, "RGB")
self.assertEqual(image1.size, (460, 352))
self.assertEqual(image1.format, "EPS")
image2 = Image.open(file2)
image2.load()
self.assertEqual(image2.mode, "RGB")
self.assertEqual(image2.size, (360, 252))
self.assertEqual(image2.format, "EPS")
with Image.open(file2) as image2:
image2.load()
self.assertEqual(image2.mode, "RGB")
self.assertEqual(image2.size, (360, 252))
self.assertEqual(image2.format, "EPS")
# Double scale
image1_scale2 = Image.open(file1)
image1_scale2.load(scale=2)
self.assertEqual(image1_scale2.mode, "RGB")
self.assertEqual(image1_scale2.size, (920, 704))
self.assertEqual(image1_scale2.format, "EPS")
with Image.open(file1) as image1_scale2:
image1_scale2.load(scale=2)
self.assertEqual(image1_scale2.mode, "RGB")
self.assertEqual(image1_scale2.size, (920, 704))
self.assertEqual(image1_scale2.format, "EPS")
image2_scale2 = Image.open(file2)
image2_scale2.load(scale=2)
self.assertEqual(image2_scale2.mode, "RGB")
self.assertEqual(image2_scale2.size, (720, 504))
self.assertEqual(image2_scale2.format, "EPS")
with Image.open(file2) as image2_scale2:
image2_scale2.load(scale=2)
self.assertEqual(image2_scale2.mode, "RGB")
self.assertEqual(image2_scale2.size, (720, 504))
self.assertEqual(image2_scale2.format, "EPS")
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -57,55 +58,55 @@ class TestFileEps(PillowTestCase):
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_cmyk(self):
cmyk_image = Image.open("Tests/images/pil_sample_cmyk.eps")
with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image:
self.assertEqual(cmyk_image.mode, "CMYK")
self.assertEqual(cmyk_image.size, (100, 100))
self.assertEqual(cmyk_image.format, "EPS")
self.assertEqual(cmyk_image.mode, "CMYK")
self.assertEqual(cmyk_image.size, (100, 100))
self.assertEqual(cmyk_image.format, "EPS")
cmyk_image.load()
self.assertEqual(cmyk_image.mode, "RGB")
cmyk_image.load()
self.assertEqual(cmyk_image.mode, "RGB")
if "jpeg_decoder" in dir(Image.core):
target = Image.open("Tests/images/pil_sample_rgb.jpg")
self.assert_image_similar(cmyk_image, target, 10)
if "jpeg_decoder" in dir(Image.core):
with Image.open("Tests/images/pil_sample_rgb.jpg") as target:
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")
target = Image.open("Tests/images/reqd_showpage.png")
# should not crash/hang
plot_image.load()
# fonts could be slightly different
self.assert_image_similar(plot_image, target, 6)
with Image.open("Tests/images/reqd_showpage.eps") as plot_image:
with Image.open("Tests/images/reqd_showpage.png") as target:
# should not crash/hang
plot_image.load()
# 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")
with Image.open(file1) as image1:
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")
with Image.open(file1) as image1:
with 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())
img = Image.open(img_bytes)
img.load()
with Image.open(img_bytes) as img:
img.load()
image1_scale1_compare = Image.open(file1_compare).convert("RGB")
image1_scale1_compare.load()
self.assert_image_similar(img, image1_scale1_compare, 5)
with Image.open(file1_compare) as image1_scale1_compare:
image1_scale1_compare = image1_scale1_compare.convert("RGB")
image1_scale1_compare.load()
self.assert_image_similar(img, image1_scale1_compare, 5)
def test_image_mode_not_supported(self):
im = hopper("RGBA")
@ -120,18 +121,20 @@ class TestFileEps(PillowTestCase):
self.skipTest("zip/deflate support not available")
# Zero bounding box
image1_scale1 = Image.open(file1)
image1_scale1.load()
image1_scale1_compare = Image.open(file1_compare).convert("RGB")
image1_scale1_compare.load()
self.assert_image_similar(image1_scale1, image1_scale1_compare, 5)
with Image.open(file1) as image1_scale1:
image1_scale1.load()
with Image.open(file1_compare) as image1_scale1_compare:
image1_scale1_compare = image1_scale1_compare.convert("RGB")
image1_scale1_compare.load()
self.assert_image_similar(image1_scale1, image1_scale1_compare, 5)
# Non-Zero bounding box
image2_scale1 = Image.open(file2)
image2_scale1.load()
image2_scale1_compare = Image.open(file2_compare).convert("RGB")
image2_scale1_compare.load()
self.assert_image_similar(image2_scale1, image2_scale1_compare, 10)
with Image.open(file2) as image2_scale1:
image2_scale1.load()
with Image.open(file2_compare) as image2_scale1_compare:
image2_scale1_compare = image2_scale1_compare.convert("RGB")
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):
@ -141,57 +144,46 @@ class TestFileEps(PillowTestCase):
self.skipTest("zip/deflate support not available")
# Zero bounding box
image1_scale2 = Image.open(file1)
image1_scale2.load(scale=2)
image1_scale2_compare = Image.open(file1_compare_scale2).convert("RGB")
image1_scale2_compare.load()
self.assert_image_similar(image1_scale2, image1_scale2_compare, 5)
with Image.open(file1) as image1_scale2:
image1_scale2.load(scale=2)
with Image.open(file1_compare_scale2) as image1_scale2_compare:
image1_scale2_compare = image1_scale2_compare.convert("RGB")
image1_scale2_compare.load()
self.assert_image_similar(image1_scale2, image1_scale2_compare, 5)
# Non-Zero bounding box
image2_scale2 = Image.open(file2)
image2_scale2.load(scale=2)
image2_scale2_compare = Image.open(file2_compare_scale2).convert("RGB")
image2_scale2_compare.load()
self.assert_image_similar(image2_scale2, image2_scale2_compare, 10)
with Image.open(file2) as image2_scale2:
image2_scale2.load(scale=2)
with Image.open(file2_compare_scale2) as image2_scale2_compare:
image2_scale2_compare = image2_scale2_compare.convert("RGB")
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)
image2 = Image.open(file2)
image3 = Image.open("Tests/images/illu10_preview.eps")
new_size = (100, 100)
# Act
image1 = image1.resize(new_size)
image2 = image2.resize(new_size)
image3 = image3.resize(new_size)
# Assert
self.assertEqual(image1.size, new_size)
self.assertEqual(image2.size, new_size)
self.assertEqual(image3.size, new_size)
files = [file1, file2, "Tests/images/illu10_preview.eps"]
for fn in files:
with Image.open(fn) as im:
new_size = (100, 100)
im = im.resize(new_size)
self.assertEqual(im.size, new_size)
@unittest.skipUnless(HAS_GHOSTSCRIPT, "Ghostscript not available")
def test_thumbnail(self):
# Issue #619
# Arrange
image1 = Image.open(file1)
image2 = Image.open(file2)
new_size = (100, 100)
# Act
image1.thumbnail(new_size)
image2.thumbnail(new_size)
# Assert
self.assertEqual(max(image1.size), max(new_size))
self.assertEqual(max(image2.size), max(new_size))
files = [file1, file2]
for fn in files:
with Image.open(file1) as im:
new_size = (100, 100)
im.thumbnail(new_size)
self.assertEqual(max(im.size), max(new_size))
def test_read_binary_preview(self):
# Issue 302
# open image with binary preview
Image.open(file3)
with Image.open(file3):
pass
def _test_readline(self, t, ending):
ending = "Failure with line ending: %s" % (
@ -239,16 +231,16 @@ class TestFileEps(PillowTestCase):
# Act / Assert
for filename in FILES:
img = Image.open(filename)
self.assertEqual(img.mode, "RGB")
with Image.open(filename) as img:
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"
image = Image.open(emptyline_file)
image.load()
with Image.open(emptyline_file) as image:
image.load()
self.assertEqual(image.mode, "RGB")
self.assertEqual(image.size, (460, 352))
self.assertEqual(image.format, "EPS")

View File

@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/hopper.fits"
class TestFileFitsStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "FITS")
# Assert
self.assertEqual(im.format, "FITS")
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
def test_invalid_file(self):
# Arrange
@ -28,19 +28,19 @@ class TestFileFitsStub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
def test_save(self):
# Arrange
im = Image.open(TEST_FILE)
dummy_fp = None
dummy_filename = "dummy.filename"
with Image.open(TEST_FILE) as im:
dummy_fp = None
dummy_filename = "dummy.filename"
# Act / Assert: stub cannot save without an implemented handler
self.assertRaises(IOError, im.save, dummy_filename)
self.assertRaises(
IOError, FitsStubImagePlugin._save, im, dummy_fp, dummy_filename
)
# Act / Assert: stub cannot save without an implemented handler
self.assertRaises(IOError, im.save, dummy_filename)
self.assertRaises(
IOError, FitsStubImagePlugin._save, im, dummy_fp, dummy_filename
)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import FliImagePlugin, Image
from .helper import PillowTestCase
from .helper import PillowTestCase, is_pypy
# created as an export of a palette image from Gimp2.6
# save as...-> hopper.fli, default options.
@ -12,36 +14,52 @@ animated_test_file = "Tests/images/a.fli"
class TestFileFli(PillowTestCase):
def test_sanity(self):
im = Image.open(static_test_file)
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "FLI")
self.assertFalse(im.is_animated)
with Image.open(static_test_file) as im:
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "FLI")
self.assertFalse(im.is_animated)
im = Image.open(animated_test_file)
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (320, 200))
self.assertEqual(im.format, "FLI")
self.assertEqual(im.info["duration"], 71)
self.assertTrue(im.is_animated)
with Image.open(animated_test_file) as im:
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (320, 200))
self.assertEqual(im.format, "FLI")
self.assertEqual(im.info["duration"], 71)
self.assertTrue(im.is_animated)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(static_test_file)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(static_test_file)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(static_test_file) as im:
im.load()
self.assert_warning(None, open)
def test_tell(self):
# Arrange
im = Image.open(static_test_file)
with Image.open(static_test_file) as im:
# Act
frame = im.tell()
# Act
frame = im.tell()
# Assert
self.assertEqual(frame, 0)
# Assert
self.assertEqual(frame, 0)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -49,50 +67,50 @@ class TestFileFli(PillowTestCase):
self.assertRaises(SyntaxError, FliImagePlugin.FliImageFile, invalid_file)
def test_n_frames(self):
im = Image.open(static_test_file)
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
with Image.open(static_test_file) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
im = Image.open(animated_test_file)
self.assertEqual(im.n_frames, 384)
self.assertTrue(im.is_animated)
with Image.open(animated_test_file) as im:
self.assertEqual(im.n_frames, 384)
self.assertTrue(im.is_animated)
def test_eoferror(self):
im = Image.open(animated_test_file)
n_frames = im.n_frames
with Image.open(animated_test_file) as im:
n_frames = im.n_frames
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_seek_tell(self):
im = Image.open(animated_test_file)
with Image.open(animated_test_file) as im:
layer_number = im.tell()
self.assertEqual(layer_number, 0)
layer_number = im.tell()
self.assertEqual(layer_number, 0)
im.seek(0)
layer_number = im.tell()
self.assertEqual(layer_number, 0)
im.seek(0)
layer_number = im.tell()
self.assertEqual(layer_number, 0)
im.seek(1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
im.seek(1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
im.seek(2)
layer_number = im.tell()
self.assertEqual(layer_number, 2)
im.seek(2)
layer_number = im.tell()
self.assertEqual(layer_number, 2)
im.seek(1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
im.seek(1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
def test_seek(self):
im = Image.open(animated_test_file)
im.seek(50)
with Image.open(animated_test_file) as im:
im.seek(50)
expected = Image.open("Tests/images/a_fli.png")
self.assert_image_equal(im, expected)
with Image.open("Tests/images/a_fli.png") as expected:
self.assert_image_equal(im, expected)

View File

@ -1,4 +1,6 @@
from .helper import PillowTestCase, unittest
import unittest
from .helper import PillowTestCase
try:
from PIL import FpxImagePlugin

View File

@ -5,12 +5,11 @@ from .helper import PillowTestCase
class TestFileFtex(PillowTestCase):
def test_load_raw(self):
im = Image.open("Tests/images/ftex_uncompressed.ftu")
target = Image.open("Tests/images/ftex_uncompressed.png")
self.assert_image_equal(im, target)
with Image.open("Tests/images/ftex_uncompressed.ftu") as im:
with Image.open("Tests/images/ftex_uncompressed.png") as target:
self.assert_image_equal(im, target)
def test_load_dxt1(self):
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)
with Image.open("Tests/images/ftex_dxt1.ftc") as im:
with Image.open("Tests/images/ftex_dxt1.png") as target:
self.assert_image_similar(im, target.convert("RGBA"), 15)

View File

@ -10,8 +10,6 @@ class TestFileGbr(PillowTestCase):
self.assertRaises(SyntaxError, GbrImagePlugin.GbrImageFile, invalid_file)
def test_gbr_file(self):
im = Image.open("Tests/images/gbr.gbr")
target = Image.open("Tests/images/gbr.png")
self.assert_image_equal(target, im)
with Image.open("Tests/images/gbr.gbr") as im:
with Image.open("Tests/images/gbr.png") as target:
self.assert_image_equal(target, im)

View File

@ -1,4 +1,4 @@
from PIL import GdImageFile
from PIL import GdImageFile, UnidentifiedImageError
from .helper import PillowTestCase
@ -7,9 +7,9 @@ TEST_GD_FILE = "Tests/images/hopper.gd"
class TestFileGd(PillowTestCase):
def test_sanity(self):
im = GdImageFile.open(TEST_GD_FILE)
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GD")
with GdImageFile.open(TEST_GD_FILE) as im:
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GD")
def test_bad_mode(self):
self.assertRaises(ValueError, GdImageFile.open, TEST_GD_FILE, "bad mode")
@ -17,4 +17,4 @@ class TestFileGd(PillowTestCase):
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(IOError, GdImageFile.open, invalid_file)
self.assertRaises(UnidentifiedImageError, GdImageFile.open, invalid_file)

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO
from PIL import GifImagePlugin, Image, ImageDraw, ImagePalette
from .helper import PillowTestCase, hopper, netpbm_available, unittest
from .helper import PillowTestCase, hopper, is_pypy, netpbm_available
try:
from PIL import _webp
@ -26,18 +27,34 @@ class TestFileGif(PillowTestCase):
self.skipTest("gif support not available") # can this happen?
def test_sanity(self):
im = Image.open(TEST_GIF)
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GIF")
self.assertEqual(im.info["version"], b"GIF89a")
with Image.open(TEST_GIF) as im:
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "GIF")
self.assertEqual(im.info["version"], b"GIF89a")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_GIF)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_GIF)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_GIF) as im:
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
@ -71,21 +88,20 @@ class TestFileGif(PillowTestCase):
def check(colors, size, expected_palette_length):
# make an image with empty colors in the start of the palette range
im = Image.frombytes(
"P",
(colors, colors),
bytes(bytearray(range(256 - colors, 256)) * colors),
"P", (colors, colors), bytes(range(256 - colors, 256)) * colors
)
im = im.resize((size, size))
outfile = BytesIO()
im.save(outfile, "GIF")
outfile.seek(0)
reloaded = Image.open(outfile)
with Image.open(outfile) as reloaded:
# check palette length
palette_length = max(
i + 1 for i, v in enumerate(reloaded.histogram()) if v
)
self.assertEqual(expected_palette_length, palette_length)
# check palette length
palette_length = max(i + 1 for i, v in enumerate(reloaded.histogram()) if v)
self.assertEqual(expected_palette_length, palette_length)
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
# These do optimize the palette
check(128, 511, 128)
@ -103,7 +119,7 @@ class TestFileGif(PillowTestCase):
check(256, 511, 256)
def test_optimize_full_l(self):
im = Image.frombytes("L", (16, 16), bytes(bytearray(range(256))))
im = Image.frombytes("L", (16, 16), bytes(range(256)))
test_file = BytesIO()
im.save(test_file, "GIF", optimize=True)
self.assertEqual(im.mode, "L")
@ -112,67 +128,67 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im = hopper()
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_similar(reread.convert("RGB"), im, 50)
self.assert_image_similar(reread.convert("RGB"), im, 50)
def test_roundtrip2(self):
# see https://github.com/python-pillow/Pillow/issues/403
out = self.tempfile("temp.gif")
im = Image.open(TEST_GIF)
im2 = im.copy()
im2.save(out)
reread = Image.open(out)
with Image.open(TEST_GIF) as im:
im2 = im.copy()
im2.save(out)
with Image.open(out) as reread:
self.assert_image_similar(reread.convert("RGB"), hopper(), 50)
self.assert_image_similar(reread.convert("RGB"), hopper(), 50)
def test_roundtrip_save_all(self):
# Single frame image
out = self.tempfile("temp.gif")
im = hopper()
im.save(out, save_all=True)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_similar(reread.convert("RGB"), im, 50)
self.assert_image_similar(reread.convert("RGB"), im, 50)
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
reread = Image.open(out)
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 5)
self.assertEqual(reread.n_frames, 5)
def test_headers_saving_for_animated_gifs(self):
important_headers = ["background", "version", "duration", "loop"]
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
info = im.info.copy()
info = im.info.copy()
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
reread = Image.open(out)
out = self.tempfile("temp.gif")
im.save(out, save_all=True)
with Image.open(out) as reread:
for header in important_headers:
self.assertEqual(info[header], reread.info[header])
for header in important_headers:
self.assertEqual(info[header], reread.info[header])
def test_palette_handling(self):
# see https://github.com/python-pillow/Pillow/issues/513
im = Image.open(TEST_GIF)
im = im.convert("RGB")
with Image.open(TEST_GIF) as im:
im = im.convert("RGB")
im = im.resize((100, 100), Image.LANCZOS)
im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256)
im = im.resize((100, 100), Image.LANCZOS)
im2 = im.convert("P", palette=Image.ADAPTIVE, colors=256)
f = self.tempfile("temp.gif")
im2.save(f, optimize=True)
f = self.tempfile("temp.gif")
im2.save(f, optimize=True)
reloaded = Image.open(f)
with Image.open(f) as reloaded:
self.assert_image_similar(im, reloaded.convert("RGB"), 10)
self.assert_image_similar(im, reloaded.convert("RGB"), 10)
def test_palette_434(self):
# see https://github.com/python-pillow/Pillow/issues/434
@ -185,108 +201,115 @@ class TestFileGif(PillowTestCase):
return reloaded
orig = "Tests/images/test.colors.gif"
im = Image.open(orig)
with Image.open(orig) as im:
self.assert_image_similar(im, roundtrip(im), 1)
self.assert_image_similar(im, roundtrip(im, optimize=True), 1)
with roundtrip(im) as reloaded:
self.assert_image_similar(im, reloaded, 1)
with roundtrip(im, optimize=True) as reloaded:
self.assert_image_similar(im, reloaded, 1)
im = im.convert("RGB")
# check automatic P conversion
reloaded = roundtrip(im).convert("RGB")
self.assert_image_equal(im, reloaded)
im = im.convert("RGB")
# check automatic P conversion
with roundtrip(im) as reloaded:
reloaded = reloaded.convert("RGB")
self.assert_image_equal(im, reloaded)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
def test_save_netpbm_bmp_mode(self):
img = Image.open(TEST_GIF).convert("RGB")
with Image.open(TEST_GIF) as img:
img = img.convert("RGB")
tempfile = self.tempfile("temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
self.assert_image_similar(img, Image.open(tempfile).convert("RGB"), 0)
tempfile = self.tempfile("temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
with Image.open(tempfile) as reloaded:
self.assert_image_similar(img, reloaded.convert("RGB"), 0)
@unittest.skipUnless(netpbm_available(), "netpbm not available")
def test_save_netpbm_l_mode(self):
img = Image.open(TEST_GIF).convert("L")
with Image.open(TEST_GIF) as img:
img = img.convert("L")
tempfile = self.tempfile("temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
self.assert_image_similar(img, Image.open(tempfile).convert("L"), 0)
tempfile = self.tempfile("temp.gif")
GifImagePlugin._save_netpbm(img, 0, tempfile)
with Image.open(tempfile) as reloaded:
self.assert_image_similar(img, reloaded.convert("L"), 0)
def test_seek(self):
img = Image.open("Tests/images/dispose_none.gif")
framecount = 0
try:
while True:
framecount += 1
img.seek(img.tell() + 1)
except EOFError:
self.assertEqual(framecount, 5)
with Image.open("Tests/images/dispose_none.gif") as img:
framecount = 0
try:
while True:
framecount += 1
img.seek(img.tell() + 1)
except EOFError:
self.assertEqual(framecount, 5)
def test_seek_info(self):
im = Image.open("Tests/images/iss634.gif")
info = im.info.copy()
with Image.open("Tests/images/iss634.gif") as im:
info = im.info.copy()
im.seek(1)
im.seek(0)
im.seek(1)
im.seek(0)
self.assertEqual(im.info, info)
self.assertEqual(im.info, info)
def test_seek_rewind(self):
im = Image.open("Tests/images/iss634.gif")
im.seek(2)
im.seek(1)
with Image.open("Tests/images/iss634.gif") as im:
im.seek(2)
im.seek(1)
expected = Image.open("Tests/images/iss634.gif")
expected.seek(1)
self.assert_image_equal(im, expected)
with Image.open("Tests/images/iss634.gif") as expected:
expected.seek(1)
self.assert_image_equal(im, expected)
def test_n_frames(self):
for path, n_frames in [[TEST_GIF, 1], ["Tests/images/iss634.gif", 42]]:
# Test is_animated before n_frames
im = Image.open(path)
self.assertEqual(im.is_animated, n_frames != 1)
with Image.open(path) as im:
self.assertEqual(im.is_animated, n_frames != 1)
# Test is_animated after n_frames
im = Image.open(path)
self.assertEqual(im.n_frames, n_frames)
self.assertEqual(im.is_animated, n_frames != 1)
with Image.open(path) as im:
self.assertEqual(im.n_frames, n_frames)
self.assertEqual(im.is_animated, n_frames != 1)
def test_eoferror(self):
im = Image.open(TEST_GIF)
n_frames = im.n_frames
with Image.open(TEST_GIF) as im:
n_frames = im.n_frames
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_dispose_none(self):
img = Image.open("Tests/images/dispose_none.gif")
try:
while True:
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, 1)
except EOFError:
pass
with Image.open("Tests/images/dispose_none.gif") as img:
try:
while True:
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, 1)
except EOFError:
pass
def test_dispose_background(self):
img = Image.open("Tests/images/dispose_bgnd.gif")
try:
while True:
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, 2)
except EOFError:
pass
with Image.open("Tests/images/dispose_bgnd.gif") as img:
try:
while True:
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, 2)
except EOFError:
pass
def test_dispose_previous(self):
img = Image.open("Tests/images/dispose_prev.gif")
try:
while True:
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, 3)
except EOFError:
pass
with Image.open("Tests/images/dispose_prev.gif") as img:
try:
while True:
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, 3)
except EOFError:
pass
def test_save_dispose(self):
out = self.tempfile("temp.gif")
@ -299,10 +322,10 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], disposal=method
)
img = Image.open(out)
for _ in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, method)
with Image.open(out) as img:
for _ in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, method)
# check per frame disposal
im_list[0].save(
@ -312,11 +335,11 @@ class TestFileGif(PillowTestCase):
disposal=tuple(range(len(im_list))),
)
img = Image.open(out)
with Image.open(out) as img:
for i in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, i + 1)
for i in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, i + 1)
def test_dispose2_palette(self):
out = self.tempfile("temp.gif")
@ -336,17 +359,16 @@ class TestFileGif(PillowTestCase):
im_list[0].save(out, save_all=True, append_images=im_list[1:], disposal=2)
img = Image.open(out)
with Image.open(out) as img:
for i, circle in enumerate(circles):
img.seek(i)
rgb_img = img.convert("RGB")
for i, circle in enumerate(circles):
img.seek(i)
rgb_img = img.convert("RGB")
# Check top left pixel matches background
self.assertEqual(rgb_img.getpixel((0, 0)), (255, 0, 0))
# Check top left pixel matches background
self.assertEqual(rgb_img.getpixel((0, 0)), (255, 0, 0))
# Center remains red every frame
self.assertEqual(rgb_img.getpixel((50, 50)), circle)
# Center remains red every frame
self.assertEqual(rgb_img.getpixel((50, 50)), circle)
def test_dispose2_diff(self):
out = self.tempfile("temp.gif")
@ -375,20 +397,19 @@ class TestFileGif(PillowTestCase):
out, save_all=True, append_images=im_list[1:], disposal=2, transparency=0
)
img = Image.open(out)
with Image.open(out) as img:
for i, colours in enumerate(circles):
img.seek(i)
rgb_img = img.convert("RGBA")
for i, colours in enumerate(circles):
img.seek(i)
rgb_img = img.convert("RGBA")
# Check left circle is correct colour
self.assertEqual(rgb_img.getpixel((20, 50)), colours[0])
# Check left circle is correct colour
self.assertEqual(rgb_img.getpixel((20, 50)), colours[0])
# Check right circle is correct colour
self.assertEqual(rgb_img.getpixel((80, 50)), colours[1])
# Check right circle is correct colour
self.assertEqual(rgb_img.getpixel((80, 50)), colours[1])
# Check BG is correct colour
self.assertEqual(rgb_img.getpixel((1, 1)), (255, 255, 255, 0))
# Check BG is correct colour
self.assertEqual(rgb_img.getpixel((1, 1)), (255, 255, 255, 0))
def test_dispose2_background(self):
out = self.tempfile("temp.gif")
@ -411,17 +432,17 @@ class TestFileGif(PillowTestCase):
out, save_all=True, append_images=im_list[1:], disposal=[0, 2], background=1
)
im = Image.open(out)
im.seek(1)
self.assertEqual(im.getpixel((0, 0)), 0)
with Image.open(out) as im:
im.seek(1)
self.assertEqual(im.getpixel((0, 0)), 0)
def test_iss634(self):
img = Image.open("Tests/images/iss634.gif")
# seek to the second frame
img.seek(img.tell() + 1)
# all transparent pixels should be replaced with the color from the
# first frame
self.assertEqual(img.histogram()[img.info["transparency"]], 0)
with Image.open("Tests/images/iss634.gif") as img:
# seek to the second frame
img.seek(img.tell() + 1)
# all transparent pixels should be replaced with the color from the
# first frame
self.assertEqual(img.histogram()[img.info["transparency"]], 0)
def test_duration(self):
duration = 1000
@ -433,8 +454,8 @@ class TestFileGif(PillowTestCase):
im.info["duration"] = 100
im.save(out, duration=duration)
reread = Image.open(out)
self.assertEqual(reread.info["duration"], duration)
with Image.open(out) as reread:
self.assertEqual(reread.info["duration"], duration)
def test_multiple_duration(self):
duration_list = [1000, 2000, 3000]
@ -450,27 +471,27 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration_list
)
reread = Image.open(out)
with Image.open(out) as reread:
for duration in duration_list:
self.assertEqual(reread.info["duration"], duration)
try:
reread.seek(reread.tell() + 1)
except EOFError:
pass
for duration in duration_list:
self.assertEqual(reread.info["duration"], duration)
try:
reread.seek(reread.tell() + 1)
except EOFError:
pass
# duration as tuple
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
)
reread = Image.open(out)
with Image.open(out) as reread:
for duration in duration_list:
self.assertEqual(reread.info["duration"], duration)
try:
reread.seek(reread.tell() + 1)
except EOFError:
pass
for duration in duration_list:
self.assertEqual(reread.info["duration"], duration)
try:
reread.seek(reread.tell() + 1)
except EOFError:
pass
def test_identical_frames(self):
duration_list = [1000, 1500, 2000, 4000]
@ -487,13 +508,13 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration_list
)
reread = Image.open(out)
with Image.open(out) as reread:
# Assert that the first three frames were combined
self.assertEqual(reread.n_frames, 2)
# Assert that the first three frames were combined
self.assertEqual(reread.n_frames, 2)
# Assert that the new duration is the total of the identical frames
self.assertEqual(reread.info["duration"], 4500)
# Assert that the new duration is the total of the identical frames
self.assertEqual(reread.info["duration"], 4500)
def test_identical_frames_to_single_frame(self):
for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500):
@ -507,13 +528,12 @@ class TestFileGif(PillowTestCase):
im_list[0].save(
out, save_all=True, append_images=im_list[1:], duration=duration
)
reread = Image.open(out)
with Image.open(out) as reread:
# Assert that all frames were combined
self.assertEqual(reread.n_frames, 1)
# Assert that all frames were combined
self.assertEqual(reread.n_frames, 1)
# Assert that the new duration is the total of the identical frames
self.assertEqual(reread.info["duration"], 8500)
# Assert that the new duration is the total of the identical frames
self.assertEqual(reread.info["duration"], 8500)
def test_number_of_loops(self):
number_of_loops = 2
@ -521,35 +541,37 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.save(out, loop=number_of_loops)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["loop"], number_of_loops)
self.assertEqual(reread.info["loop"], number_of_loops)
def test_background(self):
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.info["background"] = 1
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["background"], im.info["background"])
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)
with Image.open("Tests/images/hopper.webp") as im:
self.assertIsInstance(im.info["background"], tuple)
im.save(out)
def test_comment(self):
im = Image.open(TEST_GIF)
self.assertEqual(im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0")
with Image.open(TEST_GIF) as im:
self.assertEqual(
im.info["comment"], b"File written by Adobe Photoshop\xa8 4.0"
)
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.info["comment"] = b"Test comment text"
im.save(out)
reread = Image.open(out)
out = self.tempfile("temp.gif")
im = Image.new("L", (100, 100), "#000")
im.info["comment"] = b"Test comment text"
im.save(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["comment"], im.info["comment"])
self.assertEqual(reread.info["comment"], im.info["comment"])
def test_comment_over_255(self):
out = self.tempfile("temp.gif")
@ -559,22 +581,22 @@ class TestFileGif(PillowTestCase):
comment += comment
im.info["comment"] = comment
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["comment"], comment)
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)
with Image.open("Tests/images/hopper_zero_comment_subblocks.gif") as im:
with Image.open(TEST_GIF) as expected:
self.assert_image_equal(im, expected)
def test_version(self):
out = self.tempfile("temp.gif")
def assertVersionAfterSave(im, version):
im.save(out)
reread = Image.open(out)
self.assertEqual(reread.info["version"], version)
with Image.open(out) as reread:
self.assertEqual(reread.info["version"], version)
# Test that GIF87a is used by default
im = Image.new("L", (100, 100), "#000")
@ -590,12 +612,12 @@ class TestFileGif(PillowTestCase):
assertVersionAfterSave(im, b"GIF89a")
# Test that a GIF87a image is also saved in that format
im = Image.open("Tests/images/test.colors.gif")
assertVersionAfterSave(im, b"GIF87a")
with Image.open("Tests/images/test.colors.gif") as im:
assertVersionAfterSave(im, b"GIF87a")
# Test that a GIF89a image is also saved in that format
im.info["version"] = b"GIF89a"
assertVersionAfterSave(im, b"GIF87a")
# Test that a GIF89a image is also saved in that format
im.info["version"] = b"GIF89a"
assertVersionAfterSave(im, b"GIF87a")
def test_append_images(self):
out = self.tempfile("temp.gif")
@ -605,26 +627,25 @@ class TestFileGif(PillowTestCase):
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
im.copy().save(out, save_all=True, append_images=ims)
reread = Image.open(out)
self.assertEqual(reread.n_frames, 3)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 3)
# Tests appending using a generator
def imGenerator(ims):
for im in ims:
yield im
yield from ims
im.save(out, save_all=True, append_images=imGenerator(ims))
reread = Image.open(out)
self.assertEqual(reread.n_frames, 3)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 3)
# Tests appending single and multiple frame images
im = Image.open("Tests/images/dispose_none.gif")
ims = [Image.open("Tests/images/dispose_prev.gif")]
im.save(out, save_all=True, append_images=ims)
with Image.open("Tests/images/dispose_none.gif") as im:
with Image.open("Tests/images/dispose_prev.gif") as im2:
im.save(out, save_all=True, append_images=[im2])
reread = Image.open(out)
self.assertEqual(reread.n_frames, 10)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 10)
def test_transparent_optimize(self):
# from issue #2195, if the transparent color is incorrectly
@ -633,7 +654,7 @@ class TestFileGif(PillowTestCase):
# that's > 128 items where the transparent color is actually
# the top palette entry to trigger the bug.
data = bytes(bytearray(range(1, 254)))
data = bytes(range(1, 254))
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
im = Image.new("L", (253, 1))
@ -642,9 +663,9 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im.save(out, transparency=253)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assertEqual(reloaded.info["transparency"], 253)
self.assertEqual(reloaded.info["transparency"], 253)
def test_rgb_transparency(self):
out = self.tempfile("temp.gif")
@ -654,8 +675,8 @@ class TestFileGif(PillowTestCase):
im.info["transparency"] = (255, 0, 0)
self.assert_warning(UserWarning, im.save, out)
reloaded = Image.open(out)
self.assertNotIn("transparency", reloaded.info)
with Image.open(out) as reloaded:
self.assertNotIn("transparency", reloaded.info)
# Multiple frames
im = Image.new("RGB", (1, 1))
@ -663,8 +684,8 @@ class TestFileGif(PillowTestCase):
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)
with Image.open(out) as reloaded:
self.assertNotIn("transparency", reloaded.info)
def test_bbox(self):
out = self.tempfile("temp.gif")
@ -673,22 +694,22 @@ class TestFileGif(PillowTestCase):
ims = [Image.new("RGB", (100, 100), "#000")]
im.save(out, save_all=True, append_images=ims)
reread = Image.open(out)
self.assertEqual(reread.n_frames, 2)
with Image.open(out) as reread:
self.assertEqual(reread.n_frames, 2)
def test_palette_save_L(self):
# generate an L mode image with a separate palette
im = hopper("P")
im_l = Image.frombytes("L", im.size, im.tobytes())
palette = bytes(bytearray(im.getpalette()))
palette = bytes(im.getpalette())
out = self.tempfile("temp.gif")
im_l.save(out, palette=palette)
reloaded = Image.open(out)
with Image.open(out) as reloaded:
self.assert_image_equal(reloaded.convert("RGB"), im.convert("RGB"))
self.assert_image_equal(reloaded.convert("RGB"), im.convert("RGB"))
def test_palette_save_P(self):
# pass in a different palette, then construct what the image
@ -696,14 +717,14 @@ class TestFileGif(PillowTestCase):
# Forcing a non-straight grayscale palette.
im = hopper("P")
palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
palette = bytes([255 - i // 3 for i in range(768)])
out = self.tempfile("temp.gif")
im.save(out, palette=palette)
reloaded = Image.open(out)
im.putpalette(palette)
self.assert_image_equal(reloaded, im)
with Image.open(out) as reloaded:
im.putpalette(palette)
self.assert_image_equal(reloaded, im)
def test_palette_save_ImagePalette(self):
# pass in a different palette, as an ImagePalette.ImagePalette
@ -715,9 +736,9 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im.save(out, palette=palette)
reloaded = Image.open(out)
im.putpalette(palette)
self.assert_image_equal(reloaded, im)
with Image.open(out) as reloaded:
im.putpalette(palette)
self.assert_image_equal(reloaded, im)
def test_save_I(self):
# Test saving something that would trigger the auto-convert to 'L'
@ -727,8 +748,8 @@ class TestFileGif(PillowTestCase):
out = self.tempfile("temp.gif")
im.save(out)
reloaded = Image.open(out)
self.assert_image_equal(reloaded.convert("L"), im.convert("L"))
with Image.open(out) as reloaded:
self.assert_image_equal(reloaded.convert("L"), im.convert("L"))
def test_getdata(self):
# test getheader/getdata against legacy values
@ -737,7 +758,7 @@ class TestFileGif(PillowTestCase):
im.putpalette(ImagePalette.ImagePalette("RGB"))
im.info = {"background": 0}
passed_palette = bytes(bytearray([255 - i // 3 for i in range(768)]))
passed_palette = bytes([255 - i // 3 for i in range(768)])
GifImagePlugin._FORCE_OPTIMIZE = True
try:
@ -759,14 +780,13 @@ class TestFileGif(PillowTestCase):
def test_lzw_bits(self):
# see https://github.com/python-pillow/Pillow/issues/2811
im = Image.open("Tests/images/issue_2811.gif")
self.assertEqual(im.tile[0][3][0], 11) # LZW bits
# codec error prepatch
im.load()
with Image.open("Tests/images/issue_2811.gif") as im:
self.assertEqual(im.tile[0][3][0], 11) # LZW bits
# codec error prepatch
im.load()
def test_extents(self):
im = Image.open("Tests/images/test_extents.gif")
self.assertEqual(im.size, (100, 100))
im.seek(1)
self.assertEqual(im.size, (150, 150))
with Image.open("Tests/images/test_extents.gif") as im:
self.assertEqual(im.size, (100, 100))
im.seek(1)
self.assertEqual(im.size, (150, 150))

View File

@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
class TestFileGribStub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "GRIB")
# Assert
self.assertEqual(im.format, "GRIB")
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
def test_invalid_file(self):
# Arrange
@ -28,10 +28,10 @@ class TestFileGribStub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
def test_save(self):
# Arrange

View File

@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/hdf5.h5"
class TestFileHdf5Stub(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "HDF5")
# Assert
self.assertEqual(im.format, "HDF5")
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
# Dummy data from the stub
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (1, 1))
def test_invalid_file(self):
# Arrange
@ -28,19 +28,19 @@ class TestFileHdf5Stub(PillowTestCase):
def test_load(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
# Act / Assert: stub cannot load without an implemented handler
self.assertRaises(IOError, im.load)
def test_save(self):
# Arrange
im = Image.open(TEST_FILE)
dummy_fp = None
dummy_filename = "dummy.filename"
with Image.open(TEST_FILE) as im:
dummy_fp = None
dummy_filename = "dummy.filename"
# Act / Assert: stub cannot save without an implemented handler
self.assertRaises(IOError, im.save, dummy_filename)
self.assertRaises(
IOError, Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename
)
# Act / Assert: stub cannot save without an implemented handler
self.assertRaises(IOError, im.save, dummy_filename)
self.assertRaises(
IOError, Hdf5StubImagePlugin._save, im, dummy_fp, dummy_filename
)

View File

@ -1,9 +1,10 @@
import io
import sys
import unittest
from PIL import IcnsImagePlugin, Image
from .helper import PillowTestCase, unittest
from .helper import PillowTestCase
# sample icon file
TEST_FILE = "Tests/images/pillow.icns"
@ -15,72 +16,71 @@ class TestFileIcns(PillowTestCase):
def test_sanity(self):
# Loading this icon by default should result in the largest size
# (512x512@2x) being loaded
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert that there is no unclosed file warning
self.assert_warning(None, 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")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (1024, 1024))
self.assertEqual(im.format, "ICNS")
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
def test_save(self):
im = Image.open(TEST_FILE)
temp_file = self.tempfile("temp.icns")
im.save(temp_file)
reread = Image.open(temp_file)
with Image.open(TEST_FILE) as im:
im.save(temp_file)
self.assertEqual(reread.mode, "RGBA")
self.assertEqual(reread.size, (1024, 1024))
self.assertEqual(reread.format, "ICNS")
with Image.open(temp_file) as reread:
self.assertEqual(reread.mode, "RGBA")
self.assertEqual(reread.size, (1024, 1024))
self.assertEqual(reread.format, "ICNS")
@unittest.skipIf(sys.platform != "darwin", "requires macOS")
def test_save_append_images(self):
im = Image.open(TEST_FILE)
temp_file = self.tempfile("temp.icns")
provided_im = Image.new("RGBA", (32, 32), (255, 0, 0, 128))
im.save(temp_file, append_images=[provided_im])
reread = Image.open(temp_file)
self.assert_image_similar(reread, im, 1)
with Image.open(TEST_FILE) as im:
im.save(temp_file, append_images=[provided_im])
reread = Image.open(temp_file)
reread.size = (16, 16, 2)
reread.load()
self.assert_image_equal(reread, provided_im)
with Image.open(temp_file) as reread:
self.assert_image_similar(reread, im, 1)
with Image.open(temp_file) as reread:
reread.size = (16, 16, 2)
reread.load()
self.assert_image_equal(reread, provided_im)
def test_sizes(self):
# Check that we can load all of the sizes, and that the final pixel
# dimensions are as expected
im = Image.open(TEST_FILE)
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im.size = (w, h, r)
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (wr, hr))
with Image.open(TEST_FILE) as im:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im.size = (w, h, r)
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (wr, hr))
# Check that we cannot load an incorrect size
with self.assertRaises(ValueError):
im.size = (1, 1)
# 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).
im = Image.open("Tests/images/pillow2.icns")
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open("Tests/images/pillow2.icns")
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, "RGBA")
self.assertEqual(im2.size, (wr, hr))
with Image.open("Tests/images/pillow2.icns") as im:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
with Image.open("Tests/images/pillow2.icns") as im2:
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, "RGBA")
self.assertEqual(im2.size, (wr, hr))
def test_jp2_icon(self):
# This icon was made by using Uli Kusterer's oldiconutil to replace
@ -93,15 +93,15 @@ class TestFileIcns(PillowTestCase):
if not enable_jpeg2k:
return
im = Image.open("Tests/images/pillow3.icns")
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
im2 = Image.open("Tests/images/pillow3.icns")
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, "RGBA")
self.assertEqual(im2.size, (wr, hr))
with Image.open("Tests/images/pillow3.icns") as im:
for w, h, r in im.info["sizes"]:
wr = w * r
hr = h * r
with Image.open("Tests/images/pillow3.icns") as im2:
im2.size = (w, h, r)
im2.load()
self.assertEqual(im2.mode, "RGBA")
self.assertEqual(im2.size, (wr, hr))
def test_getimage(self):
with open(TEST_FILE, "rb") as fp:

View File

@ -9,8 +9,8 @@ TEST_ICO_FILE = "Tests/images/hopper.ico"
class TestFileIco(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_ICO_FILE)
im.load()
with Image.open(TEST_ICO_FILE) as im:
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (16, 16))
self.assertEqual(im.format, "ICO")
@ -27,41 +27,41 @@ class TestFileIco(PillowTestCase):
# the default image
output.seek(0)
reloaded = Image.open(output)
self.assertEqual(reloaded.info["sizes"], {(32, 32), (64, 64)})
with Image.open(output) as reloaded:
self.assertEqual(reloaded.info["sizes"], {(32, 32), (64, 64)})
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual((64, 64), reloaded.size)
self.assertEqual(reloaded.format, "ICO")
self.assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS))
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual((64, 64), reloaded.size)
self.assertEqual(reloaded.format, "ICO")
self.assert_image_equal(reloaded, hopper().resize((64, 64), Image.LANCZOS))
# the other one
output.seek(0)
reloaded = Image.open(output)
reloaded.size = (32, 32)
with Image.open(output) as reloaded:
reloaded.size = (32, 32)
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual((32, 32), reloaded.size)
self.assertEqual(reloaded.format, "ICO")
self.assert_image_equal(reloaded, hopper().resize((32, 32), Image.LANCZOS))
self.assertEqual(im.mode, reloaded.mode)
self.assertEqual((32, 32), reloaded.size)
self.assertEqual(reloaded.format, "ICO")
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)
with Image.open(TEST_ICO_FILE) as im:
with self.assertRaises(ValueError):
im.size = (1, 1)
def test_save_256x256(self):
"""Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
# Arrange
im = Image.open("Tests/images/hopper_256x256.ico")
outfile = self.tempfile("temp_saved_hopper_256x256.ico")
with Image.open("Tests/images/hopper_256x256.ico") as im:
outfile = self.tempfile("temp_saved_hopper_256x256.ico")
# Act
im.save(outfile)
im_saved = Image.open(outfile)
# Act
im.save(outfile)
with Image.open(outfile) as im_saved:
# Assert
self.assertEqual(im_saved.size, (256, 256))
# Assert
self.assertEqual(im_saved.size, (256, 256))
def test_only_save_relevant_sizes(self):
"""Issue #2266 https://github.com/python-pillow/Pillow/issues/2266
@ -69,35 +69,35 @@ class TestFileIco(PillowTestCase):
and not in 16x16, 24x24, 32x32, 48x48, 48x48, 48x48, 48x48 sizes
"""
# Arrange
im = Image.open("Tests/images/python.ico") # 16x16, 32x32, 48x48
outfile = self.tempfile("temp_saved_python.ico")
with Image.open("Tests/images/python.ico") as im: # 16x16, 32x32, 48x48
outfile = self.tempfile("temp_saved_python.ico")
# Act
im.save(outfile)
# Act
im.save(outfile)
im_saved = Image.open(outfile)
# Assert
self.assertEqual(
im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)}
)
with Image.open(outfile) as im_saved:
# Assert
self.assertEqual(
im_saved.info["sizes"], {(16, 16), (24, 24), (32, 32), (48, 48)}
)
def test_unexpected_size(self):
# This image has been manually hexedited to state that it is 16x32
# while the image within is still 16x16
im = self.assert_warning(
UserWarning, Image.open, "Tests/images/hopper_unexpected.ico"
)
self.assertEqual(im.size, (16, 16))
def open():
with Image.open("Tests/images/hopper_unexpected.ico") as im:
self.assertEqual(im.size, (16, 16))
self.assert_warning(UserWarning, open)
def test_draw_reloaded(self):
im = Image.open(TEST_ICO_FILE)
outfile = self.tempfile("temp_saved_hopper_draw.ico")
with Image.open(TEST_ICO_FILE) as im:
outfile = self.tempfile("temp_saved_hopper_draw.ico")
draw = ImageDraw.Draw(im)
draw.line((0, 0) + im.size, "#f00")
im.save(outfile)
draw = ImageDraw.Draw(im)
draw.line((0, 0) + im.size, "#f00")
im.save(outfile)
im = Image.open(outfile)
im.save("Tests/images/hopper_draw.ico")
reloaded = Image.open("Tests/images/hopper_draw.ico")
self.assert_image_equal(im, reloaded)
with Image.open(outfile) as im:
im.save("Tests/images/hopper_draw.ico")
with Image.open("Tests/images/hopper_draw.ico") as reloaded:
self.assert_image_equal(im, reloaded)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImImagePlugin
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
# sample im
TEST_IM = "Tests/images/hopper.im"
@ -8,53 +10,69 @@ TEST_IM = "Tests/images/hopper.im"
class TestFileIm(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_IM)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "IM")
with Image.open(TEST_IM) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "IM")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_IM)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_IM)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_IM) as im:
im.load()
self.assert_warning(None, open)
def test_tell(self):
# Arrange
im = Image.open(TEST_IM)
with Image.open(TEST_IM) as im:
# Act
frame = im.tell()
# Act
frame = im.tell()
# Assert
self.assertEqual(frame, 0)
def test_n_frames(self):
im = Image.open(TEST_IM)
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
with Image.open(TEST_IM) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
def test_eoferror(self):
im = Image.open(TEST_IM)
n_frames = im.n_frames
with Image.open(TEST_IM) as im:
n_frames = im.n_frames
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_roundtrip(self):
for mode in ["RGB", "P", "PA"]:
out = self.tempfile("temp.im")
im = hopper(mode)
im.save(out)
reread = Image.open(out)
with Image.open(out) as reread:
self.assert_image_equal(reread, im)
self.assert_image_equal(reread, im)
def test_save_unsupported_mode(self):
out = self.tempfile("temp.im")

View File

@ -1,3 +1,6 @@
import sys
from io import StringIO
from PIL import Image, IptcImagePlugin
from .helper import PillowTestCase, hopper
@ -8,20 +11,20 @@ TEST_FILE = "Tests/images/iptc.jpg"
class TestFileIptc(PillowTestCase):
def test_getiptcinfo_jpg_none(self):
# Arrange
im = hopper()
with hopper() as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
# Assert
self.assertIsNone(iptc)
def test_getiptcinfo_jpg_found(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
# Assert
self.assertIsInstance(iptc, dict)
@ -30,10 +33,10 @@ class TestFileIptc(PillowTestCase):
def test_getiptcinfo_tiff_none(self):
# Arrange
im = Image.open("Tests/images/hopper.tif")
with Image.open("Tests/images/hopper.tif") as im:
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
# Act
iptc = IptcImagePlugin.getiptcinfo(im)
# Assert
self.assertIsNone(iptc)
@ -52,12 +55,6 @@ class TestFileIptc(PillowTestCase):
# Arrange
c = b"abc"
# Temporarily redirect stdout
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import sys
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()

View File

@ -1,10 +1,16 @@
import os
import sys
from io import BytesIO
from PIL import Image, ImageFile, JpegImagePlugin
from .helper import PillowTestCase, cjpeg_available, djpeg_available, hopper, unittest
from .helper import (
PillowTestCase,
cjpeg_available,
djpeg_available,
hopper,
is_win32,
unittest,
)
codecs = dir(Image.core)
@ -38,52 +44,56 @@ class TestFileJpeg(PillowTestCase):
# internal version number
self.assertRegex(Image.core.jpeglib_version, r"\d+\.\d+$")
im = Image.open(TEST_FILE)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "JPEG")
self.assertEqual(im.get_format_mimetype(), "image/jpeg")
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "JPEG")
self.assertEqual(im.get_format_mimetype(), "image/jpeg")
def test_app(self):
# Test APP/COM reader (@PIL135)
im = Image.open(TEST_FILE)
self.assertEqual(
im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")
)
self.assertEqual(
im.applist[1], ("COM", b"File written by Adobe Photoshop\xa8 4.0\x00")
)
self.assertEqual(len(im.applist), 2)
with Image.open(TEST_FILE) as im:
self.assertEqual(
im.applist[0], ("APP0", b"JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00")
)
self.assertEqual(
im.applist[1], ("COM", b"File written by Adobe Photoshop\xa8 4.0\x00")
)
self.assertEqual(len(im.applist), 2)
def test_cmyk(self):
# Test CMYK handling. Thanks to Tim and Charlie for test data,
# Michael for getting me to look one more time.
f = "Tests/images/pil_sample_cmyk.jpg"
im = Image.open(f)
# the source image has red pixels in the upper left corner.
c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))]
self.assertEqual(c, 0.0)
self.assertGreater(m, 0.8)
self.assertGreater(y, 0.8)
self.assertEqual(k, 0.0)
# the opposite corner is black
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))]
self.assertGreater(k, 0.9)
# roundtrip, and check again
im = self.roundtrip(im)
c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))]
self.assertEqual(c, 0.0)
self.assertGreater(m, 0.8)
self.assertGreater(y, 0.8)
self.assertEqual(k, 0.0)
c, m, y, k = [x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))]
self.assertGreater(k, 0.9)
with Image.open(f) as im:
# the source image has red pixels in the upper left corner.
c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))]
self.assertEqual(c, 0.0)
self.assertGreater(m, 0.8)
self.assertGreater(y, 0.8)
self.assertEqual(k, 0.0)
# the opposite corner is black
c, m, y, k = [
x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))
]
self.assertGreater(k, 0.9)
# roundtrip, and check again
im = self.roundtrip(im)
c, m, y, k = [x / 255.0 for x in im.getpixel((0, 0))]
self.assertEqual(c, 0.0)
self.assertGreater(m, 0.8)
self.assertGreater(y, 0.8)
self.assertEqual(k, 0.0)
c, m, y, k = [
x / 255.0 for x in im.getpixel((im.size[0] - 1, im.size[1] - 1))
]
self.assertGreater(k, 0.9)
def test_dpi(self):
def test(xdpi, ydpi=None):
im = Image.open(TEST_FILE)
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
with Image.open(TEST_FILE) as im:
im = self.roundtrip(im, dpi=(xdpi, ydpi or xdpi))
return im.info.get("dpi")
self.assertEqual(test(72), (72, 72))
@ -93,20 +103,20 @@ class TestFileJpeg(PillowTestCase):
def test_icc(self):
# Test ICC support
im1 = Image.open("Tests/images/rgb.jpg")
icc_profile = im1.info["icc_profile"]
self.assertEqual(len(icc_profile), 3144)
# Roundtrip via physical file.
f = self.tempfile("temp.jpg")
im1.save(f, icc_profile=icc_profile)
im2 = Image.open(f)
self.assertEqual(im2.info.get("icc_profile"), icc_profile)
# Roundtrip via memory buffer.
im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), icc_profile=icc_profile)
self.assert_image_equal(im1, im2)
self.assertFalse(im1.info.get("icc_profile"))
self.assertTrue(im2.info.get("icc_profile"))
with Image.open("Tests/images/rgb.jpg") as im1:
icc_profile = im1.info["icc_profile"]
self.assertEqual(len(icc_profile), 3144)
# Roundtrip via physical file.
f = self.tempfile("temp.jpg")
im1.save(f, icc_profile=icc_profile)
with Image.open(f) as im2:
self.assertEqual(im2.info.get("icc_profile"), icc_profile)
# Roundtrip via memory buffer.
im1 = self.roundtrip(hopper())
im2 = self.roundtrip(hopper(), icc_profile=icc_profile)
self.assert_image_equal(im1, im2)
self.assertFalse(im1.info.get("icc_profile"))
self.assertTrue(im2.info.get("icc_profile"))
def test_icc_big(self):
# Make sure that the "extra" support handles large blocks
@ -134,18 +144,18 @@ class TestFileJpeg(PillowTestCase):
# https://github.com/python-pillow/Pillow/issues/148
# Sometimes the meta data on the icc_profile block is bigger than
# Image.MAXBLOCK or the image size.
im = Image.open("Tests/images/icc_profile_big.jpg")
f = self.tempfile("temp.jpg")
icc_profile = im.info["icc_profile"]
# Should not raise IOError for image with icc larger than image size.
im.save(
f,
format="JPEG",
progressive=True,
quality=95,
icc_profile=icc_profile,
optimize=True,
)
with Image.open("Tests/images/icc_profile_big.jpg") as im:
f = self.tempfile("temp.jpg")
icc_profile = im.info["icc_profile"]
# Should not raise IOError for image with icc larger than image size.
im.save(
f,
format="JPEG",
progressive=True,
quality=95,
icc_profile=icc_profile,
optimize=True,
)
def test_optimize(self):
im1 = self.roundtrip(hopper())
@ -199,24 +209,24 @@ class TestFileJpeg(PillowTestCase):
im.save(f, "JPEG", quality=90, exif=b"1" * 65532)
def test_exif_typeerror(self):
im = Image.open("Tests/images/exif_typeerror.jpg")
# Should not raise a TypeError
im._getexif()
with Image.open("Tests/images/exif_typeerror.jpg") as im:
# Should not raise a TypeError
im._getexif()
def test_exif_gps(self):
# Arrange
im = Image.open("Tests/images/exif_gps.jpg")
gps_index = 34853
expected_exif_gps = {
0: b"\x00\x00\x00\x01",
2: (4294967295, 1),
5: b"\x01",
30: 65535,
29: "1999:99:99 99:99:99",
}
with Image.open("Tests/images/exif_gps.jpg") as im:
gps_index = 34853
expected_exif_gps = {
0: b"\x00\x00\x00\x01",
2: (4294967295, 1),
5: b"\x01",
30: 65535,
29: "1999:99:99 99:99:99",
}
# Act
exif = im._getexif()
# Act
exif = im._getexif()
# Assert
self.assertEqual(exif[gps_index], expected_exif_gps)
@ -250,17 +260,17 @@ class TestFileJpeg(PillowTestCase):
33434: (4294967295, 1),
}
im = Image.open("Tests/images/exif_gps.jpg")
exif = im._getexif()
with Image.open("Tests/images/exif_gps.jpg") as im:
exif = im._getexif()
for tag, value in expected_exif.items():
self.assertEqual(value, exif[tag])
def test_exif_gps_typeerror(self):
im = Image.open("Tests/images/exif_gps_typeerror.jpg")
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
# Should not raise a TypeError
im._getexif()
# Should not raise a TypeError
im._getexif()
def test_progressive_compat(self):
im1 = self.roundtrip(hopper())
@ -323,172 +333,172 @@ class TestFileJpeg(PillowTestCase):
self.assertRaises(TypeError, self.roundtrip, hopper(), subsampling="1:1:1")
def test_exif(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
info = im._getexif()
self.assertEqual(info[305], "Adobe Photoshop CS Macintosh")
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
info = im._getexif()
self.assertEqual(info[305], "Adobe Photoshop CS Macintosh")
def test_mp(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
self.assertIsNone(im._getmp())
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
self.assertIsNone(im._getmp())
def test_quality_keep(self):
# RGB
im = Image.open("Tests/images/hopper.jpg")
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
with Image.open("Tests/images/hopper.jpg") as im:
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
# Grayscale
im = Image.open("Tests/images/hopper_gray.jpg")
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
with Image.open("Tests/images/hopper_gray.jpg") as im:
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
# CMYK
im = Image.open("Tests/images/pil_sample_cmyk.jpg")
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
with Image.open("Tests/images/pil_sample_cmyk.jpg") as im:
f = self.tempfile("temp.jpg")
im.save(f, quality="keep")
def test_junk_jpeg_header(self):
# https://github.com/python-pillow/Pillow/issues/630
filename = "Tests/images/junk_jpeg_header.jpg"
Image.open(filename)
with Image.open(filename):
pass
def test_ff00_jpeg_header(self):
filename = "Tests/images/jpeg_ff00_header.jpg"
Image.open(filename)
with Image.open(filename):
pass
def test_truncated_jpeg_should_read_all_the_data(self):
filename = "Tests/images/truncated_jpeg.jpg"
ImageFile.LOAD_TRUNCATED_IMAGES = True
im = Image.open(filename)
im.load()
ImageFile.LOAD_TRUNCATED_IMAGES = False
self.assertIsNotNone(im.getbbox())
with Image.open(filename) as im:
im.load()
ImageFile.LOAD_TRUNCATED_IMAGES = False
self.assertIsNotNone(im.getbbox())
def test_truncated_jpeg_throws_IOError(self):
filename = "Tests/images/truncated_jpeg.jpg"
im = Image.open(filename)
with Image.open(filename) as im:
with self.assertRaises(IOError):
im.load()
with self.assertRaises(IOError):
im.load()
# Test that the error is raised if loaded a second time
with self.assertRaises(IOError):
im.load()
# Test that the error is raised if loaded a second time
with self.assertRaises(IOError):
im.load()
def _n_qtables_helper(self, n, test_file):
im = Image.open(test_file)
f = self.tempfile("temp.jpg")
im.save(f, qtables=[[n] * 64] * n)
im = Image.open(f)
self.assertEqual(len(im.quantization), n)
reloaded = self.roundtrip(im, qtables="keep")
self.assertEqual(im.quantization, reloaded.quantization)
with Image.open(test_file) as im:
f = self.tempfile("temp.jpg")
im.save(f, qtables=[[n] * 64] * n)
with Image.open(f) as im:
self.assertEqual(len(im.quantization), n)
reloaded = self.roundtrip(im, qtables="keep")
self.assertEqual(im.quantization, reloaded.quantization)
def test_qtables(self):
im = Image.open("Tests/images/hopper.jpg")
qtables = im.quantization
reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
self.assertEqual(im.quantization, reloaded.quantization)
self.assert_image_similar(im, self.roundtrip(im, qtables="web_low"), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="web_high"), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="keep"), 30)
with Image.open("Tests/images/hopper.jpg") as im:
qtables = im.quantization
reloaded = self.roundtrip(im, qtables=qtables, subsampling=0)
self.assertEqual(im.quantization, reloaded.quantization)
self.assert_image_similar(im, self.roundtrip(im, qtables="web_low"), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="web_high"), 30)
self.assert_image_similar(im, self.roundtrip(im, qtables="keep"), 30)
# valid bounds for baseline qtable
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
self.roundtrip(im, qtables=[bounds_qtable])
# valid bounds for baseline qtable
bounds_qtable = [int(s) for s in ("255 1 " * 32).split(None)]
self.roundtrip(im, qtables=[bounds_qtable])
# values from wizard.txt in jpeg9-a src package.
standard_l_qtable = [
int(s)
for s in """
16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99
""".split(
None
# values from wizard.txt in jpeg9-a src package.
standard_l_qtable = [
int(s)
for s in """
16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99
""".split(
None
)
]
standard_chrominance_qtable = [
int(s)
for s in """
17 18 24 47 99 99 99 99
18 21 26 66 99 99 99 99
24 26 56 99 99 99 99 99
47 66 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
""".split(
None
)
]
# list of qtable lists
self.assert_image_similar(
im,
self.roundtrip(
im, qtables=[standard_l_qtable, standard_chrominance_qtable]
),
30,
)
]
standard_chrominance_qtable = [
int(s)
for s in """
17 18 24 47 99 99 99 99
18 21 26 66 99 99 99 99
24 26 56 99 99 99 99 99
47 66 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
""".split(
None
# tuple of qtable lists
self.assert_image_similar(
im,
self.roundtrip(
im, qtables=(standard_l_qtable, standard_chrominance_qtable)
),
30,
)
]
# list of qtable lists
self.assert_image_similar(
im,
self.roundtrip(
im, qtables=[standard_l_qtable, standard_chrominance_qtable]
),
30,
)
# tuple of qtable lists
self.assert_image_similar(
im,
self.roundtrip(
im, qtables=(standard_l_qtable, standard_chrominance_qtable)
),
30,
)
# dict of qtable lists
self.assert_image_similar(
im,
self.roundtrip(
im, qtables={0: standard_l_qtable, 1: standard_chrominance_qtable}
),
30,
)
# dict of qtable lists
self.assert_image_similar(
im,
self.roundtrip(
im, qtables={0: standard_l_qtable, 1: standard_chrominance_qtable}
),
30,
)
self._n_qtables_helper(1, "Tests/images/hopper_gray.jpg")
self._n_qtables_helper(1, "Tests/images/pil_sample_rgb.jpg")
self._n_qtables_helper(2, "Tests/images/pil_sample_rgb.jpg")
self._n_qtables_helper(3, "Tests/images/pil_sample_rgb.jpg")
self._n_qtables_helper(1, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(2, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(3, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(1, "Tests/images/hopper_gray.jpg")
self._n_qtables_helper(1, "Tests/images/pil_sample_rgb.jpg")
self._n_qtables_helper(2, "Tests/images/pil_sample_rgb.jpg")
self._n_qtables_helper(3, "Tests/images/pil_sample_rgb.jpg")
self._n_qtables_helper(1, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(2, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(3, "Tests/images/pil_sample_cmyk.jpg")
self._n_qtables_helper(4, "Tests/images/pil_sample_cmyk.jpg")
# not a sequence
self.assertRaises(ValueError, self.roundtrip, im, qtables="a")
# sequence wrong length
self.assertRaises(ValueError, self.roundtrip, im, qtables=[])
# sequence wrong length
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
# not a sequence
self.assertRaises(ValueError, self.roundtrip, im, qtables="a")
# sequence wrong length
self.assertRaises(ValueError, self.roundtrip, im, qtables=[])
# sequence wrong length
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1, 2, 3, 4, 5])
# qtable entry not a sequence
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1])
# qtable entry has wrong number of items
self.assertRaises(ValueError, self.roundtrip, im, qtables=[[1, 2, 3, 4]])
# qtable entry not a sequence
self.assertRaises(ValueError, self.roundtrip, im, qtables=[1])
# qtable entry has wrong number of items
self.assertRaises(ValueError, self.roundtrip, im, qtables=[[1, 2, 3, 4]])
@unittest.skipUnless(djpeg_available(), "djpeg not available")
def test_load_djpeg(self):
img = Image.open(TEST_FILE)
img.load_djpeg()
self.assert_image_similar(img, Image.open(TEST_FILE), 0)
with Image.open(TEST_FILE) as img:
img.load_djpeg()
self.assert_image_similar(img, Image.open(TEST_FILE), 0)
@unittest.skipUnless(cjpeg_available(), "cjpeg not available")
def test_save_cjpeg(self):
img = Image.open(TEST_FILE)
tempfile = self.tempfile("temp.jpg")
JpegImagePlugin._save_cjpeg(img, 0, tempfile)
# Default save quality is 75%, so a tiny bit of difference is alright
self.assert_image_similar(img, Image.open(tempfile), 17)
with Image.open(TEST_FILE) as img:
tempfile = self.tempfile("temp.jpg")
JpegImagePlugin._save_cjpeg(img, 0, tempfile)
# Default save quality is 75%, so a tiny bit of difference is alright
self.assert_image_similar(img, Image.open(tempfile), 17)
def test_no_duplicate_0x1001_tag(self):
# Arrange
@ -505,12 +515,11 @@ class TestFileJpeg(PillowTestCase):
f = self.tempfile("temp.jpeg")
im.save(f, quality=100, optimize=True)
reloaded = Image.open(f)
# none of these should crash
reloaded.save(f, quality="keep")
reloaded.save(f, quality="keep", progressive=True)
reloaded.save(f, quality="keep", optimize=True)
with Image.open(f) as reloaded:
# none of these should crash
reloaded.save(f, quality="keep")
reloaded.save(f, quality="keep", progressive=True)
reloaded.save(f, quality="keep", optimize=True)
def test_bad_mpo_header(self):
""" Treat unknown MPO as JPEG """
@ -519,10 +528,10 @@ class TestFileJpeg(PillowTestCase):
# Act
# Shouldn't raise error
fn = "Tests/images/sugarshack_bad_mpo_header.jpg"
im = self.assert_warning(UserWarning, Image.open, fn)
with self.assert_warning(UserWarning, Image.open, fn) as im:
# Assert
self.assertEqual(im.format, "JPEG")
# Assert
self.assertEqual(im.format, "JPEG")
def test_save_correct_modes(self):
out = BytesIO()
@ -540,121 +549,127 @@ class TestFileJpeg(PillowTestCase):
def test_save_tiff_with_dpi(self):
# Arrange
outfile = self.tempfile("temp.tif")
im = Image.open("Tests/images/hopper.tif")
with Image.open("Tests/images/hopper.tif") as im:
# Act
im.save(outfile, "JPEG", dpi=im.info["dpi"])
# Act
im.save(outfile, "JPEG", dpi=im.info["dpi"])
# Assert
reloaded = Image.open(outfile)
reloaded.load()
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
# Assert
with Image.open(outfile) as reloaded:
reloaded.load()
self.assertEqual(im.info["dpi"], reloaded.info["dpi"])
def test_load_dpi_rounding(self):
# Round up
im = Image.open("Tests/images/iptc_roundUp.jpg")
self.assertEqual(im.info["dpi"], (44, 44))
with Image.open("Tests/images/iptc_roundUp.jpg") as im:
self.assertEqual(im.info["dpi"], (44, 44))
# Round down
im = Image.open("Tests/images/iptc_roundDown.jpg")
self.assertEqual(im.info["dpi"], (2, 2))
with Image.open("Tests/images/iptc_roundDown.jpg") as im:
self.assertEqual(im.info["dpi"], (2, 2))
def test_save_dpi_rounding(self):
outfile = self.tempfile("temp.jpg")
im = Image.open("Tests/images/hopper.jpg")
with Image.open("Tests/images/hopper.jpg") as im:
im.save(outfile, dpi=(72.2, 72.2))
im.save(outfile, dpi=(72.2, 72.2))
reloaded = Image.open(outfile)
self.assertEqual(reloaded.info["dpi"], (72, 72))
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (72, 72))
im.save(outfile, dpi=(72.8, 72.8))
reloaded = Image.open(outfile)
self.assertEqual(reloaded.info["dpi"], (73, 73))
im.save(outfile, dpi=(72.8, 72.8))
with Image.open(outfile) as reloaded:
self.assertEqual(reloaded.info["dpi"], (73, 73))
def test_dpi_tuple_from_exif(self):
# Arrange
# This Photoshop CC 2017 image has DPI in EXIF not metadata
# EXIF XResolution is (2000000, 10000)
im = Image.open("Tests/images/photoshop-200dpi.jpg")
with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
# Act / Assert
self.assertEqual(im.info.get("dpi"), (200, 200))
# Act / Assert
self.assertEqual(im.info.get("dpi"), (200, 200))
def test_dpi_int_from_exif(self):
# Arrange
# This image has DPI in EXIF not metadata
# EXIF XResolution is 72
im = Image.open("Tests/images/exif-72dpi-int.jpg")
with Image.open("Tests/images/exif-72dpi-int.jpg") as im:
# Act / Assert
self.assertEqual(im.info.get("dpi"), (72, 72))
# Act / Assert
self.assertEqual(im.info.get("dpi"), (72, 72))
def test_dpi_from_dpcm_exif(self):
# Arrange
# This is photoshop-200dpi.jpg with EXIF resolution unit set to cm:
# exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg
im = Image.open("Tests/images/exif-200dpcm.jpg")
with Image.open("Tests/images/exif-200dpcm.jpg") as im:
# Act / Assert
self.assertEqual(im.info.get("dpi"), (508, 508))
# Act / Assert
self.assertEqual(im.info.get("dpi"), (508, 508))
def test_dpi_exif_zero_division(self):
# Arrange
# This is photoshop-200dpi.jpg with EXIF resolution set to 0/0:
# exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg
im = Image.open("Tests/images/exif-dpi-zerodivision.jpg")
with Image.open("Tests/images/exif-dpi-zerodivision.jpg") as im:
# Act / Assert
# This should return the default, and not raise a ZeroDivisionError
self.assertEqual(im.info.get("dpi"), (72, 72))
# Act / Assert
# This should return the default, and not raise a ZeroDivisionError
self.assertEqual(im.info.get("dpi"), (72, 72))
def test_no_dpi_in_exif(self):
# Arrange
# This is photoshop-200dpi.jpg with resolution removed from EXIF:
# exiftool "-*resolution*"= photoshop-200dpi.jpg
im = Image.open("Tests/images/no-dpi-in-exif.jpg")
with Image.open("Tests/images/no-dpi-in-exif.jpg") as im:
# Act / Assert
# "When the image resolution is unknown, 72 [dpi] is designated."
# http://www.exiv2.org/tags.html
self.assertEqual(im.info.get("dpi"), (72, 72))
# Act / Assert
# "When the image resolution is unknown, 72 [dpi] is designated."
# http://www.exiv2.org/tags.html
self.assertEqual(im.info.get("dpi"), (72, 72))
def test_invalid_exif(self):
# This is no-dpi-in-exif with the tiff header of the exif block
# hexedited from MM * to FF FF FF FF
im = Image.open("Tests/images/invalid-exif.jpg")
with Image.open("Tests/images/invalid-exif.jpg") as im:
# This should return the default, and not a SyntaxError or
# OSError for unidentified image.
self.assertEqual(im.info.get("dpi"), (72, 72))
# This should return the default, and not a SyntaxError or
# 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")
with Image.open("Tests/images/exif-ifd-offset.jpg") as im:
# Act / Assert
self.assertEqual(im._getexif()[306], "2017:03:13 23:03:09")
# Act / Assert
self.assertEqual(im._getexif()[306], "2017:03:13 23:03:09")
def test_photoshop(self):
im = Image.open("Tests/images/photoshop-200dpi.jpg")
self.assertEqual(
im.info["photoshop"][0x03ED],
{
"XResolution": 200.0,
"DisplayedUnitsX": 1,
"YResolution": 200.0,
"DisplayedUnitsY": 1,
},
)
with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
self.assertEqual(
im.info["photoshop"][0x03ED],
{
"XResolution": 200.0,
"DisplayedUnitsX": 1,
"YResolution": 200.0,
"DisplayedUnitsY": 1,
},
)
# Test that the image can still load, even with broken Photoshop data
# This image had the APP13 length hexedited to be smaller
with Image.open("Tests/images/photoshop-200dpi-broken.jpg") as im_broken:
self.assert_image_equal(im_broken, im)
# This image does not contain a Photoshop header string
im = Image.open("Tests/images/app13.jpg")
self.assertNotIn("photoshop", im.info)
with Image.open("Tests/images/app13.jpg") as im:
self.assertNotIn("photoshop", im.info)
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
@unittest.skipUnless(is_win32(), "Windows only")
class TestFileCloseW32(PillowTestCase):
def setUp(self):
if "jpeg_encoder" not in codecs or "jpeg_decoder" not in codecs:

View File

@ -33,18 +33,18 @@ class TestFileJpeg2k(PillowTestCase):
# Internal version number
self.assertRegex(Image.core.jp2klib_version, r"\d+\.\d+\.\d+$")
im = Image.open("Tests/images/test-card-lossless.jp2")
px = im.load()
self.assertEqual(px[0, 0], (0, 0, 0))
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (640, 480))
self.assertEqual(im.format, "JPEG2000")
self.assertEqual(im.get_format_mimetype(), "image/jp2")
with Image.open("Tests/images/test-card-lossless.jp2") as im:
px = im.load()
self.assertEqual(px[0, 0], (0, 0, 0))
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")
with Image.open("Tests/images/balloon.jpf") as im:
self.assertEqual(im.format, "JPEG2000")
self.assertEqual(im.get_format_mimetype(), "image/jpx")
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -54,24 +54,24 @@ class TestFileJpeg2k(PillowTestCase):
def test_bytesio(self):
with open("Tests/images/test-card-lossless.jp2", "rb") as f:
data = BytesIO(f.read())
im = Image.open(data)
im.load()
self.assert_image_similar(im, test_card, 1.0e-3)
with Image.open(data) as im:
im.load()
self.assert_image_similar(im, test_card, 1.0e-3)
# These two test pre-written JPEG 2000 files that were not written with
# PIL (they were made using Adobe Photoshop)
def test_lossless(self):
im = Image.open("Tests/images/test-card-lossless.jp2")
im.load()
outfile = self.tempfile("temp_test-card.png")
im.save(outfile)
with Image.open("Tests/images/test-card-lossless.jp2") as im:
im.load()
outfile = self.tempfile("temp_test-card.png")
im.save(outfile)
self.assert_image_similar(im, test_card, 1.0e-3)
def test_lossy_tiled(self):
im = Image.open("Tests/images/test-card-lossy-tiled.jp2")
im.load()
self.assert_image_similar(im, test_card, 2.0)
with Image.open("Tests/images/test-card-lossy-tiled.jp2") as im:
im.load()
self.assert_image_similar(im, test_card, 2.0)
def test_lossless_rt(self):
im = self.roundtrip(test_card)
@ -110,10 +110,10 @@ class TestFileJpeg2k(PillowTestCase):
self.assert_image_equal(im, test_card)
def test_reduce(self):
im = Image.open("Tests/images/test-card-lossless.jp2")
im.reduce = 2
im.load()
self.assertEqual(im.size, (160, 120))
with Image.open("Tests/images/test-card-lossless.jp2") as im:
im.reduce = 2
im.load()
self.assertEqual(im.size, (160, 120))
def test_layers_type(self):
outfile = self.tempfile("temp_layers.jp2")
@ -132,64 +132,58 @@ class TestFileJpeg2k(PillowTestCase):
)
out.seek(0)
im = Image.open(out)
im.layers = 1
im.load()
self.assert_image_similar(im, test_card, 13)
with Image.open(out) as im:
im.layers = 1
im.load()
self.assert_image_similar(im, test_card, 13)
out.seek(0)
im = Image.open(out)
im.layers = 3
im.load()
self.assert_image_similar(im, test_card, 0.4)
with Image.open(out) as im:
im.layers = 3
im.load()
self.assert_image_similar(im, test_card, 0.4)
def test_rgba(self):
# Arrange
j2k = Image.open("Tests/images/rgb_trns_ycbc.j2k")
jp2 = Image.open("Tests/images/rgb_trns_ycbc.jp2")
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
# Act
j2k.load()
jp2.load()
# Act
j2k.load()
jp2.load()
# Assert
self.assertEqual(j2k.mode, "RGBA")
self.assertEqual(jp2.mode, "RGBA")
# Assert
self.assertEqual(j2k.mode, "RGBA")
self.assertEqual(jp2.mode, "RGBA")
def test_16bit_monochrome_has_correct_mode(self):
with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
j2k.load()
self.assertEqual(j2k.mode, "I;16")
j2k = Image.open("Tests/images/16bit.cropped.j2k")
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
j2k.load()
jp2.load()
self.assertEqual(j2k.mode, "I;16")
self.assertEqual(jp2.mode, "I;16")
with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
jp2.load()
self.assertEqual(jp2.mode, "I;16")
def test_16bit_monochrome_jp2_like_tiff(self):
tiff_16bit = Image.open("Tests/images/16bit.cropped.tif")
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
self.assert_image_similar(jp2, tiff_16bit, 1e-3)
with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
self.assert_image_similar(jp2, tiff_16bit, 1e-3)
def test_16bit_monochrome_j2k_like_tiff(self):
tiff_16bit = Image.open("Tests/images/16bit.cropped.tif")
j2k = Image.open("Tests/images/16bit.cropped.j2k")
self.assert_image_similar(j2k, tiff_16bit, 1e-3)
with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit:
with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
self.assert_image_similar(j2k, tiff_16bit, 1e-3)
def test_16bit_j2k_roundtrips(self):
j2k = Image.open("Tests/images/16bit.cropped.j2k")
im = self.roundtrip(j2k)
self.assert_image_equal(im, j2k)
with Image.open("Tests/images/16bit.cropped.j2k") as j2k:
im = self.roundtrip(j2k)
self.assert_image_equal(im, j2k)
def test_16bit_jp2_roundtrips(self):
jp2 = Image.open("Tests/images/16bit.cropped.jp2")
im = self.roundtrip(jp2)
self.assert_image_equal(im, jp2)
with Image.open("Tests/images/16bit.cropped.jp2") as jp2:
im = self.roundtrip(jp2)
self.assert_image_equal(im, jp2)
def test_unbound_local(self):
# prepatch, a malformed jp2 file could cause an UnboundLocalError

View File

@ -1,5 +1,4 @@
from __future__ import print_function
import base64
import distutils.version
import io
import itertools
@ -9,7 +8,6 @@ from collections import namedtuple
from ctypes import c_float
from PIL import Image, TiffImagePlugin, TiffTags, features
from PIL._util import py3
from .helper import PillowTestCase, hopper
@ -49,25 +47,23 @@ class TestFileLibTiff(LibTiffTestCase):
"""Test the ordinary file path load path"""
test_file = "Tests/images/hopper_g4_500.tif"
im = Image.open(test_file)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
with Image.open(test_file) as im:
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
def test_g4_large(self):
test_file = "Tests/images/pport_g4.tif"
im = Image.open(test_file)
self._assert_noerr(im)
with Image.open(test_file) as im:
self._assert_noerr(im)
def test_g4_tiff_file(self):
"""Testing the string load path"""
test_file = "Tests/images/hopper_g4_500.tif"
with open(test_file, "rb") as f:
im = Image.open(f)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
with Image.open(f) as im:
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
def test_g4_tiff_bytesio(self):
"""Testing the stringio loading code path"""
@ -76,10 +72,9 @@ class TestFileLibTiff(LibTiffTestCase):
with open(test_file, "rb") as f:
s.write(f.read())
s.seek(0)
im = Image.open(s)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
with Image.open(s) as im:
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
def test_g4_non_disk_file_object(self):
"""Testing loading from non-disk non-BytesIO file object"""
@ -89,69 +84,63 @@ class TestFileLibTiff(LibTiffTestCase):
s.write(f.read())
s.seek(0)
r = io.BufferedReader(s)
im = Image.open(r)
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
with Image.open(r) as im:
self.assertEqual(im.size, (500, 500))
self._assert_noerr(im)
def test_g4_eq_png(self):
""" Checking that we're actually getting the data that we expect"""
png = Image.open("Tests/images/hopper_bw_500.png")
g4 = Image.open("Tests/images/hopper_g4_500.tif")
self.assert_image_equal(g4, png)
with Image.open("Tests/images/hopper_bw_500.png") as png:
with Image.open("Tests/images/hopper_g4_500.tif") as g4:
self.assert_image_equal(g4, png)
# see https://github.com/python-pillow/Pillow/issues/279
def test_g4_fillorder_eq_png(self):
""" Checking that we're actually getting the data that we expect"""
png = Image.open("Tests/images/g4-fillorder-test.png")
g4 = Image.open("Tests/images/g4-fillorder-test.tif")
self.assert_image_equal(g4, png)
with Image.open("Tests/images/g4-fillorder-test.png") as png:
with Image.open("Tests/images/g4-fillorder-test.tif") as g4:
self.assert_image_equal(g4, png)
def test_g4_write(self):
"""Checking to see that the saved image is the same as what we wrote"""
test_file = "Tests/images/hopper_g4_500.tif"
orig = Image.open(test_file)
with Image.open(test_file) as orig:
out = self.tempfile("temp.tif")
rot = orig.transpose(Image.ROTATE_90)
self.assertEqual(rot.size, (500, 500))
rot.save(out)
out = self.tempfile("temp.tif")
rot = orig.transpose(Image.ROTATE_90)
self.assertEqual(rot.size, (500, 500))
rot.save(out)
with Image.open(out) as reread:
self.assertEqual(reread.size, (500, 500))
self._assert_noerr(reread)
self.assert_image_equal(reread, rot)
self.assertEqual(reread.info["compression"], "group4")
reread = Image.open(out)
self.assertEqual(reread.size, (500, 500))
self._assert_noerr(reread)
self.assert_image_equal(reread, rot)
self.assertEqual(reread.info["compression"], "group4")
self.assertEqual(reread.info["compression"], orig.info["compression"])
self.assertEqual(reread.info["compression"], orig.info["compression"])
self.assertNotEqual(orig.tobytes(), reread.tobytes())
self.assertNotEqual(orig.tobytes(), reread.tobytes())
def test_adobe_deflate_tiff(self):
test_file = "Tests/images/tiff_adobe_deflate.tif"
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (278, 374))
self.assertEqual(im.tile[0][:3], ("libtiff", (0, 0, 278, 374), 0))
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (278, 374))
self.assertEqual(im.tile[0][:3], ("libtiff", (0, 0, 278, 374), 0))
im.load()
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_write_metadata(self):
""" Test metadata writing through libtiff """
for legacy_api in [False, True]:
img = Image.open("Tests/images/hopper_g4.tif")
f = self.tempfile("temp.tiff")
with Image.open("Tests/images/hopper_g4.tif") as img:
img.save(f, tiffinfo=img.tag)
img.save(f, tiffinfo=img.tag)
if legacy_api:
original = img.tag.named()
else:
original = img.tag_v2.named()
if legacy_api:
original = img.tag.named()
else:
original = img.tag_v2.named()
# PhotometricInterpretation is set from SAVE_INFO,
# not the original image.
@ -162,11 +151,11 @@ class TestFileLibTiff(LibTiffTestCase):
"PhotometricInterpretation",
]
loaded = Image.open(f)
if legacy_api:
reloaded = loaded.tag.named()
else:
reloaded = loaded.tag_v2.named()
with Image.open(f) as loaded:
if legacy_api:
reloaded = loaded.tag.named()
else:
reloaded = loaded.tag_v2.named()
for tag, value in itertools.chain(reloaded.items(), original.items()):
if tag not in ignored:
@ -207,44 +196,44 @@ class TestFileLibTiff(LibTiffTestCase):
# Exclude ones that have special meaning
# that we're already testing them
im = Image.open("Tests/images/hopper_g4.tif")
for tag in im.tag_v2:
try:
del core_items[tag]
except KeyError:
pass
with Image.open("Tests/images/hopper_g4.tif") as im:
for tag in im.tag_v2:
try:
del core_items[tag]
except KeyError:
pass
# Type codes:
# 2: "ascii",
# 3: "short",
# 4: "long",
# 5: "rational",
# 12: "double",
# Type: dummy value
values = {
2: "test",
3: 1,
4: 2 ** 20,
5: TiffImagePlugin.IFDRational(100, 1),
12: 1.05,
}
# Type codes:
# 2: "ascii",
# 3: "short",
# 4: "long",
# 5: "rational",
# 12: "double",
# Type: dummy value
values = {
2: "test",
3: 1,
4: 2 ** 20,
5: TiffImagePlugin.IFDRational(100, 1),
12: 1.05,
}
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
for tag, info in core_items.items():
if info.length == 1:
new_ifd[tag] = values[info.type]
if info.length == 0:
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
else:
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
for tag, info in core_items.items():
if info.length == 1:
new_ifd[tag] = values[info.type]
if info.length == 0:
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
else:
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
# Extra samples really doesn't make sense in this application.
del new_ifd[338]
# Extra samples really doesn't make sense in this application.
del new_ifd[338]
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out, tiffinfo=new_ifd)
im.save(out, tiffinfo=new_ifd)
TiffImagePlugin.WRITE_LIBTIFF = False
@ -263,7 +252,6 @@ class TestFileLibTiff(LibTiffTestCase):
tc(4.25, TiffTags.FLOAT, True),
tc(4.25, TiffTags.DOUBLE, True),
tc("custom tag value", TiffTags.ASCII, True),
tc(u"custom tag value", TiffTags.ASCII, True),
tc(b"custom tag value", TiffTags.BYTE, True),
tc((4, 5, 6), TiffTags.SHORT, True),
tc((123456789, 9, 34, 234, 219387, 92432323), TiffTags.LONG, True),
@ -301,21 +289,21 @@ class TestFileLibTiff(LibTiffTestCase):
out = self.tempfile("temp.tif")
im.save(out, tiffinfo=tiffinfo)
reloaded = Image.open(out)
for tag, value in tiffinfo.items():
reloaded_value = reloaded.tag_v2[tag]
if (
isinstance(reloaded_value, TiffImagePlugin.IFDRational)
and libtiff
):
# libtiff does not support real RATIONALS
self.assertAlmostEqual(float(reloaded_value), float(value))
continue
with Image.open(out) as reloaded:
for tag, value in tiffinfo.items():
reloaded_value = reloaded.tag_v2[tag]
if (
isinstance(reloaded_value, TiffImagePlugin.IFDRational)
and libtiff
):
# libtiff does not support real RATIONALS
self.assertAlmostEqual(float(reloaded_value), float(value))
continue
if libtiff and isinstance(value, bytes):
value = value.decode()
if libtiff and isinstance(value, bytes):
value = value.decode()
self.assertEqual(reloaded_value, value)
self.assertEqual(reloaded_value, value)
# Test with types
ifd = TiffImagePlugin.ImageFileDirectory_v2()
@ -342,93 +330,81 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = True
im.save(out, dpi=(72, 72))
TiffImagePlugin.WRITE_LIBTIFF = False
reloaded = Image.open(out)
self.assertEqual(reloaded.info["dpi"], (72.0, 72.0))
with Image.open(out) as reloaded:
self.assertEqual(reloaded.info["dpi"], (72.0, 72.0))
def test_g3_compression(self):
i = Image.open("Tests/images/hopper_g4_500.tif")
out = self.tempfile("temp.tif")
i.save(out, compression="group3")
with Image.open("Tests/images/hopper_g4_500.tif") as i:
out = self.tempfile("temp.tif")
i.save(out, compression="group3")
reread = Image.open(out)
self.assertEqual(reread.info["compression"], "group3")
self.assert_image_equal(reread, i)
with Image.open(out) as reread:
self.assertEqual(reread.info["compression"], "group3")
self.assert_image_equal(reread, i)
def test_little_endian(self):
im = Image.open("Tests/images/16bit.deflate.tif")
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16")
with Image.open("Tests/images/16bit.deflate.tif") as im:
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16")
b = im.tobytes()
# Bytes are in image native order (little endian)
if py3:
b = im.tobytes()
# Bytes are in image native order (little endian)
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
else:
self.assertEqual(b[0], b"\xe0")
self.assertEqual(b[1], b"\x01")
out = self.tempfile("temp.tif")
# out = "temp.le.tif"
im.save(out)
reread = Image.open(out)
self.assertEqual(reread.info["compression"], im.info["compression"])
self.assertEqual(reread.getpixel((0, 0)), 480)
out = self.tempfile("temp.tif")
# out = "temp.le.tif"
im.save(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["compression"], im.info["compression"])
self.assertEqual(reread.getpixel((0, 0)), 480)
# UNDONE - libtiff defaults to writing in native endian, so
# on big endian, we'll get back mode = 'I;16B' here.
def test_big_endian(self):
im = Image.open("Tests/images/16bit.MM.deflate.tif")
with Image.open("Tests/images/16bit.MM.deflate.tif") as im:
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16B")
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16B")
b = im.tobytes()
b = im.tobytes()
# Bytes are in image native order (big endian)
if py3:
# Bytes are in image native order (big endian)
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
else:
self.assertEqual(b[0], b"\x01")
self.assertEqual(b[1], b"\xe0")
out = self.tempfile("temp.tif")
im.save(out)
reread = Image.open(out)
self.assertEqual(reread.info["compression"], im.info["compression"])
self.assertEqual(reread.getpixel((0, 0)), 480)
out = self.tempfile("temp.tif")
im.save(out)
with Image.open(out) as reread:
self.assertEqual(reread.info["compression"], im.info["compression"])
self.assertEqual(reread.getpixel((0, 0)), 480)
def test_g4_string_info(self):
"""Tests String data in info directory"""
test_file = "Tests/images/hopper_g4_500.tif"
orig = Image.open(test_file)
with Image.open(test_file) as orig:
out = self.tempfile("temp.tif")
out = self.tempfile("temp.tif")
orig.tag[269] = "temp.tif"
orig.save(out)
orig.tag[269] = "temp.tif"
orig.save(out)
reread = Image.open(out)
self.assertEqual("temp.tif", reread.tag_v2[269])
self.assertEqual("temp.tif", reread.tag[269][0])
with Image.open(out) as reread:
self.assertEqual("temp.tif", reread.tag_v2[269])
self.assertEqual("temp.tif", reread.tag[269][0])
def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open("Tests/images/12bit.cropped.tif")
im.load()
TiffImagePlugin.READ_LIBTIFF = False
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
with Image.open("Tests/images/12bit.cropped.tif") as im:
im.load()
TiffImagePlugin.READ_LIBTIFF = False
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
def test_blur(self):
# test case from irc, how to do blur on b/w image
@ -436,16 +412,16 @@ class TestFileLibTiff(LibTiffTestCase):
from PIL import ImageFilter
out = self.tempfile("temp.tif")
im = Image.open("Tests/images/pport_g4.tif")
im = im.convert("L")
with Image.open("Tests/images/pport_g4.tif") as im:
im = im.convert("L")
im = im.filter(ImageFilter.GaussianBlur(4))
im.save(out, compression="tiff_adobe_deflate")
im2 = Image.open(out)
im2.load()
with Image.open(out) as im2:
im2.load()
self.assert_image_equal(im, im2)
self.assert_image_equal(im, im2)
def test_compressions(self):
# Test various tiff compressions and assert similar image content but reduced
@ -458,18 +434,18 @@ class TestFileLibTiff(LibTiffTestCase):
for compression in ("packbits", "tiff_lzw"):
im.save(out, compression=compression)
size_compressed = os.path.getsize(out)
im2 = Image.open(out)
self.assert_image_equal(im, im2)
with Image.open(out) as im2:
self.assert_image_equal(im, im2)
im.save(out, compression="jpeg")
size_jpeg = os.path.getsize(out)
im2 = Image.open(out)
self.assert_image_similar(im, im2, 30)
with Image.open(out) as im2:
self.assert_image_similar(im, im2, 30)
im.save(out, compression="jpeg", quality=30)
size_jpeg_30 = os.path.getsize(out)
im3 = Image.open(out)
self.assert_image_similar(im2, im3, 30)
with Image.open(out) as im3:
self.assert_image_similar(im2, im3, 30)
self.assertGreater(size_raw, size_compressed)
self.assertGreater(size_compressed, size_jpeg)
@ -491,8 +467,8 @@ class TestFileLibTiff(LibTiffTestCase):
out = self.tempfile("temp.tif")
im.save(out, compression="tiff_adobe_deflate")
im2 = Image.open(out)
self.assert_image_equal(im, im2)
with Image.open(out) as im2:
self.assert_image_equal(im, im2)
def xtest_bw_compression_w_rgb(self):
""" This test passes, but when running all tests causes a failure due
@ -520,45 +496,45 @@ class TestFileLibTiff(LibTiffTestCase):
def test_multipage(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open("Tests/images/multipage.tiff")
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
with Image.open("Tests/images/multipage.tiff") as im:
# file is a multipage tiff, 10x10 green, 10x10 red, 20x20 blue
im.seek(0)
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
self.assertTrue(im.tag.next)
im.seek(0)
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
self.assertTrue(im.tag.next)
im.seek(1)
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
self.assertTrue(im.tag.next)
im.seek(1)
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
self.assertTrue(im.tag.next)
im.seek(2)
self.assertFalse(im.tag.next)
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
im.seek(2)
self.assertFalse(im.tag.next)
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
TiffImagePlugin.READ_LIBTIFF = False
def test_multipage_nframes(self):
# issue #862
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open("Tests/images/multipage.tiff")
frames = im.n_frames
self.assertEqual(frames, 3)
for _ in range(frames):
im.seek(0)
# Should not raise ValueError: I/O operation on closed file
im.load()
with Image.open("Tests/images/multipage.tiff") as im:
frames = im.n_frames
self.assertEqual(frames, 3)
for _ in range(frames):
im.seek(0)
# Should not raise ValueError: I/O operation on closed file
im.load()
TiffImagePlugin.READ_LIBTIFF = False
def test__next(self):
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open("Tests/images/hopper.tif")
self.assertFalse(im.tag.next)
im.load()
self.assertFalse(im.tag.next)
with Image.open("Tests/images/hopper.tif") as im:
self.assertFalse(im.tag.next)
im.load()
self.assertFalse(im.tag.next)
def test_4bit(self):
# Arrange
@ -567,13 +543,13 @@ class TestFileLibTiff(LibTiffTestCase):
# Act
TiffImagePlugin.READ_LIBTIFF = True
im = Image.open(test_file)
TiffImagePlugin.READ_LIBTIFF = False
with Image.open(test_file) as im:
TiffImagePlugin.READ_LIBTIFF = False
# Assert
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
# Assert
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self):
test_files = (
@ -598,15 +574,15 @@ class TestFileLibTiff(LibTiffTestCase):
)
original = hopper("L")
for epsilon, group in test_files:
im = Image.open(group[0])
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
with Image.open(group[0]) as im:
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
for file in group[1:]:
im2 = Image.open(file)
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
with Image.open(file) as im2:
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
def test_save_bytesio(self):
# PR 1011
@ -624,8 +600,8 @@ class TestFileLibTiff(LibTiffTestCase):
pilim.save(buffer_io, format="tiff", compression=compression)
buffer_io.seek(0)
pilim_load = Image.open(buffer_io)
self.assert_image_similar(pilim, pilim_load, 0)
with Image.open(buffer_io) as pilim_load:
self.assert_image_similar(pilim, pilim_load, 0)
save_bytesio()
save_bytesio("raw")
@ -637,12 +613,12 @@ class TestFileLibTiff(LibTiffTestCase):
def test_crashing_metadata(self):
# issue 1597
im = Image.open("Tests/images/rdf.tif")
out = self.tempfile("temp.tif")
with Image.open("Tests/images/rdf.tif") as im:
out = self.tempfile("temp.tif")
TiffImagePlugin.WRITE_LIBTIFF = True
# this shouldn't crash
im.save(out, format="TIFF")
TiffImagePlugin.WRITE_LIBTIFF = True
# this shouldn't crash
im.save(out, format="TIFF")
TiffImagePlugin.WRITE_LIBTIFF = False
def test_page_number_x_0(self):
@ -655,9 +631,9 @@ class TestFileLibTiff(LibTiffTestCase):
# /usr/bin/gs -q -sDEVICE=tiffg3 -sOutputFile=total-pages-zero.tif
# -dNOPAUSE /tmp/test.pdf -c quit
infile = "Tests/images/total-pages-zero.tif"
im = Image.open(infile)
# Should not divide by zero
im.save(outfile)
with Image.open(infile) as im:
# Should not divide by zero
im.save(outfile)
def test_fd_duplication(self):
# https://github.com/python-pillow/Pillow/issues/1651
@ -685,21 +661,21 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(icc, icc_libtiff)
def test_multipage_compression(self):
im = Image.open("Tests/images/compression.tif")
with Image.open("Tests/images/compression.tif") as im:
im.seek(0)
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.seek(0)
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.seek(1)
self.assertEqual(im._compression, "packbits")
self.assertEqual(im.size, (10, 10))
im.load()
im.seek(1)
self.assertEqual(im._compression, "packbits")
self.assertEqual(im.size, (10, 10))
im.load()
im.seek(0)
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.load()
im.seek(0)
self.assertEqual(im._compression, "tiff_ccitt")
self.assertEqual(im.size, (10, 10))
im.load()
def test_save_tiff_with_jpegtables(self):
# Arrange
@ -708,44 +684,50 @@ class TestFileLibTiff(LibTiffTestCase):
# Created with ImageMagick: convert hopper.jpg hopper_jpg.tif
# Contains JPEGTables (347) tag
infile = "Tests/images/hopper_jpg.tif"
im = Image.open(infile)
# Act / Assert
# Should not raise UnicodeDecodeError or anything else
im.save(outfile)
with Image.open(infile) as im:
# Act / Assert
# Should not raise UnicodeDecodeError or anything else
im.save(outfile)
def test_16bit_RGB_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGB.tiff")
with Image.open("Tests/images/tiff_16bit_RGB.tiff") as im:
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
[
(
"libtiff",
(0, 0, 100, 40),
0,
("RGB;16N", "tiff_adobe_deflate", False, 8),
)
],
)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
[
(
"libtiff",
(0, 0, 100, 40),
0,
("RGB;16N", "tiff_adobe_deflate", False, 8),
)
],
)
im.load()
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png")
def test_16bit_RGBa_tiff(self):
im = Image.open("Tests/images/tiff_16bit_RGBa.tiff")
with Image.open("Tests/images/tiff_16bit_RGBa.tiff") as im:
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
[
(
"libtiff",
(0, 0, 100, 40),
0,
("RGBa;16N", "tiff_lzw", False, 38236),
)
],
)
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (100, 40))
self.assertEqual(
im.tile,
[("libtiff", (0, 0, 100, 40), 0, ("RGBa;16N", "tiff_lzw", False, 38236))],
)
im.load()
self.assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png")
self.assert_image_equal_tofile(
im, "Tests/images/tiff_16bit_RGBa_target.png"
)
def test_gimp_tiff(self):
# Read TIFF JPEG images from GIMP [@PIL168]
@ -755,105 +737,99 @@ class TestFileLibTiff(LibTiffTestCase):
self.skipTest("jpeg support not available")
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
with Image.open(filename) as im:
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (256, 256))
self.assertEqual(
im.tile,
[("libtiff", (0, 0, 256, 256), 0, ("RGB", "jpeg", False, 5122))],
)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (256, 256))
self.assertEqual(
im.tile, [("libtiff", (0, 0, 256, 256), 0, ("RGB", "jpeg", False, 5122))]
)
im.load()
self.assert_image_equal_tofile(im, "Tests/images/pil168.png")
self.assert_image_equal_tofile(im, "Tests/images/pil168.png")
def test_sampleformat(self):
# https://github.com/python-pillow/Pillow/issues/1466
im = Image.open("Tests/images/copyleft.tiff")
self.assertEqual(im.mode, "RGB")
with Image.open("Tests/images/copyleft.tiff") as im:
self.assertEqual(im.mode, "RGB")
self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")
self.assert_image_equal_tofile(im, "Tests/images/copyleft.png", mode="RGB")
def test_lzw(self):
im = Image.open("Tests/images/hopper_lzw.tif")
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "TIFF")
im2 = hopper()
self.assert_image_similar(im, im2, 5)
with Image.open("Tests/images/hopper_lzw.tif") as im:
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "TIFF")
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)
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
with Image.open(infile) as im:
self.assert_image_similar_tofile(
im, "Tests/images/pil_sample_cmyk.jpg", 0.5
)
def test_strip_cmyk_16l_jpeg(self):
infile = "Tests/images/tiff_strip_cmyk_16l_jpeg.tif"
im = Image.open(infile)
self.assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
with Image.open(infile) as im:
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)
with Image.open(infile) as im:
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")
with Image.open(infile) as im:
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)
with Image.open(infile) as im:
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")
with Image.open(infile) as im:
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)
with Image.open(infile) as im:
self.assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
def test_old_style_jpeg(self):
infile = "Tests/images/old-style-jpeg-compression.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(
im, "Tests/images/old-style-jpeg-compression.png"
)
with Image.open(infile) as im:
self.assert_image_equal_tofile(
im, "Tests/images/old-style-jpeg-compression.png"
)
def test_no_rows_per_strip(self):
# This image does not have a RowsPerStrip TIFF tag
infile = "Tests/images/no_rows_per_strip.tif"
im = Image.open(infile)
im.load()
with Image.open(infile) as im:
im.load()
self.assertEqual(im.size, (950, 975))
def test_orientation(self):
base_im = Image.open("Tests/images/g4_orientation_1.tif")
with Image.open("Tests/images/g4_orientation_1.tif") as base_im:
for i in range(2, 9):
with Image.open("Tests/images/g4_orientation_" + str(i) + ".tif") as im:
im.load()
for i in range(2, 9):
im = Image.open("Tests/images/g4_orientation_" + str(i) + ".tif")
im.load()
self.assert_image_similar(base_im, im, 0.7)
self.assert_image_similar(base_im, im, 0.7)
def test_sampleformat_not_corrupted(self):
# Assert that a TIFF image with SampleFormat=UINT tag is not corrupted
# when saving to a new file.
# Pillow 6.0 fails with "OSError: cannot identify image file".
import base64
tiff = io.BytesIO(
base64.b64decode(
b"SUkqAAgAAAAPAP4ABAABAAAAAAAAAAABBAABAAAAAQAAAAEBBAABAAAAAQAA"

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .test_file_libtiff import LibTiffTestCase
@ -18,30 +20,25 @@ class TestFileLibTiffSmall(LibTiffTestCase):
test_file = "Tests/images/hopper_g4.tif"
with open(test_file, "rb") as f:
im = Image.open(f)
self.assertEqual(im.size, (128, 128))
self._assert_noerr(im)
with Image.open(f) as im:
self.assertEqual(im.size, (128, 128))
self._assert_noerr(im)
def test_g4_hopper_bytesio(self):
"""Testing the bytesio loading code path"""
from io import BytesIO
test_file = "Tests/images/hopper_g4.tif"
s = BytesIO()
with open(test_file, "rb") as f:
s.write(f.read())
s.seek(0)
im = Image.open(s)
self.assertEqual(im.size, (128, 128))
self._assert_noerr(im)
with Image.open(s) as im:
self.assertEqual(im.size, (128, 128))
self._assert_noerr(im)
def test_g4_hopper(self):
"""The 128x128 lena image failed for some reason."""
test_file = "Tests/images/hopper_g4.tif"
im = Image.open(test_file)
self.assertEqual(im.size, (128, 128))
self._assert_noerr(im)
with Image.open(test_file) as im:
self.assertEqual(im.size, (128, 128))
self._assert_noerr(im)

View File

@ -17,12 +17,12 @@ class TestFileMcIdas(PillowTestCase):
saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png"
# Act
im = Image.open(test_file)
im.load()
with Image.open(test_file) as im:
im.load()
# Assert
self.assertEqual(im.format, "MCIDAS")
self.assertEqual(im.mode, "I")
self.assertEqual(im.size, (1800, 400))
im2 = Image.open(saved_file)
self.assert_image_equal(im, im2)
# Assert
self.assertEqual(im.format, "MCIDAS")
self.assertEqual(im.mode, "I")
self.assertEqual(im.size, (1800, 400))
with Image.open(saved_file) as im2:
self.assert_image_equal(im, im2)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, ImagePalette, features
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
try:
from PIL import MicImagePlugin
@ -16,42 +18,42 @@ TEST_FILE = "Tests/images/hopper.mic"
@unittest.skipUnless(features.check("libtiff"), "libtiff not installed")
class TestFileMic(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "MIC")
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "MIC")
# Adjust for the gamma of 2.2 encoded into the file
lut = ImagePalette.make_gamma_lut(1 / 2.2)
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
# Adjust for the gamma of 2.2 encoded into the file
lut = ImagePalette.make_gamma_lut(1 / 2.2)
im = Image.merge("RGBA", [chan.point(lut) for chan in im.split()])
im2 = hopper("RGBA")
self.assert_image_similar(im, im2, 10)
im2 = hopper("RGBA")
self.assert_image_similar(im, im2, 10)
def test_n_frames(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.n_frames, 1)
self.assertEqual(im.n_frames, 1)
def test_is_animated(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertFalse(im.is_animated)
self.assertFalse(im.is_animated)
def test_tell(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.tell(), 0)
self.assertEqual(im.tell(), 0)
def test_seek(self):
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
im.seek(0)
self.assertEqual(im.tell(), 0)
im.seek(0)
self.assertEqual(im.tell(), 0)
self.assertRaises(EOFError, im.seek, 99)
self.assertEqual(im.tell(), 0)
self.assertRaises(EOFError, im.seek, 99)
self.assertEqual(im.tell(), 0)
def test_invalid_file(self):
# Test an invalid OLE file

View File

@ -1,8 +1,9 @@
import unittest
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
from .helper import PillowTestCase, is_pypy
test_files = ["Tests/images/sugarshack.mpo", "Tests/images/frozenpond.mpo"]
@ -25,78 +26,104 @@ class TestFileMpo(PillowTestCase):
def test_sanity(self):
for test_file in test_files:
im = Image.open(test_file)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (640, 480))
self.assertEqual(im.format, "MPO")
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (640, 480))
self.assertEqual(im.format, "MPO")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(test_files[0])
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(test_files[0])
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(test_files[0]) as im:
im.load()
self.assert_warning(None, open)
def test_app(self):
for test_file in test_files:
# Test APP/COM reader (@PIL135)
im = Image.open(test_file)
self.assertEqual(im.applist[0][0], "APP1")
self.assertEqual(im.applist[1][0], "APP2")
self.assertEqual(
im.applist[1][1][:16], b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00"
)
self.assertEqual(len(im.applist), 2)
with Image.open(test_file) as im:
self.assertEqual(im.applist[0][0], "APP1")
self.assertEqual(im.applist[1][0], "APP2")
self.assertEqual(
im.applist[1][1][:16],
b"MPF\x00MM\x00*\x00\x00\x00\x08\x00\x03\xb0\x00",
)
self.assertEqual(len(im.applist), 2)
def test_exif(self):
for test_file in test_files:
im = Image.open(test_file)
info = im._getexif()
self.assertEqual(info[272], "Nintendo 3DS")
self.assertEqual(info[296], 2)
self.assertEqual(info[34665], 188)
with Image.open(test_file) as im:
info = im._getexif()
self.assertEqual(info[272], "Nintendo 3DS")
self.assertEqual(info[296], 2)
self.assertEqual(info[34665], 188)
def test_frame_size(self):
# This image has been hexedited to contain a different size
# in the EXIF data of the second frame
im = Image.open("Tests/images/sugarshack_frame_size.mpo")
self.assertEqual(im.size, (640, 480))
with Image.open("Tests/images/sugarshack_frame_size.mpo") as im:
self.assertEqual(im.size, (640, 480))
im.seek(1)
self.assertEqual(im.size, (680, 480))
im.seek(1)
self.assertEqual(im.size, (680, 480))
def test_parallax(self):
# Nintendo
im = Image.open("Tests/images/sugarshack.mpo")
exif = im.getexif()
self.assertEqual(exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375)
with Image.open("Tests/images/sugarshack.mpo") as im:
exif = im.getexif()
self.assertEqual(
exif.get_ifd(0x927C)[0x1101]["Parallax"], -44.798187255859375
)
# Fujifilm
im = Image.open("Tests/images/fujifilm.mpo")
im.seek(1)
exif = im.getexif()
self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125)
with Image.open("Tests/images/fujifilm.mpo") as im:
im.seek(1)
exif = im.getexif()
self.assertEqual(exif.get_ifd(0x927C)[0xB211], -3.125)
def test_mp(self):
for test_file in test_files:
im = Image.open(test_file)
mpinfo = im._getmp()
self.assertEqual(mpinfo[45056], b"0100")
self.assertEqual(mpinfo[45057], 2)
with Image.open(test_file) as im:
mpinfo = im._getmp()
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)
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
mpinfo = im._getmp()
self.assertEqual(mpinfo[45056], b"0100")
self.assertEqual(mpinfo[45057], 2)
def test_mp_no_data(self):
# This image has been manually hexedited to have the second frame
# beyond the end of the file
with Image.open("Tests/images/sugarshack_no_data.mpo") as im:
with self.assertRaises(ValueError):
im.seek(1)
def test_mp_attribute(self):
for test_file in test_files:
im = Image.open(test_file)
mpinfo = im._getmp()
with Image.open(test_file) as im:
mpinfo = im._getmp()
frameNumber = 0
for mpentry in mpinfo[45058]:
mpattr = mpentry["Attribute"]
@ -113,62 +140,62 @@ class TestFileMpo(PillowTestCase):
def test_seek(self):
for test_file in test_files:
im = Image.open(test_file)
self.assertEqual(im.tell(), 0)
# prior to first image raises an error, both blatant and borderline
self.assertRaises(EOFError, im.seek, -1)
self.assertRaises(EOFError, im.seek, -523)
# after the final image raises an error,
# both blatant and borderline
self.assertRaises(EOFError, im.seek, 2)
self.assertRaises(EOFError, im.seek, 523)
# bad calls shouldn't change the frame
self.assertEqual(im.tell(), 0)
# this one will work
im.seek(1)
self.assertEqual(im.tell(), 1)
# and this one, too
im.seek(0)
self.assertEqual(im.tell(), 0)
with Image.open(test_file) as im:
self.assertEqual(im.tell(), 0)
# prior to first image raises an error, both blatant and borderline
self.assertRaises(EOFError, im.seek, -1)
self.assertRaises(EOFError, im.seek, -523)
# after the final image raises an error,
# both blatant and borderline
self.assertRaises(EOFError, im.seek, 2)
self.assertRaises(EOFError, im.seek, 523)
# bad calls shouldn't change the frame
self.assertEqual(im.tell(), 0)
# this one will work
im.seek(1)
self.assertEqual(im.tell(), 1)
# and this one, too
im.seek(0)
self.assertEqual(im.tell(), 0)
def test_n_frames(self):
im = Image.open("Tests/images/sugarshack.mpo")
self.assertEqual(im.n_frames, 2)
self.assertTrue(im.is_animated)
with Image.open("Tests/images/sugarshack.mpo") as im:
self.assertEqual(im.n_frames, 2)
self.assertTrue(im.is_animated)
def test_eoferror(self):
im = Image.open("Tests/images/sugarshack.mpo")
n_frames = im.n_frames
with Image.open("Tests/images/sugarshack.mpo") as im:
n_frames = im.n_frames
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_image_grab(self):
for test_file in test_files:
im = Image.open(test_file)
self.assertEqual(im.tell(), 0)
im0 = im.tobytes()
im.seek(1)
self.assertEqual(im.tell(), 1)
im1 = im.tobytes()
im.seek(0)
self.assertEqual(im.tell(), 0)
im02 = im.tobytes()
self.assertEqual(im0, im02)
self.assertNotEqual(im0, im1)
with Image.open(test_file) as im:
self.assertEqual(im.tell(), 0)
im0 = im.tobytes()
im.seek(1)
self.assertEqual(im.tell(), 1)
im1 = im.tobytes()
im.seek(0)
self.assertEqual(im.tell(), 0)
im02 = im.tobytes()
self.assertEqual(im0, im02)
self.assertNotEqual(im0, im1)
def test_save(self):
# Note that only individual frames can be saved at present
for test_file in test_files:
im = Image.open(test_file)
self.assertEqual(im.tell(), 0)
jpg0 = self.frame_roundtrip(im)
self.assert_image_similar(im, jpg0, 30)
im.seek(1)
self.assertEqual(im.tell(), 1)
jpg1 = self.frame_roundtrip(im)
self.assert_image_similar(im, jpg1, 30)
with Image.open(test_file) as im:
self.assertEqual(im.tell(), 0)
jpg0 = self.frame_roundtrip(im)
self.assert_image_similar(im, jpg0, 30)
im.seek(1)
self.assertEqual(im.tell(), 1)
jpg1 = self.frame_roundtrip(im)
self.assert_image_similar(im, jpg1, 30)

View File

@ -1,8 +1,9 @@
import os
import unittest
from PIL import Image, MspImagePlugin
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
TEST_FILE = "Tests/images/hopper.msp"
EXTRA_DIR = "Tests/images/picins"
@ -15,11 +16,11 @@ class TestFileMsp(PillowTestCase):
hopper("1").save(test_file)
im = Image.open(test_file)
im.load()
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "MSP")
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "MSP")
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -37,16 +38,16 @@ class TestFileMsp(PillowTestCase):
def test_open_windows_v1(self):
# Arrange
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assert_image_equal(im, hopper("1"))
self.assertIsInstance(im, MspImagePlugin.MspImageFile)
# Assert
self.assert_image_equal(im, hopper("1"))
self.assertIsInstance(im, MspImagePlugin.MspImageFile)
def _assert_file_image_equal(self, source_path, target_path):
with Image.open(source_path) as im:
target = Image.open(target_path)
self.assert_image_equal(im, target)
with Image.open(target_path) as target:
self.assert_image_equal(im, target)
@unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed")
def test_open_windows_v2(self):

View File

@ -5,8 +5,8 @@ from .helper import PillowTestCase
class TestFilePcd(PillowTestCase):
def test_load_raw(self):
im = Image.open("Tests/images/hopper.pcd")
im.load() # should not segfault.
with Image.open("Tests/images/hopper.pcd") as im:
im.load() # should not segfault.
# Note that this image was created with a resized hopper
# image, which was then converted to pcd with imagemagick

View File

@ -7,13 +7,12 @@ class TestFilePcx(PillowTestCase):
def _roundtrip(self, im):
f = self.tempfile("temp.pcx")
im.save(f)
im2 = Image.open(f)
self.assertEqual(im2.mode, im.mode)
self.assertEqual(im2.size, im.size)
self.assertEqual(im2.format, "PCX")
self.assertEqual(im2.get_format_mimetype(), "image/x-pcx")
self.assert_image_equal(im2, im)
with Image.open(f) as im2:
self.assertEqual(im2.mode, im.mode)
self.assertEqual(im2.size, im.size)
self.assertEqual(im2.format, "PCX")
self.assertEqual(im2.get_format_mimetype(), "image/x-pcx")
self.assert_image_equal(im2, im)
def test_sanity(self):
for mode in ("1", "L", "P", "RGB"):
@ -42,13 +41,12 @@ class TestFilePcx(PillowTestCase):
# Check reading of files where xmin/xmax is not zero.
test_file = "Tests/images/pil184.pcx"
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.size, (447, 144))
self.assertEqual(im.tile[0][1], (0, 0, 447, 144))
self.assertEqual(im.size, (447, 144))
self.assertEqual(im.tile[0][1], (0, 0, 447, 144))
# Make sure all pixels are either 0 or 255.
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447 * 144)
# Make sure all pixels are either 0 or 255.
self.assertEqual(im.histogram()[0] + im.histogram()[255], 447 * 144)
def test_1px_width(self):
im = Image.new("L", (1, 256))

View File

@ -82,44 +82,43 @@ class TestFilePdf(PillowTestCase):
self.helper_save_as_pdf("RGB", save_all=True)
# Multiframe image
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = self.tempfile("temp.pdf")
im.save(outfile, save_all=True)
outfile = self.tempfile("temp.pdf")
im.save(outfile, save_all=True)
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
# Append images
ims = [hopper()]
im.copy().save(outfile, save_all=True, append_images=ims)
# Append images
ims = [hopper()]
im.copy().save(outfile, save_all=True, append_images=ims)
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
# Test appending using a generator
def imGenerator(ims):
for im in ims:
yield im
# Test appending using a generator
def imGenerator(ims):
yield from ims
im.save(outfile, save_all=True, append_images=imGenerator(ims))
im.save(outfile, save_all=True, append_images=imGenerator(ims))
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
# Append JPEG images
jpeg = Image.open("Tests/images/flower.jpg")
jpeg.save(outfile, save_all=True, append_images=[jpeg.copy()])
with Image.open("Tests/images/flower.jpg") as jpeg:
jpeg.save(outfile, save_all=True, append_images=[jpeg.copy()])
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
def test_multiframe_normal_save(self):
# Test saving a multiframe image without save_all
im = Image.open("Tests/images/dispose_bgnd.gif")
with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = self.tempfile("temp.pdf")
im.save(outfile)
outfile = self.tempfile("temp.pdf")
im.save(outfile)
self.assertTrue(os.path.isfile(outfile))
self.assertGreater(os.path.getsize(outfile), 0)
@ -163,13 +162,10 @@ class TestFilePdf(PillowTestCase):
def test_pdf_append_fails_on_nonexistent_file(self):
im = hopper("RGB")
temp_dir = tempfile.mkdtemp()
try:
with tempfile.TemporaryDirectory() as temp_dir:
self.assertRaises(
IOError, im.save, os.path.join(temp_dir, "nonexistent.pdf"), append=True
)
finally:
os.rmdir(temp_dir)
def check_pdf_pages_consistency(self, pdf):
pages_info = pdf.read_indirect(pdf.pages_ref)
@ -207,7 +203,7 @@ class TestFilePdf(PillowTestCase):
# append some info
pdf.info.Title = "abc"
pdf.info.Author = "def"
pdf.info.Subject = u"ghi\uABCD"
pdf.info.Subject = "ghi\uABCD"
pdf.info.Keywords = "qw)e\\r(ty"
pdf.info.Creator = "hopper()"
pdf.start_writing()
@ -235,7 +231,7 @@ class TestFilePdf(PillowTestCase):
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.assertEqual(pdf.info.Subject, "ghi\uABCD")
self.assertIn(b"CreationDate", pdf.info)
self.assertIn(b"ModDate", pdf.info)
self.check_pdf_pages_consistency(pdf)

View File

@ -7,15 +7,15 @@ TEST_FILE = "Tests/images/hopper.pxr"
class TestFilePixar(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PIXAR")
self.assertIsNone(im.get_format_mimetype())
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PIXAR")
self.assertIsNone(im.get_format_mimetype())
im2 = hopper()
self.assert_image_similar(im, im2, 4.8)
im2 = hopper()
self.assert_image_similar(im, im2, 4.8)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"

View File

@ -1,11 +1,10 @@
import sys
import unittest
import zlib
from io import BytesIO
from PIL import Image, ImageFile, PngImagePlugin
from PIL._util import py3
from .helper import PillowLeakTestCase, PillowTestCase, hopper, unittest
from .helper import PillowLeakTestCase, PillowTestCase, hopper, is_win32
try:
from PIL import _webp
@ -82,20 +81,20 @@ class TestFilePng(PillowTestCase):
hopper("RGB").save(test_file)
im = Image.open(test_file)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PNG")
self.assertEqual(im.get_format_mimetype(), "image/png")
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PNG")
self.assertEqual(im.get_format_mimetype(), "image/png")
for mode in ["1", "L", "P", "RGB", "I", "I;16"]:
im = hopper(mode)
im.save(test_file)
reloaded = Image.open(test_file)
if mode == "I;16":
reloaded = reloaded.convert(mode)
self.assert_image_equal(reloaded, im)
with Image.open(test_file) as reloaded:
if mode == "I;16":
reloaded = reloaded.convert(mode)
self.assert_image_equal(reloaded, im)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -196,27 +195,24 @@ class TestFilePng(PillowTestCase):
def test_interlace(self):
test_file = "Tests/images/pil123p.png"
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assert_image(im, "P", (162, 150))
self.assertTrue(im.info.get("interlace"))
self.assert_image(im, "P", (162, 150))
self.assertTrue(im.info.get("interlace"))
im.load()
im.load()
test_file = "Tests/images/pil123rgba.png"
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assert_image(im, "RGBA", (162, 150))
self.assertTrue(im.info.get("interlace"))
self.assert_image(im, "RGBA", (162, 150))
self.assertTrue(im.info.get("interlace"))
im.load()
im.load()
def test_load_transparent_p(self):
test_file = "Tests/images/pil123p.png"
im = Image.open(test_file)
self.assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
with Image.open(test_file) as im:
self.assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (162, 150))
# image has 124 unique alpha values
@ -224,11 +220,11 @@ class TestFilePng(PillowTestCase):
def test_load_transparent_rgb(self):
test_file = "Tests/images/rgb_trns.png"
im = Image.open(test_file)
self.assertEqual(im.info["transparency"], (0, 255, 52))
with Image.open(test_file) as im:
self.assertEqual(im.info["transparency"], (0, 255, 52))
self.assert_image(im, "RGB", (64, 64))
im = im.convert("RGBA")
self.assert_image(im, "RGB", (64, 64))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (64, 64))
# image has 876 transparent pixels
@ -236,21 +232,20 @@ class TestFilePng(PillowTestCase):
def test_save_p_transparent_palette(self):
in_file = "Tests/images/pil123p.png"
im = Image.open(in_file)
with Image.open(in_file) as im:
# 'transparency' contains a byte string with the opacity for
# each palette entry
self.assertEqual(len(im.info["transparency"]), 256)
# 'transparency' contains a byte string with the opacity for
# each palette entry
self.assertEqual(len(im.info["transparency"]), 256)
test_file = self.tempfile("temp.png")
im.save(test_file)
test_file = self.tempfile("temp.png")
im.save(test_file)
# check if saved image contains same transparency
im = Image.open(test_file)
self.assertEqual(len(im.info["transparency"]), 256)
with Image.open(test_file) as im:
self.assertEqual(len(im.info["transparency"]), 256)
self.assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
self.assert_image(im, "P", (162, 150))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (162, 150))
# image has 124 unique alpha values
@ -258,21 +253,20 @@ class TestFilePng(PillowTestCase):
def test_save_p_single_transparency(self):
in_file = "Tests/images/p_trns_single.png"
im = Image.open(in_file)
with Image.open(in_file) as im:
# pixel value 164 is full transparent
self.assertEqual(im.info["transparency"], 164)
self.assertEqual(im.getpixel((31, 31)), 164)
# pixel value 164 is full transparent
self.assertEqual(im.info["transparency"], 164)
self.assertEqual(im.getpixel((31, 31)), 164)
test_file = self.tempfile("temp.png")
im.save(test_file)
test_file = self.tempfile("temp.png")
im.save(test_file)
# check if saved image contains same transparency
im = Image.open(test_file)
self.assertEqual(im.info["transparency"], 164)
self.assertEqual(im.getpixel((31, 31)), 164)
self.assert_image(im, "P", (64, 64))
im = im.convert("RGBA")
with Image.open(test_file) as im:
self.assertEqual(im.info["transparency"], 164)
self.assertEqual(im.getpixel((31, 31)), 164)
self.assert_image(im, "P", (64, 64))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (64, 64))
self.assertEqual(im.getpixel((31, 31)), (0, 255, 52, 0))
@ -291,30 +285,30 @@ class TestFilePng(PillowTestCase):
im.save(test_file)
# check if saved image contains same transparency
im = Image.open(test_file)
self.assertEqual(len(im.info["transparency"]), 256)
self.assert_image(im, "P", (10, 10))
im = im.convert("RGBA")
with Image.open(test_file) as im:
self.assertEqual(len(im.info["transparency"]), 256)
self.assert_image(im, "P", (10, 10))
im = im.convert("RGBA")
self.assert_image(im, "RGBA", (10, 10))
self.assertEqual(im.getcolors(), [(100, (0, 0, 0, 0))])
def test_save_greyscale_transparency(self):
for mode, num_transparent in {"1": 1994, "L": 559, "I": 559}.items():
in_file = "Tests/images/" + mode.lower() + "_trns.png"
im = Image.open(in_file)
self.assertEqual(im.mode, mode)
self.assertEqual(im.info["transparency"], 255)
with Image.open(in_file) as im:
self.assertEqual(im.mode, mode)
self.assertEqual(im.info["transparency"], 255)
im_rgba = im.convert("RGBA")
im_rgba = im.convert("RGBA")
self.assertEqual(im_rgba.getchannel("A").getcolors()[0][0], num_transparent)
test_file = self.tempfile("temp.png")
im.save(test_file)
test_im = Image.open(test_file)
self.assertEqual(test_im.mode, mode)
self.assertEqual(test_im.info["transparency"], 255)
self.assert_image_equal(im, test_im)
with Image.open(test_file) as test_im:
self.assertEqual(test_im.mode, mode)
self.assertEqual(test_im.info["transparency"], 255)
self.assert_image_equal(im, test_im)
test_im_rgba = test_im.convert("RGBA")
self.assertEqual(
@ -323,22 +317,20 @@ class TestFilePng(PillowTestCase):
def test_save_rgb_single_transparency(self):
in_file = "Tests/images/caption_6_33_22.png"
im = Image.open(in_file)
test_file = self.tempfile("temp.png")
im.save(test_file)
with Image.open(in_file) as im:
test_file = self.tempfile("temp.png")
im.save(test_file)
def test_load_verify(self):
# Check open/load/verify exception (@PIL150)
im = Image.open(TEST_PNG_FILE)
with Image.open(TEST_PNG_FILE) as im:
# Assert that there is no unclosed file warning
self.assert_warning(None, im.verify)
# Assert that there is no unclosed file warning
self.assert_warning(None, im.verify)
im = Image.open(TEST_PNG_FILE)
im.load()
self.assertRaises(RuntimeError, im.verify)
with Image.open(TEST_PNG_FILE) as im:
im.load()
self.assertRaises(RuntimeError, im.verify)
def test_verify_struct_error(self):
# Check open/load/verify exception (#1755)
@ -351,9 +343,9 @@ class TestFilePng(PillowTestCase):
with open(TEST_PNG_FILE, "rb") as f:
test_file = f.read()[:offset]
im = Image.open(BytesIO(test_file))
self.assertIsNotNone(im.fp)
self.assertRaises((IOError, SyntaxError), im.verify)
with Image.open(BytesIO(test_file)) as im:
self.assertIsNotNone(im.fp)
self.assertRaises((IOError, SyntaxError), im.verify)
def test_verify_ignores_crc_error(self):
# check ignores crc errors in ancillary chunks
@ -387,24 +379,22 @@ class TestFilePng(PillowTestCase):
def test_roundtrip_dpi(self):
# Check dpi roundtripping
im = Image.open(TEST_PNG_FILE)
im = roundtrip(im, dpi=(100, 100))
with Image.open(TEST_PNG_FILE) as im:
im = roundtrip(im, dpi=(100, 100))
self.assertEqual(im.info["dpi"], (100, 100))
def test_load_dpi_rounding(self):
# Round up
im = Image.open(TEST_PNG_FILE)
self.assertEqual(im.info["dpi"], (96, 96))
with Image.open(TEST_PNG_FILE) as im:
self.assertEqual(im.info["dpi"], (96, 96))
# Round down
im = Image.open("Tests/images/icc_profile_none.png")
self.assertEqual(im.info["dpi"], (72, 72))
with Image.open("Tests/images/icc_profile_none.png") as im:
self.assertEqual(im.info["dpi"], (72, 72))
def test_save_dpi_rounding(self):
im = Image.open(TEST_PNG_FILE)
im = roundtrip(im, dpi=(72.2, 72.2))
with Image.open(TEST_PNG_FILE) as im:
im = roundtrip(im, dpi=(72.2, 72.2))
self.assertEqual(im.info["dpi"], (72, 72))
im = roundtrip(im, dpi=(72.8, 72.8))
@ -413,13 +403,12 @@ class TestFilePng(PillowTestCase):
def test_roundtrip_text(self):
# Check text roundtripping
im = Image.open(TEST_PNG_FILE)
with Image.open(TEST_PNG_FILE) as im:
info = PngImagePlugin.PngInfo()
info.add_text("TXT", "VALUE")
info.add_text("ZIP", "VALUE", zip=True)
info = PngImagePlugin.PngInfo()
info.add_text("TXT", "VALUE")
info.add_text("ZIP", "VALUE", zip=True)
im = roundtrip(im, pnginfo=info)
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"TXT": "VALUE", "ZIP": "VALUE"})
self.assertEqual(im.text, {"TXT": "VALUE", "ZIP": "VALUE"})
@ -449,9 +438,7 @@ class TestFilePng(PillowTestCase):
self.assertIsInstance(im.info["Text"], str)
def test_unicode_text(self):
# Check preservation of non-ASCII characters on Python 3
# This cannot really be meaningfully tested on Python 2,
# since it didn't preserve charsets to begin with.
# Check preservation of non-ASCII characters
def rt_text(value):
im = Image.new("RGB", (32, 32))
@ -460,12 +447,11 @@ class TestFilePng(PillowTestCase):
im = roundtrip(im, pnginfo=info)
self.assertEqual(im.info, {"Text": value})
if py3:
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
# CJK:
rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
rt_text(" Aa" + chr(0xA0) + chr(0xC4) + chr(0xFF)) # Latin1
rt_text(chr(0x400) + chr(0x472) + chr(0x4FF)) # Cyrillic
# CJK:
rt_text(chr(0x4E00) + chr(0x66F0) + chr(0x9FBA) + chr(0x3042) + chr(0xAC00))
rt_text("A" + chr(0xC4) + chr(0x472) + chr(0x3042)) # Combined
def test_scary(self):
# Check reading of evil PNG file. For information, see:
@ -484,11 +470,11 @@ class TestFilePng(PillowTestCase):
# Independent file sample provided by Sebastian Spaeth.
test_file = "Tests/images/caption_6_33_22.png"
im = Image.open(test_file)
self.assertEqual(im.info["transparency"], (248, 248, 248))
with Image.open(test_file) as im:
self.assertEqual(im.info["transparency"], (248, 248, 248))
# check saving transparency by default
im = roundtrip(im)
# check saving transparency by default
im = roundtrip(im)
self.assertEqual(im.info["transparency"], (248, 248, 248))
im = roundtrip(im, transparency=(0, 1, 2))
@ -502,59 +488,58 @@ class TestFilePng(PillowTestCase):
f = self.tempfile("temp.png")
im.save(f)
im2 = Image.open(f)
self.assertIn("transparency", im2.info)
with Image.open(f) as im2:
self.assertIn("transparency", im2.info)
self.assert_image_equal(im2.convert("RGBA"), im.convert("RGBA"))
self.assert_image_equal(im2.convert("RGBA"), im.convert("RGBA"))
def test_trns_null(self):
# Check reading images with null tRNS value, issue #1239
test_file = "Tests/images/tRNS_null_1x1.png"
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertEqual(im.info["transparency"], 0)
self.assertEqual(im.info["transparency"], 0)
def test_save_icc_profile(self):
im = Image.open("Tests/images/icc_profile_none.png")
self.assertIsNone(im.info["icc_profile"])
with Image.open("Tests/images/icc_profile_none.png") as im:
self.assertIsNone(im.info["icc_profile"])
with_icc = Image.open("Tests/images/icc_profile.png")
expected_icc = with_icc.info["icc_profile"]
with Image.open("Tests/images/icc_profile.png") as with_icc:
expected_icc = with_icc.info["icc_profile"]
im = roundtrip(im, icc_profile=expected_icc)
self.assertEqual(im.info["icc_profile"], expected_icc)
im = roundtrip(im, icc_profile=expected_icc)
self.assertEqual(im.info["icc_profile"], expected_icc)
def test_discard_icc_profile(self):
im = Image.open("Tests/images/icc_profile.png")
im = roundtrip(im, icc_profile=None)
with Image.open("Tests/images/icc_profile.png") as im:
im = roundtrip(im, icc_profile=None)
self.assertNotIn("icc_profile", im.info)
def test_roundtrip_icc_profile(self):
im = Image.open("Tests/images/icc_profile.png")
expected_icc = im.info["icc_profile"]
with Image.open("Tests/images/icc_profile.png") as im:
expected_icc = im.info["icc_profile"]
im = roundtrip(im)
im = roundtrip(im)
self.assertEqual(im.info["icc_profile"], expected_icc)
def test_roundtrip_no_icc_profile(self):
im = Image.open("Tests/images/icc_profile_none.png")
self.assertIsNone(im.info["icc_profile"])
with Image.open("Tests/images/icc_profile_none.png") as im:
self.assertIsNone(im.info["icc_profile"])
im = roundtrip(im)
im = roundtrip(im)
self.assertNotIn("icc_profile", im.info)
def test_repr_png(self):
im = hopper()
repr_png = Image.open(BytesIO(im._repr_png_()))
self.assertEqual(repr_png.format, "PNG")
self.assert_image_equal(im, repr_png)
with Image.open(BytesIO(im._repr_png_())) as repr_png:
self.assertEqual(repr_png.format, "PNG")
self.assert_image_equal(im, repr_png)
def test_chunk_order(self):
im = Image.open("Tests/images/icc_profile.png")
test_file = self.tempfile("temp.png")
im.convert("P").save(test_file, dpi=(100, 100))
with Image.open("Tests/images/icc_profile.png") as im:
test_file = self.tempfile("temp.png")
im.convert("P").save(test_file, dpi=(100, 100))
chunks = self.get_chunks(test_file)
@ -579,78 +564,75 @@ class TestFilePng(PillowTestCase):
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)
with Image.open("Tests/images/hopper.png") as im:
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)
with Image.open("Tests/images/broken_data_stream.png") as im:
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
with Image.open("Tests/images/truncated_image.png") as im:
# 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"})
with Image.open("Tests/images/hopper_idat_after_image_end.png") as im:
self.assertEqual(im.text, {"TXT": "VALUE", "ZIP": "VALUE"})
def test_exif(self):
im = Image.open("Tests/images/exif.png")
exif = im._getexif()
with Image.open("Tests/images/exif.png") as im:
exif = im._getexif()
self.assertEqual(exif[274], 1)
def test_exif_save(self):
im = Image.open("Tests/images/exif.png")
with Image.open("Tests/images/exif.png") as im:
test_file = self.tempfile("temp.png")
im.save(test_file)
test_file = self.tempfile("temp.png")
im.save(test_file)
reloaded = Image.open(test_file)
exif = reloaded._getexif()
with Image.open(test_file) as reloaded:
exif = reloaded._getexif()
self.assertEqual(exif[274], 1)
def test_exif_from_jpg(self):
im = Image.open("Tests/images/pil_sample_rgb.jpg")
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
test_file = self.tempfile("temp.png")
im.save(test_file)
test_file = self.tempfile("temp.png")
im.save(test_file)
reloaded = Image.open(test_file)
exif = reloaded._getexif()
with Image.open(test_file) as reloaded:
exif = reloaded._getexif()
self.assertEqual(exif[305], "Adobe Photoshop CS Macintosh")
def test_exif_argument(self):
im = Image.open(TEST_PNG_FILE)
with Image.open(TEST_PNG_FILE) as im:
test_file = self.tempfile("temp.png")
im.save(test_file, exif=b"exifstring")
test_file = self.tempfile("temp.png")
im.save(test_file, exif=b"exifstring")
reloaded = Image.open(test_file)
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
with Image.open(test_file) as reloaded:
self.assertEqual(reloaded.info["exif"], b"Exif\x00\x00exifstring")
@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")
with Image.open("Tests/images/iss634.apng") as im:
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)
# This also tests reading unknown PNG chunks (fcTL and fdAT) in load_end
with Image.open("Tests/images/iss634.webp") as expected:
self.assert_image_similar(im, expected, 0.23)
@unittest.skipIf(sys.platform.startswith("win32"), "requires Unix or macOS")
@unittest.skipIf(is_win32(), "requires Unix or macOS")
class TestTruncatedPngPLeaks(PillowLeakTestCase):
mem_limit = 2 * 1024 # max increase in K
iterations = 100 # Leak is 56k/iteration, this will leak 5.6megs

View File

@ -8,42 +8,42 @@ test_file = "Tests/images/hopper.ppm"
class TestFilePpm(PillowTestCase):
def test_sanity(self):
im = Image.open(test_file)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PPM")
self.assertEqual(im.get_format_mimetype(), "image/x-portable-pixmap")
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PPM")
self.assertEqual(im.get_format_mimetype(), "image/x-portable-pixmap")
def test_16bit_pgm(self):
im = Image.open("Tests/images/16_bit_binary.pgm")
im.load()
self.assertEqual(im.mode, "I")
self.assertEqual(im.size, (20, 100))
self.assertEqual(im.get_format_mimetype(), "image/x-portable-graymap")
with Image.open("Tests/images/16_bit_binary.pgm") as im:
im.load()
self.assertEqual(im.mode, "I")
self.assertEqual(im.size, (20, 100))
self.assertEqual(im.get_format_mimetype(), "image/x-portable-graymap")
tgt = Image.open("Tests/images/16_bit_binary_pgm.png")
self.assert_image_equal(im, tgt)
with Image.open("Tests/images/16_bit_binary_pgm.png") as tgt:
self.assert_image_equal(im, tgt)
def test_16bit_pgm_write(self):
im = Image.open("Tests/images/16_bit_binary.pgm")
im.load()
with Image.open("Tests/images/16_bit_binary.pgm") as im:
im.load()
f = self.tempfile("temp.pgm")
im.save(f, "PPM")
f = self.tempfile("temp.pgm")
im.save(f, "PPM")
reloaded = Image.open(f)
self.assert_image_equal(im, reloaded)
with Image.open(f) as reloaded:
self.assert_image_equal(im, reloaded)
def test_pnm(self):
im = Image.open("Tests/images/hopper.pnm")
self.assert_image_similar(im, hopper(), 0.0001)
with Image.open("Tests/images/hopper.pnm") as im:
self.assert_image_similar(im, hopper(), 0.0001)
f = self.tempfile("temp.pnm")
im.save(f)
f = self.tempfile("temp.pnm")
im.save(f)
reloaded = Image.open(f)
self.assert_image_equal(im, reloaded)
with Image.open(f) as reloaded:
self.assert_image_equal(im, reloaded)
def test_truncated_file(self):
path = self.tempfile("temp.pgm")
@ -66,10 +66,10 @@ class TestFilePpm(PillowTestCase):
with open(path, "w") as f:
f.write("P4\n128 128\n255")
im = Image.open(path)
self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap")
with Image.open(path) as im:
self.assertEqual(im.get_format_mimetype(), "image/x-portable-bitmap")
with open(path, "w") as f:
f.write("PyCMYK\n128 128\n255")
im = Image.open(path)
self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap")
with Image.open(path) as im:
self.assertEqual(im.get_format_mimetype(), "image/x-portable-anymap")

View File

@ -1,26 +1,44 @@
import unittest
from PIL import Image, PsdImagePlugin
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
test_file = "Tests/images/hopper.psd"
class TestImagePsd(PillowTestCase):
def test_sanity(self):
im = Image.open(test_file)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PSD")
with Image.open(test_file) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "PSD")
im2 = hopper()
self.assert_image_similar(im, im2, 4.8)
im2 = hopper()
self.assert_image_similar(im, im2, 4.8)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(test_file)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(test_file)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(test_file) as im:
im.load()
self.assert_warning(None, open)
def test_invalid_file(self):
@ -29,64 +47,63 @@ class TestImagePsd(PillowTestCase):
self.assertRaises(SyntaxError, PsdImagePlugin.PsdImageFile, invalid_file)
def test_n_frames(self):
im = Image.open("Tests/images/hopper_merged.psd")
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
with Image.open("Tests/images/hopper_merged.psd") as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
im = Image.open(test_file)
self.assertEqual(im.n_frames, 2)
self.assertTrue(im.is_animated)
with Image.open(test_file) as im:
self.assertEqual(im.n_frames, 2)
self.assertTrue(im.is_animated)
def test_eoferror(self):
im = Image.open(test_file)
# PSD seek index starts at 1 rather than 0
n_frames = im.n_frames + 1
with Image.open(test_file) as im:
# PSD seek index starts at 1 rather than 0
n_frames = im.n_frames + 1
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_seek_tell(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
layer_number = im.tell()
self.assertEqual(layer_number, 1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
self.assertRaises(EOFError, im.seek, 0)
self.assertRaises(EOFError, im.seek, 0)
im.seek(1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
im.seek(1)
layer_number = im.tell()
self.assertEqual(layer_number, 1)
im.seek(2)
layer_number = im.tell()
self.assertEqual(layer_number, 2)
im.seek(2)
layer_number = im.tell()
self.assertEqual(layer_number, 2)
def test_seek_eoferror(self):
im = Image.open(test_file)
with Image.open(test_file) as im:
self.assertRaises(EOFError, im.seek, -1)
self.assertRaises(EOFError, im.seek, -1)
def test_open_after_exclusive_load(self):
im = Image.open(test_file)
im.load()
im.seek(im.tell() + 1)
im.load()
with Image.open(test_file) as im:
im.load()
im.seek(im.tell() + 1)
im.load()
def test_icc_profile(self):
im = Image.open(test_file)
self.assertIn("icc_profile", im.info)
with Image.open(test_file) as im:
self.assertIn("icc_profile", im.info)
icc_profile = im.info["icc_profile"]
self.assertEqual(len(icc_profile), 3144)
icc_profile = im.info["icc_profile"]
self.assertEqual(len(icc_profile), 3144)
def test_no_icc_profile(self):
im = Image.open("Tests/images/hopper_merged.psd")
self.assertNotIn("icc_profile", im.info)
with Image.open("Tests/images/hopper_merged.psd") as im:
self.assertNotIn("icc_profile", im.info)
def test_combined_larger_than_size(self):
# The 'combined' sizes of the individual parts is larger than the

View File

@ -9,50 +9,50 @@ class TestFileSgi(PillowTestCase):
# convert hopper.ppm -compress None sgi:hopper.rgb
test_file = "Tests/images/hopper.rgb"
im = Image.open(test_file)
self.assert_image_equal(im, hopper())
self.assertEqual(im.get_format_mimetype(), "image/rgb")
with Image.open(test_file) as im:
self.assert_image_equal(im, hopper())
self.assertEqual(im.get_format_mimetype(), "image/rgb")
def test_rgb16(self):
test_file = "Tests/images/hopper16.rgb"
im = Image.open(test_file)
self.assert_image_equal(im, hopper())
with Image.open(test_file) as im:
self.assert_image_equal(im, hopper())
def test_l(self):
# Created with ImageMagick
# convert hopper.ppm -monochrome -compress None sgi:hopper.bw
test_file = "Tests/images/hopper.bw"
im = Image.open(test_file)
self.assert_image_similar(im, hopper("L"), 2)
self.assertEqual(im.get_format_mimetype(), "image/sgi")
with Image.open(test_file) as im:
self.assert_image_similar(im, hopper("L"), 2)
self.assertEqual(im.get_format_mimetype(), "image/sgi")
def test_rgba(self):
# Created with ImageMagick:
# convert transparent.png -compress None transparent.sgi
test_file = "Tests/images/transparent.sgi"
im = Image.open(test_file)
target = Image.open("Tests/images/transparent.png")
self.assert_image_equal(im, target)
self.assertEqual(im.get_format_mimetype(), "image/sgi")
with Image.open(test_file) as im:
with Image.open("Tests/images/transparent.png") as target:
self.assert_image_equal(im, target)
self.assertEqual(im.get_format_mimetype(), "image/sgi")
def test_rle(self):
# Created with ImageMagick:
# convert hopper.ppm hopper.sgi
test_file = "Tests/images/hopper.sgi"
im = Image.open(test_file)
target = Image.open("Tests/images/hopper.rgb")
self.assert_image_equal(im, target)
with Image.open(test_file) as im:
with Image.open("Tests/images/hopper.rgb") as target:
self.assert_image_equal(im, target)
def test_rle16(self):
test_file = "Tests/images/tv16.sgi"
im = Image.open(test_file)
target = Image.open("Tests/images/tv.rgb")
self.assert_image_equal(im, target)
with Image.open(test_file) as im:
with Image.open("Tests/images/tv.rgb") as target:
self.assert_image_equal(im, target)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -63,8 +63,8 @@ class TestFileSgi(PillowTestCase):
def roundtrip(img):
out = self.tempfile("temp.sgi")
img.save(out, format="sgi")
reloaded = Image.open(out)
self.assert_image_equal(img, reloaded)
with Image.open(out) as reloaded:
self.assert_image_equal(img, reloaded)
for mode in ("L", "RGB", "RGBA"):
roundtrip(hopper(mode))
@ -75,12 +75,12 @@ class TestFileSgi(PillowTestCase):
def test_write16(self):
test_file = "Tests/images/hopper16.rgb"
im = Image.open(test_file)
out = self.tempfile("temp.sgi")
im.save(out, format="sgi", bpc=2)
with Image.open(test_file) as im:
out = self.tempfile("temp.sgi")
im.save(out, format="sgi", bpc=2)
reloaded = Image.open(out)
self.assert_image_equal(im, reloaded)
with Image.open(out) as reloaded:
self.assert_image_equal(im, reloaded)
def test_unsupported_mode(self):
im = hopper("LA")

View File

@ -1,26 +1,43 @@
import tempfile
import unittest
from io import BytesIO
from PIL import Image, ImageSequence, SpiderImagePlugin
from .helper import PillowTestCase, hopper
from .helper import PillowTestCase, hopper, is_pypy
TEST_FILE = "Tests/images/hopper.spider"
class TestImageSpider(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "SPIDER")
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "F")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "SPIDER")
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open(TEST_FILE)
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open(TEST_FILE) as im:
im.load()
self.assert_warning(None, open)
def test_save(self):
@ -32,10 +49,10 @@ class TestImageSpider(PillowTestCase):
im.save(temp, "SPIDER")
# Assert
im2 = Image.open(temp)
self.assertEqual(im2.mode, "F")
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.format, "SPIDER")
with Image.open(temp) as im2:
self.assertEqual(im2.mode, "F")
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.format, "SPIDER")
def test_tempfile(self):
# Arrange
@ -47,28 +64,28 @@ class TestImageSpider(PillowTestCase):
# Assert
fp.seek(0)
reloaded = Image.open(fp)
self.assertEqual(reloaded.mode, "F")
self.assertEqual(reloaded.size, (128, 128))
self.assertEqual(reloaded.format, "SPIDER")
with Image.open(fp) as reloaded:
self.assertEqual(reloaded.mode, "F")
self.assertEqual(reloaded.size, (128, 128))
self.assertEqual(reloaded.format, "SPIDER")
def test_isSpiderImage(self):
self.assertTrue(SpiderImagePlugin.isSpiderImage(TEST_FILE))
def test_tell(self):
# Arrange
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Act
index = im.tell()
# Act
index = im.tell()
# Assert
self.assertEqual(index, 0)
# Assert
self.assertEqual(index, 0)
def test_n_frames(self):
im = Image.open(TEST_FILE)
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
with Image.open(TEST_FILE) as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
def test_loadImageSeries(self):
# Arrange
@ -109,15 +126,14 @@ class TestImageSpider(PillowTestCase):
self.assertRaises(IOError, Image.open, invalid_file)
def test_nonstack_file(self):
im = Image.open(TEST_FILE)
self.assertRaises(EOFError, im.seek, 0)
with Image.open(TEST_FILE) as im:
self.assertRaises(EOFError, im.seek, 0)
def test_nonstack_dos(self):
im = Image.open(TEST_FILE)
for i, frame in enumerate(ImageSequence.Iterator(im)):
if i > 1:
self.fail("Non-stack DOS file test failed")
with Image.open(TEST_FILE) as im:
for i, frame in enumerate(ImageSequence.Iterator(im)):
if i > 1:
self.fail("Non-stack DOS file test failed")
# for issue #4093
def test_odd_size(self):
@ -127,5 +143,5 @@ class TestImageSpider(PillowTestCase):
im.save(data, format="SPIDER")
data.seek(0)
im2 = Image.open(data)
self.assert_image_equal(im, im2)
with Image.open(data) as im2:
self.assert_image_equal(im, im2)

View File

@ -1,8 +1,9 @@
import os
import unittest
from PIL import Image, SunImagePlugin
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
EXTRA_DIR = "Tests/images/sunraster"
@ -14,20 +15,20 @@ class TestFileSun(PillowTestCase):
test_file = "Tests/images/hopper.ras"
# Act
im = Image.open(test_file)
with Image.open(test_file) as im:
# Assert
self.assertEqual(im.size, (128, 128))
# Assert
self.assertEqual(im.size, (128, 128))
self.assert_image_similar(im, hopper(), 5) # visually verified
self.assert_image_similar(im, hopper(), 5) # visually verified
invalid_file = "Tests/images/flower.jpg"
self.assertRaises(SyntaxError, SunImagePlugin.SunImageFile, invalid_file)
def test_im1(self):
im = Image.open("Tests/images/sunraster.im1")
target = Image.open("Tests/images/sunraster.im1.png")
self.assert_image_equal(im, target)
with Image.open("Tests/images/sunraster.im1") as im:
with Image.open("Tests/images/sunraster.im1.png") as target:
self.assert_image_equal(im, target)
@unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed")
def test_others(self):

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, TarIO
from .helper import PillowTestCase
from .helper import PillowTestCase, is_pypy
codecs = dir(Image.core)
@ -19,17 +21,30 @@ class TestFileTar(PillowTestCase):
["jpeg_decoder", "hopper.jpg", "JPEG"],
]:
if codec in codecs:
tar = TarIO.TarIO(TEST_TAR_FILE, test_path)
im = Image.open(tar)
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, format)
with TarIO.TarIO(TEST_TAR_FILE, test_path) as tar:
with Image.open(tar) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, format)
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
self.assert_warning(ResourceWarning, open)
def test_close(self):
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
tar.close()
def open():
tar = TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
tar.close()
self.assert_warning(None, open)
def test_contextmanager(self):
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
pass
def open():
with TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg"):
pass
self.assert_warning(None, open)

View File

@ -24,177 +24,179 @@ class TestFileTga(PillowTestCase):
)
for png_path in png_paths:
reference_im = Image.open(png_path)
self.assertEqual(reference_im.mode, mode)
with Image.open(png_path) as reference_im:
self.assertEqual(reference_im.mode, mode)
path_no_ext = os.path.splitext(png_path)[0]
for origin, rle in product(self._ORIGINS, (True, False)):
tga_path = "{}_{}_{}.tga".format(
path_no_ext, origin, "rle" if rle else "raw"
)
original_im = Image.open(tga_path)
self.assertEqual(original_im.format, "TGA")
self.assertEqual(original_im.get_format_mimetype(), "image/x-tga")
if rle:
self.assertEqual(original_im.info["compression"], "tga_rle")
self.assertEqual(
original_im.info["orientation"],
self._ORIGIN_TO_ORIENTATION[origin],
)
if mode == "P":
self.assertEqual(
original_im.getpalette(), reference_im.getpalette()
path_no_ext = os.path.splitext(png_path)[0]
for origin, rle in product(self._ORIGINS, (True, False)):
tga_path = "{}_{}_{}.tga".format(
path_no_ext, origin, "rle" if rle else "raw"
)
self.assert_image_equal(original_im, reference_im)
with Image.open(tga_path) as original_im:
self.assertEqual(original_im.format, "TGA")
self.assertEqual(
original_im.get_format_mimetype(), "image/x-tga"
)
if rle:
self.assertEqual(
original_im.info["compression"], "tga_rle"
)
self.assertEqual(
original_im.info["orientation"],
self._ORIGIN_TO_ORIENTATION[origin],
)
if mode == "P":
self.assertEqual(
original_im.getpalette(), reference_im.getpalette()
)
# Generate a new test name every time so the
# test will not fail with permission error
# on Windows.
out = self.tempfile("temp.tga")
self.assert_image_equal(original_im, reference_im)
original_im.save(out, rle=rle)
saved_im = Image.open(out)
if rle:
self.assertEqual(
saved_im.info["compression"],
original_im.info["compression"],
)
self.assertEqual(
saved_im.info["orientation"], original_im.info["orientation"]
)
if mode == "P":
self.assertEqual(
saved_im.getpalette(), original_im.getpalette()
)
# Generate a new test name every time so the
# test will not fail with permission error
# on Windows.
out = self.tempfile("temp.tga")
self.assert_image_equal(saved_im, original_im)
original_im.save(out, rle=rle)
with Image.open(out) as saved_im:
if rle:
self.assertEqual(
saved_im.info["compression"],
original_im.info["compression"],
)
self.assertEqual(
saved_im.info["orientation"],
original_im.info["orientation"],
)
if mode == "P":
self.assertEqual(
saved_im.getpalette(), original_im.getpalette()
)
self.assert_image_equal(saved_im, original_im)
def test_id_field(self):
# tga file with id field
test_file = "Tests/images/tga_id_field.tga"
# Act
im = Image.open(test_file)
with Image.open(test_file) as im:
# Assert
self.assertEqual(im.size, (100, 100))
# Assert
self.assertEqual(im.size, (100, 100))
def test_id_field_rle(self):
# tga file with id field
test_file = "Tests/images/rgb32rle.tga"
# Act
im = Image.open(test_file)
with Image.open(test_file) as im:
# Assert
self.assertEqual(im.size, (199, 199))
# Assert
self.assertEqual(im.size, (199, 199))
def test_save(self):
test_file = "Tests/images/tga_id_field.tga"
im = Image.open(test_file)
with Image.open(test_file) as im:
out = self.tempfile("temp.tga")
out = self.tempfile("temp.tga")
# Save
im.save(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (100, 100))
self.assertEqual(test_im.info["id_section"], im.info["id_section"])
# Save
im.save(out)
test_im = Image.open(out)
self.assertEqual(test_im.size, (100, 100))
self.assertEqual(test_im.info["id_section"], im.info["id_section"])
# RGBA save
im.convert("RGBA").save(out)
test_im = Image.open(out)
self.assertEqual(test_im.size, (100, 100))
# RGBA save
im.convert("RGBA").save(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (100, 100))
def test_save_id_section(self):
test_file = "Tests/images/rgb32rle.tga"
im = Image.open(test_file)
with Image.open(test_file) as im:
out = self.tempfile("temp.tga")
out = self.tempfile("temp.tga")
# Check there is no id section
im.save(out)
test_im = Image.open(out)
self.assertNotIn("id_section", test_im.info)
# Check there is no id section
im.save(out)
with Image.open(out) as test_im:
self.assertNotIn("id_section", test_im.info)
# Save with custom id section
im.save(out, id_section=b"Test content")
test_im = Image.open(out)
self.assertEqual(test_im.info["id_section"], b"Test content")
with Image.open(out) as test_im:
self.assertEqual(test_im.info["id_section"], b"Test content")
# Save with custom id section greater than 255 characters
id_section = b"Test content" * 25
self.assert_warning(UserWarning, lambda: im.save(out, id_section=id_section))
test_im = Image.open(out)
self.assertEqual(test_im.info["id_section"], id_section[:255])
with Image.open(out) as test_im:
self.assertEqual(test_im.info["id_section"], id_section[:255])
test_file = "Tests/images/tga_id_field.tga"
im = Image.open(test_file)
with Image.open(test_file) as im:
# Save with no id section
im.save(out, id_section="")
test_im = Image.open(out)
self.assertNotIn("id_section", test_im.info)
# Save with no id section
im.save(out, id_section="")
with Image.open(out) as test_im:
self.assertNotIn("id_section", test_im.info)
def test_save_orientation(self):
test_file = "Tests/images/rgb32rle.tga"
im = Image.open(test_file)
self.assertEqual(im.info["orientation"], -1)
out = self.tempfile("temp.tga")
with Image.open(test_file) as im:
self.assertEqual(im.info["orientation"], -1)
im.save(out, orientation=1)
test_im = Image.open(out)
self.assertEqual(test_im.info["orientation"], 1)
im.save(out, orientation=1)
with Image.open(out) as test_im:
self.assertEqual(test_im.info["orientation"], 1)
def test_save_rle(self):
test_file = "Tests/images/rgb32rle.tga"
im = Image.open(test_file)
self.assertEqual(im.info["compression"], "tga_rle")
with Image.open(test_file) as im:
self.assertEqual(im.info["compression"], "tga_rle")
out = self.tempfile("temp.tga")
out = self.tempfile("temp.tga")
# Save
im.save(out)
test_im = Image.open(out)
self.assertEqual(test_im.size, (199, 199))
self.assertEqual(test_im.info["compression"], "tga_rle")
# Save
im.save(out)
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (199, 199))
self.assertEqual(test_im.info["compression"], "tga_rle")
# Save without compression
im.save(out, compression=None)
test_im = Image.open(out)
self.assertNotIn("compression", test_im.info)
with Image.open(out) as test_im:
self.assertNotIn("compression", test_im.info)
# RGBA save
im.convert("RGBA").save(out)
test_im = Image.open(out)
self.assertEqual(test_im.size, (199, 199))
with Image.open(out) as test_im:
self.assertEqual(test_im.size, (199, 199))
test_file = "Tests/images/tga_id_field.tga"
im = Image.open(test_file)
self.assertNotIn("compression", im.info)
with Image.open(test_file) as im:
self.assertNotIn("compression", im.info)
# Save with compression
im.save(out, compression="tga_rle")
test_im = Image.open(out)
self.assertEqual(test_im.info["compression"], "tga_rle")
# Save with compression
im.save(out, compression="tga_rle")
with Image.open(out) as test_im:
self.assertEqual(test_im.info["compression"], "tga_rle")
def test_save_l_transparency(self):
# There are 559 transparent pixels in la.tga.
num_transparent = 559
in_file = "Tests/images/la.tga"
im = Image.open(in_file)
self.assertEqual(im.mode, "LA")
self.assertEqual(im.getchannel("A").getcolors()[0][0], num_transparent)
with Image.open(in_file) as im:
self.assertEqual(im.mode, "LA")
self.assertEqual(im.getchannel("A").getcolors()[0][0], num_transparent)
out = self.tempfile("temp.tga")
im.save(out)
out = self.tempfile("temp.tga")
im.save(out)
test_im = Image.open(out)
self.assertEqual(test_im.mode, "LA")
self.assertEqual(test_im.getchannel("A").getcolors()[0][0], num_transparent)
with Image.open(out) as test_im:
self.assertEqual(test_im.mode, "LA")
self.assertEqual(test_im.getchannel("A").getcolors()[0][0], num_transparent)
self.assert_image_equal(im, test_im)
self.assert_image_equal(im, test_im)

View File

@ -1,12 +1,13 @@
import logging
import sys
import os
import unittest
from io import BytesIO
import pytest
from PIL import Image, TiffImagePlugin
from PIL._util import py3
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper, is_pypy, is_win32
logger = logging.getLogger(__name__)
@ -18,54 +19,73 @@ class TestFileTiff(PillowTestCase):
hopper("RGB").save(filename)
im = Image.open(filename)
im.load()
with Image.open(filename) as im:
im.load()
self.assertEqual(im.mode, "RGB")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "TIFF")
hopper("1").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("L").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("P").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("RGB").save(filename)
Image.open(filename)
with Image.open(filename):
pass
hopper("I").save(filename)
Image.open(filename)
with Image.open(filename):
pass
@unittest.skipIf(is_pypy(), "Requires CPython")
def test_unclosed_file(self):
def open():
im = Image.open("Tests/images/multipage.tiff")
im.load()
self.assert_warning(ResourceWarning, open)
def test_closed_file(self):
def open():
im = Image.open("Tests/images/multipage.tiff")
im.load()
im.close()
self.assert_warning(None, open)
def test_context_manager(self):
def open():
with Image.open("Tests/images/multipage.tiff") as im:
im.load()
self.assert_warning(None, open)
def test_mac_tiff(self):
# Read RGBa images from macOS [@PIL136]
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (55, 43))
self.assertEqual(im.tile, [("raw", (0, 0, 55, 43), 8, ("RGBa", 0, 1))])
im.load()
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (55, 43))
self.assertEqual(im.tile, [("raw", (0, 0, 55, 43), 8, ("RGBa", 0, 1))])
im.load()
self.assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
self.assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
def test_wrong_bits_per_sample(self):
im = Image.open("Tests/images/tiff_wrong_bits_per_sample.tiff")
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (52, 53))
self.assertEqual(im.tile, [("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))])
im.load()
with Image.open("Tests/images/tiff_wrong_bits_per_sample.tiff") as im:
self.assertEqual(im.mode, "RGBA")
self.assertEqual(im.size, (52, 53))
self.assertEqual(im.tile, [("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))])
im.load()
def test_set_legacy_api(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()
@ -73,86 +93,76 @@ class TestFileTiff(PillowTestCase):
ifd.legacy_api = None
self.assertEqual(str(e.exception), "Not allowing setting of legacy api")
def test_size(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
def set_size():
im.size = (256, 256)
self.assert_warning(DeprecationWarning, set_size)
def test_xyres_tiff(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
with Image.open(filename) as im:
# legacy api
self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple)
self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple)
# legacy api
self.assertIsInstance(im.tag[X_RESOLUTION][0], tuple)
self.assertIsInstance(im.tag[Y_RESOLUTION][0], tuple)
# v2 api
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
# v2 api
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertEqual(im.info["dpi"], (72.0, 72.0))
self.assertEqual(im.info["dpi"], (72.0, 72.0))
def test_xyres_fallback_tiff(self):
filename = "Tests/images/compression.tif"
im = Image.open(filename)
with Image.open(filename) as im:
# v2 api
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertRaises(KeyError, lambda: im.tag_v2[RESOLUTION_UNIT])
# v2 api
self.assertIsInstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertIsInstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
self.assertRaises(KeyError, lambda: im.tag_v2[RESOLUTION_UNIT])
# Legacy.
self.assertEqual(im.info["resolution"], (100.0, 100.0))
# Fallback "inch".
self.assertEqual(im.info["dpi"], (100.0, 100.0))
# Legacy.
self.assertEqual(im.info["resolution"], (100.0, 100.0))
# Fallback "inch".
self.assertEqual(im.info["dpi"], (100.0, 100.0))
def test_int_resolution(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
with Image.open(filename) as im:
# Try to read a file where X,Y_RESOLUTION are ints
im.tag_v2[X_RESOLUTION] = 71
im.tag_v2[Y_RESOLUTION] = 71
im._setup()
self.assertEqual(im.info["dpi"], (71.0, 71.0))
# Try to read a file where X,Y_RESOLUTION are ints
im.tag_v2[X_RESOLUTION] = 71
im.tag_v2[Y_RESOLUTION] = 71
im._setup()
self.assertEqual(im.info["dpi"], (71.0, 71.0))
def test_load_dpi_rounding(self):
for resolutionUnit, dpi in ((None, (72, 73)), (2, (72, 73)), (3, (183, 185))):
im = Image.open(
with Image.open(
"Tests/images/hopper_roundDown_" + str(resolutionUnit) + ".tif"
)
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
self.assertEqual(im.info["dpi"], (dpi[0], dpi[0]))
) as im:
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
self.assertEqual(im.info["dpi"], (dpi[0], dpi[0]))
im = Image.open(
with Image.open(
"Tests/images/hopper_roundUp_" + str(resolutionUnit) + ".tif"
)
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
self.assertEqual(im.info["dpi"], (dpi[1], dpi[1]))
) as im:
self.assertEqual(im.tag_v2.get(RESOLUTION_UNIT), resolutionUnit)
self.assertEqual(im.info["dpi"], (dpi[1], dpi[1]))
def test_save_dpi_rounding(self):
outfile = self.tempfile("temp.tif")
im = Image.open("Tests/images/hopper.tif")
with Image.open("Tests/images/hopper.tif") as im:
for dpi in (72.2, 72.8):
im.save(outfile, dpi=(dpi, dpi))
for dpi in (72.2, 72.8):
im.save(outfile, dpi=(dpi, dpi))
reloaded = Image.open(outfile)
reloaded.load()
self.assertEqual((round(dpi), round(dpi)), reloaded.info["dpi"])
with Image.open(outfile) as reloaded:
reloaded.load()
self.assertEqual((round(dpi), round(dpi)), reloaded.info["dpi"])
def test_save_setting_missing_resolution(self):
b = BytesIO()
Image.open("Tests/images/10ct_32bit_128.tiff").save(
b, format="tiff", resolution=123.45
)
im = Image.open(b)
self.assertEqual(float(im.tag_v2[X_RESOLUTION]), 123.45)
self.assertEqual(float(im.tag_v2[Y_RESOLUTION]), 123.45)
with Image.open(b) as im:
self.assertEqual(float(im.tag_v2[X_RESOLUTION]), 123.45)
self.assertEqual(float(im.tag_v2[Y_RESOLUTION]), 123.45)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -164,9 +174,9 @@ class TestFileTiff(PillowTestCase):
TiffImagePlugin.PREFIXES.pop()
def test_bad_exif(self):
i = Image.open("Tests/images/hopper_bad_exif.jpg")
# Should not raise struct.error.
self.assert_warning(UserWarning, i._getexif)
with Image.open("Tests/images/hopper_bad_exif.jpg") as i:
# Should not raise struct.error.
self.assert_warning(UserWarning, i._getexif)
def test_save_rgba(self):
im = hopper("RGBA")
@ -179,63 +189,53 @@ class TestFileTiff(PillowTestCase):
self.assertRaises(IOError, im.save, outfile)
def test_little_endian(self):
im = Image.open("Tests/images/16bit.cropped.tif")
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16")
with Image.open("Tests/images/16bit.cropped.tif") as im:
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16")
b = im.tobytes()
b = im.tobytes()
# Bytes are in image native order (little endian)
if py3:
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
else:
self.assertEqual(b[0], b"\xe0")
self.assertEqual(b[1], b"\x01")
self.assertEqual(b[0], ord(b"\xe0"))
self.assertEqual(b[1], ord(b"\x01"))
def test_big_endian(self):
im = Image.open("Tests/images/16bit.MM.cropped.tif")
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16B")
b = im.tobytes()
with Image.open("Tests/images/16bit.MM.cropped.tif") as im:
self.assertEqual(im.getpixel((0, 0)), 480)
self.assertEqual(im.mode, "I;16B")
b = im.tobytes()
# Bytes are in image native order (big endian)
if py3:
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
else:
self.assertEqual(b[0], b"\x01")
self.assertEqual(b[1], b"\xe0")
self.assertEqual(b[0], ord(b"\x01"))
self.assertEqual(b[1], ord(b"\xe0"))
def test_16bit_s(self):
im = Image.open("Tests/images/16bit.s.tif")
im.load()
self.assertEqual(im.mode, "I")
self.assertEqual(im.getpixel((0, 0)), 32767)
self.assertEqual(im.getpixel((0, 1)), 0)
with Image.open("Tests/images/16bit.s.tif") as im:
im.load()
self.assertEqual(im.mode, "I")
self.assertEqual(im.getpixel((0, 0)), 32767)
self.assertEqual(im.getpixel((0, 1)), 0)
def test_12bit_rawmode(self):
""" Are we generating the same interpretation
of the image as Imagemagick is? """
im = Image.open("Tests/images/12bit.cropped.tif")
with Image.open("Tests/images/12bit.cropped.tif") as im:
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
self.assert_image_equal_tofile(im, "Tests/images/12in16bit.tif")
def test_32bit_float(self):
# Issue 614, specific 32-bit float format
path = "Tests/images/10ct_32bit_128.tiff"
im = Image.open(path)
im.load()
with Image.open(path) as im:
im.load()
self.assertEqual(im.getpixel((0, 0)), -0.4526388943195343)
self.assertEqual(im.getextrema(), (-3.140936851501465, 3.140684127807617))
self.assertEqual(im.getpixel((0, 0)), -0.4526388943195343)
self.assertEqual(im.getextrema(), (-3.140936851501465, 3.140684127807617))
def test_unknown_pixel_mode(self):
self.assertRaises(
@ -247,109 +247,109 @@ class TestFileTiff(PillowTestCase):
["Tests/images/multipage-lastframe.tif", 1],
["Tests/images/multipage.tiff", 3],
]:
im = Image.open(path)
self.assertEqual(im.n_frames, n_frames)
self.assertEqual(im.is_animated, n_frames != 1)
with Image.open(path) as im:
self.assertEqual(im.n_frames, n_frames)
self.assertEqual(im.is_animated, n_frames != 1)
def test_eoferror(self):
im = Image.open("Tests/images/multipage-lastframe.tif")
n_frames = im.n_frames
with Image.open("Tests/images/multipage-lastframe.tif") as im:
n_frames = im.n_frames
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test seeking past the last frame
self.assertRaises(EOFError, im.seek, n_frames)
self.assertLess(im.tell(), n_frames)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
# Test that seeking to the last frame does not raise an error
im.seek(n_frames - 1)
def test_multipage(self):
# issue #862
im = Image.open("Tests/images/multipage.tiff")
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
with Image.open("Tests/images/multipage.tiff") as im:
# file is a multipage tiff: 10x10 green, 10x10 red, 20x20 blue
im.seek(0)
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
im.seek(0)
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
im.seek(1)
im.load()
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
im.seek(1)
im.load()
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (255, 0, 0))
im.seek(0)
im.load()
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
im.seek(0)
im.load()
self.assertEqual(im.size, (10, 10))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 128, 0))
im.seek(2)
im.load()
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
im.seek(2)
im.load()
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
def test_multipage_last_frame(self):
im = Image.open("Tests/images/multipage-lastframe.tif")
im.load()
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
with Image.open("Tests/images/multipage-lastframe.tif") as im:
im.load()
self.assertEqual(im.size, (20, 20))
self.assertEqual(im.convert("RGB").getpixel((0, 0)), (0, 0, 255))
def test___str__(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
# Act
ret = str(im.ifd)
# Act
ret = str(im.ifd)
# Assert
self.assertIsInstance(ret, str)
# Assert
self.assertIsInstance(ret, str)
def test_dict(self):
# Arrange
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
with Image.open(filename) as im:
# v2 interface
v2_tags = {
256: 55,
257: 43,
258: (8, 8, 8, 8),
259: 1,
262: 2,
296: 2,
273: (8,),
338: (1,),
277: 4,
279: (9460,),
282: 72.0,
283: 72.0,
284: 1,
}
self.assertEqual(dict(im.tag_v2), v2_tags)
# v2 interface
v2_tags = {
256: 55,
257: 43,
258: (8, 8, 8, 8),
259: 1,
262: 2,
296: 2,
273: (8,),
338: (1,),
277: 4,
279: (9460,),
282: 72.0,
283: 72.0,
284: 1,
}
self.assertEqual(dict(im.tag_v2), v2_tags)
# legacy interface
legacy_tags = {
256: (55,),
257: (43,),
258: (8, 8, 8, 8),
259: (1,),
262: (2,),
296: (2,),
273: (8,),
338: (1,),
277: (4,),
279: (9460,),
282: ((720000, 10000),),
283: ((720000, 10000),),
284: (1,),
}
self.assertEqual(dict(im.tag), legacy_tags)
# legacy interface
legacy_tags = {
256: (55,),
257: (43,),
258: (8, 8, 8, 8),
259: (1,),
262: (2,),
296: (2,),
273: (8,),
338: (1,),
277: (4,),
279: (9460,),
282: ((720000, 10000),),
283: ((720000, 10000),),
284: (1,),
}
self.assertEqual(dict(im.tag), legacy_tags)
def test__delitem__(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
len_before = len(dict(im.ifd))
del im.ifd[256]
len_after = len(dict(im.ifd))
self.assertEqual(len_before, len_after + 1)
with Image.open(filename) as im:
len_before = len(dict(im.ifd))
del im.ifd[256]
len_after = len(dict(im.ifd))
self.assertEqual(len_before, len_after + 1)
def test_load_byte(self):
for legacy_api in [False, True]:
@ -378,16 +378,16 @@ class TestFileTiff(PillowTestCase):
def test_seek(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
im.seek(0)
self.assertEqual(im.tell(), 0)
with Image.open(filename) as im:
im.seek(0)
self.assertEqual(im.tell(), 0)
def test_seek_eof(self):
filename = "Tests/images/pil136.tiff"
im = Image.open(filename)
self.assertEqual(im.tell(), 0)
self.assertRaises(EOFError, im.seek, -1)
self.assertRaises(EOFError, im.seek, 1)
with Image.open(filename) as im:
self.assertEqual(im.tell(), 0)
self.assertRaises(EOFError, im.seek, -1)
self.assertRaises(EOFError, im.seek, 1)
def test__limit_rational_int(self):
from PIL.TiffImagePlugin import _limit_rational
@ -406,10 +406,10 @@ class TestFileTiff(PillowTestCase):
def test_4bit(self):
test_file = "Tests/images/hopper_gray_4bpp.tif"
original = hopper("L")
im = Image.open(test_file)
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
with Image.open(test_file) as im:
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self):
test_files = (
@ -434,73 +434,68 @@ class TestFileTiff(PillowTestCase):
)
original = hopper("L")
for epsilon, group in test_files:
im = Image.open(group[0])
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
for file in group[1:]:
im2 = Image.open(file)
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
with Image.open(group[0]) as im:
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
for file in group[1:]:
with Image.open(file) as im2:
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
def test_with_underscores(self):
kwargs = {"resolution_unit": "inch", "x_resolution": 72, "y_resolution": 36}
filename = self.tempfile("temp.tif")
hopper("RGB").save(filename, **kwargs)
im = Image.open(filename)
with Image.open(filename) as im:
# legacy interface
self.assertEqual(im.tag[X_RESOLUTION][0][0], 72)
self.assertEqual(im.tag[Y_RESOLUTION][0][0], 36)
# legacy interface
self.assertEqual(im.tag[X_RESOLUTION][0][0], 72)
self.assertEqual(im.tag[Y_RESOLUTION][0][0], 36)
# v2 interface
self.assertEqual(im.tag_v2[X_RESOLUTION], 72)
self.assertEqual(im.tag_v2[Y_RESOLUTION], 36)
# v2 interface
self.assertEqual(im.tag_v2[X_RESOLUTION], 72)
self.assertEqual(im.tag_v2[Y_RESOLUTION], 36)
def test_roundtrip_tiff_uint16(self):
# Test an image of all '0' values
pixel_value = 0x1234
infile = "Tests/images/uint16_1_4660.tif"
im = Image.open(infile)
self.assertEqual(im.getpixel((0, 0)), pixel_value)
with Image.open(infile) as im:
self.assertEqual(im.getpixel((0, 0)), pixel_value)
tmpfile = self.tempfile("temp.tif")
im.save(tmpfile)
tmpfile = self.tempfile("temp.tif")
im.save(tmpfile)
reloaded = Image.open(tmpfile)
self.assert_image_equal(im, reloaded)
with Image.open(tmpfile) as reloaded:
self.assert_image_equal(im, reloaded)
def test_strip_raw(self):
infile = "Tests/images/tiff_strip_raw.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
with Image.open(infile) as im:
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_strip_planar_raw(self):
# gdal_translate -of GTiff -co INTERLEAVE=BAND \
# tiff_strip_raw.tif tiff_strip_planar_raw.tiff
infile = "Tests/images/tiff_strip_planar_raw.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
with Image.open(infile) as im:
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_strip_planar_raw_with_overviews(self):
# gdaladdo tiff_strip_planar_raw2.tif 2 4 8 16
infile = "Tests/images/tiff_strip_planar_raw_with_overviews.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
with Image.open(infile) as im:
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_tiled_planar_raw(self):
# gdal_translate -of GTiff -co TILED=YES -co BLOCKXSIZE=32 \
# -co BLOCKYSIZE=32 -co INTERLEAVE=BAND \
# tiff_tiled_raw.tif tiff_tiled_planar_raw.tiff
infile = "Tests/images/tiff_tiled_planar_raw.tif"
im = Image.open(infile)
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
with Image.open(infile) as im:
self.assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png")
def test_palette(self):
for mode in ["P", "PA"]:
@ -509,14 +504,11 @@ class TestFileTiff(PillowTestCase):
im = hopper(mode)
im.save(outfile)
reloaded = Image.open(outfile)
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
with Image.open(outfile) as reloaded:
self.assert_image_equal(im.convert("RGB"), reloaded.convert("RGB"))
def test_tiff_save_all(self):
import io
import os
mp = io.BytesIO()
mp = BytesIO()
with Image.open("Tests/images/multipage.tiff") as im:
im.save(mp, format="tiff", save_all=True)
@ -525,26 +517,25 @@ class TestFileTiff(PillowTestCase):
self.assertEqual(im.n_frames, 3)
# Test appending images
mp = io.BytesIO()
mp = BytesIO()
im = Image.new("RGB", (100, 100), "#f00")
ims = [Image.new("RGB", (100, 100), color) for color in ["#0f0", "#00f"]]
im.copy().save(mp, format="TIFF", save_all=True, append_images=ims)
mp.seek(0, os.SEEK_SET)
reread = Image.open(mp)
self.assertEqual(reread.n_frames, 3)
with Image.open(mp) as reread:
self.assertEqual(reread.n_frames, 3)
# Test appending using a generator
def imGenerator(ims):
for im in ims:
yield im
yield from ims
mp = io.BytesIO()
mp = BytesIO()
im.save(mp, format="TIFF", save_all=True, append_images=imGenerator(ims))
mp.seek(0, os.SEEK_SET)
reread = Image.open(mp)
self.assertEqual(reread.n_frames, 3)
with Image.open(mp) as reread:
self.assertEqual(reread.n_frames, 3)
def test_saving_icc_profile(self):
# Tests saving TIFF with icc_profile set.
@ -557,9 +548,8 @@ class TestFileTiff(PillowTestCase):
# Try save-load round trip to make sure both handle icc_profile.
tmpfile = self.tempfile("temp.tif")
im.save(tmpfile, "TIFF", compression="raw")
reloaded = Image.open(tmpfile)
self.assertEqual(b"Dummy value", reloaded.info["icc_profile"])
with Image.open(tmpfile) as reloaded:
self.assertEqual(b"Dummy value", reloaded.info["icc_profile"])
def test_close_on_load_exclusive(self):
# similar to test_fd_leak, but runs on unixlike os
@ -587,17 +577,19 @@ class TestFileTiff(PillowTestCase):
im.load()
self.assertFalse(fp.closed)
# Ignore this UserWarning which triggers for four tags:
# "Possibly corrupt EXIF data. Expecting to read 50404352 bytes but..."
@pytest.mark.filterwarnings("ignore:Possibly corrupt EXIF data")
def test_string_dimension(self):
# Assert that an error is raised if one of the dimensions is a string
with self.assertRaises(ValueError):
Image.open("Tests/images/string_dimension.tiff")
@unittest.skipUnless(sys.platform.startswith("win32"), "Windows only")
@unittest.skipUnless(is_win32(), "Windows only")
class TestFileTiffW32(PillowTestCase):
def test_fd_leak(self):
tmpfile = self.tempfile("temp.tif")
import os
# this is an mmaped file.
with Image.open("Tests/images/uint16_1_4660.tif") as im:

View File

@ -52,89 +52,92 @@ class TestFileTiffMetadata(PillowTestCase):
img.save(f, tiffinfo=info)
loaded = Image.open(f)
with Image.open(f) as loaded:
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag[ImageJMetaData], bindata)
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
self.assertEqual(loaded.tag[ImageJMetaData], bindata)
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,))
self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata)
self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,))
self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata)
loaded_float = loaded.tag[tag_ids["RollAngle"]][0]
self.assertAlmostEqual(loaded_float, floatdata, places=5)
loaded_double = loaded.tag[tag_ids["YawAngle"]][0]
self.assertAlmostEqual(loaded_double, doubledata)
loaded_float = loaded.tag[tag_ids["RollAngle"]][0]
self.assertAlmostEqual(loaded_float, floatdata, places=5)
loaded_double = loaded.tag[tag_ids["YawAngle"]][0]
self.assertAlmostEqual(loaded_double, doubledata)
# check with 2 element ImageJMetaDataByteCounts, issue #2006
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
img.save(f, tiffinfo=info)
loaded = Image.open(f)
with Image.open(f) as loaded:
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
self.assertEqual(
loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8)
)
self.assertEqual(
loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8)
)
def test_read_metadata(self):
img = Image.open("Tests/images/hopper_g4.tif")
with Image.open("Tests/images/hopper_g4.tif") as img:
self.assertEqual(
{
"YResolution": IFDRational(4294967295, 113653537),
"PlanarConfiguration": 1,
"BitsPerSample": (1,),
"ImageLength": 128,
"Compression": 4,
"FillOrder": 1,
"RowsPerStrip": 128,
"ResolutionUnit": 3,
"PhotometricInterpretation": 0,
"PageNumber": (0, 1),
"XResolution": IFDRational(4294967295, 113653537),
"ImageWidth": 128,
"Orientation": 1,
"StripByteCounts": (1968,),
"SamplesPerPixel": 1,
"StripOffsets": (8,),
},
img.tag_v2.named(),
)
self.assertEqual(
{
"YResolution": IFDRational(4294967295, 113653537),
"PlanarConfiguration": 1,
"BitsPerSample": (1,),
"ImageLength": 128,
"Compression": 4,
"FillOrder": 1,
"RowsPerStrip": 128,
"ResolutionUnit": 3,
"PhotometricInterpretation": 0,
"PageNumber": (0, 1),
"XResolution": IFDRational(4294967295, 113653537),
"ImageWidth": 128,
"Orientation": 1,
"StripByteCounts": (1968,),
"SamplesPerPixel": 1,
"StripOffsets": (8,),
},
img.tag_v2.named(),
)
self.assertEqual(
{
"YResolution": ((4294967295, 113653537),),
"PlanarConfiguration": (1,),
"BitsPerSample": (1,),
"ImageLength": (128,),
"Compression": (4,),
"FillOrder": (1,),
"RowsPerStrip": (128,),
"ResolutionUnit": (3,),
"PhotometricInterpretation": (0,),
"PageNumber": (0, 1),
"XResolution": ((4294967295, 113653537),),
"ImageWidth": (128,),
"Orientation": (1,),
"StripByteCounts": (1968,),
"SamplesPerPixel": (1,),
"StripOffsets": (8,),
},
img.tag.named(),
)
self.assertEqual(
{
"YResolution": ((4294967295, 113653537),),
"PlanarConfiguration": (1,),
"BitsPerSample": (1,),
"ImageLength": (128,),
"Compression": (4,),
"FillOrder": (1,),
"RowsPerStrip": (128,),
"ResolutionUnit": (3,),
"PhotometricInterpretation": (0,),
"PageNumber": (0, 1),
"XResolution": ((4294967295, 113653537),),
"ImageWidth": (128,),
"Orientation": (1,),
"StripByteCounts": (1968,),
"SamplesPerPixel": (1,),
"StripOffsets": (8,),
},
img.tag.named(),
)
def test_write_metadata(self):
""" Test metadata writing through the python code """
img = Image.open("Tests/images/hopper.tif")
with Image.open("Tests/images/hopper.tif") as img:
f = self.tempfile("temp.tiff")
img.save(f, tiffinfo=img.tag)
f = self.tempfile("temp.tiff")
img.save(f, tiffinfo=img.tag)
original = img.tag_v2.named()
loaded = Image.open(f)
original = img.tag_v2.named()
reloaded = loaded.tag_v2.named()
with Image.open(f) as loaded:
reloaded = loaded.tag_v2.named()
for k, v in original.items():
if isinstance(v, IFDRational):
@ -157,13 +160,13 @@ class TestFileTiffMetadata(PillowTestCase):
self.assert_deep_equal(
original[tag],
value,
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
)
else:
self.assertEqual(
original[tag],
value,
"%s didn't roundtrip, %s, %s" % (tag, original[tag], value),
"{} didn't roundtrip, {}, {}".format(tag, original[tag], value),
)
for tag, value in original.items():
@ -183,32 +186,32 @@ class TestFileTiffMetadata(PillowTestCase):
def test_iccprofile(self):
# https://github.com/python-pillow/Pillow/issues/1462
im = Image.open("Tests/images/hopper.iccprofile.tif")
out = self.tempfile("temp.tiff")
with Image.open("Tests/images/hopper.iccprofile.tif") as im:
im.save(out)
im.save(out)
reloaded = Image.open(out)
self.assertNotIsInstance(im.info["icc_profile"], tuple)
self.assertEqual(im.info["icc_profile"], reloaded.info["icc_profile"])
with Image.open(out) as reloaded:
self.assertNotIsInstance(im.info["icc_profile"], tuple)
self.assertEqual(im.info["icc_profile"], reloaded.info["icc_profile"])
def test_iccprofile_binary(self):
# https://github.com/python-pillow/Pillow/issues/1526
# We should be able to load this,
# but probably won't be able to save it.
im = Image.open("Tests/images/hopper.iccprofile_binary.tif")
self.assertEqual(im.tag_v2.tagtype[34675], 1)
self.assertTrue(im.info["icc_profile"])
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
self.assertEqual(im.tag_v2.tagtype[34675], 1)
self.assertTrue(im.info["icc_profile"])
def test_iccprofile_save_png(self):
im = Image.open("Tests/images/hopper.iccprofile.tif")
outfile = self.tempfile("temp.png")
im.save(outfile)
with Image.open("Tests/images/hopper.iccprofile.tif") as im:
outfile = self.tempfile("temp.png")
im.save(outfile)
def test_iccprofile_binary_save_png(self):
im = Image.open("Tests/images/hopper.iccprofile_binary.tif")
outfile = self.tempfile("temp.png")
im.save(outfile)
with Image.open("Tests/images/hopper.iccprofile_binary.tif") as im:
outfile = self.tempfile("temp.png")
im.save(outfile)
def test_exif_div_zero(self):
im = hopper()
@ -218,9 +221,9 @@ class TestFileTiffMetadata(PillowTestCase):
out = self.tempfile("temp.tiff")
im.save(out, tiffinfo=info, compression="raw")
reloaded = Image.open(out)
self.assertEqual(0, reloaded.tag_v2[41988].numerator)
self.assertEqual(0, reloaded.tag_v2[41988].denominator)
with Image.open(out) as reloaded:
self.assertEqual(0, reloaded.tag_v2[41988].numerator)
self.assertEqual(0, reloaded.tag_v2[41988].denominator)
def test_empty_values(self):
data = io.BytesIO(
@ -237,15 +240,14 @@ class TestFileTiffMetadata(PillowTestCase):
self.assertIn(33432, info)
def test_PhotoshopInfo(self):
im = Image.open("Tests/images/issue_2278.tif")
self.assertEqual(len(im.tag_v2[34377]), 1)
self.assertIsInstance(im.tag_v2[34377][0], bytes)
out = self.tempfile("temp.tiff")
im.save(out)
reloaded = Image.open(out)
self.assertEqual(len(reloaded.tag_v2[34377]), 1)
self.assertIsInstance(reloaded.tag_v2[34377][0], bytes)
with Image.open("Tests/images/issue_2278.tif") as im:
self.assertEqual(len(im.tag_v2[34377]), 1)
self.assertIsInstance(im.tag_v2[34377][0], bytes)
out = self.tempfile("temp.tiff")
im.save(out)
with Image.open(out) as reloaded:
self.assertEqual(len(reloaded.tag_v2[34377]), 1)
self.assertIsInstance(reloaded.tag_v2[34377][0], bytes)
def test_too_many_entries(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image, WebPImagePlugin
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
try:
from PIL import _webp
@ -39,19 +41,18 @@ class TestFileWebp(PillowTestCase):
Does it have the bits we expect?
"""
image = Image.open("Tests/images/hopper.webp")
with Image.open("Tests/images/hopper.webp") as image:
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
# generated with:
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
self.assert_image_similar_tofile(
image, "Tests/images/hopper_webp_bits.ppm", 1.0
)
# generated with:
# dwebp -ppm ../../Tests/images/hopper.webp -o hopper_webp_bits.ppm
self.assert_image_similar_tofile(
image, "Tests/images/hopper_webp_bits.ppm", 1.0
)
def test_write_rgb(self):
"""
@ -62,26 +63,25 @@ class TestFileWebp(PillowTestCase):
temp_file = self.tempfile("temp.webp")
hopper(self.rgb_mode).save(temp_file)
image = Image.open(temp_file)
with Image.open(temp_file) as image:
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
# generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm
self.assert_image_similar_tofile(
image, "Tests/images/hopper_webp_write.ppm", 12.0
)
# generated with: dwebp -ppm temp.webp -o hopper_webp_write.ppm
self.assert_image_similar_tofile(
image, "Tests/images/hopper_webp_write.ppm", 12.0
)
# This test asserts that the images are similar. If the average pixel
# difference between the two images is less than the epsilon value,
# then we're going to accept that it's a reasonable lossy version of
# the image. The old lena images for WebP are showing ~16 on
# Ubuntu, the jpegs are showing ~18.
target = hopper(self.rgb_mode)
self.assert_image_similar(image, target, 12.0)
# This test asserts that the images are similar. If the average pixel
# difference between the two images is less than the epsilon value,
# then we're going to accept that it's a reasonable lossy version of
# the image. The old lena images for WebP are showing ~16 on
# Ubuntu, the jpegs are showing ~18.
target = hopper(self.rgb_mode)
self.assert_image_similar(image, target, 12.0)
def test_write_unsupported_mode_L(self):
"""
@ -91,17 +91,16 @@ class TestFileWebp(PillowTestCase):
temp_file = self.tempfile("temp.webp")
hopper("L").save(temp_file)
image = Image.open(temp_file)
with Image.open(temp_file) as image:
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
target = hopper("L").convert(self.rgb_mode)
image.load()
image.getdata()
target = hopper("L").convert(self.rgb_mode)
self.assert_image_similar(image, target, 10.0)
self.assert_image_similar(image, target, 10.0)
def test_write_unsupported_mode_P(self):
"""
@ -111,17 +110,16 @@ class TestFileWebp(PillowTestCase):
temp_file = self.tempfile("temp.webp")
hopper("P").save(temp_file)
image = Image.open(temp_file)
with Image.open(temp_file) as image:
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
target = hopper("P").convert(self.rgb_mode)
image.load()
image.getdata()
target = hopper("P").convert(self.rgb_mode)
self.assert_image_similar(image, target, 50.0)
self.assert_image_similar(image, target, 50.0)
def test_WebPEncode_with_invalid_args(self):
"""
@ -143,10 +141,9 @@ class TestFileWebp(PillowTestCase):
def test_no_resource_warning(self):
file_path = "Tests/images/hopper.webp"
image = Image.open(file_path)
temp_file = self.tempfile("temp.webp")
self.assert_warning(None, image.save, temp_file)
with Image.open(file_path) as image:
temp_file = self.tempfile("temp.webp")
self.assert_warning(None, image.save, temp_file)
def test_file_pointer_could_be_reused(self):
file_path = "Tests/images/hopper.webp"
@ -158,19 +155,19 @@ class TestFileWebp(PillowTestCase):
HAVE_WEBP and _webp.HAVE_WEBPANIM, "WebP save all not available"
)
def test_background_from_gif(self):
im = Image.open("Tests/images/chi.gif")
original_value = im.convert("RGB").getpixel((1, 1))
with Image.open("Tests/images/chi.gif") as im:
original_value = im.convert("RGB").getpixel((1, 1))
# Save as WEBP
out_webp = self.tempfile("temp.webp")
im.save(out_webp, save_all=True)
# Save as WEBP
out_webp = self.tempfile("temp.webp")
im.save(out_webp, save_all=True)
# Save as GIF
out_gif = self.tempfile("temp.gif")
Image.open(out_webp).save(out_gif)
reread = Image.open(out_gif)
reread_value = reread.convert("RGB").getpixel((1, 1))
with Image.open(out_gif) as reread:
reread_value = reread.convert("RGB").getpixel((1, 1))
difference = sum(
[abs(original_value[i] - reread_value[i]) for i in range(0, 3)]
)

View File

@ -1,6 +1,8 @@
import unittest
from PIL import Image
from .helper import PillowTestCase, hopper, unittest
from .helper import PillowTestCase, hopper
try:
from PIL import _webp
@ -24,18 +26,17 @@ class TestFileWebpAlpha(PillowTestCase):
# Generated with `cwebp transparent.png -o transparent.webp`
file_path = "Tests/images/transparent.webp"
image = Image.open(file_path)
with Image.open(file_path) as image:
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (200, 150))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (200, 150))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
image.tobytes()
image.tobytes()
target = Image.open("Tests/images/transparent.png")
self.assert_image_similar(image, target, 20.0)
with Image.open("Tests/images/transparent.png") as target:
self.assert_image_similar(image, target, 20.0)
def test_write_lossless_rgb(self):
"""
@ -54,16 +55,16 @@ class TestFileWebpAlpha(PillowTestCase):
pil_image.save(temp_file, lossless=True)
image = Image.open(temp_file)
image.load()
with Image.open(temp_file) as image:
image.load()
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, pil_image.size)
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, pil_image.size)
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assert_image_equal(image, pil_image)
self.assert_image_equal(image, pil_image)
def test_write_rgba(self):
"""
@ -79,21 +80,21 @@ class TestFileWebpAlpha(PillowTestCase):
if _webp.WebPDecoderBuggyAlpha(self):
return
image = Image.open(temp_file)
image.load()
with Image.open(temp_file) as image:
image.load()
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (10, 10))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (10, 10))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
# early versions of webp are known to produce higher deviations:
# deal with it
if _webp.WebPDecoderVersion(self) <= 0x201:
self.assert_image_similar(image, pil_image, 3.0)
else:
self.assert_image_similar(image, pil_image, 1.0)
# early versions of webp are known to produce higher deviations:
# deal with it
if _webp.WebPDecoderVersion(self) <= 0x201:
self.assert_image_similar(image, pil_image, 3.0)
else:
self.assert_image_similar(image, pil_image, 1.0)
def test_write_unsupported_mode_PA(self):
"""
@ -103,15 +104,16 @@ class TestFileWebpAlpha(PillowTestCase):
temp_file = self.tempfile("temp.webp")
file_path = "Tests/images/transparent.gif"
Image.open(file_path).save(temp_file)
image = Image.open(temp_file)
with Image.open(file_path) as im:
im.save(temp_file)
with Image.open(temp_file) as image:
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (200, 150))
self.assertEqual(image.format, "WEBP")
self.assertEqual(image.mode, "RGBA")
self.assertEqual(image.size, (200, 150))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
with Image.open(file_path) as im:
target = im.convert("RGBA")
image.load()
image.getdata()
target = Image.open(file_path).convert("RGBA")
self.assert_image_similar(image, target, 25.0)
self.assert_image_similar(image, target, 25.0)

View File

@ -28,13 +28,13 @@ class TestFileWebpAnimation(PillowTestCase):
attributes correctly.
"""
im = Image.open("Tests/images/hopper.webp")
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
with Image.open("Tests/images/hopper.webp") as im:
self.assertEqual(im.n_frames, 1)
self.assertFalse(im.is_animated)
im = Image.open("Tests/images/iss634.webp")
self.assertEqual(im.n_frames, 42)
self.assertTrue(im.is_animated)
with Image.open("Tests/images/iss634.webp") as im:
self.assertEqual(im.n_frames, 42)
self.assertTrue(im.is_animated)
def test_write_animation_L(self):
"""
@ -43,23 +43,23 @@ class TestFileWebpAnimation(PillowTestCase):
visually similar.
"""
orig = Image.open("Tests/images/iss634.gif")
self.assertGreater(orig.n_frames, 1)
with Image.open("Tests/images/iss634.gif") as orig:
self.assertGreater(orig.n_frames, 1)
temp_file = self.tempfile("temp.webp")
orig.save(temp_file, save_all=True)
im = Image.open(temp_file)
self.assertEqual(im.n_frames, orig.n_frames)
temp_file = self.tempfile("temp.webp")
orig.save(temp_file, save_all=True)
with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, orig.n_frames)
# Compare first and last frames to the original animated GIF
orig.load()
im.load()
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
orig.seek(orig.n_frames - 1)
im.seek(im.n_frames - 1)
orig.load()
im.load()
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
# Compare first and last frames to the original animated GIF
orig.load()
im.load()
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
orig.seek(orig.n_frames - 1)
im.seek(im.n_frames - 1)
orig.load()
im.load()
self.assert_image_similar(im, orig.convert("RGBA"), 25.0)
def test_write_animation_RGB(self):
"""
@ -68,40 +68,38 @@ class TestFileWebpAnimation(PillowTestCase):
"""
def check(temp_file):
im = Image.open(temp_file)
self.assertEqual(im.n_frames, 2)
with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 2)
# Compare first frame to original
im.load()
self.assert_image_equal(im, frame1.convert("RGBA"))
# Compare first frame to original
im.load()
self.assert_image_equal(im, frame1.convert("RGBA"))
# Compare second frame to original
im.seek(1)
im.load()
self.assert_image_equal(im, frame2.convert("RGBA"))
# Compare second frame to original
im.seek(1)
im.load()
self.assert_image_equal(im, frame2.convert("RGBA"))
frame1 = Image.open("Tests/images/anim_frame1.webp")
frame2 = Image.open("Tests/images/anim_frame2.webp")
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
temp_file1 = self.tempfile("temp.webp")
frame1.copy().save(
temp_file1, save_all=True, append_images=[frame2], lossless=True
)
check(temp_file1)
temp_file1 = self.tempfile("temp.webp")
frame1.copy().save(
temp_file1, save_all=True, append_images=[frame2], lossless=True
)
check(temp_file1)
# Tests appending using a generator
def imGenerator(ims):
yield from ims
# Tests appending using a generator
def imGenerator(ims):
for im in ims:
yield im
temp_file2 = self.tempfile("temp_generator.webp")
frame1.copy().save(
temp_file2,
save_all=True,
append_images=imGenerator([frame2]),
lossless=True,
)
check(temp_file2)
temp_file2 = self.tempfile("temp_generator.webp")
frame1.copy().save(
temp_file2,
save_all=True,
append_images=imGenerator([frame2]),
lossless=True,
)
check(temp_file2)
def test_timestamp_and_duration(self):
"""
@ -111,27 +109,27 @@ class TestFileWebpAnimation(PillowTestCase):
durations = [0, 10, 20, 30, 40]
temp_file = self.tempfile("temp.webp")
frame1 = Image.open("Tests/images/anim_frame1.webp")
frame2 = Image.open("Tests/images/anim_frame2.webp")
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=durations,
)
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=durations,
)
im = Image.open(temp_file)
self.assertEqual(im.n_frames, 5)
self.assertTrue(im.is_animated)
with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 5)
self.assertTrue(im.is_animated)
# Check that timestamps and durations match original values specified
ts = 0
for frame in range(im.n_frames):
im.seek(frame)
im.load()
self.assertEqual(im.info["duration"], durations[frame])
self.assertEqual(im.info["timestamp"], ts)
ts += durations[frame]
# Check that timestamps and durations match original values specified
ts = 0
for frame in range(im.n_frames):
im.seek(frame)
im.load()
self.assertEqual(im.info["duration"], durations[frame])
self.assertEqual(im.info["timestamp"], ts)
ts += durations[frame]
def test_seeking(self):
"""
@ -142,24 +140,24 @@ class TestFileWebpAnimation(PillowTestCase):
dur = 33
temp_file = self.tempfile("temp.webp")
frame1 = Image.open("Tests/images/anim_frame1.webp")
frame2 = Image.open("Tests/images/anim_frame2.webp")
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=dur,
)
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2, frame1],
duration=dur,
)
im = Image.open(temp_file)
self.assertEqual(im.n_frames, 5)
self.assertTrue(im.is_animated)
with Image.open(temp_file) as im:
self.assertEqual(im.n_frames, 5)
self.assertTrue(im.is_animated)
# Traverse frames in reverse, checking timestamps and durations
ts = dur * (im.n_frames - 1)
for frame in reversed(range(im.n_frames)):
im.seek(frame)
im.load()
self.assertEqual(im.info["duration"], dur)
self.assertEqual(im.info["timestamp"], ts)
ts -= dur
# Traverse frames in reverse, checking timestamps and durations
ts = dur * (im.n_frames - 1)
for frame in reversed(range(im.n_frames)):
im.seek(frame)
im.load()
self.assertEqual(im.info["duration"], dur)
self.assertEqual(im.info["timestamp"], ts)
ts -= dur

View File

@ -26,13 +26,13 @@ class TestFileWebpLossless(PillowTestCase):
hopper(self.rgb_mode).save(temp_file, lossless=True)
image = Image.open(temp_file)
image.load()
with Image.open(temp_file) as image:
image.load()
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assertEqual(image.mode, self.rgb_mode)
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.format, "WEBP")
image.load()
image.getdata()
self.assert_image_equal(image, hopper(self.rgb_mode))
self.assert_image_equal(image, hopper(self.rgb_mode))

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
@ -22,37 +24,33 @@ class TestFileWebpMetadata(PillowTestCase):
def test_read_exif_metadata(self):
file_path = "Tests/images/flower.webp"
image = Image.open(file_path)
with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP")
exif_data = image.info.get("exif", None)
self.assertTrue(exif_data)
self.assertEqual(image.format, "WEBP")
exif_data = image.info.get("exif", None)
self.assertTrue(exif_data)
exif = image._getexif()
exif = image._getexif()
# camera make
self.assertEqual(exif[271], "Canon")
# camera make
self.assertEqual(exif[271], "Canon")
jpeg_image = Image.open("Tests/images/flower.jpg")
expected_exif = jpeg_image.info["exif"]
with Image.open("Tests/images/flower.jpg") as jpeg_image:
expected_exif = jpeg_image.info["exif"]
self.assertEqual(exif_data, expected_exif)
self.assertEqual(exif_data, expected_exif)
def test_write_exif_metadata(self):
from io import BytesIO
file_path = "Tests/images/flower.jpg"
image = Image.open(file_path)
expected_exif = image.info["exif"]
test_buffer = BytesIO()
with Image.open(file_path) as image:
expected_exif = image.info["exif"]
image.save(test_buffer, "webp", exif=expected_exif)
image.save(test_buffer, "webp", exif=expected_exif)
test_buffer.seek(0)
webp_image = Image.open(test_buffer)
webp_exif = webp_image.info.get("exif", None)
with Image.open(test_buffer) as webp_image:
webp_exif = webp_image.info.get("exif", None)
self.assertTrue(webp_exif)
if webp_exif:
self.assertEqual(webp_exif, expected_exif, "WebP EXIF didn't match")
@ -60,33 +58,29 @@ class TestFileWebpMetadata(PillowTestCase):
def test_read_icc_profile(self):
file_path = "Tests/images/flower2.webp"
image = Image.open(file_path)
with Image.open(file_path) as image:
self.assertEqual(image.format, "WEBP")
self.assertTrue(image.info.get("icc_profile", None))
self.assertEqual(image.format, "WEBP")
self.assertTrue(image.info.get("icc_profile", None))
icc = image.info["icc_profile"]
icc = image.info["icc_profile"]
jpeg_image = Image.open("Tests/images/flower2.jpg")
expected_icc = jpeg_image.info["icc_profile"]
with Image.open("Tests/images/flower2.jpg") as jpeg_image:
expected_icc = jpeg_image.info["icc_profile"]
self.assertEqual(icc, expected_icc)
self.assertEqual(icc, expected_icc)
def test_write_icc_metadata(self):
from io import BytesIO
file_path = "Tests/images/flower2.jpg"
image = Image.open(file_path)
expected_icc_profile = image.info["icc_profile"]
test_buffer = BytesIO()
with Image.open(file_path) as image:
expected_icc_profile = image.info["icc_profile"]
image.save(test_buffer, "webp", icc_profile=expected_icc_profile)
image.save(test_buffer, "webp", icc_profile=expected_icc_profile)
test_buffer.seek(0)
webp_image = Image.open(test_buffer)
webp_icc_profile = webp_image.info.get("icc_profile", None)
with Image.open(test_buffer) as webp_image:
webp_icc_profile = webp_image.info.get("icc_profile", None)
self.assertTrue(webp_icc_profile)
if webp_icc_profile:
@ -95,45 +89,41 @@ class TestFileWebpMetadata(PillowTestCase):
)
def test_read_no_exif(self):
from io import BytesIO
file_path = "Tests/images/flower.jpg"
image = Image.open(file_path)
self.assertIn("exif", image.info)
test_buffer = BytesIO()
with Image.open(file_path) as image:
self.assertIn("exif", image.info)
image.save(test_buffer, "webp")
image.save(test_buffer, "webp")
test_buffer.seek(0)
webp_image = Image.open(test_buffer)
self.assertFalse(webp_image._getexif())
with Image.open(test_buffer) as webp_image:
self.assertFalse(webp_image._getexif())
def test_write_animated_metadata(self):
if not _webp.HAVE_WEBPANIM:
self.skipTest("WebP animation support not available")
iccp_data = "<iccp_data>".encode("utf-8")
exif_data = "<exif_data>".encode("utf-8")
xmp_data = "<xmp_data>".encode("utf-8")
iccp_data = b"<iccp_data>"
exif_data = b"<exif_data>"
xmp_data = b"<xmp_data>"
temp_file = self.tempfile("temp.webp")
frame1 = Image.open("Tests/images/anim_frame1.webp")
frame2 = Image.open("Tests/images/anim_frame2.webp")
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2],
icc_profile=iccp_data,
exif=exif_data,
xmp=xmp_data,
)
with Image.open("Tests/images/anim_frame1.webp") as frame1:
with Image.open("Tests/images/anim_frame2.webp") as frame2:
frame1.save(
temp_file,
save_all=True,
append_images=[frame2, frame1, frame2],
icc_profile=iccp_data,
exif=exif_data,
xmp=xmp_data,
)
image = Image.open(temp_file)
self.assertIn("icc_profile", image.info)
self.assertIn("exif", image.info)
self.assertIn("xmp", image.info)
self.assertEqual(iccp_data, image.info.get("icc_profile", None))
self.assertEqual(exif_data, image.info.get("exif", None))
self.assertEqual(xmp_data, image.info.get("xmp", None))
with Image.open(temp_file) as image:
self.assertIn("icc_profile", image.info)
self.assertIn("exif", image.info)
self.assertIn("xmp", image.info)
self.assertEqual(iccp_data, image.info.get("icc_profile", None))
self.assertEqual(exif_data, image.info.get("exif", None))
self.assertEqual(xmp_data, image.info.get("xmp", None))

View File

@ -7,24 +7,24 @@ class TestFileWmf(PillowTestCase):
def test_load_raw(self):
# Test basic EMF open and rendering
im = Image.open("Tests/images/drawing.emf")
if hasattr(Image.core, "drawwmf"):
# Currently, support for WMF/EMF is Windows-only
im.load()
# Compare to reference rendering
imref = Image.open("Tests/images/drawing_emf_ref.png")
imref.load()
self.assert_image_similar(im, imref, 0)
with Image.open("Tests/images/drawing.emf") as im:
if hasattr(Image.core, "drawwmf"):
# Currently, support for WMF/EMF is Windows-only
im.load()
# Compare to reference rendering
with Image.open("Tests/images/drawing_emf_ref.png") as imref:
imref.load()
self.assert_image_similar(im, imref, 0)
# Test basic WMF open and rendering
im = Image.open("Tests/images/drawing.wmf")
if hasattr(Image.core, "drawwmf"):
# Currently, support for WMF/EMF is Windows-only
im.load()
# Compare to reference rendering
imref = Image.open("Tests/images/drawing_wmf_ref.png")
imref.load()
self.assert_image_similar(im, imref, 2.0)
with Image.open("Tests/images/drawing.wmf") as im:
if hasattr(Image.core, "drawwmf"):
# Currently, support for WMF/EMF is Windows-only
im.load()
# Compare to reference rendering
with Image.open("Tests/images/drawing_wmf_ref.png") as imref:
imref.load()
self.assert_image_similar(im, imref, 2.0)
def test_register_handler(self):
class TestHandler:
@ -46,12 +46,12 @@ class TestFileWmf(PillowTestCase):
def test_load_dpi_rounding(self):
# Round up
im = Image.open("Tests/images/drawing.emf")
self.assertEqual(im.info["dpi"], 1424)
with Image.open("Tests/images/drawing.emf") as im:
self.assertEqual(im.info["dpi"], 1424)
# Round down
im = Image.open("Tests/images/drawing_roundDown.emf")
self.assertEqual(im.info["dpi"], 1426)
with Image.open("Tests/images/drawing_roundDown.emf") as im:
self.assertEqual(im.info["dpi"], 1426)
def test_save(self):
im = hopper()

View File

@ -1,3 +1,5 @@
from io import BytesIO
from PIL import Image
from .helper import PillowTestCase
@ -28,13 +30,10 @@ static char basic_bits[] = {
class TestFileXbm(PillowTestCase):
def test_pil151(self):
from io import BytesIO
im = Image.open(BytesIO(PIL151))
im.load()
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (32, 32))
with Image.open(BytesIO(PIL151)) as im:
im.load()
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (32, 32))
def test_open(self):
# Arrange
@ -42,11 +41,11 @@ class TestFileXbm(PillowTestCase):
filename = "Tests/images/hopper.xbm"
# Act
im = Image.open(filename)
with Image.open(filename) as im:
# Assert
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (128, 128))
# Assert
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (128, 128))
def test_open_filename_with_underscore(self):
# Arrange
@ -54,8 +53,8 @@ class TestFileXbm(PillowTestCase):
filename = "Tests/images/hopper_underscore.xbm"
# Act
im = Image.open(filename)
with Image.open(filename) as im:
# Assert
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (128, 128))
# Assert
self.assertEqual(im.mode, "1")
self.assertEqual(im.size, (128, 128))

View File

@ -7,14 +7,14 @@ TEST_FILE = "Tests/images/hopper.xpm"
class TestFileXpm(PillowTestCase):
def test_sanity(self):
im = Image.open(TEST_FILE)
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "XPM")
with Image.open(TEST_FILE) as im:
im.load()
self.assertEqual(im.mode, "P")
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.format, "XPM")
# large error due to quantization->44 colors.
self.assert_image_similar(im.convert("RGB"), hopper("RGB"), 60)
# large error due to quantization->44 colors.
self.assert_image_similar(im.convert("RGB"), hopper("RGB"), 60)
def test_invalid_file(self):
invalid_file = "Tests/images/flower.jpg"
@ -23,11 +23,11 @@ class TestFileXpm(PillowTestCase):
def test_load_read(self):
# Arrange
im = Image.open(TEST_FILE)
dummy_bytes = 1
with Image.open(TEST_FILE) as im:
dummy_bytes = 1
# Act
data = im.load_read(dummy_bytes)
# Act
data = im.load_read(dummy_bytes)
# Assert
self.assertEqual(len(data), 16384)

View File

@ -8,14 +8,14 @@ TEST_FILE = "Tests/images/hopper.p7"
class TestFileXVThumb(PillowTestCase):
def test_open(self):
# Act
im = Image.open(TEST_FILE)
with Image.open(TEST_FILE) as im:
# Assert
self.assertEqual(im.format, "XVThumb")
# Assert
self.assertEqual(im.format, "XVThumb")
# Create a Hopper image with a similar XV palette
im_hopper = hopper().quantize(palette=im)
self.assert_image_similar(im, im_hopper, 9)
# Create a Hopper image with a similar XV palette
im_hopper = hopper().quantize(palette=im)
self.assert_image_similar(im, im_hopper, 9)
def test_unexpected_eof(self):
# Test unexpected EOF reading XV thumbnail file

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