From e3dd4de1934c35144430de1a411d1df5bad84732 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sun, 15 Jan 2023 20:08:37 -0600 Subject: [PATCH 01/40] parametrize check_jpeg_leaks::test_qtables_leak() Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- Tests/check_jpeg_leaks.py | 71 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/Tests/check_jpeg_leaks.py b/Tests/check_jpeg_leaks.py index ab8d7771992..940c0b00d5b 100644 --- a/Tests/check_jpeg_leaks.py +++ b/Tests/check_jpeg_leaks.py @@ -75,43 +75,42 @@ """ -def test_qtables_leak(): +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], + ), +) +def test_qtables_leak(qtables): 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 - ) - ] - - qtables = [standard_l_qtable, standard_chrominance_qtable] - for _ in range(iterations): test_output = BytesIO() im.save(test_output, "JPEG", qtables=qtables) From e8307d74064d555524558a1dcb8828006ab3d65a Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 18 Jan 2023 23:03:13 -0600 Subject: [PATCH 02/40] more imagepath tests --- Tests/test_imagepath.py | 83 +++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 861fb64f072..2b378d333b2 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -8,7 +8,6 @@ def test_path(): - p = ImagePath.Path(list(range(10))) # sequence interface @@ -39,48 +38,76 @@ def test_path(): p.transform((1, 0, 1, 0, 1, 1)) assert list(p) == [(1.0, 2.0), (5.0, 6.0), (9.0, 10.0)] - # alternative constructors - p = ImagePath.Path([0, 1]) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path([0.0, 1.0]) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path([0, 1]) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path([(0, 1)]) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path(p) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path(p.tolist(0)) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path(p.tolist(1)) - assert list(p) == [(0.0, 1.0)] - p = ImagePath.Path(array.array("f", [0, 1])) - assert list(p) == [(0.0, 1.0)] - arr = array.array("f", [0, 1]) - p = ImagePath.Path(arr.tobytes()) +@pytest.mark.parametrize( + "coords", + ( + (0, 1), + [0, 1], + (0.0, 1.0), + [0.0, 1.0], + ((0, 1),), + [(0, 1)], + ((0.0, 1.0),), + [(0.0, 1.0)], + array.array("f", [0, 1]), + array.array("f", [0.0, 1.0]), + ImagePath.Path((0, 1)), + ), +) +def test_path_constructors(coords): + # Arrange / Act + p = ImagePath.Path(coords) + + # Assert assert list(p) == [(0.0, 1.0)] -def test_invalid_coords(): +def test_path_constructor_text(): # Arrange - coords = ["a", "b"] + arr = array.array("f", (0, 1)) - # Act / Assert + # Act + p = ImagePath.Path(arr.tobytes()) + + # Assert + assert list(p) == [(0.0, 1.0)] + + +@pytest.mark.parametrize( + "coords", + ( + ("a", "b"), + ([0, 1],), + [[0, 1]], + ([0.0, 1.0],), + [[0.0, 1.0]], + ), +) +def test_invalid_path_constructors(coords): + # Act with pytest.raises(ValueError) as e: ImagePath.Path(coords) + # Assert assert str(e.value) == "incorrect coordinate type" -def test_path_odd_number_of_coordinates(): - # Arrange - coords = [0] - - # Act / Assert +@pytest.mark.parametrize( + "coords", + ( + (0,), + [0], + (0, 1, 2), + [0, 1, 2], + ), +) +def test_path_odd_number_of_coordinates(coords): + # Act with pytest.raises(ValueError) as e: ImagePath.Path(coords) + # Assert assert str(e.value) == "wrong number of coordinates" From 4e8de9ac9a1e14593e17a2cd1ff82c45ed0900cd Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 25 Jan 2023 08:13:40 -0600 Subject: [PATCH 03/40] add path-from-bytes test Also `array.array("f", [0, 1]) == array.array("f", [0.0, 1.0])` so we didn't need both of them. --- Tests/test_imagepath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 2b378d333b2..7a517b6f61d 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -51,7 +51,7 @@ def test_path(): ((0.0, 1.0),), [(0.0, 1.0)], array.array("f", [0, 1]), - array.array("f", [0.0, 1.0]), + array.array("f", [0, 1]).tobytes(), ImagePath.Path((0, 1)), ), ) From f619675115275a330b0d99660c4442fe7f7d3fe2 Mon Sep 17 00:00:00 2001 From: Nulano Date: Wed, 12 Apr 2023 21:14:38 +0200 Subject: [PATCH 04/40] Update vendored Raqm to 0.10.1 --- src/thirdparty/raqm/COPYING | 2 +- src/thirdparty/raqm/NEWS | 35 ++++++++++++++++++++++++++++++ src/thirdparty/raqm/README.md | 2 +- src/thirdparty/raqm/raqm-version.h | 4 ++-- src/thirdparty/raqm/raqm.c | 25 ++++++++++++++++----- src/thirdparty/raqm/raqm.h | 2 +- 6 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/thirdparty/raqm/COPYING b/src/thirdparty/raqm/COPYING index c605a5dc67a..97e2489b779 100644 --- a/src/thirdparty/raqm/COPYING +++ b/src/thirdparty/raqm/COPYING @@ -1,7 +1,7 @@ The MIT License (MIT) Copyright © 2015 Information Technology Authority (ITA) -Copyright © 2016-2022 Khaled Hosny +Copyright © 2016-2023 Khaled Hosny Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/thirdparty/raqm/NEWS b/src/thirdparty/raqm/NEWS index ae1128485f2..e8bf32e0bbb 100644 --- a/src/thirdparty/raqm/NEWS +++ b/src/thirdparty/raqm/NEWS @@ -1,3 +1,38 @@ +Overview of changes leading to 0.10.1 +Wednesday, April 12, 2023 +==================================== + +Make combining marks always inherit the script of their base. + +Overview of changes leading to 0.10.0 +Wednesday, January 11, 2023 +==================================== + +Fix font feature ranges. + +Fix resolved direction for all-neutral text. + +Implement letter and word spacing support. + +New API: + * raqm_set_text_utf16 + +Overview of changes leading to 0.9.0 +Sunday, January 30, 2022 +==================================== + +Raise the minimum versions of Raqm dependencies: no longer conditionally +enabling any features based on specific dependency version. + +raqm_t objects can now be reused by calling raqm_clear_contents() before +re-use, to potentially reduce the number memory allocations. + +Don't hardcode python3 in tests. + +New API: + * raqm_set_freetype_load_flags_range + * raqm_clear_contents + Overview of changes leading to 0.8.0 Monday, December 13, 2021 ==================================== diff --git a/src/thirdparty/raqm/README.md b/src/thirdparty/raqm/README.md index 315e0c8d822..ab729cdc036 100644 --- a/src/thirdparty/raqm/README.md +++ b/src/thirdparty/raqm/README.md @@ -81,5 +81,5 @@ The following projects have patches to support complex text layout using Raqm: [1]: /~https://github.com/fribidi/fribidi [2]: /~https://github.com/Tehreer/SheenBidi [3]: /~https://github.com/harfbuzz/harfbuzz -[4]: https://www.freetype.org +[4]: https://freetype.org/ [5]: https://www.gtk.org/gtk-doc diff --git a/src/thirdparty/raqm/raqm-version.h b/src/thirdparty/raqm/raqm-version.h index bdb6fb66264..62d2d206459 100644 --- a/src/thirdparty/raqm/raqm-version.h +++ b/src/thirdparty/raqm/raqm-version.h @@ -33,9 +33,9 @@ #define RAQM_VERSION_MAJOR 0 #define RAQM_VERSION_MINOR 10 -#define RAQM_VERSION_MICRO 0 +#define RAQM_VERSION_MICRO 1 -#define RAQM_VERSION_STRING "0.10.0" +#define RAQM_VERSION_STRING "0.10.1" #define RAQM_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ diff --git a/src/thirdparty/raqm/raqm.c b/src/thirdparty/raqm/raqm.c index 770ea30182b..2b331e1afb0 100644 --- a/src/thirdparty/raqm/raqm.c +++ b/src/thirdparty/raqm/raqm.c @@ -1,6 +1,6 @@ /* * Copyright © 2015 Information Technology Authority (ITA) - * Copyright © 2016-2022 Khaled Hosny + * Copyright © 2016-2023 Khaled Hosny * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to @@ -1432,7 +1432,7 @@ raqm_get_glyphs (raqm_t *rq, * * Since: 0.8 */ -RAQM_API raqm_direction_t +raqm_direction_t raqm_get_par_resolved_direction (raqm_t *rq) { if (!rq) @@ -1455,7 +1455,7 @@ raqm_get_par_resolved_direction (raqm_t *rq) * * Since: 0.8 */ -RAQM_API raqm_direction_t +raqm_direction_t raqm_get_direction_at_index (raqm_t *rq, size_t index) { @@ -2021,6 +2021,22 @@ _get_pair_index (const uint32_t ch) #define STACK_IS_EMPTY(script) ((script)->size <= 0) #define IS_OPEN(pair_index) (((pair_index) & 1) == 0) +static hb_script_t +_raqm_unicode_script (hb_codepoint_t u) +{ + static hb_unicode_funcs_t* unicode_funcs; + + unicode_funcs = hb_unicode_funcs_get_default (); + + /* Make combining marks inherit the script of their bases, regardless of + * their own script. + */ + if (hb_unicode_general_category (unicode_funcs, u) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) + return HB_SCRIPT_INHERITED; + + return hb_unicode_script (unicode_funcs, u); +} + /* Resolve the script for each character in the input string, if the character * script is common or inherited it takes the script of the character before it * except paired characters which we try to make them use the same script. We @@ -2033,10 +2049,9 @@ _raqm_resolve_scripts (raqm_t *rq) int last_set_index = -1; hb_script_t last_script = HB_SCRIPT_INVALID; _raqm_stack_t *stack = NULL; - hb_unicode_funcs_t* unicode_funcs = hb_unicode_funcs_get_default (); for (size_t i = 0; i < rq->text_len; ++i) - rq->text_info[i].script = hb_unicode_script (unicode_funcs, rq->text[i]); + rq->text_info[i].script = _raqm_unicode_script (rq->text[i]); #ifdef RAQM_TESTING RAQM_TEST ("Before script detection:\n"); diff --git a/src/thirdparty/raqm/raqm.h b/src/thirdparty/raqm/raqm.h index 2fd836c8607..6fd6089c70d 100644 --- a/src/thirdparty/raqm/raqm.h +++ b/src/thirdparty/raqm/raqm.h @@ -1,6 +1,6 @@ /* * Copyright © 2015 Information Technology Authority (ITA) - * Copyright © 2016-2022 Khaled Hosny + * Copyright © 2016-2023 Khaled Hosny * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to From 86716ff2b094bb0b071208bdf7299d5eefa95085 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 13 Apr 2023 07:52:32 +1000 Subject: [PATCH 05/40] Updated raqm to 0.10.1 --- depends/install_raqm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/install_raqm.sh b/depends/install_raqm.sh index d1b31cfa53b..24c1f9c3029 100755 --- a/depends/install_raqm.sh +++ b/depends/install_raqm.sh @@ -2,7 +2,7 @@ # install raqm -archive=libraqm-0.10.0 +archive=libraqm-0.10.1 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz From accbd8ad93203d7c6068c75885e22f81e7164c98 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 14 Apr 2023 11:13:28 +1000 Subject: [PATCH 06/40] Updated nasm to 2.16.01 --- .appveyor.yml | 4 ++-- .github/workflows/test-windows.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index b2599e3d889..36f5bd0ad68 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -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\ diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 8f4d53ecf06..a008801114f 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -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 From 73e94824888e6ed8019cc36099c92eea9b45e340 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 15 Apr 2023 09:41:19 +1000 Subject: [PATCH 07/40] Select Python version --- .github/workflows/test-cygwin.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml index 14a5f2c146b..6a5f738575f 100644 --- a/.github/workflows/test-cygwin.yml +++ b/.github/workflows/test-cygwin.yml @@ -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" From 6acb381656626305fb2695ef955cfd8bec858570 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 15 Apr 2023 17:23:08 +1000 Subject: [PATCH 08/40] Simplified NumPy install command --- .github/workflows/test-cygwin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml index 6a5f738575f..2b597a94580 100644 --- a/.github/workflows/test-cygwin.yml +++ b/.github/workflows/test-cygwin.yml @@ -99,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}" From 57bbe6df2c25a1a5155f4c25ae0bdf2f2769d035 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 15 Apr 2023 15:59:12 +1000 Subject: [PATCH 09/40] Remove use of deprecated "bpp" member --- src/libImaging/Jpeg2KEncode.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libImaging/Jpeg2KEncode.c b/src/libImaging/Jpeg2KEncode.c index 8f637006160..0d7e896b7f8 100644 --- a/src/libImaging/Jpeg2KEncode.c +++ b/src/libImaging/Jpeg2KEncode.c @@ -281,7 +281,6 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) { int ret = -1; unsigned prec = 8; - unsigned bpp = 8; unsigned _overflow_scale_factor; stream = opj_stream_create(BUFFER_SIZE, OPJ_FALSE); @@ -313,7 +312,6 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) { color_space = OPJ_CLRSPC_GRAY; pack = j2k_pack_i16; prec = 16; - bpp = 12; } else if (strcmp(im->mode, "LA") == 0) { components = 2; color_space = OPJ_CLRSPC_GRAY; @@ -342,7 +340,6 @@ j2k_encode_entry(Imaging im, ImagingCodecState state) { image_params[n].h = im->ysize; image_params[n].x0 = image_params[n].y0 = 0; image_params[n].prec = prec; - image_params[n].bpp = bpp; image_params[n].sgnd = context->sgnd == 0 ? 0 : 1; } From 4e6f1f1ac60cb9e88c0605739468693e0e17e4e9 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 17 Apr 2023 19:08:59 +1000 Subject: [PATCH 10/40] Removed Fedora 36 --- .github/workflows/test-docker.yml | 1 - docs/installation.rst | 2 -- 2 files changed, 3 deletions(-) diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index 14592ea1d53..cbe6c2ca3d8 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -39,7 +39,6 @@ jobs: centos-stream-8-amd64, centos-stream-9-amd64, debian-11-bullseye-x86, - fedora-36-amd64, fedora-37-amd64, gentoo, ubuntu-18.04-bionic-amd64, diff --git a/docs/installation.rst b/docs/installation.rst index 7088657f905..0ac5914dabc 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -448,8 +448,6 @@ These platforms are built and tested for every change. +----------------------------------+----------------------------+---------------------+ | Debian 11 Bullseye | 3.9 | x86 | +----------------------------------+----------------------------+---------------------+ -| Fedora 36 | 3.10 | x86-64 | -+----------------------------------+----------------------------+---------------------+ | Fedora 37 | 3.11 | x86-64 | +----------------------------------+----------------------------+---------------------+ | Gentoo | 3.9 | x86-64 | From 6ffa189d0156f52df422cd99fa3d28ebb0432107 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 09:16:01 +0000 Subject: [PATCH 11/40] Update cygwin/cygwin-install-action action to v4 --- .github/workflows/test-cygwin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-cygwin.yml b/.github/workflows/test-cygwin.yml index 2b597a94580..9a1e46705de 100644 --- a/.github/workflows/test-cygwin.yml +++ b/.github/workflows/test-cygwin.yml @@ -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: > From 75c4acf02c6128f1fe03a14c202a6bcf57eaa31f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 19 Apr 2023 06:46:58 -0600 Subject: [PATCH 12/40] Fix typo --- docs/reference/Image.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 35a4c21107d..41d3b8fcec0 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -439,7 +439,7 @@ Used to specify the dithering method to use for the Palettes ^^^^^^^^ -Used to specify the pallete to use for the :meth:`~Image.convert` method. +Used to specify the palette to use for the :meth:`~Image.convert` method. .. autoclass:: Palette :members: From d2256338b82730fef647a3cd8b65bc9040a7d73e Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 20 Apr 2023 23:15:20 +1000 Subject: [PATCH 13/40] Use later value for duplicate xref entries --- Tests/images/duplicate_xref_entry.pdf | Bin 0 -> 3326 bytes Tests/test_pdfparser.py | 6 ++++++ src/PIL/PdfParser.py | 9 +++------ 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 Tests/images/duplicate_xref_entry.pdf diff --git a/Tests/images/duplicate_xref_entry.pdf b/Tests/images/duplicate_xref_entry.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f57a57d61c6ad0649448af316f689db4e7f1322e GIT binary patch literal 3326 zcmeH}S#Z-v7{?{cr{WAa2{dFvvpL)(9cpQ1`C?K!#KsU>hQvt=rPBu=n?xDMN@V3? zrVr4YH+r{EK<~cMmR?V#rRN(xfxeX9?GyB-54hh-K4N>ADRh|WbXZv$>)UU4zfY_G z_mg)x7QYVrWZsL?8cFITgHlUqSjlG91%yQ(Ju+loMBs-qnleu`UPdBPQ&R&2yfC&j zLy!dCA+!3)F536e(v=uhw)HjrEf+<1Cht5G`bra+-sVeSG25c>$rMtTYEd|@%5sv zb=~dleWCt!B9>*jqc?JWSQ_y8WrcSs#sUif`UBv~_gs z=392`ymePPL&hg2m8rZwH@~pBwENDx?!M>V`|jWOz=IDx{K%t^J^sX@C!c!ynP;DS z{)HD`dilsJufF#B8*jaR?45Vtd;fzEKl=ESPe1$o#K}{qzxw){Z@>HghaZ1B`|~fq z{`UJHf1dk`=EX9cnHF5l#A@>LKwcKBm9si%UaVySPR?Vsbz*zd#t}zywz*5%<7^q+ zfAH{8SGPZLW>rc%&adu~PkYbO)QrsjSz>!HDYJ57mApuq>@K|!@nqas$i;ijjE_d?$oguT~S4{zapYpI=RtG zD^+gN(?~Fbi>YXYuTMN!nR-movjp{>FEBbom^`ERL#(ubDQYeTWeoMj)=Q$~7iCGr zQb3eLyTD_cnz>+Sxn3=5WSkdKh&SV;R}>5c{6RF1N;VvTSd5-r*%pz*wKj~!dOtA$ z8(1?|j6`Z}7)O?k)wQIOh1yHEIiadLqD43Xl~CDDAXH%}H?AW3e2hKK>q$*F^1xCg z!h5}&w#U7fQ0ei1>{Y|1x3;JROyAZjw$z}gZa^JVs$e9QVPs^UK(M3LObXR5c!fz9 zM%5K2RkQYg%p@w5f6XK+u8Uz3)J$3f&5zJ3Ce`YmdR`_d;bp+P{8Yjv0*Rtjp^^mO zz6Mh01;_vmQ(DPLs@Q?kB|H6Nwu&tXpTnjN$OAh;8!FQchh?a>)ix>UuOpchia?32 z_QN4*8Oe-J5r;x%Jj>Sz1nc~yaCq4obrduJP{JUV=_e4GM+WpvBpSO@!$c_(4wy{* E8-kd> ]" assert pdf_repr(PdfBinary(b"\x90\x1F\xA0")) == b"<901FA0>" + + +def test_duplicate_xref_entry(): + pdf = PdfParser("Tests/images/duplicate_xref_entry.pdf") + assert pdf.xref_table.existing_entries[6][0] == 1197 + pdf.close() diff --git a/src/PIL/PdfParser.py b/src/PIL/PdfParser.py index 1b3cb52a2dc..dc1012f54d3 100644 --- a/src/PIL/PdfParser.py +++ b/src/PIL/PdfParser.py @@ -957,14 +957,11 @@ def read_xref_table(self, xref_section_offset): check_format_condition(m, "xref entry not found") offset = m.end() is_free = m.group(3) == b"f" - generation = int(m.group(2)) if not is_free: + generation = int(m.group(2)) new_entry = (int(m.group(1)), generation) - check_format_condition( - i not in self.xref_table or self.xref_table[i] == new_entry, - "xref entry duplicated (and not identical)", - ) - self.xref_table[i] = new_entry + if i not in self.xref_table: + self.xref_table[i] = new_entry return offset def read_indirect(self, ref, max_nesting=-1): From 895f5a4ffc70fafaae2d16e6618c373e1689186d Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 21 Apr 2023 09:04:46 +1000 Subject: [PATCH 14/40] Updated macOS tested Pillow versions [ci skip] --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 0ac5914dabc..8798c079169 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -490,7 +490,7 @@ These platforms have been reported to work at the versions mentioned. | Operating system | | Tested Python | | Latest tested | | Tested | | | | versions | | Pillow version | | processors | +==================================+===========================+==================+==============+ -| macOS 13 Ventura | 3.7, 3.8, 3.9, 3.10, 3.11 | 9.4.0 |arm | +| macOS 13 Ventura | 3.7, 3.8, 3.9, 3.10, 3.11 | 9.5.0 |arm | +----------------------------------+---------------------------+------------------+--------------+ | macOS 12 Big Sur | 3.7, 3.8, 3.9, 3.10, 3.11 | 9.3.0 |arm | +----------------------------------+---------------------------+------------------+--------------+ From b10379b3c14eba9d32a5e81d5242c7c5857a32cc Mon Sep 17 00:00:00 2001 From: Alexander Piskun Date: Fri, 21 Apr 2023 17:42:45 +0300 Subject: [PATCH 15/40] Load image before deepcopy(__getstate__) Signed-off-by: bigcat88 --- Tests/test_numpy.py | 9 +++++++++ src/PIL/Image.py | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index 147f94a71fd..6dc53d1e81f 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -1,4 +1,5 @@ import warnings +from copy import deepcopy import pytest @@ -226,6 +227,14 @@ def test_load_first(): assert a.shape == (88, 590) +@skip_unless_feature("libtiff") +def test_load_first_deepcopy(): + with Image.open("Tests/images/g4_orientation_5.tif") as im: + im_deepcopy = deepcopy(im) + a = numpy.array(im_deepcopy) + assert a.shape == (88, 590) + + def test_bool(): # /~https://github.com/python-pillow/Pillow/issues/2044 a = numpy.zeros((10, 2), dtype=bool) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 5a43f6c4a43..bee9e23d088 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -672,7 +672,8 @@ def __array_interface__(self): return new def __getstate__(self): - return [self.info, self.mode, self.size, self.getpalette(), self.tobytes()] + im_data = self.tobytes() # load image first + return [self.info, self.mode, self.size, self.getpalette(), im_data] def __setstate__(self, state): Image.__init__(self) From 91b69857c78cb75bb096306a6460c27e70a55c38 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 22 Apr 2023 10:13:56 +1000 Subject: [PATCH 16/40] Removed duplicate code --- src/PIL/ImageCms.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index 31b0e5a5ee6..38cbab19ce7 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -185,12 +185,8 @@ def __init__(self, profile): def _set(self, profile, filename=None): self.profile = profile self.filename = filename - if profile: - self.product_name = None # profile.product_name - self.product_info = None # profile.product_info - else: - self.product_name = None - self.product_info = None + self.product_name = None # profile.product_name + self.product_info = None # profile.product_info def tobytes(self): """ From b62287da3a529bc8e47ab330a81dfd1d8959cef8 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 22 Apr 2023 11:18:56 +1000 Subject: [PATCH 17/40] Moved test to test_image_copy --- Tests/test_image_copy.py | 9 ++++++++- Tests/test_numpy.py | 9 --------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Tests/test_image_copy.py b/Tests/test_image_copy.py index 591832147d7..cd602fc76f6 100644 --- a/Tests/test_image_copy.py +++ b/Tests/test_image_copy.py @@ -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")) @@ -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) diff --git a/Tests/test_numpy.py b/Tests/test_numpy.py index 6dc53d1e81f..147f94a71fd 100644 --- a/Tests/test_numpy.py +++ b/Tests/test_numpy.py @@ -1,5 +1,4 @@ import warnings -from copy import deepcopy import pytest @@ -227,14 +226,6 @@ def test_load_first(): assert a.shape == (88, 590) -@skip_unless_feature("libtiff") -def test_load_first_deepcopy(): - with Image.open("Tests/images/g4_orientation_5.tif") as im: - im_deepcopy = deepcopy(im) - a = numpy.array(im_deepcopy) - assert a.shape == (88, 590) - - def test_bool(): # /~https://github.com/python-pillow/Pillow/issues/2044 a = numpy.zeros((10, 2), dtype=bool) From 81a756e93b102b20a8c4599d4b5b3235109ef5ab Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 22 Apr 2023 13:45:18 +1000 Subject: [PATCH 18/40] Support float font sizes --- Tests/test_imagefont.py | 10 ++++++++++ src/_imagingft.c | 14 +++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 623365d53fe..7ea485a55ec 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -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) diff --git a/src/_imagingft.c b/src/_imagingft.c index 19785a47f69..78e3f7f104f 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -116,7 +116,9 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) { int error = 0; char *filename = NULL; - Py_ssize_t size; + float size; + FT_Size_RequestRec req; + FT_Long width; Py_ssize_t index = 0; Py_ssize_t layout_engine = 0; unsigned char *encoding; @@ -133,7 +135,7 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) { if (!PyArg_ParseTupleAndKeywords( args, kw, - "etn|nsy#n", + "etf|nsy#n", kwlist, Py_FileSystemDefaultEncoding, &filename, @@ -179,7 +181,13 @@ getfont(PyObject *self_, PyObject *args, PyObject *kw) { } if (!error) { - error = FT_Set_Pixel_Sizes(self->face, 0, size); + width = size * 64; + req.type = FT_SIZE_REQUEST_TYPE_NOMINAL; + req.width = width; + req.height = width; + req.horiResolution = 0; + req.vertResolution = 0; + error = FT_Request_Size(self->face, &req); } if (!error && encoding && strlen((char *)encoding) == 4) { From d0b41da094c48077c3511988e98c168bd45f84dc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 22 Apr 2023 21:22:01 +1000 Subject: [PATCH 19/40] Support I mode for BuiltinFilter --- Tests/images/hopper_emboss_I.png | Bin 0 -> 13273 bytes Tests/images/hopper_emboss_more_I.png | Bin 0 -> 14624 bytes Tests/test_image_filter.py | 43 +++++---- src/libImaging/Filter.c | 133 ++++++++++++++++++-------- 4 files changed, 120 insertions(+), 56 deletions(-) create mode 100644 Tests/images/hopper_emboss_I.png create mode 100644 Tests/images/hopper_emboss_more_I.png diff --git a/Tests/images/hopper_emboss_I.png b/Tests/images/hopper_emboss_I.png new file mode 100644 index 0000000000000000000000000000000000000000..f4dab388fe5c2dce3771133525df2c09b0fada45 GIT binary patch literal 13273 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 WC}ig2^aR-e0000= pow(2, 31) - 1) { + return pow(2, 31) - 1; + } + return (INT32)in; +} + Imaging ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) { Imaging imOut; @@ -96,8 +107,8 @@ ImagingExpand(Imaging imIn, int xmargin, int ymargin, int mode) { void ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) { #define KERNEL1x3(in0, x, kernel, d) \ - (_i2f((UINT8)in0[x - d]) * (kernel)[0] + _i2f((UINT8)in0[x]) * (kernel)[1] + \ - _i2f((UINT8)in0[x + d]) * (kernel)[2]) + (_i2f(in0[x - d]) * (kernel)[0] + _i2f(in0[x]) * (kernel)[1] + \ + _i2f(in0[x + d]) * (kernel)[2]) int x = 0, y = 0; @@ -105,21 +116,40 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) { if (im->bands == 1) { // Add one time for rounding offset += 0.5; - for (y = 1; y < im->ysize - 1; y++) { - UINT8 *in_1 = (UINT8 *)im->image[y - 1]; - UINT8 *in0 = (UINT8 *)im->image[y]; - UINT8 *in1 = (UINT8 *)im->image[y + 1]; - UINT8 *out = (UINT8 *)imOut->image[y]; + if (im->type == IMAGING_TYPE_INT32) { + for (y = 1; y < im->ysize - 1; y++) { + INT32 *in_1 = (INT32 *)im->image[y - 1]; + INT32 *in0 = (INT32 *)im->image[y]; + INT32 *in1 = (INT32 *)im->image[y + 1]; + INT32 *out = (INT32 *)imOut->image[y]; + + out[0] = in0[0]; + for (x = 1; x < im->xsize - 1; x++) { + float ss = offset; + ss += KERNEL1x3(in1, x, &kernel[0], 1); + ss += KERNEL1x3(in0, x, &kernel[3], 1); + ss += KERNEL1x3(in_1, x, &kernel[6], 1); + out[x] = clip32(ss); + } + out[x] = in0[x]; + } + } else { + for (y = 1; y < im->ysize - 1; y++) { + UINT8 *in_1 = (UINT8 *)im->image[y - 1]; + UINT8 *in0 = (UINT8 *)im->image[y]; + UINT8 *in1 = (UINT8 *)im->image[y + 1]; + UINT8 *out = (UINT8 *)imOut->image[y]; - out[0] = in0[0]; - for (x = 1; x < im->xsize - 1; x++) { - float ss = offset; - ss += KERNEL1x3(in1, x, &kernel[0], 1); - ss += KERNEL1x3(in0, x, &kernel[3], 1); - ss += KERNEL1x3(in_1, x, &kernel[6], 1); - out[x] = clip8(ss); + out[0] = in0[0]; + for (x = 1; x < im->xsize - 1; x++) { + float ss = offset; + ss += KERNEL1x3(in1, x, &kernel[0], 1); + ss += KERNEL1x3(in0, x, &kernel[3], 1); + ss += KERNEL1x3(in_1, x, &kernel[6], 1); + out[x] = clip8(ss); + } + out[x] = in0[x]; } - out[x] = in0[x]; } } else { // Add one time for rounding @@ -195,10 +225,10 @@ ImagingFilter3x3(Imaging imOut, Imaging im, const float *kernel, float offset) { void ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) { #define KERNEL1x5(in0, x, kernel, d) \ - (_i2f((UINT8)in0[x - d - d]) * (kernel)[0] + \ - _i2f((UINT8)in0[x - d]) * (kernel)[1] + _i2f((UINT8)in0[x]) * (kernel)[2] + \ - _i2f((UINT8)in0[x + d]) * (kernel)[3] + \ - _i2f((UINT8)in0[x + d + d]) * (kernel)[4]) + (_i2f(in0[x - d - d]) * (kernel)[0] + \ + _i2f(in0[x - d]) * (kernel)[1] + _i2f(in0[x]) * (kernel)[2] + \ + _i2f(in0[x + d]) * (kernel)[3] + \ + _i2f(in0[x + d + d]) * (kernel)[4]) int x = 0, y = 0; @@ -207,27 +237,52 @@ ImagingFilter5x5(Imaging imOut, Imaging im, const float *kernel, float offset) { if (im->bands == 1) { // Add one time for rounding offset += 0.5; - for (y = 2; y < im->ysize - 2; y++) { - UINT8 *in_2 = (UINT8 *)im->image[y - 2]; - UINT8 *in_1 = (UINT8 *)im->image[y - 1]; - UINT8 *in0 = (UINT8 *)im->image[y]; - UINT8 *in1 = (UINT8 *)im->image[y + 1]; - UINT8 *in2 = (UINT8 *)im->image[y + 2]; - UINT8 *out = (UINT8 *)imOut->image[y]; + if (im->type == IMAGING_TYPE_INT32) { + for (y = 2; y < im->ysize - 2; y++) { + INT32 *in_2 = (INT32 *)im->image[y - 2]; + INT32 *in_1 = (INT32 *)im->image[y - 1]; + INT32 *in0 = (INT32 *)im->image[y]; + INT32 *in1 = (INT32 *)im->image[y + 1]; + INT32 *in2 = (INT32 *)im->image[y + 2]; + INT32 *out = (INT32 *)imOut->image[y]; - out[0] = in0[0]; - out[1] = in0[1]; - for (x = 2; x < im->xsize - 2; x++) { - float ss = offset; - ss += KERNEL1x5(in2, x, &kernel[0], 1); - ss += KERNEL1x5(in1, x, &kernel[5], 1); - ss += KERNEL1x5(in0, x, &kernel[10], 1); - ss += KERNEL1x5(in_1, x, &kernel[15], 1); - ss += KERNEL1x5(in_2, x, &kernel[20], 1); - out[x] = clip8(ss); + out[0] = in0[0]; + out[1] = in0[1]; + for (x = 2; x < im->xsize - 2; x++) { + float ss = offset; + ss += KERNEL1x5(in2, x, &kernel[0], 1); + ss += KERNEL1x5(in1, x, &kernel[5], 1); + ss += KERNEL1x5(in0, x, &kernel[10], 1); + ss += KERNEL1x5(in_1, x, &kernel[15], 1); + ss += KERNEL1x5(in_2, x, &kernel[20], 1); + out[x] = clip32(ss); + } + out[x + 0] = in0[x + 0]; + out[x + 1] = in0[x + 1]; + } + } else { + for (y = 2; y < im->ysize - 2; y++) { + UINT8 *in_2 = (UINT8 *)im->image[y - 2]; + UINT8 *in_1 = (UINT8 *)im->image[y - 1]; + UINT8 *in0 = (UINT8 *)im->image[y]; + UINT8 *in1 = (UINT8 *)im->image[y + 1]; + UINT8 *in2 = (UINT8 *)im->image[y + 2]; + UINT8 *out = (UINT8 *)imOut->image[y]; + + out[0] = in0[0]; + out[1] = in0[1]; + for (x = 2; x < im->xsize - 2; x++) { + float ss = offset; + ss += KERNEL1x5(in2, x, &kernel[0], 1); + ss += KERNEL1x5(in1, x, &kernel[5], 1); + ss += KERNEL1x5(in0, x, &kernel[10], 1); + ss += KERNEL1x5(in_1, x, &kernel[15], 1); + ss += KERNEL1x5(in_2, x, &kernel[20], 1); + out[x] = clip8(ss); + } + out[x + 0] = in0[x + 0]; + out[x + 1] = in0[x + 1]; } - out[x + 0] = in0[x + 0]; - out[x + 1] = in0[x + 1]; } } else { // Add one time for rounding @@ -327,7 +382,7 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 o Imaging imOut; ImagingSectionCookie cookie; - if (!im || im->type != IMAGING_TYPE_UINT8) { + if (im->type != IMAGING_TYPE_UINT8 && im->type != IMAGING_TYPE_INT32) { return (Imaging)ImagingError_ModeError(); } From f5c1f7a2c27c810d3d95dc659c5c24c455ca6f74 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 22 Apr 2023 21:47:36 +1000 Subject: [PATCH 20/40] Added Fedora 38 --- .github/workflows/test-docker.yml | 1 + docs/installation.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index cbe6c2ca3d8..84c46b1d4fb 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -40,6 +40,7 @@ jobs: centos-stream-9-amd64, debian-11-bullseye-x86, fedora-37-amd64, + fedora-38-amd64, gentoo, ubuntu-18.04-bionic-amd64, ubuntu-20.04-focal-amd64, diff --git a/docs/installation.rst b/docs/installation.rst index 8798c079169..21dcd02274f 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -450,6 +450,8 @@ These platforms are built and tested for every change. +----------------------------------+----------------------------+---------------------+ | Fedora 37 | 3.11 | x86-64 | +----------------------------------+----------------------------+---------------------+ +| Fedora 38 | 3.11 | x86-64 | ++----------------------------------+----------------------------+---------------------+ | Gentoo | 3.9 | x86-64 | +----------------------------------+----------------------------+---------------------+ | macOS 12 Monterey | 3.8, 3.9, 3.10, 3.11, | x86-64 | From e3cb4bb8e00fcaf4c3e0783f7c02e51372595659 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 24 Apr 2023 07:48:53 +1000 Subject: [PATCH 21/40] Update CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index cd0b95085cd..b82333af7a1 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 10.0.0 (unreleased) ------------------- +- Load before getting size in __getstate__ #7105 + [bigcat88, radarhere] + - Fixed type handling for include and lib directories #7069 [adisbladis, radarhere] From ab3d0c071e60da904062d22f6b9a73e8fc6cdcb9 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 24 Apr 2023 21:03:27 +1000 Subject: [PATCH 22/40] Raise error from stderr of Linux grabclipboard command --- src/PIL/ImageGrab.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/PIL/ImageGrab.py b/src/PIL/ImageGrab.py index 982f77f206d..2592ba2df3d 100644 --- a/src/PIL/ImageGrab.py +++ b/src/PIL/ImageGrab.py @@ -141,8 +141,11 @@ def grabclipboard(): msg = "wl-paste or xclip is required for ImageGrab.grabclipboard() on Linux" raise NotImplementedError(msg) fh, filepath = tempfile.mkstemp() - subprocess.call(args, stdout=fh) + err = subprocess.run(args, stdout=fh, stderr=subprocess.PIPE).stderr os.close(fh) + if err: + msg = f"{args[0]} error: {err.strip().decode()}" + raise ChildProcessError(msg) im = Image.open(filepath) im.load() os.unlink(filepath) From 99a474a9e63d5bf2ea2654bb8102731db90ff8c2 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 25 Apr 2023 23:55:29 +1000 Subject: [PATCH 23/40] Removed Ubuntu 18.04 --- .github/workflows/test-docker.yml | 1 - docs/installation.rst | 2 -- 2 files changed, 3 deletions(-) diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index 84c46b1d4fb..4f01abe44c2 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -42,7 +42,6 @@ jobs: fedora-37-amd64, fedora-38-amd64, gentoo, - ubuntu-18.04-bionic-amd64, ubuntu-20.04-focal-amd64, ubuntu-22.04-jammy-amd64, ] diff --git a/docs/installation.rst b/docs/installation.rst index 21dcd02274f..a254ec8c2ad 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -457,8 +457,6 @@ These platforms are built and tested for every change. | macOS 12 Monterey | 3.8, 3.9, 3.10, 3.11, | x86-64 | | | 3.12, PyPy3 | | +----------------------------------+----------------------------+---------------------+ -| Ubuntu Linux 18.04 LTS (Bionic) | 3.9 | x86-64 | -+----------------------------------+----------------------------+---------------------+ | Ubuntu Linux 20.04 LTS (Focal) | 3.8 | x86-64 | +----------------------------------+----------------------------+---------------------+ | Ubuntu Linux 22.04 LTS (Jammy) | 3.8, 3.9, 3.10, 3.11, | x86-64 | From d0e9a13c0c8ee0c77559e604c8758720991d930a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 26 Apr 2023 17:08:06 +1000 Subject: [PATCH 24/40] Build all readthedocs formats --- .readthedocs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index 98d9e4425ac..ec3300dd1f2 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,5 +1,7 @@ version: 2 +formats: all + build: os: ubuntu-22.04 tools: From 0c8db130afe5343358b30fadffa6e59d2c877083 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 27 Apr 2023 13:31:14 +1000 Subject: [PATCH 25/40] Updated harfbuzz to 7.2.0 --- winbuild/build_prepare.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index 3f639454b08..9b5fc5d1840 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -337,9 +337,9 @@ def cmd_msbuild( "libs": [r"imagequant.lib"], }, "harfbuzz": { - "url": "/~https://github.com/harfbuzz/harfbuzz/archive/7.1.0.zip", - "filename": "harfbuzz-7.1.0.zip", - "dir": "harfbuzz-7.1.0", + "url": "/~https://github.com/harfbuzz/harfbuzz/archive/7.2.0.zip", + "filename": "harfbuzz-7.2.0.zip", + "dir": "harfbuzz-7.2.0", "license": "COPYING", "build": [ *cmds_cmake( From b62c3baeeedb642b8eaf4dc16245fb54bcb92dfd Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Apr 2023 06:32:27 +1000 Subject: [PATCH 26/40] Update CHANGES.rst [ci skip] --- CHANGES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index b82333af7a1..7b13900a8df 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,12 @@ Changelog (Pillow) 10.0.0 (unreleased) ------------------- +- 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] From ff003bfbcc9cfd7d281030f836616c0cdd59cfa6 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Apr 2023 14:49:40 +1000 Subject: [PATCH 27/40] Added unpacker from I;16B to I;16 --- Tests/test_lib_pack.py | 1 + src/libImaging/Unpack.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index de3e7d1569b..f7812f62bd8 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -757,6 +757,7 @@ def test_F_float(self): def test_I16(self): self.assert_unpack("I;16", "I;16", 2, 0x0201, 0x0403, 0x0605) + self.assert_unpack("I;16", "I;16B", 2, 0x0102, 0x0304, 0x0506) self.assert_unpack("I;16B", "I;16B", 2, 0x0102, 0x0304, 0x0506) self.assert_unpack("I;16L", "I;16L", 2, 0x0201, 0x0403, 0x0605) self.assert_unpack("I;16", "I;12", 2, 0x0010, 0x0203, 0x0040) diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index 7eeadf944ea..a0fa22c7d3e 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -1149,6 +1149,16 @@ unpackI16N_I16(UINT8 *out, const UINT8 *in, int pixels) { } } static void +unpackI16B_I16(UINT8 *out, const UINT8 *in, int pixels) { + int i; + for (i = 0; i < pixels; i++) { + out[0] = in[1]; + out[1] = in[0]; + in += 2; + out += 2; + } +} +static void unpackI16R_I16(UINT8 *out, const UINT8 *in, int pixels) { int i; for (i = 0; i < pixels; i++) { @@ -1764,6 +1774,7 @@ static struct { {"I;16L", "I;16L", 16, copy2}, {"I;16N", "I;16N", 16, copy2}, + {"I;16", "I;16B", 16, unpackI16B_I16}, {"I;16", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. {"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. {"I;16B", "I;16N", 16, unpackI16N_I16B}, From b7d19e83d00b08c643c69bca6ea3f6e603c72a98 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 19:15:29 +0000 Subject: [PATCH 28/40] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/tox-dev/tox-ini-fmt: 1.0.0 → 1.3.0](/~https://github.com/tox-dev/tox-ini-fmt/compare/1.0.0...1.3.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c3b6dc0a6ad..4882a317faa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -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 From a766fa4cd1c749ca27375079ef92a57dc538c905 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 19:16:00 +0000 Subject: [PATCH 29/40] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tox.ini | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index d7948ef6dfb..458a0010734 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] -minversion = 1.9 -envlist = +requires = + tox>=4.2 +env_list = lint py{py3, 311, 310, 39, 38} @@ -23,7 +24,7 @@ skip_install = true deps = check-manifest pre-commit -passenv = +pass_env = PRE_COMMIT_COLOR commands = pre-commit run --all-files --show-diff-on-failure From d9921f697aed24bd21b7c090bb6edd55acc8997f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 3 May 2023 08:29:20 +1000 Subject: [PATCH 30/40] Use stdlib for setuptools on MinGW --- .github/workflows/test-mingw.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-mingw.yml b/.github/workflows/test-mingw.yml index ddfafc9d7f4..a109ec0d8b5 100644 --- a/.github/workflows/test-mingw.yml +++ b/.github/workflows/test-mingw.yml @@ -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: | From db7326674e5261e19fa35f3a32efaf6dea48a5cc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 1 May 2023 13:03:31 +1000 Subject: [PATCH 31/40] Updated libimagequant to 4.2.0 --- depends/install_imagequant.sh | 2 +- docs/installation.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/install_imagequant.sh b/depends/install_imagequant.sh index 362ad95a2db..fd6000ee12b 100755 --- a/depends/install_imagequant.sh +++ b/depends/install_imagequant.sh @@ -1,7 +1,7 @@ #!/bin/bash # install libimagequant -archive=libimagequant-4.1.1 +archive=libimagequant-4.2.0 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz diff --git a/docs/installation.rst b/docs/installation.rst index a254ec8c2ad..ad27b67eeaf 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -181,7 +181,7 @@ Many of Pillow's features require external libraries: * **libimagequant** provides improved color quantization - * Pillow has been tested with libimagequant **2.6-4.1.1** + * Pillow has been tested with libimagequant **2.6-4.2** * Libimagequant is licensed GPLv3, which is more restrictive than the Pillow license, therefore we will not be distributing binaries with libimagequant support enabled. From 3fc446c2770b091b07d3b6cff63e87385c19e7fc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 3 May 2023 22:54:18 +1000 Subject: [PATCH 32/40] Added width argument to regular_polygon --- Tests/images/imagedraw_triangle_width.png | Bin 0 -> 499 bytes Tests/test_imagedraw.py | 20 ++++++++++---------- docs/reference/ImageDraw.rst | 3 ++- src/PIL/ImageDraw.py | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 Tests/images/imagedraw_triangle_width.png diff --git a/Tests/images/imagedraw_triangle_width.png b/Tests/images/imagedraw_triangle_width.png new file mode 100644 index 0000000000000000000000000000000000000000..3d35326e73b92ffb24b9d64cc771662eee87000c GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0vp^DImD;uumf=k2YHeTNK0SOcs7 z|DV6msp$lZm}+J5+nH&zb(QAFEMItk*2G_{>lmti1tOXb2(e64*uc`L%Aw$qU_*5&+_>uupeX5C~oixu{%*F`cV5M`^+^t6UwtW;ym>{J}i7cmHX4mfDJwq z^7*X=RE1MQ*4H&8pJJBW`?dD-_sjpAPcv~^--$oPB)K)#^@mrH!?$&-I!`hF^gpP5 zlEE@dmQkZ-LOj3W7puq3J-@zfU|z3hc0x)1)AJh&?jqZS^iDLr&gkVSN^#UqY|`1) zcdbJqeeX_1?T3v$R>iUgB4Q_QhKC;5dYoye(vPc086$r<|C3>U^2%Ifj}Y656|C1U zN--{ZwW?{|61kQzLoZ#AukA7wy5BZkXDqONb1i$vo=pi?8!lYG7o7YVvOvzStWc37?}*7u6{1-oD!M<@Fc=% literal 0 HcmV?d00001 diff --git a/Tests/test_imagedraw.py b/Tests/test_imagedraw.py index 7ffd7969d90..406f44c06e3 100644 --- a/Tests/test_imagedraw.py +++ b/Tests/test_imagedraw.py @@ -1347,20 +1347,20 @@ def test_same_color_outline(): @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) diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index aec7a3ef89f..29115120c13 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -296,7 +296,7 @@ Methods :param width: The line width, in pixels. -.. py:method:: ImageDraw.regular_polygon(bounding_circle, n_sides, rotation=0, fill=None, outline=None) +.. py:method:: ImageDraw.regular_polygon(bounding_circle, n_sides, rotation=0, fill=None, outline=None, width=1) Draws a regular polygon inscribed in ``bounding_circle``, with ``n_sides``, and rotation of ``rotation`` degrees. @@ -311,6 +311,7 @@ Methods (e.g. ``rotation=90``, applies a 90 degree rotation). :param fill: Color to use for the fill. :param outline: Color to use for the outline. + :param width: The line width, in pixels. .. py:method:: ImageDraw.rectangle(xy, fill=None, outline=None, width=1) diff --git a/src/PIL/ImageDraw.py b/src/PIL/ImageDraw.py index e9ccf80413f..1e4eeab2543 100644 --- a/src/PIL/ImageDraw.py +++ b/src/PIL/ImageDraw.py @@ -279,11 +279,11 @@ def polygon(self, xy, fill=None, outline=None, width=1): self.im.paste(im.im, (0, 0) + im.size, mask.im) def regular_polygon( - self, bounding_circle, n_sides, rotation=0, fill=None, outline=None + self, bounding_circle, n_sides, rotation=0, fill=None, outline=None, width=1 ): """Draw a regular polygon.""" xy = _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation) - self.polygon(xy, fill, outline) + self.polygon(xy, fill, outline, width) def rectangle(self, xy, fill=None, outline=None, width=1): """Draw a rectangle.""" From a4986ba9866797648b602ce62fee393f43b522df Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 4 May 2023 07:54:30 +1000 Subject: [PATCH 33/40] Support reading signed 8-bit TIFF images --- Tests/images/8bit.s.tif | Bin 0 -> 16518 bytes Tests/test_file_tiff.py | 6 ++++++ src/PIL/TiffImagePlugin.py | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 Tests/images/8bit.s.tif diff --git a/Tests/images/8bit.s.tif b/Tests/images/8bit.s.tif new file mode 100644 index 0000000000000000000000000000000000000000..043cba6af8bbfe6d7386ac7ca247c5235c0dc387 GIT binary patch literal 16518 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 z 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 TR=N?=Kr4|!DMe+Lt#1AQlp!)* literal 0 HcmV?d00001 diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index 97a02ac969f..30c6303a2a9 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -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 diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 3d4d0910abd..1ca1b6ea9af 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -170,6 +170,8 @@ (MM, 0, (1,), 2, (8,), ()): ("L", "L;IR"), (II, 1, (1,), 1, (8,), ()): ("L", "L"), (MM, 1, (1,), 1, (8,), ()): ("L", "L"), + (II, 1, (2,), 1, (8,), ()): ("L", "L"), + (MM, 1, (2,), 1, (8,), ()): ("L", "L"), (II, 1, (1,), 2, (8,), ()): ("L", "L;R"), (MM, 1, (1,), 2, (8,), ()): ("L", "L;R"), (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"), From 9154a6b22d2915d4ca689054a239ceeed078ef2d Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 4 May 2023 08:01:48 +1000 Subject: [PATCH 34/40] Added release notes --- docs/releasenotes/10.0.0.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/releasenotes/10.0.0.rst b/docs/releasenotes/10.0.0.rst index 3ee1a9973cf..1004ba57d79 100644 --- a/docs/releasenotes/10.0.0.rst +++ b/docs/releasenotes/10.0.0.rst @@ -159,7 +159,8 @@ TODO Other Changes ============= -TODO -^^^^ +Support reading signed 8-bit TIFF images +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -TODO +TIFF images with signed integer data, 8 bits per sample and a photometric +interpretaton of BlackIsZero can now be read. From 2467db492e7e50efaf39d445c92190c713e40f6f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 4 May 2023 08:15:48 +1000 Subject: [PATCH 35/40] Update CHANGES.rst [ci skip] --- CHANGES.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 7b13900a8df..93517e1cd32 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,18 @@ Changelog (Pillow) 10.0.0 (unreleased) ------------------- +- 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] From 9f0c4164694ce99e14e7ec7fbfa8938acfb74823 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 4 May 2023 15:30:17 +1000 Subject: [PATCH 36/40] Update CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 93517e1cd32..f8844dacad8 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 10.0.0 (unreleased) ------------------- +- Support reading signed 8-bit TIFF images #7111 + [radarhere] + - Added width argument to ImageDraw regular_polygon #7132 [radarhere] From 3ae321832a52cf185ae2c10a5b17f7ea1c6f2dbe Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 4 May 2023 15:37:35 +1000 Subject: [PATCH 37/40] Added release notes for #7132 --- docs/releasenotes/10.0.0.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/releasenotes/10.0.0.rst b/docs/releasenotes/10.0.0.rst index 1004ba57d79..e2005b710e6 100644 --- a/docs/releasenotes/10.0.0.rst +++ b/docs/releasenotes/10.0.0.rst @@ -135,10 +135,11 @@ TODO API Changes =========== -TODO -^^^^ +Added line width parameter to ImageDraw regular_polygon +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -TODO +An optional line ``width`` parameter has been added to +``ImageDraw.Draw.regular_polygon``. API Additions ============= From 04191d15f6fee33c50536991e734454195c2da8a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 5 May 2023 17:54:42 +1000 Subject: [PATCH 38/40] Removed separate test for array tobytes() --- Tests/test_imagepath.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 7a517b6f61d..5082f9a79c0 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -63,17 +63,6 @@ def test_path_constructors(coords): assert list(p) == [(0.0, 1.0)] -def test_path_constructor_text(): - # Arrange - arr = array.array("f", (0, 1)) - - # Act - p = ImagePath.Path(arr.tobytes()) - - # Assert - assert list(p) == [(0.0, 1.0)] - - @pytest.mark.parametrize( "coords", ( From 17fbafb10b6fbb7d364ff4e6474149c12bc03a42 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 5 May 2023 18:12:10 +1000 Subject: [PATCH 39/40] Updated ImagePath tolist() default --- docs/reference/ImagePath.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/ImagePath.rst b/docs/reference/ImagePath.rst index 7c1a3ad7017..500096ef7dc 100644 --- a/docs/reference/ImagePath.rst +++ b/docs/reference/ImagePath.rst @@ -48,7 +48,7 @@ vector data. Path objects can be passed to the methods on the Maps the path through a function. -.. py:method:: PIL.ImagePath.Path.tolist(flat=0) +.. py:method:: PIL.ImagePath.Path.tolist(flat=False) Converts the path to a Python list [(x, y), …]. From 38c40d81d2d0a97e208c7f3bcf468a81176f6288 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 5 May 2023 18:25:05 +1000 Subject: [PATCH 40/40] Use boolean instead of integer --- Tests/test_imagepath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imagepath.py b/Tests/test_imagepath.py index 8f8a9f44915..5c40d475619 100644 --- a/Tests/test_imagepath.py +++ b/Tests/test_imagepath.py @@ -28,7 +28,7 @@ def test_path(): (6.0, 7.0), (8.0, 9.0), ] - assert p.tolist(1) == [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] + assert p.tolist(True) == [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] assert p.getbbox() == (0.0, 1.0, 8.0, 9.0)