Skip to content

Commit

Permalink
Merge branch 'main' into test_lists_and_tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed May 6, 2023
2 parents 886ed7a + e3990f6 commit fa97a1a
Show file tree
Hide file tree
Showing 47 changed files with 406 additions and 202 deletions.
4 changes: 2 additions & 2 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ install:
- 7z x pillow-test-images.zip -oc:\
- mv c:\pillow-depends-main c:\pillow-depends
- 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.16.01-win64.zip -oc:\
- choco install ghostscript --version=10.0.0.20230317
- path c:\nasm-2.15.05;C:\Program Files\gs\gs10.00.0\bin;%PATH%
- path c:\nasm-2.16.01;C:\Program Files\gs\gs10.00.0\bin;%PATH%
- cd c:\pillow\winbuild\
- ps: |
c:\python38\python.exe c:\pillow\winbuild\build_prepare.py -v --depends=C:\pillow-depends\
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/test-cygwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
uses: actions/checkout@v3

- name: Install Cygwin
uses: cygwin/cygwin-install-action@v3
uses: cygwin/cygwin-install-action@v4
with:
platform: x86_64
packages: >
Expand Down Expand Up @@ -84,6 +84,10 @@ jobs:
restore-keys: |
${{ runner.os }}-cygwin-pip3.${{ matrix.python-minor-version }}-
- name: Select Python version
run: |
ln -sf c:/cygwin/bin/python3.${{ matrix.python-minor-version }} c:/cygwin/bin/python3
- name: Build system information
run: |
dash.exe -c "python3 .github/workflows/system-info.py"
Expand All @@ -95,7 +99,7 @@ jobs:
- name: Install a different NumPy
shell: dash.exe -l "{0}"
run: |
python3 -m pip install -U 'numpy!=1.21.*'
python3 -m pip install -U numpy
- name: Build
shell: bash.exe -eo pipefail -o igncr "{0}"
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/test-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ jobs:
centos-stream-8-amd64,
centos-stream-9-amd64,
debian-11-bullseye-x86,
fedora-36-amd64,
fedora-37-amd64,
fedora-38-amd64,
gentoo,
ubuntu-18.04-bionic-amd64,
ubuntu-20.04-focal-amd64,
ubuntu-22.04-jammy-amd64,
]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-mingw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
pushd depends && ./install_extra_test_images.sh && popd
- name: Build Pillow
run: CFLAGS="-coverage" python3 -m pip install --global-option="build_ext" .
run: SETUPTOOLS_USE_DISTUTILS="stdlib" CFLAGS="-coverage" python3 -m pip install --global-option="build_ext" .

- name: Test Pillow
run: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ jobs:
- name: Install dependencies
id: install
run: |
7z x winbuild\depends\nasm-2.15.05-win64.zip "-o$env:RUNNER_WORKSPACE\"
echo "$env:RUNNER_WORKSPACE\nasm-2.15.05" >> $env:GITHUB_PATH
7z x winbuild\depends\nasm-2.16.01-win64.zip "-o$env:RUNNER_WORKSPACE\"
echo "$env:RUNNER_WORKSPACE\nasm-2.16.01" >> $env:GITHUB_PATH
choco install ghostscript --version=10.0.0.20230317
echo "C:\Program Files\gs\gs10.00.0\bin" >> $env:GITHUB_PATH
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ repos:
- id: sphinx-lint

- repo: /~https://github.com/tox-dev/tox-ini-fmt
rev: 1.0.0
rev: 1.3.0
hooks:
- id: tox-ini-fmt

Expand Down
2 changes: 2 additions & 0 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
version: 2

formats: all

build:
os: ubuntu-22.04
tools:
Expand Down
24 changes: 24 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,30 @@ Changelog (Pillow)
10.0.0 (unreleased)
-------------------

- Support reading signed 8-bit TIFF images #7111
[radarhere]

- Added width argument to ImageDraw regular_polygon #7132
[radarhere]

- Support I mode for ImageFilter.BuiltinFilter #7108
[radarhere]

- Raise error from stderr of Linux ImageGrab.grabclipboard() command #7112
[radarhere]

- Added unpacker from I;16B to I;16 #7125
[radarhere]

- Support float font sizes #7107
[radarhere]

- Use later value for duplicate xref entries in PdfParser #7102
[radarhere]

- Load before getting size in __getstate__ #7105
[bigcat88, radarhere]

- Fixed type handling for include and lib directories #7069
[adisbladis, radarhere]

Expand Down
77 changes: 37 additions & 40 deletions Tests/check_jpeg_leaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,48 +75,45 @@
"""


def test_qtables_leak():
im = hopper("RGB")

standard_l_qtable = [
int(s)
for s in """
16 11 10 16 24 40 51 61
12 12 14 19 26 58 60 55
14 13 16 24 40 57 69 56
14 17 22 29 51 87 80 62
18 22 37 56 68 109 103 77
24 35 55 64 81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99
""".split(
None
)
]

standard_chrominance_qtable = [
int(s)
for s in """
17 18 24 47 99 99 99 99
18 21 26 66 99 99 99 99
24 26 56 99 99 99 99 99
47 66 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
99 99 99 99 99 99 99 99
""".split(
None
)
]

for qtables in (
standard_l_qtable = (
# fmt: off
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99,
# fmt: on
)

standard_chrominance_qtable = (
# fmt: off
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
# fmt: on
)


@pytest.mark.parametrize(
"qtables",
(
(standard_l_qtable, standard_chrominance_qtable),
[standard_l_qtable, standard_chrominance_qtable],
):
for _ in range(iterations):
test_output = BytesIO()
im.save(test_output, "JPEG", qtables=qtables)
),
)
def test_qtables_leak(qtables):
im = hopper("RGB")
for _ in range(iterations):
test_output = BytesIO()
im.save(test_output, "JPEG", qtables=qtables)


def test_exif_leak():
Expand Down
Binary file added Tests/images/8bit.s.tif
Binary file not shown.
Binary file added Tests/images/duplicate_xref_entry.pdf
Binary file not shown.
Binary file added Tests/images/hopper_emboss_I.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/hopper_emboss_more_I.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/imagedraw_triangle_width.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ def test_save_unsupported_mode(self, tmp_path):
with pytest.raises(OSError):
im.save(outfile)

def test_8bit_s(self):
with Image.open("Tests/images/8bit.s.tif") as im:
im.load()
assert im.mode == "L"
assert im.getpixel((50, 50)) == 184

def test_little_endian(self):
with Image.open("Tests/images/16bit.cropped.tif") as im:
assert im.getpixel((0, 0)) == 480
Expand Down
9 changes: 8 additions & 1 deletion Tests/test_image_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from PIL import Image

from .helper import hopper
from .helper import hopper, skip_unless_feature


@pytest.mark.parametrize("mode", ("1", "P", "L", "RGB", "I", "F"))
Expand Down Expand Up @@ -42,3 +42,10 @@ def test_copy_zero():
out = im.copy()
assert out.mode == im.mode
assert out.size == im.size


@skip_unless_feature("libtiff")
def test_deepcopy():
with Image.open("Tests/images/g4_orientation_5.tif") as im:
out = copy.deepcopy(im)
assert out.size == (590, 88)
43 changes: 26 additions & 17 deletions Tests/test_image_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,16 @@
ImageFilter.UnsharpMask(10),
),
)
@pytest.mark.parametrize("mode", ("L", "RGB", "CMYK"))
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
def test_sanity(filter_to_apply, mode):
im = hopper(mode)
out = im.filter(filter_to_apply)
assert out.mode == im.mode
assert out.size == im.size
if mode != "I" or isinstance(filter_to_apply, ImageFilter.BuiltinFilter):
out = im.filter(filter_to_apply)
assert out.mode == im.mode
assert out.size == im.size


@pytest.mark.parametrize("mode", ("L", "RGB", "CMYK"))
@pytest.mark.parametrize("mode", ("L", "I", "RGB", "CMYK"))
def test_sanity_error(mode):
with pytest.raises(TypeError):
im = hopper(mode)
Expand Down Expand Up @@ -130,10 +131,12 @@ def test_kernel_not_enough_coefficients():
ImageFilter.Kernel((3, 3), (0, 0))


@pytest.mark.parametrize("mode", ("L", "LA", "RGB", "CMYK"))
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
def test_consistency_3x3(mode):
with Image.open("Tests/images/hopper.bmp") as source:
with Image.open("Tests/images/hopper_emboss.bmp") as reference:
reference_name = "hopper_emboss"
reference_name += "_I.png" if mode == "I" else ".bmp"
with Image.open("Tests/images/" + reference_name) as reference:
kernel = ImageFilter.Kernel(
(3, 3),
# fmt: off
Expand All @@ -146,16 +149,20 @@ def test_consistency_3x3(mode):
source = source.split() * 2
reference = reference.split() * 2

assert_image_equal(
Image.merge(mode, source[: len(mode)]).filter(kernel),
Image.merge(mode, reference[: len(mode)]),
)
if mode == "I":
source = source[0].convert(mode)
else:
source = Image.merge(mode, source[: len(mode)])
reference = Image.merge(mode, reference[: len(mode)])
assert_image_equal(source.filter(kernel), reference)


@pytest.mark.parametrize("mode", ("L", "LA", "RGB", "CMYK"))
@pytest.mark.parametrize("mode", ("L", "LA", "I", "RGB", "CMYK"))
def test_consistency_5x5(mode):
with Image.open("Tests/images/hopper.bmp") as source:
with Image.open("Tests/images/hopper_emboss_more.bmp") as reference:
reference_name = "hopper_emboss_more"
reference_name += "_I.png" if mode == "I" else ".bmp"
with Image.open("Tests/images/" + reference_name) as reference:
kernel = ImageFilter.Kernel(
(5, 5),
# fmt: off
Expand All @@ -170,10 +177,12 @@ def test_consistency_5x5(mode):
source = source.split() * 2
reference = reference.split() * 2

assert_image_equal(
Image.merge(mode, source[: len(mode)]).filter(kernel),
Image.merge(mode, reference[: len(mode)]),
)
if mode == "I":
source = source[0].convert(mode)
else:
source = Image.merge(mode, source[: len(mode)])
reference = Image.merge(mode, reference[: len(mode)])
assert_image_equal(source.filter(kernel), reference)


def test_invalid_box_blur_filter():
Expand Down
20 changes: 10 additions & 10 deletions Tests/test_imagedraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -1380,20 +1380,20 @@ def test_same_color_outline(bbox):


@pytest.mark.parametrize(
"n_sides, rotation, polygon_name",
[(4, 0, "square"), (8, 0, "regular_octagon"), (4, 45, "square")],
"n_sides, polygon_name, args",
[
(4, "square", {}),
(8, "regular_octagon", {}),
(4, "square_rotate_45", {"rotation": 45}),
(3, "triangle_width", {"width": 5, "outline": "yellow"}),
],
)
def test_draw_regular_polygon(n_sides, rotation, polygon_name):
def test_draw_regular_polygon(n_sides, polygon_name, args):
im = Image.new("RGBA", size=(W, H), color=(255, 0, 0, 0))
filename_base = f"Tests/images/imagedraw_{polygon_name}"
filename = (
f"{filename_base}.png"
if rotation == 0
else f"{filename_base}_rotate_{rotation}.png"
)
filename = f"Tests/images/imagedraw_{polygon_name}.png"
draw = ImageDraw.Draw(im)
bounding_circle = ((W // 2, H // 2), 25)
draw.regular_polygon(bounding_circle, n_sides, rotation=rotation, fill="red")
draw.regular_polygon(bounding_circle, n_sides, fill="red", **args)
assert_image_equal_tofile(im, filename)


Expand Down
10 changes: 10 additions & 0 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@ def test_getlength(
assert length == length_raqm


def test_float_size():
lengths = []
for size in (48, 48.5, 49):
f = ImageFont.truetype(
"Tests/fonts/NotoSans-Regular.ttf", size, layout_engine=layout_engine
)
lengths.append(f.getlength("text"))
assert lengths[0] != lengths[1] != lengths[2]


def test_render_multiline(font):
im = Image.new(mode="RGB", size=(300, 100))
draw = ImageDraw.Draw(im)
Expand Down
Loading

0 comments on commit fa97a1a

Please sign in to comment.