Merge branch 'main' into pdf

This commit is contained in:
Andrew Murray 2023-03-12 23:31:26 +11:00
commit 36ee817329
205 changed files with 955 additions and 909 deletions

View File

@ -21,9 +21,11 @@ environment:
install: install:
- '%PYTHON%\%EXECUTABLE% --version' - '%PYTHON%\%EXECUTABLE% --version'
- curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/main.zip - curl -fsSL -o pillow-depends.zip https://github.com/python-pillow/pillow-depends/archive/main.zip
- curl -fsSL -o pillow-test-images.zip https://github.com/python-pillow/test-images/archive/main.zip
- 7z x pillow-depends.zip -oc:\ - 7z x pillow-depends.zip -oc:\
- 7z x pillow-test-images.zip -oc:\
- mv c:\pillow-depends-main c:\pillow-depends - mv c:\pillow-depends-main c:\pillow-depends
- xcopy /S /Y c:\pillow-depends\test_images\* c:\pillow\tests\images - xcopy /S /Y c:\test-images-main\* c:\pillow\tests\images
- 7z x ..\pillow-depends\nasm-2.15.05-win64.zip -oc:\ - 7z x ..\pillow-depends\nasm-2.15.05-win64.zip -oc:\
- ..\pillow-depends\gs1000w32.exe /S - ..\pillow-depends\gs1000w32.exe /S
- path c:\nasm-2.15.05;C:\Program Files (x86)\gs\gs10.0.0\bin;%PATH% - path c:\nasm-2.15.05;C:\Program Files (x86)\gs\gs10.0.0\bin;%PATH%

View File

@ -37,7 +37,8 @@ python3 -m pip install -U pytest-timeout
python3 -m pip install pyroma python3 -m pip install pyroma
if [[ $(uname) != CYGWIN* ]]; then if [[ $(uname) != CYGWIN* ]]; then
python3 -m pip install numpy # TODO Remove condition when NumPy supports 3.12
if ! [ "$GHA_PYTHON_VERSION" == "3.12-dev" ]; then python3 -m pip install numpy ; fi
# PyQt6 doesn't support PyPy3 # PyQt6 doesn't support PyPy3
if [[ $GHA_PYTHON_VERSION == 3.* ]]; then if [[ $GHA_PYTHON_VERSION == 3.* ]]; then

View File

@ -3,10 +3,12 @@ name: CIFuzz
on: on:
push: push:
paths: paths:
- ".github/workflows/cifuzz.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
pull_request: pull_request:
paths: paths:
- ".github/workflows/cifuzz.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
workflow_dispatch: workflow_dispatch:
@ -14,7 +16,7 @@ on:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

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

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

View File

@ -13,7 +13,8 @@ python3 -m pip install -U pytest-cov
python3 -m pip install -U pytest-timeout python3 -m pip install -U pytest-timeout
python3 -m pip install pyroma python3 -m pip install pyroma
python3 -m pip install numpy # TODO Remove condition when NumPy supports 3.12
if ! [ "$GHA_PYTHON_VERSION" == "3.12-dev" ]; then python3 -m pip install numpy ; fi
# extra test images # extra test images
pushd depends && ./install_extra_test_images.sh && popd pushd depends && ./install_extra_test_images.sh && popd

View File

@ -1,6 +1,15 @@
name: Test Cygwin name: Test Cygwin
on: [push, pull_request, workflow_dispatch] on:
push:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -59,7 +68,7 @@ jobs:
python3${{ matrix.python-minor-version }}-sip python3${{ matrix.python-minor-version }}-sip
python3${{ matrix.python-minor-version }}-tkinter python3${{ matrix.python-minor-version }}-tkinter
qt5-devel-tools qt5-devel-tools
subversion wget
xorg-server-extra xorg-server-extra
zlib-devel zlib-devel

View File

@ -1,6 +1,15 @@
name: Test Docker name: Test Docker
on: [push, pull_request, workflow_dispatch] on:
push:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -87,6 +96,7 @@ jobs:
with: with:
flags: GHA_Docker flags: GHA_Docker
name: ${{ matrix.docker }} name: ${{ matrix.docker }}
gcov: true
success: success:
permissions: permissions:

View File

@ -1,6 +1,15 @@
name: Test MinGW name: Test MinGW
on: [push, pull_request, workflow_dispatch] on:
push:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -59,8 +68,7 @@ jobs:
${{ matrix.package }}-python3-numpy \ ${{ matrix.package }}-python3-numpy \
${{ matrix.package }}-python3-olefile \ ${{ matrix.package }}-python3-olefile \
${{ matrix.package }}-python3-pip \ ${{ matrix.package }}-python3-pip \
${{ matrix.package }}-python3-setuptools \ ${{ matrix.package }}-python3-setuptools
subversion
if [ ${{ matrix.package }} == "mingw-w64-x86_64" ]; then if [ ${{ matrix.package }} == "mingw-w64-x86_64" ]; then
pacman -S --noconfirm \ pacman -S --noconfirm \

View File

@ -5,10 +5,12 @@ name: Test Valgrind
on: on:
push: push:
paths: paths:
- ".github/workflows/test-valgrind.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
pull_request: pull_request:
paths: paths:
- ".github/workflows/test-valgrind.yml"
- "**.c" - "**.c"
- "**.h" - "**.h"
workflow_dispatch: workflow_dispatch:
@ -16,7 +18,7 @@ on:
permissions: permissions:
contents: read contents: read
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true

View File

@ -1,6 +1,15 @@
name: Test Windows name: Test Windows
on: [push, pull_request, workflow_dispatch] on:
push:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -15,7 +24,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12-dev"]
architecture: ["x86", "x64"] architecture: ["x86", "x64"]
include: include:
# PyPy 7.3.4+ only ships 64-bit binaries for Windows # PyPy 7.3.4+ only ships 64-bit binaries for Windows
@ -38,6 +47,12 @@ jobs:
repository: python-pillow/pillow-depends repository: python-pillow/pillow-depends
path: winbuild\depends path: winbuild\depends
- name: Checkout extra test images
uses: actions/checkout@v3
with:
repository: python-pillow/test-images
path: Tests\test-images
# sets env: pythonLocation # sets env: pythonLocation
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
@ -62,7 +77,8 @@ jobs:
winbuild\depends\gs1000w32.exe /S winbuild\depends\gs1000w32.exe /S
echo "C:\Program Files (x86)\gs\gs10.0.0\bin" >> $env:GITHUB_PATH echo "C:\Program Files (x86)\gs\gs10.0.0\bin" >> $env:GITHUB_PATH
xcopy /S /Y winbuild\depends\test_images\* Tests\images\ # Install extra test images
xcopy /S /Y Tests\test-images\* Tests\images
# make cache key depend on VS version # make cache key depend on VS version
& "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" ` & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" `

View File

@ -1,6 +1,15 @@
name: Test name: Test
on: [push, pull_request, workflow_dispatch] on:
push:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
pull_request:
paths-ignore:
- ".github/workflows/docs.yml"
- "docs/**"
workflow_dispatch:
permissions: permissions:
contents: read contents: read
@ -22,6 +31,7 @@ jobs:
python-version: [ python-version: [
"pypy3.9", "pypy3.9",
"pypy3.8", "pypy3.8",
"3.12-dev",
"3.11", "3.11",
"3.10", "3.10",
"3.9", "3.9",
@ -95,11 +105,6 @@ jobs:
name: errors name: errors
path: Tests/errors path: Tests/errors
- name: Docs
if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.11
run: |
make doccheck
- name: After success - name: After success
run: | run: |
.ci/after_success.sh .ci/after_success.sh
@ -107,9 +112,9 @@ jobs:
- name: Upload coverage - name: Upload coverage
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
with: with:
file: ./coverage.xml
flags: ${{ matrix.os == 'macos-latest' && 'GHA_macOS' || 'GHA_Ubuntu' }} flags: ${{ matrix.os == 'macos-latest' && 'GHA_macOS' || 'GHA_Ubuntu' }}
name: ${{ matrix.os }} Python ${{ matrix.python-version }} name: ${{ matrix.os }} Python ${{ matrix.python-version }}
gcov: true
success: success:
permissions: permissions:

2
.gitignore vendored
View File

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

View File

@ -1,6 +1,6 @@
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.12.0 rev: 23.1.0
hooks: hooks:
- id: black - id: black
args: [--target-version=py37] args: [--target-version=py37]

View File

@ -5,6 +5,39 @@ Changelog (Pillow)
9.5.0 (unreleased) 9.5.0 (unreleased)
------------------ ------------------
- Close OleFileIO instance when closing or exiting FPX or MIC #7005
[radarhere]
- Added __int__ to IFDRational for Python >= 3.11 #6998
[radarhere]
- Added memoryview support to Dib.frombytes() #6988
[radarhere, nulano]
- Close file pointer copy in the libtiff encoder if still open #6986
[fcarron, radarhere]
- Raise an error if ImageDraw co-ordinates are incorrectly ordered #6978
[radarhere]
- Added "corners" argument to ImageDraw rounded_rectangle() #6954
[radarhere]
- Added memoryview support to frombytes() #6974
[radarhere]
- Allow comments in FITS images #6973
[radarhere]
- Support saving PDF with different X and Y resolutions #6961
[jvanderneutstulen, radarhere, hugovk]
- Fixed writing int as UNDEFINED tag #6950
[radarhere]
- Raise an error if EXIF data is too long when saving JPEG #6939
[radarhere]
- Handle more than one directory returned by pkg-config #6896 - Handle more than one directory returned by pkg-config #6896
[sebastic, radarhere] [sebastic, radarhere]

View File

@ -13,8 +13,8 @@ By obtaining, using, and/or copying this software and/or its associated
documentation, you agree that you have read, understood, and will comply documentation, you agree that you have read, understood, and will comply
with the following terms and conditions: with the following terms and conditions:
Permission to use, copy, modify, and distribute this software and its Permission to use, copy, modify and distribute this software and its
associated documentation for any purpose and without fee is hereby granted, documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appears in all copies, and that provided that the above copyright notice appears in all copies, and that
both that copyright notice and this permission notice appear in supporting both that copyright notice and this permission notice appear in supporting
documentation, and that the name of Secret Labs AB or the author not be documentation, and that the name of Secret Labs AB or the author not be

View File

@ -4,7 +4,6 @@ TEST_FILE = "Tests/images/fli_overflow.fli"
def test_fli_overflow(): def test_fli_overflow():
# this should not crash with a malloc error or access violation # this should not crash with a malloc error or access violation
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
im.load() im.load()

View File

@ -23,7 +23,6 @@ def test_ignore_dos_text():
def test_dos_text(): def test_dos_text():
try: try:
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()

View File

@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)
HAS_UPLOADER = False HAS_UPLOADER = False
if os.environ.get("SHOW_ERRORS", None): if os.environ.get("SHOW_ERRORS"):
# local img.show for errors. # local img.show for errors.
HAS_UPLOADER = True HAS_UPLOADER = True
@ -271,7 +271,7 @@ def netpbm_available():
def magick_command(): def magick_command():
if sys.platform == "win32": if sys.platform == "win32":
magickhome = os.environ.get("MAGICK_HOME", "") magickhome = os.environ.get("MAGICK_HOME")
if magickhome: if magickhome:
imagemagick = [os.path.join(magickhome, "convert.exe")] imagemagick = [os.path.join(magickhome, "convert.exe")]
graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"] graphicsmagick = [os.path.join(magickhome, "gm.exe"), "convert"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 B

View File

@ -18,7 +18,6 @@ def test_bad():
"""These shouldn't crash/dos, but they shouldn't return anything """These shouldn't crash/dos, but they shouldn't return anything
either""" either"""
for f in get_files("b"): for f in get_files("b"):
# Assert that there is no unclosed file warning # Assert that there is no unclosed file warning
with warnings.catch_warnings(): with warnings.catch_warnings():
try: try:

View File

@ -177,13 +177,14 @@ class TestEnvVars:
Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"}) Image._apply_env_variables({"PILLOW_BLOCK_SIZE": "2m"})
assert Image.core.get_block_size() == 2 * 1024 * 1024 assert Image.core.get_block_size() == 2 * 1024 * 1024
def test_warnings(self): @pytest.mark.parametrize(
pytest.warns( "var",
UserWarning, Image._apply_env_variables, {"PILLOW_ALIGNMENT": "15"} (
) {"PILLOW_ALIGNMENT": "15"},
pytest.warns( {"PILLOW_BLOCK_SIZE": "1024"},
UserWarning, Image._apply_env_variables, {"PILLOW_BLOCK_SIZE": "1024"} {"PILLOW_BLOCKS_MAX": "wat"},
) ),
pytest.warns( )
UserWarning, Image._apply_env_variables, {"PILLOW_BLOCKS_MAX": "wat"} def test_warnings(self, var):
) with pytest.warns(UserWarning):
Image._apply_env_variables(var)

View File

@ -36,12 +36,10 @@ class TestDecompressionBomb:
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1 Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1 assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1
def open(): with pytest.warns(Image.DecompressionBombWarning):
with Image.open(TEST_FILE): with Image.open(TEST_FILE):
pass pass
pytest.warns(Image.DecompressionBombWarning, open)
def test_exception(self): def test_exception(self):
# Set limit to trigger exception on the test file # Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1 Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
@ -87,7 +85,8 @@ class TestDecompressionCrop:
# same decompression bomb warnings on them. # same decompression bomb warnings on them.
with hopper() as src: with hopper() as src:
box = (0, 0, src.width * 2, src.height * 2) box = (0, 0, src.width * 2, src.height * 2)
pytest.warns(Image.DecompressionBombWarning, src.crop, box) with pytest.warns(Image.DecompressionBombWarning):
src.crop(box)
def test_crop_decompression_checks(self): def test_crop_decompression_checks(self):
im = Image.new("RGB", (100, 100)) im = Image.new("RGB", (100, 100))
@ -95,7 +94,8 @@ class TestDecompressionCrop:
for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)): for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)):
assert im.crop(value).size == (9, 9) assert im.crop(value).size == (9, 9)
pytest.warns(Image.DecompressionBombWarning, im.crop, (-160, -160, 99, 99)) with pytest.warns(Image.DecompressionBombWarning):
im.crop((-160, -160, 99, 99))
with pytest.raises(Image.DecompressionBombError): with pytest.raises(Image.DecompressionBombError):
im.crop((-99909, -99990, 99999, 99999)) im.crop((-99909, -99990, 99999, 99999))

View File

@ -263,13 +263,11 @@ def test_apng_chunk_errors():
with Image.open("Tests/images/apng/chunk_no_actl.png") as im: with Image.open("Tests/images/apng/chunk_no_actl.png") as im:
assert not im.is_animated assert not im.is_animated
def open(): with pytest.warns(UserWarning):
with Image.open("Tests/images/apng/chunk_multi_actl.png") as im: with Image.open("Tests/images/apng/chunk_multi_actl.png") as im:
im.load() im.load()
assert not im.is_animated assert not im.is_animated
pytest.warns(UserWarning, open)
with Image.open("Tests/images/apng/chunk_actl_after_idat.png") as im: with Image.open("Tests/images/apng/chunk_actl_after_idat.png") as im:
assert not im.is_animated assert not im.is_animated
@ -287,21 +285,17 @@ def test_apng_chunk_errors():
def test_apng_syntax_errors(): def test_apng_syntax_errors():
def open_frames_zero(): with pytest.warns(UserWarning):
with Image.open("Tests/images/apng/syntax_num_frames_zero.png") as im: with Image.open("Tests/images/apng/syntax_num_frames_zero.png") as im:
assert not im.is_animated assert not im.is_animated
with pytest.raises(OSError): with pytest.raises(OSError):
im.load() im.load()
pytest.warns(UserWarning, open_frames_zero) with pytest.warns(UserWarning):
def open_frames_zero_default():
with Image.open("Tests/images/apng/syntax_num_frames_zero_default.png") as im: with Image.open("Tests/images/apng/syntax_num_frames_zero_default.png") as im:
assert not im.is_animated assert not im.is_animated
im.load() im.load()
pytest.warns(UserWarning, open_frames_zero_default)
# we can handle this case gracefully # we can handle this case gracefully
exception = None exception = None
with Image.open("Tests/images/apng/syntax_num_frames_low.png") as im: with Image.open("Tests/images/apng/syntax_num_frames_low.png") as im:
@ -316,13 +310,11 @@ def test_apng_syntax_errors():
im.seek(im.n_frames - 1) im.seek(im.n_frames - 1)
im.load() im.load()
def open(): with pytest.warns(UserWarning):
with Image.open("Tests/images/apng/syntax_num_frames_invalid.png") as im: with Image.open("Tests/images/apng/syntax_num_frames_invalid.png") as im:
assert not im.is_animated assert not im.is_animated
im.load() im.load()
pytest.warns(UserWarning, open)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"test_file", "test_file",

View File

@ -141,7 +141,6 @@ def test_rgba_bitfields():
# This test image has been manually hexedited # This test image has been manually hexedited
# to change the bitfield compression in the header from XBGR to RGBA # to change the bitfield compression in the header from XBGR to RGBA
with Image.open("Tests/images/rgb32bf-rgba.bmp") as im: with Image.open("Tests/images/rgb32bf-rgba.bmp") as im:
# So before the comparing the image, swap the channels # So before the comparing the image, swap the channels
b, g, r = im.split()[1:] b, g, r = im.split()[1:]
im = Image.merge("RGB", (r, g, b)) im = Image.merge("RGB", (r, g, b))

View File

@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/gfs.t06z.rassda.tm00.bufr_d"
def test_open(): def test_open():
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert im.format == "BUFR" assert im.format == "BUFR"
@ -31,7 +30,6 @@ def test_invalid_file():
def test_load(): def test_load():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler # Act / Assert: stub cannot load without an implemented handler
with pytest.raises(OSError): with pytest.raises(OSError):
im.load() im.load()
@ -58,6 +56,7 @@ def test_handler(tmp_path):
def load(self, im): def load(self, im):
self.loaded = True self.loaded = True
im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
def save(self, im, fp, filename): def save(self, im, fp, filename):

View File

@ -15,7 +15,6 @@ def test_sanity():
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert im.size == (128, 128) assert im.size == (128, 128)
assert isinstance(im, DcxImagePlugin.DcxImageFile) assert isinstance(im, DcxImagePlugin.DcxImageFile)
@ -29,7 +28,8 @@ def test_unclosed_file():
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():
@ -54,7 +54,6 @@ def test_invalid_file():
def test_tell(): def test_tell():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act # Act
frame = im.tell() frame = im.tell()

View File

@ -80,7 +80,6 @@ def test_invalid_file():
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available") @pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
def test_cmyk(): def test_cmyk():
with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image: with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image:
assert cmyk_image.mode == "CMYK" assert cmyk_image.mode == "CMYK"
assert cmyk_image.size == (100, 100) assert cmyk_image.size == (100, 100)
assert cmyk_image.format == "EPS" assert cmyk_image.format == "EPS"

View File

@ -12,7 +12,6 @@ TEST_FILE = "Tests/images/hopper.fits"
def test_open(): def test_open():
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert im.format == "FITS" assert im.format == "FITS"
assert im.size == (128, 128) assert im.size == (128, 128)
@ -45,6 +44,12 @@ def test_naxis_zero():
pass pass
def test_comment():
image_data = b"SIMPLE = T / comment string"
with pytest.raises(OSError):
FitsImagePlugin.FitsImageFile(BytesIO(image_data))
def test_stub_deprecated(): def test_stub_deprecated():
class Handler: class Handler:
opened = False opened = False
@ -55,6 +60,7 @@ def test_stub_deprecated():
def load(self, im): def load(self, im):
self.loaded = True self.loaded = True
im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
handler = Handler() handler = Handler()

View File

@ -36,7 +36,8 @@ def test_unclosed_file():
im = Image.open(static_test_file) im = Image.open(static_test_file)
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():
@ -64,7 +65,6 @@ def test_context_manager():
def test_tell(): def test_tell():
# Arrange # Arrange
with Image.open(static_test_file) as im: with Image.open(static_test_file) as im:
# Act # Act
frame = im.tell() frame = im.tell()
@ -110,7 +110,6 @@ def test_eoferror():
def test_seek_tell(): def test_seek_tell():
with Image.open(animated_test_file) as im: with Image.open(animated_test_file) as im:
layer_number = im.tell() layer_number = im.tell()
assert layer_number == 0 assert layer_number == 0

View File

@ -18,6 +18,16 @@ def test_sanity():
assert_image_equal_tofile(im, "Tests/images/input_bw_one_band.png") assert_image_equal_tofile(im, "Tests/images/input_bw_one_band.png")
def test_close():
with Image.open("Tests/images/input_bw_one_band.fpx") as im:
pass
assert im.ole.fp.closed
im = Image.open("Tests/images/input_bw_one_band.fpx")
im.close()
assert im.ole.fp.closed
def test_invalid_file(): def test_invalid_file():
# Test an invalid OLE file # Test an invalid OLE file
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"

View File

@ -36,7 +36,8 @@ def test_unclosed_file():
im = Image.open(TEST_GIF) im = Image.open(TEST_GIF)
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():
@ -209,7 +210,7 @@ def test_optimize_if_palette_can_be_reduced_by_half():
im = im.resize((591, 443)) im = im.resize((591, 443))
im_rgb = im.convert("RGB") im_rgb = im.convert("RGB")
for (optimize, colors) in ((False, 256), (True, 8)): for optimize, colors in ((False, 256), (True, 8)):
out = BytesIO() out = BytesIO()
im_rgb.save(out, "GIF", optimize=optimize) im_rgb.save(out, "GIF", optimize=optimize)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
@ -221,7 +222,6 @@ def test_roundtrip(tmp_path):
im = hopper() im = hopper()
im.save(out) im.save(out)
with Image.open(out) as reread: with Image.open(out) as reread:
assert_image_similar(reread.convert("RGB"), im, 50) assert_image_similar(reread.convert("RGB"), im, 50)
@ -232,7 +232,6 @@ def test_roundtrip2(tmp_path):
im2 = im.copy() im2 = im.copy()
im2.save(out) im2.save(out)
with Image.open(out) as reread: with Image.open(out) as reread:
assert_image_similar(reread.convert("RGB"), hopper(), 50) assert_image_similar(reread.convert("RGB"), hopper(), 50)
@ -242,7 +241,6 @@ def test_roundtrip_save_all(tmp_path):
im = hopper() im = hopper()
im.save(out, save_all=True) im.save(out, save_all=True)
with Image.open(out) as reread: with Image.open(out) as reread:
assert_image_similar(reread.convert("RGB"), im, 50) assert_image_similar(reread.convert("RGB"), im, 50)
# Multiframe image # Multiframe image
@ -284,13 +282,11 @@ def test_headers_saving_for_animated_gifs(tmp_path):
important_headers = ["background", "version", "duration", "loop"] important_headers = ["background", "version", "duration", "loop"]
# Multiframe image # Multiframe image
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
info = im.info.copy() info = im.info.copy()
out = str(tmp_path / "temp.gif") out = str(tmp_path / "temp.gif")
im.save(out, save_all=True) im.save(out, save_all=True)
with Image.open(out) as reread: with Image.open(out) as reread:
for header in important_headers: for header in important_headers:
assert info[header] == reread.info[header] assert info[header] == reread.info[header]
@ -308,7 +304,6 @@ def test_palette_handling(tmp_path):
im2.save(f, optimize=True) im2.save(f, optimize=True)
with Image.open(f) as reloaded: with Image.open(f) as reloaded:
assert_image_similar(im, reloaded.convert("RGB"), 10) assert_image_similar(im, reloaded.convert("RGB"), 10)
@ -324,7 +319,6 @@ def test_palette_434(tmp_path):
orig = "Tests/images/test.colors.gif" orig = "Tests/images/test.colors.gif"
with Image.open(orig) as im: with Image.open(orig) as im:
with roundtrip(im) as reloaded: with roundtrip(im) as reloaded:
assert_image_similar(im, reloaded, 1) assert_image_similar(im, reloaded, 1)
with roundtrip(im, optimize=True) as reloaded: with roundtrip(im, optimize=True) as reloaded:
@ -575,7 +569,6 @@ def test_save_dispose(tmp_path):
) )
with Image.open(out) as img: with Image.open(out) as img:
for i in range(2): for i in range(2):
img.seek(img.tell() + 1) img.seek(img.tell() + 1)
assert img.disposal_method == i + 1 assert img.disposal_method == i + 1
@ -773,7 +766,6 @@ def test_multiple_duration(tmp_path):
out, save_all=True, append_images=im_list[1:], duration=duration_list out, save_all=True, append_images=im_list[1:], duration=duration_list
) )
with Image.open(out) as reread: with Image.open(out) as reread:
for duration in duration_list: for duration in duration_list:
assert reread.info["duration"] == duration assert reread.info["duration"] == duration
try: try:
@ -786,7 +778,6 @@ def test_multiple_duration(tmp_path):
out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list) out, save_all=True, append_images=im_list[1:], duration=tuple(duration_list)
) )
with Image.open(out) as reread: with Image.open(out) as reread:
for duration in duration_list: for duration in duration_list:
assert reread.info["duration"] == duration assert reread.info["duration"] == duration
try: try:
@ -844,7 +835,6 @@ def test_identical_frames(tmp_path):
out, save_all=True, append_images=im_list[1:], duration=duration_list out, save_all=True, append_images=im_list[1:], duration=duration_list
) )
with Image.open(out) as reread: with Image.open(out) as reread:
# Assert that the first three frames were combined # Assert that the first three frames were combined
assert reread.n_frames == 2 assert reread.n_frames == 2
@ -1098,7 +1088,8 @@ def test_rgb_transparency(tmp_path):
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
im.info["transparency"] = b"" im.info["transparency"] = b""
ims = [Image.new("RGB", (1, 1))] ims = [Image.new("RGB", (1, 1))]
pytest.warns(UserWarning, im.save, out, save_all=True, append_images=ims) with pytest.warns(UserWarning):
im.save(out, save_all=True, append_images=ims)
with Image.open(out) as reloaded: with Image.open(out) as reloaded:
assert "transparency" not in reloaded.info assert "transparency" not in reloaded.info

View File

@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/WAlaska.wind.7days.grb"
def test_open(): def test_open():
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert im.format == "GRIB" assert im.format == "GRIB"
@ -31,7 +30,6 @@ def test_invalid_file():
def test_load(): def test_load():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler # Act / Assert: stub cannot load without an implemented handler
with pytest.raises(OSError): with pytest.raises(OSError):
im.load() im.load()
@ -58,6 +56,7 @@ def test_handler(tmp_path):
def load(self, im): def load(self, im):
self.loaded = True self.loaded = True
im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
def save(self, im, fp, filename): def save(self, im, fp, filename):

View File

@ -8,7 +8,6 @@ TEST_FILE = "Tests/images/hdf5.h5"
def test_open(): def test_open():
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert im.format == "HDF5" assert im.format == "HDF5"
@ -29,7 +28,6 @@ def test_invalid_file():
def test_load(): def test_load():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act / Assert: stub cannot load without an implemented handler # Act / Assert: stub cannot load without an implemented handler
with pytest.raises(OSError): with pytest.raises(OSError):
im.load() im.load()
@ -59,6 +57,7 @@ def test_handler(tmp_path):
def load(self, im): def load(self, im):
self.loaded = True self.loaded = True
im.fp.close()
return Image.new("RGB", (1, 1)) return Image.new("RGB", (1, 1))
def save(self, im, fp, filename): def save(self, im, fp, filename):

View File

@ -16,7 +16,6 @@ def test_sanity():
# Loading this icon by default should result in the largest size # Loading this icon by default should result in the largest size
# (512x512@2x) being loaded # (512x512@2x) being loaded
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert that there is no unclosed file warning # Assert that there is no unclosed file warning
with warnings.catch_warnings(): with warnings.catch_warnings():
im.load() im.load()

View File

@ -175,7 +175,6 @@ def test_save_256x256(tmp_path):
# Act # Act
im.save(outfile) im.save(outfile)
with Image.open(outfile) as im_saved: with Image.open(outfile) as im_saved:
# Assert # Assert
assert im_saved.size == (256, 256) assert im_saved.size == (256, 256)
@ -213,12 +212,10 @@ def test_save_append_images(tmp_path):
def test_unexpected_size(): def test_unexpected_size():
# This image has been manually hexedited to state that it is 16x32 # This image has been manually hexedited to state that it is 16x32
# while the image within is still 16x16 # while the image within is still 16x16
def open(): with pytest.warns(UserWarning):
with Image.open("Tests/images/hopper_unexpected.ico") as im: with Image.open("Tests/images/hopper_unexpected.ico") as im:
assert im.size == (16, 16) assert im.size == (16, 16)
pytest.warns(UserWarning, open)
def test_draw_reloaded(tmp_path): def test_draw_reloaded(tmp_path):
with Image.open(TEST_ICO_FILE) as im: with Image.open(TEST_ICO_FILE) as im:

View File

@ -32,7 +32,8 @@ def test_unclosed_file():
im = Image.open(TEST_IM) im = Image.open(TEST_IM)
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():
@ -51,7 +52,6 @@ def test_context_manager():
def test_tell(): def test_tell():
# Arrange # Arrange
with Image.open(TEST_IM) as im: with Image.open(TEST_IM) as im:
# Act # Act
frame = im.tell() frame = im.tell()

View File

@ -11,7 +11,6 @@ TEST_FILE = "Tests/images/iptc.jpg"
def test_getiptcinfo_jpg_none(): def test_getiptcinfo_jpg_none():
# Arrange # Arrange
with hopper() as im: with hopper() as im:
# Act # Act
iptc = IptcImagePlugin.getiptcinfo(im) iptc = IptcImagePlugin.getiptcinfo(im)
@ -22,7 +21,6 @@ def test_getiptcinfo_jpg_none():
def test_getiptcinfo_jpg_found(): def test_getiptcinfo_jpg_found():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act # Act
iptc = IptcImagePlugin.getiptcinfo(im) iptc = IptcImagePlugin.getiptcinfo(im)
@ -35,7 +33,6 @@ def test_getiptcinfo_jpg_found():
def test_getiptcinfo_tiff_none(): def test_getiptcinfo_tiff_none():
# Arrange # Arrange
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
# Act # Act
iptc = IptcImagePlugin.getiptcinfo(im) iptc = IptcImagePlugin.getiptcinfo(im)

View File

@ -57,7 +57,6 @@ class TestFileJpeg:
return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode))) return Image.frombytes(mode, size, os.urandom(size[0] * size[1] * len(mode)))
def test_sanity(self): def test_sanity(self):
# internal version number # internal version number
assert re.search(r"\d+\.\d+$", features.version_codec("jpg")) assert re.search(r"\d+\.\d+$", features.version_codec("jpg"))
@ -271,7 +270,10 @@ class TestFileJpeg:
# https://github.com/python-pillow/Pillow/issues/148 # https://github.com/python-pillow/Pillow/issues/148
f = str(tmp_path / "temp.jpg") f = str(tmp_path / "temp.jpg")
im = hopper() im = hopper()
im.save(f, "JPEG", quality=90, exif=b"1" * 65532) im.save(f, "JPEG", quality=90, exif=b"1" * 65533)
with pytest.raises(ValueError):
im.save(f, "JPEG", quality=90, exif=b"1" * 65534)
def test_exif_typeerror(self): def test_exif_typeerror(self):
with Image.open("Tests/images/exif_typeerror.jpg") as im: with Image.open("Tests/images/exif_typeerror.jpg") as im:
@ -368,7 +370,6 @@ class TestFileJpeg:
def test_exif_gps_typeerror(self): def test_exif_gps_typeerror(self):
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im: with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
# Should not raise a TypeError # Should not raise a TypeError
im._getexif() im._getexif()
@ -447,7 +448,7 @@ class TestFileJpeg:
ims = im.get_child_images() ims = im.get_child_images()
assert len(ims) == 1 assert len(ims) == 1
assert_image_equal_tofile(ims[0], "Tests/images/flower_thumbnail.png") assert_image_similar_tofile(ims[0], "Tests/images/flower_thumbnail.png", 2.1)
def test_mp(self): def test_mp(self):
with Image.open("Tests/images/pil_sample_rgb.jpg") as im: with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
@ -682,7 +683,6 @@ class TestFileJpeg:
# Shouldn't raise error # Shouldn't raise error
fn = "Tests/images/sugarshack_bad_mpo_header.jpg" fn = "Tests/images/sugarshack_bad_mpo_header.jpg"
with pytest.warns(UserWarning, Image.open, fn) as im: with pytest.warns(UserWarning, Image.open, fn) as im:
# Assert # Assert
assert im.format == "JPEG" assert im.format == "JPEG"
@ -704,7 +704,6 @@ class TestFileJpeg:
# Arrange # Arrange
outfile = str(tmp_path / "temp.tif") outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/hopper.tif") as im: with Image.open("Tests/images/hopper.tif") as im:
# Act # Act
im.save(outfile, "JPEG", dpi=im.info["dpi"]) im.save(outfile, "JPEG", dpi=im.info["dpi"])
@ -731,7 +730,6 @@ class TestFileJpeg:
# This Photoshop CC 2017 image has DPI in EXIF not metadata # This Photoshop CC 2017 image has DPI in EXIF not metadata
# EXIF XResolution is (2000000, 10000) # EXIF XResolution is (2000000, 10000)
with Image.open("Tests/images/photoshop-200dpi.jpg") as im: with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
# Act / Assert # Act / Assert
assert im.info.get("dpi") == (200, 200) assert im.info.get("dpi") == (200, 200)
@ -740,7 +738,6 @@ class TestFileJpeg:
# This image has DPI in EXIF not metadata # This image has DPI in EXIF not metadata
# EXIF XResolution is 72 # EXIF XResolution is 72
with Image.open("Tests/images/exif-72dpi-int.jpg") as im: with Image.open("Tests/images/exif-72dpi-int.jpg") as im:
# Act / Assert # Act / Assert
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
@ -749,7 +746,6 @@ class TestFileJpeg:
# This is photoshop-200dpi.jpg with EXIF resolution unit set to cm: # This is photoshop-200dpi.jpg with EXIF resolution unit set to cm:
# exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg # exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg
with Image.open("Tests/images/exif-200dpcm.jpg") as im: with Image.open("Tests/images/exif-200dpcm.jpg") as im:
# Act / Assert # Act / Assert
assert im.info.get("dpi") == (508, 508) assert im.info.get("dpi") == (508, 508)
@ -758,7 +754,6 @@ class TestFileJpeg:
# This is photoshop-200dpi.jpg with EXIF resolution set to 0/0: # This is photoshop-200dpi.jpg with EXIF resolution set to 0/0:
# exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg # exiftool -XResolution=0/0 -YResolution=0/0 photoshop-200dpi.jpg
with Image.open("Tests/images/exif-dpi-zerodivision.jpg") as im: with Image.open("Tests/images/exif-dpi-zerodivision.jpg") as im:
# Act / Assert # Act / Assert
# This should return the default, and not raise a ZeroDivisionError # This should return the default, and not raise a ZeroDivisionError
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
@ -767,7 +762,6 @@ class TestFileJpeg:
# Arrange # Arrange
# 0x011A tag in this exif contains string '300300\x02' # 0x011A tag in this exif contains string '300300\x02'
with Image.open("Tests/images/broken_exif_dpi.jpg") as im: with Image.open("Tests/images/broken_exif_dpi.jpg") as im:
# Act / Assert # Act / Assert
# This should return the default # This should return the default
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
@ -777,7 +771,6 @@ class TestFileJpeg:
# This is photoshop-200dpi.jpg with resolution removed from EXIF: # This is photoshop-200dpi.jpg with resolution removed from EXIF:
# exiftool "-*resolution*"= photoshop-200dpi.jpg # exiftool "-*resolution*"= photoshop-200dpi.jpg
with Image.open("Tests/images/no-dpi-in-exif.jpg") as im: with Image.open("Tests/images/no-dpi-in-exif.jpg") as im:
# Act / Assert # Act / Assert
# "When the image resolution is unknown, 72 [dpi] is designated." # "When the image resolution is unknown, 72 [dpi] is designated."
# https://exiv2.org/tags.html # https://exiv2.org/tags.html
@ -787,7 +780,6 @@ class TestFileJpeg:
# This is no-dpi-in-exif with the tiff header of the exif block # This is no-dpi-in-exif with the tiff header of the exif block
# hexedited from MM * to FF FF FF FF # hexedited from MM * to FF FF FF FF
with Image.open("Tests/images/invalid-exif.jpg") as im: with Image.open("Tests/images/invalid-exif.jpg") as im:
# This should return the default, and not a SyntaxError or # This should return the default, and not a SyntaxError or
# OSError for unidentified image. # OSError for unidentified image.
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
@ -810,7 +802,6 @@ class TestFileJpeg:
def test_invalid_exif_x_resolution(self): def test_invalid_exif_x_resolution(self):
# When no x or y resolution is defined in EXIF # When no x or y resolution is defined in EXIF
with Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") as im: with Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") as im:
# This should return the default, and not a ValueError or # This should return the default, and not a ValueError or
# OSError for an unidentified image. # OSError for an unidentified image.
assert im.info.get("dpi") == (72, 72) assert im.info.get("dpi") == (72, 72)
@ -820,7 +811,6 @@ class TestFileJpeg:
# This image has been manually hexedited to have an IFD offset of 10, # This image has been manually hexedited to have an IFD offset of 10,
# in contrast to normal 8 # in contrast to normal 8
with Image.open("Tests/images/exif-ifd-offset.jpg") as im: with Image.open("Tests/images/exif-ifd-offset.jpg") as im:
# Act / Assert # Act / Assert
assert im._getexif()[306] == "2017:03:13 23:03:09" assert im._getexif()[306] == "2017:03:13 23:03:09"

View File

@ -270,7 +270,6 @@ def test_rgba():
# Arrange # Arrange
with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k: with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k:
with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2: with Image.open("Tests/images/rgb_trns_ycbc.jp2") as jp2:
# Act # Act
j2k.load() j2k.load()
jp2.load() jp2.load()

View File

@ -645,7 +645,6 @@ class TestFileLibTiff(LibTiffTestCase):
pilim = hopper() pilim = hopper()
def save_bytesio(compression=None): def save_bytesio(compression=None):
buffer_io = io.BytesIO() buffer_io = io.BytesIO()
pilim.save(buffer_io, format="tiff", compression=compression) pilim.save(buffer_io, format="tiff", compression=compression)
buffer_io.seek(0) buffer_io.seek(0)
@ -740,7 +739,6 @@ class TestFileLibTiff(LibTiffTestCase):
def test_multipage_compression(self): def test_multipage_compression(self):
with Image.open("Tests/images/compression.tif") as im: with Image.open("Tests/images/compression.tif") as im:
im.seek(0) im.seek(0)
assert im._compression == "tiff_ccitt" assert im._compression == "tiff_ccitt"
assert im.size == (10, 10) assert im.size == (10, 10)
@ -1067,3 +1065,9 @@ class TestFileLibTiff(LibTiffTestCase):
out = str(tmp_path / "temp.tif") out = str(tmp_path / "temp.tif")
with pytest.raises(SystemError): with pytest.raises(SystemError):
im.save(out, compression=compression) im.save(out, compression=compression)
def test_save_many_compressed(self, tmp_path):
im = hopper()
out = str(tmp_path / "temp.tif")
for _ in range(10000):
im.save(out, compression="jpeg")

View File

@ -51,6 +51,16 @@ def test_seek():
assert im.tell() == 0 assert im.tell() == 0
def test_close():
with Image.open(TEST_FILE) as im:
pass
assert im.ole.fp.closed
im = Image.open(TEST_FILE)
im.close()
assert im.ole.fp.closed
def test_invalid_file(): def test_invalid_file():
# Test an invalid OLE file # Test an invalid OLE file
invalid_file = "Tests/images/flower.jpg" invalid_file = "Tests/images/flower.jpg"

View File

@ -42,7 +42,8 @@ def test_unclosed_file():
im = Image.open(test_files[0]) im = Image.open(test_files[0])
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():

View File

@ -44,7 +44,6 @@ def test_open_windows_v1():
# Arrange # Arrange
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert_image_equal(im, hopper("1")) assert_image_equal(im, hopper("1"))
assert isinstance(im, MspImagePlugin.MspImageFile) assert isinstance(im, MspImagePlugin.MspImageFile)
@ -59,7 +58,6 @@ def _assert_file_image_equal(source_path, target_path):
not os.path.exists(EXTRA_DIR), reason="Extra image files not installed" not os.path.exists(EXTRA_DIR), reason="Extra image files not installed"
) )
def test_open_windows_v2(): def test_open_windows_v2():
files = ( files = (
os.path.join(EXTRA_DIR, f) os.path.join(EXTRA_DIR, f)
for f in os.listdir(EXTRA_DIR) for f in os.listdir(EXTRA_DIR)

View File

@ -85,6 +85,34 @@ def test_resolution(tmp_path):
assert size == (61.44, 61.44) assert size == (61.44, 61.44)
@pytest.mark.parametrize(
"params",
(
{"dpi": (75, 150)},
{"dpi": (75, 150), "resolution": 200},
),
)
def test_dpi(params, tmp_path):
im = hopper()
outfile = str(tmp_path / "temp.pdf")
im.save(outfile, **params)
with open(outfile, "rb") as fp:
contents = fp.read()
size = tuple(
float(d)
for d in contents.split(b"stream\nq ")[1].split(b" 0 0 cm")[0].split(b" 0 0 ")
)
assert size == (122.88, 61.44)
size = tuple(
float(d) for d in contents.split(b"/MediaBox [ 0 0 ")[1].split(b"]")[0].split()
)
assert size == (122.88, 61.44)
@mark_if_feature_version( @mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing" pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
) )
@ -94,7 +122,6 @@ def test_save_all(tmp_path):
# Multiframe image # Multiframe image
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
im.save(outfile, save_all=True) im.save(outfile, save_all=True)
@ -128,7 +155,6 @@ def test_save_all(tmp_path):
def test_multiframe_normal_save(tmp_path): def test_multiframe_normal_save(tmp_path):
# Test saving a multiframe image without save_all # Test saving a multiframe image without save_all
with Image.open("Tests/images/dispose_bgnd.gif") as im: with Image.open("Tests/images/dispose_bgnd.gif") as im:
outfile = str(tmp_path / "temp.pdf") outfile = str(tmp_path / "temp.pdf")
im.save(outfile) im.save(outfile)

View File

@ -78,7 +78,6 @@ class TestFilePng:
return chunks return chunks
def test_sanity(self, tmp_path): def test_sanity(self, tmp_path):
# internal version number # internal version number
assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", features.version_codec("zlib")) assert re.search(r"\d+\.\d+\.\d+(\.\d+)?$", features.version_codec("zlib"))
@ -156,7 +155,6 @@ class TestFilePng:
assert im.info == {"spam": "egg"} assert im.info == {"spam": "egg"}
def test_bad_itxt(self): def test_bad_itxt(self):
im = load(HEAD + chunk(b"iTXt") + TAIL) im = load(HEAD + chunk(b"iTXt") + TAIL)
assert im.info == {} assert im.info == {}
@ -201,7 +199,6 @@ class TestFilePng:
assert im.info["spam"].tkey == "Spam" assert im.info["spam"].tkey == "Spam"
def test_interlace(self): def test_interlace(self):
test_file = "Tests/images/pil123p.png" test_file = "Tests/images/pil123p.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert_image(im, "P", (162, 150)) assert_image(im, "P", (162, 150))
@ -495,7 +492,6 @@ class TestFilePng:
# Check reading images with null tRNS value, issue #1239 # Check reading images with null tRNS value, issue #1239
test_file = "Tests/images/tRNS_null_1x1.png" test_file = "Tests/images/tRNS_null_1x1.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert im.info["transparency"] == 0 assert im.info["transparency"] == 0
def test_save_icc_profile(self): def test_save_icc_profile(self):

View File

@ -27,7 +27,8 @@ def test_unclosed_file():
im = Image.open(test_file) im = Image.open(test_file)
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():
@ -77,7 +78,6 @@ def test_eoferror():
def test_seek_tell(): def test_seek_tell():
with Image.open(test_file) as im: with Image.open(test_file) as im:
layer_number = im.tell() layer_number = im.tell()
assert layer_number == 1 assert layer_number == 1
@ -95,7 +95,6 @@ def test_seek_tell():
def test_seek_eoferror(): def test_seek_eoferror():
with Image.open(test_file) as im: with Image.open(test_file) as im:
with pytest.raises(EOFError): with pytest.raises(EOFError):
im.seek(-1) im.seek(-1)

View File

@ -25,7 +25,8 @@ def test_unclosed_file():
im = Image.open(TEST_FILE) im = Image.open(TEST_FILE)
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(): def test_closed_file():
@ -79,7 +80,6 @@ def test_is_spider_image():
def test_tell(): def test_tell():
# Arrange # Arrange
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Act # Act
index = im.tell() index = im.tell()

View File

@ -16,7 +16,6 @@ def test_sanity():
# Act # Act
with Image.open(test_file) as im: with Image.open(test_file) as im:
# Assert # Assert
assert im.size == (128, 128) assert im.size == (128, 128)

View File

@ -29,11 +29,9 @@ def test_sanity(codec, test_path, format):
@pytest.mark.skipif(is_pypy(), reason="Requires CPython") @pytest.mark.skipif(is_pypy(), reason="Requires CPython")
def test_unclosed_file(): def test_unclosed_file():
def open(): with pytest.warns(ResourceWarning):
TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg") TarIO.TarIO(TEST_TAR_FILE, "hopper.jpg")
pytest.warns(ResourceWarning, open)
def test_close(): def test_close():
with warnings.catch_warnings(): with warnings.catch_warnings():

View File

@ -78,7 +78,6 @@ def test_id_field():
# Act # Act
with Image.open(test_file) as im: with Image.open(test_file) as im:
# Assert # Assert
assert im.size == (100, 100) assert im.size == (100, 100)
@ -89,7 +88,6 @@ def test_id_field_rle():
# Act # Act
with Image.open(test_file) as im: with Image.open(test_file) as im:
# Assert # Assert
assert im.size == (199, 199) assert im.size == (199, 199)
@ -165,13 +163,14 @@ def test_save_id_section(tmp_path):
# Save with custom id section greater than 255 characters # Save with custom id section greater than 255 characters
id_section = b"Test content" * 25 id_section = b"Test content" * 25
pytest.warns(UserWarning, lambda: im.save(out, id_section=id_section)) with pytest.warns(UserWarning):
im.save(out, id_section=id_section)
with Image.open(out) as test_im: with Image.open(out) as test_im:
assert test_im.info["id_section"] == id_section[:255] assert test_im.info["id_section"] == id_section[:255]
test_file = "Tests/images/tga_id_field.tga" test_file = "Tests/images/tga_id_field.tga"
with Image.open(test_file) as im: with Image.open(test_file) as im:
# Save with no id section # Save with no id section
im.save(out, id_section="") im.save(out, id_section="")
with Image.open(out) as test_im: with Image.open(out) as test_im:

View File

@ -25,7 +25,6 @@ except ImportError:
class TestFileTiff: class TestFileTiff:
def test_sanity(self, tmp_path): def test_sanity(self, tmp_path):
filename = str(tmp_path / "temp.tif") filename = str(tmp_path / "temp.tif")
hopper("RGB").save(filename) hopper("RGB").save(filename)
@ -62,7 +61,8 @@ class TestFileTiff:
im = Image.open("Tests/images/multipage.tiff") im = Image.open("Tests/images/multipage.tiff")
im.load() im.load()
pytest.warns(ResourceWarning, open) with pytest.warns(ResourceWarning):
open()
def test_closed_file(self): def test_closed_file(self):
with warnings.catch_warnings(): with warnings.catch_warnings():
@ -157,7 +157,6 @@ class TestFileTiff:
def test_xyres_tiff(self): def test_xyres_tiff(self):
filename = "Tests/images/pil168.tif" filename = "Tests/images/pil168.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
# legacy api # legacy api
assert isinstance(im.tag[X_RESOLUTION][0], tuple) assert isinstance(im.tag[X_RESOLUTION][0], tuple)
assert isinstance(im.tag[Y_RESOLUTION][0], tuple) assert isinstance(im.tag[Y_RESOLUTION][0], tuple)
@ -171,7 +170,6 @@ class TestFileTiff:
def test_xyres_fallback_tiff(self): def test_xyres_fallback_tiff(self):
filename = "Tests/images/compression.tif" filename = "Tests/images/compression.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
# v2 api # v2 api
assert isinstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational) assert isinstance(im.tag_v2[X_RESOLUTION], TiffImagePlugin.IFDRational)
assert isinstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational) assert isinstance(im.tag_v2[Y_RESOLUTION], TiffImagePlugin.IFDRational)
@ -186,7 +184,6 @@ class TestFileTiff:
def test_int_resolution(self): def test_int_resolution(self):
filename = "Tests/images/pil168.tif" filename = "Tests/images/pil168.tif"
with Image.open(filename) as im: with Image.open(filename) as im:
# Try to read a file where X,Y_RESOLUTION are ints # Try to read a file where X,Y_RESOLUTION are ints
im.tag_v2[X_RESOLUTION] = 71 im.tag_v2[X_RESOLUTION] = 71
im.tag_v2[Y_RESOLUTION] = 71 im.tag_v2[Y_RESOLUTION] = 71
@ -235,7 +232,8 @@ class TestFileTiff:
def test_bad_exif(self): def test_bad_exif(self):
with Image.open("Tests/images/hopper_bad_exif.jpg") as i: with Image.open("Tests/images/hopper_bad_exif.jpg") as i:
# Should not raise struct.error. # Should not raise struct.error.
pytest.warns(UserWarning, i._getexif) with pytest.warns(UserWarning):
i._getexif()
def test_save_rgba(self, tmp_path): def test_save_rgba(self, tmp_path):
im = hopper("RGBA") im = hopper("RGBA")
@ -381,7 +379,6 @@ class TestFileTiff:
def test___str__(self): def test___str__(self):
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
# Act # Act
ret = str(im.ifd) ret = str(im.ifd)
@ -392,7 +389,6 @@ class TestFileTiff:
# Arrange # Arrange
filename = "Tests/images/pil136.tiff" filename = "Tests/images/pil136.tiff"
with Image.open(filename) as im: with Image.open(filename) as im:
# v2 interface # v2 interface
v2_tags = { v2_tags = {
256: 55, 256: 55,
@ -630,7 +626,6 @@ class TestFileTiff:
filename = str(tmp_path / "temp.tif") filename = str(tmp_path / "temp.tif")
hopper("RGB").save(filename, **kwargs) hopper("RGB").save(filename, **kwargs)
with Image.open(filename) as im: with Image.open(filename) as im:
# legacy interface # legacy interface
assert im.tag[X_RESOLUTION][0][0] == 72 assert im.tag[X_RESOLUTION][0][0] == 72
assert im.tag[Y_RESOLUTION][0][0] == 36 assert im.tag[Y_RESOLUTION][0][0] == 36

View File

@ -54,7 +54,6 @@ def test_rt_metadata(tmp_path):
img.save(f, tiffinfo=info) img.save(f, tiffinfo=info)
with Image.open(f) as loaded: with Image.open(f) as loaded:
assert loaded.tag[ImageJMetaDataByteCounts] == (len(bin_data),) assert loaded.tag[ImageJMetaDataByteCounts] == (len(bin_data),)
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bin_data),) assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bin_data),)
@ -74,14 +73,12 @@ def test_rt_metadata(tmp_path):
info[ImageJMetaDataByteCounts] = (8, len(bin_data) - 8) info[ImageJMetaDataByteCounts] = (8, len(bin_data) - 8)
img.save(f, tiffinfo=info) img.save(f, tiffinfo=info)
with Image.open(f) as loaded: with Image.open(f) as loaded:
assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8) assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8) assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bin_data) - 8)
def test_read_metadata(): def test_read_metadata():
with Image.open("Tests/images/hopper_g4.tif") as img: with Image.open("Tests/images/hopper_g4.tif") as img:
assert { assert {
"YResolution": IFDRational(4294967295, 113653537), "YResolution": IFDRational(4294967295, 113653537),
"PlanarConfiguration": 1, "PlanarConfiguration": 1,
@ -219,6 +216,22 @@ def test_writing_other_types_to_bytes(value, tmp_path):
assert reloaded.tag_v2[700] == b"\x01" assert reloaded.tag_v2[700] == b"\x01"
def test_writing_other_types_to_undefined(tmp_path):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()
tag = TiffTags.TAGS_V2[33723]
assert tag.type == TiffTags.UNDEFINED
info[33723] = 1
out = str(tmp_path / "temp.tiff")
im.save(out, tiffinfo=info)
with Image.open(out) as reloaded:
assert reloaded.tag_v2[33723] == b"1"
def test_undefined_zero(tmp_path): def test_undefined_zero(tmp_path):
# Check that the tag has not been changed since this test was created # Check that the tag has not been changed since this test was created
tag = TiffTags.TAGS_V2[45059] tag = TiffTags.TAGS_V2[45059]
@ -239,7 +252,8 @@ def test_empty_metadata():
head = f.read(8) head = f.read(8)
info = TiffImagePlugin.ImageFileDirectory(head) info = TiffImagePlugin.ImageFileDirectory(head)
# Should not raise struct.error. # Should not raise struct.error.
pytest.warns(UserWarning, info.load, f) with pytest.warns(UserWarning):
info.load(f)
def test_iccprofile(tmp_path): def test_iccprofile(tmp_path):
@ -405,11 +419,12 @@ def test_too_many_entries():
ifd = TiffImagePlugin.ImageFileDirectory_v2() ifd = TiffImagePlugin.ImageFileDirectory_v2()
# 277: ("SamplesPerPixel", SHORT, 1), # 277: ("SamplesPerPixel", SHORT, 1),
ifd._tagdata[277] = struct.pack("hh", 4, 4) ifd._tagdata[277] = struct.pack("<hh", 4, 4)
ifd.tagtype[277] = TiffTags.SHORT ifd.tagtype[277] = TiffTags.SHORT
# Should not raise ValueError. # Should not raise ValueError.
pytest.warns(UserWarning, lambda: ifd[277]) with pytest.warns(UserWarning):
assert ifd[277] == 4
def test_tag_group_data(): def test_tag_group_data():

View File

@ -29,7 +29,10 @@ class TestUnsupportedWebp:
WebPImagePlugin.SUPPORTED = False WebPImagePlugin.SUPPORTED = False
file_path = "Tests/images/hopper.webp" file_path = "Tests/images/hopper.webp"
pytest.warns(UserWarning, lambda: pytest.raises(OSError, Image.open, file_path)) with pytest.warns(UserWarning):
with pytest.raises(OSError):
with Image.open(file_path):
pass
if HAVE_WEBP: if HAVE_WEBP:
WebPImagePlugin.SUPPORTED = True WebPImagePlugin.SUPPORTED = True

View File

@ -18,10 +18,8 @@ except ImportError:
def test_read_exif_metadata(): def test_read_exif_metadata():
file_path = "Tests/images/flower.webp" file_path = "Tests/images/flower.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
assert image.format == "WEBP" assert image.format == "WEBP"
exif_data = image.info.get("exif", None) exif_data = image.info.get("exif", None)
assert exif_data assert exif_data
@ -64,10 +62,8 @@ def test_write_exif_metadata():
def test_read_icc_profile(): def test_read_icc_profile():
file_path = "Tests/images/flower2.webp" file_path = "Tests/images/flower2.webp"
with Image.open(file_path) as image: with Image.open(file_path) as image:
assert image.format == "WEBP" assert image.format == "WEBP"
assert image.info.get("icc_profile", None) assert image.info.get("icc_profile", None)

View File

@ -6,7 +6,6 @@ from .helper import assert_image_similar_tofile, hopper
def test_load_raw(): def test_load_raw():
# Test basic EMF open and rendering # Test basic EMF open and rendering
with Image.open("Tests/images/drawing.emf") as im: with Image.open("Tests/images/drawing.emf") as im:
if hasattr(Image.core, "drawwmf"): if hasattr(Image.core, "drawwmf"):

View File

@ -44,7 +44,6 @@ def test_open():
# Act # Act
with Image.open(filename) as im: with Image.open(filename) as im:
# Assert # Assert
assert im.mode == "1" assert im.mode == "1"
assert im.size == (128, 128) assert im.size == (128, 128)
@ -57,7 +56,6 @@ def test_open_filename_with_underscore():
# Act # Act
with Image.open(filename) as im: with Image.open(filename) as im:
# Assert # Assert
assert im.mode == "1" assert im.mode == "1"
assert im.size == (128, 128) assert im.size == (128, 128)

View File

@ -10,7 +10,6 @@ TEST_FILE = "Tests/images/hopper.p7"
def test_open(): def test_open():
# Act # Act
with Image.open(TEST_FILE) as im: with Image.open(TEST_FILE) as im:
# Assert # Assert
assert im.format == "XVThumb" assert im.format == "XVThumb"

View File

@ -69,7 +69,6 @@ class TestImage:
assert issubclass(UnidentifiedImageError, OSError) assert issubclass(UnidentifiedImageError, OSError)
def test_sanity(self): def test_sanity(self):
im = Image.new("L", (100, 100)) im = Image.new("L", (100, 100))
assert repr(im)[:45] == "<PIL.Image.Image image mode=L size=100x100 at" assert repr(im)[:45] == "<PIL.Image.Image image mode=L size=100x100 at"
assert im.mode == "L" assert im.mode == "L"
@ -1007,7 +1006,6 @@ def mock_encode(*args):
class TestRegistry: class TestRegistry:
def test_encode_registry(self): def test_encode_registry(self):
Image.register_encoder("MOCK", mock_encode) Image.register_encoder("MOCK", mock_encode)
assert "MOCK" in Image.ENCODERS assert "MOCK" in Image.ENCODERS

View File

@ -132,22 +132,26 @@ class TestImageGetPixel(AccessTest):
return 1 return 1
return tuple(range(1, bands + 1)) return tuple(range(1, bands + 1))
def check(self, mode, c=None): def check(self, mode, expected_color=None):
if not c: if not expected_color:
c = self.color(mode) expected_color = self.color(mode)
# check putpixel # check putpixel
im = Image.new(mode, (1, 1), None) im = Image.new(mode, (1, 1), None)
im.putpixel((0, 0), c) im.putpixel((0, 0), expected_color)
assert ( actual_color = im.getpixel((0, 0))
im.getpixel((0, 0)) == c assert actual_color == expected_color, (
), f"put/getpixel roundtrip failed for mode {mode}, color {c}" f"put/getpixel roundtrip failed for mode {mode}, "
f"expected {expected_color} got {actual_color}"
)
# check putpixel negative index # check putpixel negative index
im.putpixel((-1, -1), c) im.putpixel((-1, -1), expected_color)
assert ( actual_color = im.getpixel((-1, -1))
im.getpixel((-1, -1)) == c assert actual_color == expected_color, (
), f"put/getpixel roundtrip negative index failed for mode {mode}, color {c}" f"put/getpixel roundtrip negative index failed for mode {mode}, "
f"expected {expected_color} got {actual_color}"
)
# Check 0 # Check 0
im = Image.new(mode, (0, 0), None) im = Image.new(mode, (0, 0), None)
@ -155,27 +159,32 @@ class TestImageGetPixel(AccessTest):
error = ValueError if self._need_cffi_access else IndexError error = ValueError if self._need_cffi_access else IndexError
with pytest.raises(error): with pytest.raises(error):
im.putpixel((0, 0), c) im.putpixel((0, 0), expected_color)
with pytest.raises(error): with pytest.raises(error):
im.getpixel((0, 0)) im.getpixel((0, 0))
# Check 0 negative index # Check 0 negative index
with pytest.raises(error): with pytest.raises(error):
im.putpixel((-1, -1), c) im.putpixel((-1, -1), expected_color)
with pytest.raises(error): with pytest.raises(error):
im.getpixel((-1, -1)) im.getpixel((-1, -1))
# check initial color # check initial color
im = Image.new(mode, (1, 1), c) im = Image.new(mode, (1, 1), expected_color)
assert ( actual_color = im.getpixel((0, 0))
im.getpixel((0, 0)) == c assert actual_color == expected_color, (
), f"initial color failed for mode {mode}, color {c} " f"initial color failed for mode {mode}, "
f"expected {expected_color} got {actual_color}"
)
# check initial color negative index # check initial color negative index
assert ( actual_color = im.getpixel((-1, -1))
im.getpixel((-1, -1)) == c assert actual_color == expected_color, (
), f"initial color failed with negative index for mode {mode}, color {c} " f"initial color failed with negative index for mode {mode}, "
f"expected {expected_color} got {actual_color}"
)
# Check 0 # Check 0
im = Image.new(mode, (0, 0), c) im = Image.new(mode, (0, 0), expected_color)
with pytest.raises(error): with pytest.raises(error):
im.getpixel((0, 0)) im.getpixel((0, 0))
# Check 0 negative index # Check 0 negative index
@ -205,13 +214,13 @@ class TestImageGetPixel(AccessTest):
self.check(mode) self.check(mode)
@pytest.mark.parametrize("mode", ("I;16", "I;16B")) @pytest.mark.parametrize("mode", ("I;16", "I;16B"))
def test_signedness(self, mode): @pytest.mark.parametrize(
"expected_color", (2**15 - 1, 2**15, 2**15 + 1, 2**16 - 1)
)
def test_signedness(self, mode, expected_color):
# see https://github.com/python-pillow/Pillow/issues/452 # see https://github.com/python-pillow/Pillow/issues/452
# pixelaccess is using signed int* instead of uint* # pixelaccess is using signed int* instead of uint*
self.check(mode, 2**15 - 1) self.check(mode, expected_color)
self.check(mode, 2**15)
self.check(mode, 2**15 + 1)
self.check(mode, 2**16 - 1)
@pytest.mark.parametrize("mode", ("P", "PA")) @pytest.mark.parametrize("mode", ("P", "PA"))
@pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255))) @pytest.mark.parametrize("color", ((255, 0, 0), (255, 0, 0, 255)))

View File

@ -45,7 +45,6 @@ def test_unsupported_conversion():
def test_default(): def test_default():
im = hopper("P") im = hopper("P")
assert im.mode == "P" assert im.mode == "P"
converted_im = im.convert() converted_im = im.convert()
@ -255,17 +254,6 @@ def test_p2pa_palette():
assert im_pa.getpalette() == im.getpalette() assert im_pa.getpalette() == im.getpalette()
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
def test_rgb_lab(mode):
im = Image.new(mode, (1, 1))
converted_im = im.convert("LAB")
assert converted_im.getpixel((0, 0)) == (0, 128, 128)
im = Image.new("LAB", (1, 1), (255, 0, 0))
converted_im = im.convert(mode)
assert converted_im.getpixel((0, 0))[:3] == (0, 255, 255)
def test_matrix_illegal_conversion(): def test_matrix_illegal_conversion():
# Arrange # Arrange
im = hopper("CMYK") im = hopper("CMYK")

View File

@ -86,7 +86,6 @@ def test_crop_crash():
def test_crop_zero(): def test_crop_zero():
im = Image.new("RGB", (0, 0), "white") im = Image.new("RGB", (0, 0), "white")
cropped = im.crop((0, 0, 0, 0)) cropped = im.crop((0, 0, 0, 0))

View File

@ -1,10 +1,17 @@
import pytest
from PIL import Image from PIL import Image
from .helper import assert_image_equal, hopper from .helper import assert_image_equal, hopper
def test_sanity(): @pytest.mark.parametrize("data_type", ("bytes", "memoryview"))
def test_sanity(data_type):
im1 = hopper() im1 = hopper()
im2 = Image.frombytes(im1.mode, im1.size, im1.tobytes())
data = im1.tobytes()
if data_type == "memoryview":
data = memoryview(data)
im2 = Image.frombytes(im1.mode, im1.size, data)
assert_image_equal(im1, im2) assert_image_equal(im1, im2)

View File

@ -4,7 +4,6 @@ from .helper import hopper
def test_sanity(): def test_sanity():
bbox = hopper().getbbox() bbox = hopper().getbbox()
assert isinstance(bbox, tuple) assert isinstance(bbox, tuple)

View File

@ -6,7 +6,6 @@ from .helper import hopper
def test_sanity(): def test_sanity():
with hopper() as im: with hopper() as im:
im.mode im.mode

View File

@ -52,7 +52,7 @@ def test_resample():
# >>> im.save('Tests/images/hopper_45.png') # >>> im.save('Tests/images/hopper_45.png')
with Image.open("Tests/images/hopper_45.png") as target: with Image.open("Tests/images/hopper_45.png") as target:
for (resample, epsilon) in ( for resample, epsilon in (
(Image.Resampling.NEAREST, 10), (Image.Resampling.NEAREST, 10),
(Image.Resampling.BILINEAR, 5), (Image.Resampling.BILINEAR, 5),
(Image.Resampling.BICUBIC, 0), (Image.Resampling.BICUBIC, 0),

View File

@ -4,7 +4,6 @@ from .helper import assert_image_equal, fromstring, hopper
def test_sanity(): def test_sanity():
with pytest.raises(ValueError): with pytest.raises(ValueError):
hopper().tobitmap() hopper().tobitmap()

View File

@ -50,7 +50,6 @@ def test_add():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
# Act # Act
new = ImageChops.add(im1, im2) new = ImageChops.add(im1, im2)
@ -63,7 +62,6 @@ def test_add_scale_offset():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
# Act # Act
new = ImageChops.add(im1, im2, scale=2.5, offset=100) new = ImageChops.add(im1, im2, scale=2.5, offset=100)
@ -87,7 +85,6 @@ def test_add_modulo():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
# Act # Act
new = ImageChops.add_modulo(im1, im2) new = ImageChops.add_modulo(im1, im2)
@ -111,7 +108,6 @@ def test_blend():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
# Act # Act
new = ImageChops.blend(im1, im2, 0.5) new = ImageChops.blend(im1, im2, 0.5)
@ -137,7 +133,6 @@ def test_darker_image():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.darker(im1, im2) new = ImageChops.darker(im1, im2)
@ -149,7 +144,6 @@ def test_darker_pixel():
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.darker(im1, im2) new = ImageChops.darker(im1, im2)
@ -161,7 +155,6 @@ def test_difference():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1: with Image.open("Tests/images/imagedraw_arc_end_le_start.png") as im1:
with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2: with Image.open("Tests/images/imagedraw_arc_no_loops.png") as im2:
# Act # Act
new = ImageChops.difference(im1, im2) new = ImageChops.difference(im1, im2)
@ -173,7 +166,6 @@ def test_difference_pixel():
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2: with Image.open("Tests/images/imagedraw_polygon_kite_RGB.png") as im2:
# Act # Act
new = ImageChops.difference(im1, im2) new = ImageChops.difference(im1, im2)
@ -195,7 +187,6 @@ def test_duplicate():
def test_invert(): def test_invert():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im:
# Act # Act
new = ImageChops.invert(im) new = ImageChops.invert(im)
@ -209,7 +200,6 @@ def test_lighter_image():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.lighter(im1, im2) new = ImageChops.lighter(im1, im2)
@ -221,7 +211,6 @@ def test_lighter_pixel():
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.lighter(im1, im2) new = ImageChops.lighter(im1, im2)
@ -275,7 +264,6 @@ def test_offset():
xoffset = 45 xoffset = 45
yoffset = 20 yoffset = 20
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im:
# Act # Act
new = ImageChops.offset(im, xoffset, yoffset) new = ImageChops.offset(im, xoffset, yoffset)
@ -292,7 +280,6 @@ def test_screen():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1: with Image.open("Tests/images/imagedraw_ellipse_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2: with Image.open("Tests/images/imagedraw_floodfill_RGB.png") as im2:
# Act # Act
new = ImageChops.screen(im1, im2) new = ImageChops.screen(im1, im2)
@ -305,7 +292,6 @@ def test_subtract():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.subtract(im1, im2) new = ImageChops.subtract(im1, im2)
@ -319,7 +305,6 @@ def test_subtract_scale_offset():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.subtract(im1, im2, scale=2.5, offset=100) new = ImageChops.subtract(im1, im2, scale=2.5, offset=100)
@ -332,7 +317,6 @@ def test_subtract_clip():
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.subtract(im1, im2) new = ImageChops.subtract(im1, im2)
@ -344,7 +328,6 @@ def test_subtract_modulo():
# Arrange # Arrange
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im1:
with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_outline_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.subtract_modulo(im1, im2) new = ImageChops.subtract_modulo(im1, im2)
@ -358,7 +341,6 @@ def test_subtract_modulo_no_clip():
# Arrange # Arrange
im1 = hopper() im1 = hopper()
with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2: with Image.open("Tests/images/imagedraw_chord_RGB.png") as im2:
# Act # Act
new = ImageChops.subtract_modulo(im1, im2) new = ImageChops.subtract_modulo(im1, im2)
@ -370,7 +352,6 @@ def test_soft_light():
# Arrange # Arrange
with Image.open("Tests/images/hopper.png") as im1: with Image.open("Tests/images/hopper.png") as im1:
with Image.open("Tests/images/hopper-XYZ.png") as im2: with Image.open("Tests/images/hopper-XYZ.png") as im2:
# Act # Act
new = ImageChops.soft_light(im1, im2) new = ImageChops.soft_light(im1, im2)
@ -383,7 +364,6 @@ def test_hard_light():
# Arrange # Arrange
with Image.open("Tests/images/hopper.png") as im1: with Image.open("Tests/images/hopper.png") as im1:
with Image.open("Tests/images/hopper-XYZ.png") as im2: with Image.open("Tests/images/hopper-XYZ.png") as im2:
# Act # Act
new = ImageChops.hard_light(im1, im2) new = ImageChops.hard_light(im1, im2)
@ -396,7 +376,6 @@ def test_overlay():
# Arrange # Arrange
with Image.open("Tests/images/hopper.png") as im1: with Image.open("Tests/images/hopper.png") as im1:
with Image.open("Tests/images/hopper-XYZ.png") as im2: with Image.open("Tests/images/hopper-XYZ.png") as im2:
# Act # Act
new = ImageChops.overlay(im1, im2) new = ImageChops.overlay(im1, im2)

View File

@ -625,3 +625,14 @@ def test_constants_deprecation():
for name in enum.__members__: for name in enum.__members__:
with pytest.warns(DeprecationWarning): with pytest.warns(DeprecationWarning):
assert getattr(ImageCms, prefix + name) == enum[name] assert getattr(ImageCms, prefix + name) == enum[name]
@pytest.mark.parametrize("mode", ("RGB", "RGBA", "RGBX"))
def test_rgb_lab(mode):
im = Image.new(mode, (1, 1))
converted_im = im.convert("LAB")
assert converted_im.getpixel((0, 0)) == (0, 128, 128)
im = Image.new("LAB", (1, 1), (255, 0, 0))
converted_im = im.convert(mode)
assert converted_im.getpixel((0, 0))[:3] == (0, 255, 255)

View File

@ -52,7 +52,6 @@ def test_sanity():
def test_valueerror(): def test_valueerror():
with Image.open("Tests/images/chi.gif") as im: with Image.open("Tests/images/chi.gif") as im:
draw = ImageDraw.Draw(im) draw = ImageDraw.Draw(im)
draw.line((0, 0), fill=(0, 0, 0)) draw.line((0, 0), fill=(0, 0, 0))
@ -356,7 +355,13 @@ def ellipse_various_sizes_helper(filled):
for w in ellipse_sizes: for w in ellipse_sizes:
y = 1 y = 1
for h in ellipse_sizes: for h in ellipse_sizes:
border = [x, y, x + w - 1, y + h - 1] x1 = x + w
if w:
x1 -= 1
y1 = y + h
if h:
y1 -= 1
border = [x, y, x1, y1]
if filled: if filled:
draw.ellipse(border, fill="white") draw.ellipse(border, fill="white")
else: else:
@ -736,6 +741,36 @@ def test_rounded_rectangle(xy):
assert_image_equal_tofile(im, "Tests/images/imagedraw_rounded_rectangle.png") assert_image_equal_tofile(im, "Tests/images/imagedraw_rounded_rectangle.png")
@pytest.mark.parametrize("top_left", (True, False))
@pytest.mark.parametrize("top_right", (True, False))
@pytest.mark.parametrize("bottom_right", (True, False))
@pytest.mark.parametrize("bottom_left", (True, False))
def test_rounded_rectangle_corners(top_left, top_right, bottom_right, bottom_left):
corners = (top_left, top_right, bottom_right, bottom_left)
# Arrange
im = Image.new("RGB", (200, 200))
draw = ImageDraw.Draw(im)
# Act
draw.rounded_rectangle(
(10, 20, 190, 180), 30, fill="red", outline="green", width=5, corners=corners
)
# Assert
suffix = "".join(
(
("y" if top_left else "n"),
("y" if top_right else "n"),
("y" if bottom_right else "n"),
("y" if bottom_left else "n"),
)
)
assert_image_equal_tofile(
im, "Tests/images/imagedraw_rounded_rectangle_corners_" + suffix + ".png"
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"xy, radius, type", "xy, radius, type",
[ [
@ -903,9 +938,6 @@ def test_square():
img, draw = create_base_image_draw((10, 10)) img, draw = create_base_image_draw((10, 10))
draw.rectangle((2, 2, 7, 7), BLACK) draw.rectangle((2, 2, 7, 7), BLACK)
assert_image_equal_tofile(img, expected, "square as normal rectangle failed") assert_image_equal_tofile(img, expected, "square as normal rectangle failed")
img, draw = create_base_image_draw((10, 10))
draw.rectangle((7, 7, 2, 2), BLACK)
assert_image_equal_tofile(img, expected, "square as inverted rectangle failed")
def test_triangle_right(): def test_triangle_right():
@ -1470,3 +1502,21 @@ def test_polygon2():
draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red") draw.polygon([(18, 30), (19, 31), (18, 30), (85, 30), (60, 72)], "red")
expected = "Tests/images/imagedraw_outline_polygon_RGB.png" expected = "Tests/images/imagedraw_outline_polygon_RGB.png"
assert_image_similar_tofile(im, expected, 1) assert_image_similar_tofile(im, expected, 1)
@pytest.mark.parametrize("xy", ((1, 1, 0, 1), (1, 1, 1, 0)))
def test_incorrectly_ordered_coordinates(xy):
im = Image.new("RGB", (W, H))
draw = ImageDraw.Draw(im)
with pytest.raises(ValueError):
draw.arc(xy, 10, 260)
with pytest.raises(ValueError):
draw.chord(xy, 10, 260)
with pytest.raises(ValueError):
draw.ellipse(xy)
with pytest.raises(ValueError):
draw.pieslice(xy, 10, 260)
with pytest.raises(ValueError):
draw.rectangle(xy)
with pytest.raises(ValueError):
draw.rounded_rectangle(xy)

View File

@ -30,7 +30,6 @@ SAFEBLOCK = ImageFile.SAFEBLOCK
class TestImageFile: class TestImageFile:
def test_parser(self): def test_parser(self):
def roundtrip(format): def roundtrip(format):
im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST) im = hopper("L").resize((1000, 1000), Image.Resampling.NEAREST)
if format in ("MSP", "XBM"): if format in ("MSP", "XBM"):
im = im.convert("1") im = im.convert("1")

View File

@ -351,7 +351,8 @@ def test_rotated_transposed_font(font, orientation):
assert bbox_b[3] == 20 + bbox_a[2] - bbox_a[0] assert bbox_b[3] == 20 + bbox_a[2] - bbox_a[0]
# text length is undefined for vertical text # text length is undefined for vertical text
pytest.raises(ValueError, draw.textlength, word) with pytest.raises(ValueError):
draw.textlength(word)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -872,25 +873,23 @@ def test_anchor_invalid(font):
d.font = font d.font = font
for anchor in ["", "l", "a", "lax", "sa", "xa", "lx"]: for anchor in ["", "l", "a", "lax", "sa", "xa", "lx"]:
pytest.raises(ValueError, lambda: font.getmask2("hello", anchor=anchor)) with pytest.raises(ValueError):
pytest.raises(ValueError, lambda: font.getbbox("hello", anchor=anchor)) font.getmask2("hello", anchor=anchor)
pytest.raises(ValueError, lambda: d.text((0, 0), "hello", anchor=anchor)) with pytest.raises(ValueError):
pytest.raises(ValueError, lambda: d.textbbox((0, 0), "hello", anchor=anchor)) font.getbbox("hello", anchor=anchor)
pytest.raises( with pytest.raises(ValueError):
ValueError, lambda: d.multiline_text((0, 0), "foo\nbar", anchor=anchor) d.text((0, 0), "hello", anchor=anchor)
) with pytest.raises(ValueError):
pytest.raises( d.textbbox((0, 0), "hello", anchor=anchor)
ValueError, with pytest.raises(ValueError):
lambda: d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor), d.multiline_text((0, 0), "foo\nbar", anchor=anchor)
) with pytest.raises(ValueError):
d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor)
for anchor in ["lt", "lb"]: for anchor in ["lt", "lb"]:
pytest.raises( with pytest.raises(ValueError):
ValueError, lambda: d.multiline_text((0, 0), "foo\nbar", anchor=anchor) d.multiline_text((0, 0), "foo\nbar", anchor=anchor)
) with pytest.raises(ValueError):
pytest.raises( d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor)
ValueError,
lambda: d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor),
)
@pytest.mark.parametrize("bpp", (1, 2, 4, 8)) @pytest.mark.parametrize("bpp", (1, 2, 4, 8))

View File

@ -360,37 +360,20 @@ def test_anchor_invalid_ttb():
d.font = font d.font = font
for anchor in ["", "l", "a", "lax", "xa", "la", "ls", "ld", "lx"]: for anchor in ["", "l", "a", "lax", "xa", "la", "ls", "ld", "lx"]:
pytest.raises( with pytest.raises(ValueError):
ValueError, lambda: font.getmask2("hello", anchor=anchor, direction="ttb") font.getmask2("hello", anchor=anchor, direction="ttb")
) with pytest.raises(ValueError):
pytest.raises( font.getbbox("hello", anchor=anchor, direction="ttb")
ValueError, lambda: font.getbbox("hello", anchor=anchor, direction="ttb") with pytest.raises(ValueError):
) d.text((0, 0), "hello", anchor=anchor, direction="ttb")
pytest.raises( with pytest.raises(ValueError):
ValueError, lambda: d.text((0, 0), "hello", anchor=anchor, direction="ttb") d.textbbox((0, 0), "hello", anchor=anchor, direction="ttb")
) with pytest.raises(ValueError):
pytest.raises( d.multiline_text((0, 0), "foo\nbar", anchor=anchor, direction="ttb")
ValueError, with pytest.raises(ValueError):
lambda: d.textbbox((0, 0), "hello", anchor=anchor, direction="ttb"), d.multiline_textbbox((0, 0), "foo\nbar", anchor=anchor, direction="ttb")
)
pytest.raises(
ValueError,
lambda: d.multiline_text(
(0, 0), "foo\nbar", anchor=anchor, direction="ttb"
),
)
pytest.raises(
ValueError,
lambda: d.multiline_textbbox(
(0, 0), "foo\nbar", anchor=anchor, direction="ttb"
),
)
# ttb multiline text does not support anchors at all # ttb multiline text does not support anchors at all
pytest.raises( with pytest.raises(ValueError):
ValueError, d.multiline_text((0, 0), "foo\nbar", anchor="mm", direction="ttb")
lambda: d.multiline_text((0, 0), "foo\nbar", anchor="mm", direction="ttb"), with pytest.raises(ValueError):
) d.multiline_textbbox((0, 0), "foo\nbar", anchor="mm", direction="ttb")
pytest.raises(
ValueError,
lambda: d.multiline_textbbox((0, 0), "foo\nbar", anchor="mm", direction="ttb"),
)

View File

@ -21,7 +21,6 @@ deformer = Deformer()
def test_sanity(): def test_sanity():
ImageOps.autocontrast(hopper("L")) ImageOps.autocontrast(hopper("L"))
ImageOps.autocontrast(hopper("RGB")) ImageOps.autocontrast(hopper("RGB"))
@ -419,7 +418,6 @@ def test_autocontrast_cutoff():
def test_autocontrast_mask_toy_input(): def test_autocontrast_mask_toy_input():
# Test the mask argument of autocontrast # Test the mask argument of autocontrast
with Image.open("Tests/images/bw_gradient.png") as img: with Image.open("Tests/images/bw_gradient.png") as img:
rect_mask = Image.new("L", img.size, 0) rect_mask = Image.new("L", img.size, 0)
draw = ImageDraw.Draw(rect_mask) draw = ImageDraw.Draw(rect_mask)
x0 = img.size[0] // 4 x0 = img.size[0] // 4
@ -439,7 +437,6 @@ def test_autocontrast_mask_toy_input():
def test_autocontrast_mask_real_input(): def test_autocontrast_mask_real_input():
# Test the autocontrast with a rectangular mask # Test the autocontrast with a rectangular mask
with Image.open("Tests/images/iptc.jpg") as img: with Image.open("Tests/images/iptc.jpg") as img:
rect_mask = Image.new("L", img.size, 0) rect_mask = Image.new("L", img.size, 0)
draw = ImageDraw.Draw(rect_mask) draw = ImageDraw.Draw(rect_mask)
x0, y0 = img.size[0] // 2, img.size[1] // 2 x0, y0 = img.size[0] // 2, img.size[1] // 2

View File

@ -6,7 +6,6 @@ from .helper import assert_image_equal, assert_image_equal_tofile
def test_sanity(): def test_sanity():
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
assert len(palette.colors) == 256 assert len(palette.colors) == 256
@ -23,7 +22,6 @@ def test_reload():
def test_getcolor(): def test_getcolor():
palette = ImagePalette.ImagePalette() palette = ImagePalette.ImagePalette()
assert len(palette.palette) == 0 assert len(palette.palette) == 0
assert len(palette.colors) == 0 assert len(palette.colors) == 0
@ -84,7 +82,6 @@ def test_getcolor_not_special(index, palette):
def test_file(tmp_path): def test_file(tmp_path):
palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3) palette = ImagePalette.ImagePalette("RGB", list(range(256)) * 3)
f = str(tmp_path / "temp.lut") f = str(tmp_path / "temp.lut")

View File

@ -8,7 +8,6 @@ from PIL import Image, ImagePath
def test_path(): def test_path():
p = ImagePath.Path(list(range(10))) p = ImagePath.Path(list(range(10)))
# sequence interface # sequence interface

View File

@ -6,7 +6,6 @@ from .helper import assert_image_equal, hopper, skip_unless_feature
def test_sanity(tmp_path): def test_sanity(tmp_path):
test_file = str(tmp_path / "temp.im") test_file = str(tmp_path / "temp.im")
im = hopper("RGB") im = hopper("RGB")

View File

@ -55,8 +55,8 @@ def test_show_without_viewers():
viewers = ImageShow._viewers viewers = ImageShow._viewers
ImageShow._viewers = [] ImageShow._viewers = []
im = hopper() with hopper() as im:
assert not ImageShow.show(im) assert not ImageShow.show(im)
ImageShow._viewers = viewers ImageShow._viewers = viewers

View File

@ -6,7 +6,6 @@ from .helper import hopper
def test_sanity(): def test_sanity():
im = hopper() im = hopper()
st = ImageStat.Stat(im) st = ImageStat.Stat(im)
@ -31,7 +30,6 @@ def test_sanity():
def test_hopper(): def test_hopper():
im = hopper() im = hopper()
st = ImageStat.Stat(im) st = ImageStat.Stat(im)
@ -45,7 +43,6 @@ def test_hopper():
def test_constant(): def test_constant():
im = Image.new("L", (128, 128), 128) im = Image.new("L", (128, 128), 128)
st = ImageStat.Stat(im) st = ImageStat.Stat(im)

View File

@ -100,8 +100,11 @@ class TestImageWinDib:
# Act # Act
# Make one the same as the using tobytes()/frombytes() # Make one the same as the using tobytes()/frombytes()
test_buffer = dib1.tobytes() test_buffer = dib1.tobytes()
dib2.frombytes(test_buffer) for datatype in ("bytes", "memoryview"):
if datatype == "memoryview":
test_buffer = memoryview(test_buffer)
dib2.frombytes(test_buffer)
# Assert # Assert
# Confirm they're the same # Confirm they're the same
assert dib1.tobytes() == dib2.tobytes() assert dib1.tobytes() == dib2.tobytes()

View File

@ -4,7 +4,6 @@ from PIL import Image
def test_setmode(): def test_setmode():
im = Image.new("L", (1, 1), 255) im = Image.new("L", (1, 1), 255)
im.im.setmode("1") im.im.setmode("1")
assert im.im.getpixel((0, 0)) == 255 assert im.im.getpixel((0, 0)) == 255

View File

@ -42,7 +42,6 @@ def test_basic(tmp_path, mode):
im_in.save(filename) im_in.save(filename)
with Image.open(filename) as im_out: with Image.open(filename) as im_out:
verify(im_in) verify(im_in)
verify(im_out) verify(im_out)
@ -87,7 +86,6 @@ def test_tobytes():
def test_convert(): def test_convert():
im = original.copy() im = original.copy()
verify(im.convert("I;16")) verify(im.convert("I;16"))

View File

@ -235,7 +235,6 @@ def test_no_resource_warning_for_numpy_array():
test_file = "Tests/images/hopper.png" test_file = "Tests/images/hopper.png"
with Image.open(test_file) as im: with Image.open(test_file) as im:
# Act/Assert # Act/Assert
with warnings.catch_warnings(): with warnings.catch_warnings():
array(im) array(im)

View File

@ -89,7 +89,6 @@ def test_pickle_la_mode_with_palette(tmp_path):
def test_pickle_tell(): def test_pickle_tell():
# Arrange # Arrange
with Image.open("Tests/images/hopper.webp") as image: with Image.open("Tests/images/hopper.webp") as image:
# Act: roundtrip # Act: roundtrip
unpickled_image = pickle.loads(pickle.dumps(image)) unpickled_image = pickle.loads(pickle.dumps(image))

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