From bcc766e02da39d94aa01f91422596efd4d3219e4 Mon Sep 17 00:00:00 2001 From: Bei Pang Date: Thu, 17 Oct 2019 10:02:15 -0700 Subject: [PATCH 01/29] Use default DPI when exif provides invalid x_resolution --- .../images/invalid-exif-without-x-resolution.jpg | Bin 0 -> 2546 bytes Tests/test_file_jpeg.py | 8 ++++++++ src/PIL/JpegImagePlugin.py | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 Tests/images/invalid-exif-without-x-resolution.jpg diff --git a/Tests/images/invalid-exif-without-x-resolution.jpg b/Tests/images/invalid-exif-without-x-resolution.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00f6bd2f30541c65db4a1d2792cd1197661bb9f0 GIT binary patch literal 2546 zcmcIlU2GIp6uz^&`~*p1Z3|_)4VM8n4eajx?ca=@lKra`U0d5#kOY$H%(NZ4v$M`l z>2^uf2NPZiKTjs0(S*bh2>4_Ok*HDB0MQ2m_+WT2;Q=rqLSodcXJ&sW&@E5iQ;RHkZqe;nAHV`4Qk;hR~4}$O9V9 zvb6h%3w49;f%7~K-3PksSi+BecM>xG_jL%~U3Z zvCL58Ecg=1Mo@EebKyBIY?xCN!}B~vvlPpQ01+zB7cHq0Dwa1l88T{FHnoza8AWU} zN)yJcC6eH&6M`bQSWB~J!QoV7N-e0mTC~cLF2;_^!KzTD**z`1td*qjff8jeJ85m= zAW1FIqWNzEOU=St9NyY~mOYnS+@N{Cy591+Y>lZ;61S)~<@|g}rN-2A^yz&Ddv zk%dXa)FsH2rb|;Qb)ck9k+_}#;dQlG&KZhY5XmgInef@N&;+Zlk*wL zQbn?D2i2izQw3NH8VfOOi01Om;&1RlaVe4|wP1_)GM5#hl6Igp482+T}5v5lIL)tZ0hBWwY@_nvP_7mSdPKpNPaWsRW;iC*w?nrz4JU zU^`qaTT)S0o3`2$Tdu7wbOYRoY^TaF8?7;}zT40W+Te4K(Ew!^JM7@PR!37$v4HD# zFsi8?RFxsq(6Li3g0{fL6qjbWIL)T`NH)dr8J4C~$y6lDCh6!9m&lS08)ZRCUT8x# zy;{(m%_Zn~TWvix@X>m#)FRxA2~Sb&KB_)>wYe~j5~<;w$A110O8JSs$lbg3Rlf_~ zTIBM(Mv?cq1o>TYw9>v~hNU^bYXH5(FibqcZKq*4Y+D_+wZB~3fBf#rwbu@PdH7!c z-oewg2dKlTDx_Qn1X24HeTZJ}=;&C}(Y0nxS6`>Mvya@+)wO{ndwP65J!GJ76ULkR z0)Y_4QlY@WKr(61rv}m4*}1M~UGMt!y}s@Z-9GH|`+bvq6PH zEb2WU8JE4!Fu?!IZM51=z%gzw+JS!1tMBZd`n>;!E;!Q8N}ECKzy9g5gVm$kZ+-LK z_koQ!sz=)Z?Pb^1bFXc?_bBVTdTt~PvS$fw@b;e%A6(DBd8Q#hXpaS2hwlHQb-aFo zw-?Sj-dc`a%G*n)ZMrSHzqtGRzLTFVfkfw~e*W>IINV)$@1Kv39op4C18CLbeXCDx xJo9MFTj&3NSRA?EzXW#M&42%j2Oghz`=?Lrn_I#G*QHbG0JypY8G65V>p$U+Z&?5U literal 0 HcmV?d00001 diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 5a34a3faa..2d9864d9a 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -634,6 +634,14 @@ class TestFileJpeg(PillowTestCase): # OSError for unidentified image. self.assertEqual(im.info.get("dpi"), (72, 72)) + def test_invalid_exif_x_resolution(self): + # When no x or y resolution defined in EXIF + im = Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") + + # This should return the default, and not a ValueError or + # OSError for unidentified image. + self.assertEqual(im.info.get("dpi"), (72, 72)) + def test_ifd_offset_exif(self): # Arrange # This image has been manually hexedited to have an IFD offset of 10, diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index da0759129..62c8d6281 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -172,7 +172,7 @@ def APP(self, marker): # 1 dpcm = 2.54 dpi dpi *= 2.54 self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5) - except (KeyError, SyntaxError, ZeroDivisionError): + except (KeyError, SyntaxError, ValueError, ZeroDivisionError): # SyntaxError for invalid/unreadable EXIF # KeyError for dpi not included # ZeroDivisionError for invalid dpi rational value From a2b0269167329a110b8ff0ed930ee632c87f6b7a Mon Sep 17 00:00:00 2001 From: Bei Pang Date: Thu, 24 Oct 2019 16:32:11 -0700 Subject: [PATCH 02/29] Added comment to ValueError --- src/PIL/JpegImagePlugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 62c8d6281..00ea95e41 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -172,10 +172,11 @@ def APP(self, marker): # 1 dpcm = 2.54 dpi dpi *= 2.54 self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5) - except (KeyError, SyntaxError, ValueError, ZeroDivisionError): + except (KeyError, TypeError, SyntaxError, ValueError, ZeroDivisionError): # SyntaxError for invalid/unreadable EXIF # KeyError for dpi not included # ZeroDivisionError for invalid dpi rational value + # ValueError for x_resolution[0] being an invalid float self.info["dpi"] = 72, 72 From f53b86b6730aa730c3bf73e5d868ceadecdfd026 Mon Sep 17 00:00:00 2001 From: Bei Pang Date: Mon, 28 Oct 2019 09:48:37 -0700 Subject: [PATCH 03/29] Removed TypeError exception check in JpegImagePlugin; Updated comments in test --- Tests/test_file_jpeg.py | 4 ++-- src/PIL/JpegImagePlugin.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_file_jpeg.py b/Tests/test_file_jpeg.py index 2d9864d9a..1ad9961a2 100644 --- a/Tests/test_file_jpeg.py +++ b/Tests/test_file_jpeg.py @@ -635,11 +635,11 @@ class TestFileJpeg(PillowTestCase): self.assertEqual(im.info.get("dpi"), (72, 72)) def test_invalid_exif_x_resolution(self): - # When no x or y resolution defined in EXIF + # When no x or y resolution is defined in EXIF im = Image.open("Tests/images/invalid-exif-without-x-resolution.jpg") # This should return the default, and not a ValueError or - # OSError for unidentified image. + # OSError for an unidentified image. self.assertEqual(im.info.get("dpi"), (72, 72)) def test_ifd_offset_exif(self): diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 00ea95e41..193ca4bd0 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -172,7 +172,7 @@ def APP(self, marker): # 1 dpcm = 2.54 dpi dpi *= 2.54 self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5) - except (KeyError, TypeError, SyntaxError, ValueError, ZeroDivisionError): + except (KeyError, SyntaxError, ValueError, ZeroDivisionError): # SyntaxError for invalid/unreadable EXIF # KeyError for dpi not included # ZeroDivisionError for invalid dpi rational value From a27e676b1128c4db81843d0f8556fbc3b3d9b415 Mon Sep 17 00:00:00 2001 From: Hugo Date: Tue, 19 Nov 2019 14:47:15 +0200 Subject: [PATCH 04/29] Recommend upgrading pip before Pillow, and use python -m pip --- docs/installation.rst | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 4ccc47ae4..796ba9b38 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -46,7 +46,8 @@ Basic Installation Install Pillow with :command:`pip`:: - $ pip install Pillow + python -m pip install pip + python -m pip install Pillow Windows Installation @@ -57,7 +58,8 @@ supported Pythons in both 32 and 64-bit versions in wheel, egg, and executable installers. These binaries have all of the optional libraries included except for raqm and libimagequant:: - > pip install Pillow + python -m pip install pip + python -m pip install Pillow macOS Installation @@ -68,7 +70,8 @@ versions in the wheel format. These include support for all optional libraries except libimagequant. Raqm support requires libraqm, fribidi, and harfbuzz to be installed separately:: - $ pip install Pillow + python -m pip install pip + python -m pip install Pillow Linux Installation ^^^^^^^^^^^^^^^^^^ @@ -78,7 +81,8 @@ versions in the manylinux wheel format. These include support for all optional libraries except libimagequant. Raqm support requires libraqm, fribidi, and harfbuzz to be installed separately:: - $ pip install Pillow + python -m pip install pip + python -m pip install Pillow Most major Linux distributions, including Fedora, Debian/Ubuntu and ArchLinux also include Pillow in packages that previously contained @@ -194,7 +198,8 @@ Many of Pillow's features require external libraries: Once you have installed the prerequisites, run:: - $ pip install Pillow + python -m pip install pip + python -m pip install Pillow If the prerequisites are installed in the standard library locations for your machine (e.g. :file:`/usr` or :file:`/usr/local`), no @@ -204,7 +209,7 @@ those locations by editing :file:`setup.py` or :file:`setup.cfg`, or by adding environment variables on the command line:: - $ CFLAGS="-I/usr/pkg/include" pip install pillow + CFLAGS="-I/usr/pkg/include" python -m pip install pillow If Pillow has been previously built without the required prerequisites, it may be necessary to manually clear the pip cache or @@ -248,11 +253,11 @@ Build Options Sample usage:: - $ MAX_CONCURRENCY=1 python setup.py build_ext --enable-[feature] install + MAX_CONCURRENCY=1 python setup.py build_ext --enable-[feature] install or using pip:: - $ pip install pillow --global-option="build_ext" --global-option="--enable-[feature]" + python -m pip install pillow --global-option="build_ext" --global-option="--enable-[feature]" Building on macOS @@ -268,21 +273,22 @@ tools. The easiest way to install external libraries is via `Homebrew `_. After you install Homebrew, run:: - $ brew install libtiff libjpeg webp little-cms2 + brew install libtiff libjpeg webp little-cms2 To install libraqm on macOS use Homebrew to install its dependencies:: - $ brew install freetype harfbuzz fribidi + brew install freetype harfbuzz fribidi Then see ``depends/install_raqm_cmake.sh`` to install libraqm. Now install Pillow with:: - $ pip install Pillow + python -m pip install pip + python -m pip install Pillow or from within the uncompressed source directory:: - $ python setup.py install + python setup.py install Building on Windows ^^^^^^^^^^^^^^^^^^^ @@ -296,17 +302,17 @@ Building on FreeBSD .. Note:: Only FreeBSD 10 and 11 tested -Make sure you have Python's development libraries installed.:: +Make sure you have Python's development libraries installed:: - $ sudo pkg install python2 + sudo pkg install python2 Or for Python 3:: - $ sudo pkg install python3 + sudo pkg install python3 Prerequisites are installed on **FreeBSD 10 or 11** with:: - $ sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 openjpeg harfbuzz fribidi + sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 openjpeg harfbuzz fribidi Then see ``depends/install_raqm_cmake.sh`` to install libraqm. @@ -319,25 +325,25 @@ development libraries installed. In Debian or Ubuntu:: - $ sudo apt-get install python-dev python-setuptools + sudo apt-get install python-dev python-setuptools Or for Python 3:: - $ sudo apt-get install python3-dev python3-setuptools + sudo apt-get install python3-dev python3-setuptools In Fedora, the command is:: - $ sudo dnf install python-devel redhat-rpm-config + sudo dnf install python-devel redhat-rpm-config Or for Python 3:: - $ sudo dnf install python3-devel redhat-rpm-config + sudo dnf install python3-devel redhat-rpm-config .. Note:: ``redhat-rpm-config`` is required on Fedora 23, but not earlier versions. Prerequisites are installed on **Ubuntu 16.04 LTS** with:: - $ sudo apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev \ + sudo apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev \ libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk \ libharfbuzz-dev libfribidi-dev @@ -345,7 +351,7 @@ Then see ``depends/install_raqm.sh`` to install libraqm. Prerequisites are installed on recent **RedHat** **Centos** or **Fedora** with:: - $ sudo dnf install libtiff-devel libjpeg-devel openjpeg2-devel zlib-devel \ + sudo dnf install libtiff-devel libjpeg-devel openjpeg2-devel zlib-devel \ freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel \ harfbuzz-devel fribidi-devel libraqm-devel libimagequant-devel @@ -362,7 +368,7 @@ Building on Android Basic Android support has been added for compilation within the Termux environment. The dependencies can be installed by:: - $ pkg -y install python python-dev ndk-sysroot clang make \ + pkg -y install python python-dev ndk-sysroot clang make \ libjpeg-turbo-dev This has been tested within the Termux app on ChromeOS, on x86. From f663079a13f8b963ef0eac0212f4c0c2a36c69f0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 7 Dec 2019 09:26:48 +1100 Subject: [PATCH 05/29] Removed prompts [ci skip] --- docs/installation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 796ba9b38..39005db8e 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -95,11 +95,11 @@ Pillow can be installed on FreeBSD via the official Ports or Packages systems: **Ports**:: - $ cd /usr/ports/graphics/py-pillow && make install clean + cd /usr/ports/graphics/py-pillow && make install clean **Packages**:: - $ pkg install py27-pillow + pkg install py27-pillow .. note:: From 77ad951d9604ce975751a3767a5e0b4f4106f052 Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 12 Dec 2019 00:07:00 +0200 Subject: [PATCH 06/29] GHA: Use python-pillow/Pillow's Codecov token for own builds --- .codecov.yml | 2 -- .github/workflows/codecov-upstream.yml | 18 ++++++++++++++++++ .github/workflows/test-windows.yml | 14 ++++++++++---- .github/workflows/test.yml | 14 +++++++++----- 4 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/codecov-upstream.yml diff --git a/.codecov.yml b/.codecov.yml index 060b2685e..a9ab1c2d7 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -6,8 +6,6 @@ codecov: # https://docs.codecov.io/docs/comparing-commits allow_coverage_offsets: true - token: 6dafc396-e7f5-4221-a38a-8b07a49fbdae - comment: off # Matches 'omit:' in .coveragerc diff --git a/.github/workflows/codecov-upstream.yml b/.github/workflows/codecov-upstream.yml new file mode 100644 index 000000000..d348345dc --- /dev/null +++ b/.github/workflows/codecov-upstream.yml @@ -0,0 +1,18 @@ +# Documentation: https://docs.codecov.io/docs/codecov-yaml + +codecov: + # Avoid "Missing base report" due to committing CHANGES.rst with "[CI skip]" + # https://github.com/codecov/support/issues/363 + # https://docs.codecov.io/v4.3.6/docs/comparing-commits + allow_coverage_offsets: true + + token: 6dafc396-e7f5-4221-a38a-8b07a49fbdae + +comment: off + +# Matches 'omit:' in .coveragerc +ignore: + - "Tests/32bit_segfault_check.py" + - "Tests/bench_cffi_access.py" + - "Tests/check_*.py" + - "Tests/createfontdatachunk.py" diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index e0c55bc1a..fc97df3f3 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -366,10 +366,16 @@ jobs: - name: Upload coverage if: success() - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - name: ${{ runner.os }} Python ${{ matrix.python-version }} + run: | + if [ "$GITHUB_REPOSITORY" == "python-pillow/Pillow" ]; then + echo "CI on python-pillow/Pillow, copy CodeCov settings" + cp .github/workflows/codecov-upstream.yml .codecov.yml + fi + curl -s https://codecov.io/bash | bash + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + CODECOV_NAME: ${{ runner.os }} Python ${{ matrix.python-version }} + shell: bash - name: Build wheel id: wheel diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 78307b7a1..4419adad4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -95,12 +95,16 @@ jobs: .travis/after_success.sh env: MATRIX_OS: ${{ matrix.os }} - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - name: Upload coverage if: success() - uses: codecov/codecov-action@v1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - name: ${{ matrix.os }} Python ${{ matrix.python-version }} + run: | + if [ "$GITHUB_REPOSITORY" == "python-pillow/Pillow" ]; then + echo "CI on python-pillow/Pillow, copy CodeCov settings" + cp .github/workflows/codecov-upstream.yml .codecov.yml + fi + bash <(curl -s https://codecov.io/bash) + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + CODECOV_NAME: ${{ matrix.os }} Python ${{ matrix.python-version }} From 1c90c9d541211f287380e206cc207ebf100d91b0 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 14 Dec 2019 13:42:54 +0200 Subject: [PATCH 07/29] Add echo to debug 'Windows / Python 3.5 x86' --- .github/workflows/test-windows.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index fc97df3f3..a49679a4f 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -371,7 +371,8 @@ jobs: echo "CI on python-pillow/Pillow, copy CodeCov settings" cp .github/workflows/codecov-upstream.yml .codecov.yml fi - curl -s https://codecov.io/bash | bash + echo Upload coverage + curl -s https://codecov.io/bash | bash env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} CODECOV_NAME: ${{ runner.os }} Python ${{ matrix.python-version }} From 1275b10e6f034518318317648206846e624924d0 Mon Sep 17 00:00:00 2001 From: Alexander Date: Fri, 20 Dec 2019 23:21:43 +0300 Subject: [PATCH 08/29] update release notes --- docs/releasenotes/7.0.0.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/releasenotes/7.0.0.rst b/docs/releasenotes/7.0.0.rst index 08933eaf8..01fa0b8a3 100644 --- a/docs/releasenotes/7.0.0.rst +++ b/docs/releasenotes/7.0.0.rst @@ -118,8 +118,12 @@ Use instead: with Image.open("hopper.png") as im: im.save("out.jpg") -Better thumbnail aspect ratio preservation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Better thumbnail geometry +^^^^^^^^^^^^^^^^^^^^^^^^^ When calculating the new dimensions in ``Image.thumbnail``, round to the nearest integer, instead of always rounding down. +This better preserves the original aspect ratio. + +The last row and column in the image get the correct weight after +JPEG DCT scaling when image size is not divisible by 8. From ce62dca3264db9b31ce251106c5170eac491e92e Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 21 Dec 2019 08:15:48 +1100 Subject: [PATCH 09/29] Aligned comments correctly --- src/PIL/BmpImagePlugin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index cdef77ced..5f88c2b75 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -322,11 +322,11 @@ def _save(im, fp, filename, bitmap_header=True): if bitmap_header: offset = 14 + header + colors * 4 fp.write( - b"BM" - + o32(offset + image) # file type (magic) - + o32(0) # file size - + o32(offset) # reserved - ) # image data offset + b"BM" # file type (magic) + + o32(offset + image) # file size + + o32(0) # reserved + + o32(offset) # image data offset + ) # bitmap info header fp.write( From 945b4e9c826ab51530f716b512575d1d8f29dc00 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 21 Dec 2019 00:25:52 +0300 Subject: [PATCH 10/29] add references, fix release notes syntax --- docs/releasenotes/7.0.0.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/releasenotes/7.0.0.rst b/docs/releasenotes/7.0.0.rst index f9634e8cc..ac4fcb922 100644 --- a/docs/releasenotes/7.0.0.rst +++ b/docs/releasenotes/7.0.0.rst @@ -52,8 +52,8 @@ Default resampling filter The default resampling filter has been changed to the high-quality convolution ``Image.BICUBIC`` instead of ``Image.NEAREST``, for the :py:meth:`~PIL.Image.Image.resize` -method and the :py:meth:`~PIL.ImageOps.pad``, :py:meth:`~PIL.ImageOps.scale`` -and :py:meth:`~PIL.ImageOps.fit`` functions. +method and the :py:meth:`~PIL.ImageOps.pad`, :py:meth:`~PIL.ImageOps.scale` +and :py:meth:`~PIL.ImageOps.fit` functions. ``Image.NEAREST`` is still always used for images in "P" and "1" modes. See :ref:`concept-filters` to learn the difference. In short, ``Image.NEAREST`` is a very fast filter, but simple and low-quality. @@ -87,8 +87,8 @@ Image.__del__ ^^^^^^^^^^^^^ Implicitly closing the image's underlying file in ``Image.__del__`` has been removed. -Use a context manager or call ``Image.close()`` instead to close the file in a -deterministic way. +Use a context manager or call :py:meth:`~PIL.Image.Image.close` instead to close +the file in a deterministic way. Previous method: @@ -107,5 +107,5 @@ Use instead: Better thumbnail aspect ratio preservation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -When calculating the new dimensions in ``Image.thumbnail``, round to the -nearest integer, instead of always rounding down. +When calculating the new dimensions in :py:meth:`~PIL.Image.Image.thumbnail`, +round to the nearest integer, instead of always rounding down. From 4580b156b77e490d8db4545beb7a88f9494bf718 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 21 Dec 2019 08:37:40 +1100 Subject: [PATCH 11/29] Raise an error if BMP file size is too large when saving --- Tests/test_file_bmp.py | 7 +++++++ src/PIL/BmpImagePlugin.py | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index 76cd98aba..338f52cd7 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -41,6 +41,13 @@ class TestFileBmp(PillowTestCase): self.assertEqual(im.size, reloaded.size) self.assertEqual(reloaded.format, "BMP") + def test_save_too_large(self): + outfile = self.tempfile("temp.bmp") + with Image.new("RGB", (1, 1)) as im: + im._size = (37838, 37838) + with self.assertRaises(ValueError): + im.save(outfile) + def test_dpi(self): dpi = (72, 72) diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index 5f88c2b75..85e2350c5 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -321,9 +321,12 @@ def _save(im, fp, filename, bitmap_header=True): # bitmap header if bitmap_header: offset = 14 + header + colors * 4 + file_size = offset + image + if file_size > 2 ** 32 - 1: + raise ValueError("File size is too large for the BMP format") fp.write( b"BM" # file type (magic) - + o32(offset + image) # file size + + o32(file_size) # file size + o32(0) # reserved + o32(offset) # image data offset ) From 49a5bd3602001e00f276efb333a12f25fed61258 Mon Sep 17 00:00:00 2001 From: Alexander Karpinsky Date: Sat, 21 Dec 2019 03:42:06 +0300 Subject: [PATCH 12/29] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 1ea09fff8..fe50b55e0 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 7.0.0 (unreleased) ------------------ +- Fixed black lines on upscaled images with the BOX filter #4278 + [homm] + - Change default resize resampling filter from NEAREST to BICUBIC #4255 [homm] From eced5620125d1cbafb9fdedc5a318220f3e5a323 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 21 Dec 2019 12:24:45 +0200 Subject: [PATCH 13/29] Fix 404 Co-Authored-By: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- .github/workflows/codecov-upstream.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codecov-upstream.yml b/.github/workflows/codecov-upstream.yml index d348345dc..060b2685e 100644 --- a/.github/workflows/codecov-upstream.yml +++ b/.github/workflows/codecov-upstream.yml @@ -3,7 +3,7 @@ codecov: # Avoid "Missing base report" due to committing CHANGES.rst with "[CI skip]" # https://github.com/codecov/support/issues/363 - # https://docs.codecov.io/v4.3.6/docs/comparing-commits + # https://docs.codecov.io/docs/comparing-commits allow_coverage_offsets: true token: 6dafc396-e7f5-4221-a38a-8b07a49fbdae From 6a256a83965a48b90a1900e31609f7ca717f9aee Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 21 Dec 2019 13:11:12 +0200 Subject: [PATCH 14/29] make doccheck: turn warnings into errors --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 1a912039e..510c4e2cc 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -42,7 +42,7 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXBUILD) -b html -W $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." From b3547dc2c0a574545604649fb8a69eb8ea37b2ba Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 21 Dec 2019 13:46:38 +0200 Subject: [PATCH 15/29] --keep-going to show all of the problems Co-Authored-By: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 510c4e2cc..ba79d9070 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -42,7 +42,7 @@ clean: -rm -rf $(BUILDDIR)/* html: - $(SPHINXBUILD) -b html -W $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXBUILD) -b html -W --keep-going $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." From 113477fbeeec718c01449dec93f40eaa66782f27 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 21 Dec 2019 14:05:50 +0200 Subject: [PATCH 16/29] Fix unexpected unindents --- src/PIL/Image.py | 2 ++ src/PIL/ImageOps.py | 1 + 2 files changed, 3 insertions(+) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index ed90a26f7..b36f64735 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2181,12 +2181,14 @@ class Image: It may also be an :py:class:`~PIL.Image.ImageTransformHandler` object:: + class Example(Image.ImageTransformHandler): def transform(size, method, data, resample, fill=1): # Return result It may also be an object with a :py:meth:`~method.getdata` method that returns a tuple supplying new **method** and **data** values:: + class Example(object): def getdata(self): method = Image.EXTENT diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 3a6dabf5e..4391af569 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -234,6 +234,7 @@ def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)): :param color: The background color of the padded image. :param centering: Control the position of the original image within the padded version. + (0.5, 0.5) will keep the image centered (0, 0) will keep the image aligned to the top left (1, 1) will keep the image aligned to the bottom From d025fbe16de642d96a861653293636e4fd82f322 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 21 Dec 2019 15:48:00 +0200 Subject: [PATCH 17/29] Install TkInter for Python 3, not 2 --- .travis/install.sh | 2 +- docs/installation.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis/install.sh b/.travis/install.sh index 747acb448..48bcf0016 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -3,7 +3,7 @@ set -e sudo apt-get update -sudo apt-get -qq install libfreetype6-dev liblcms2-dev python-tk\ +sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ ghostscript libffi-dev libjpeg-turbo-progs libopenjp2-7-dev\ cmake imagemagick libharfbuzz-dev libfribidi-dev diff --git a/docs/installation.rst b/docs/installation.rst index 385b570b6..a68668973 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -335,7 +335,7 @@ Or for Python 3:: Prerequisites are installed on **Ubuntu 16.04 LTS** with:: $ sudo apt-get install libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev \ - libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk \ + libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python3-tk \ libharfbuzz-dev libfribidi-dev Then see ``depends/install_raqm.sh`` to install libraqm. From 5027b97c69692e5a86552dfd82833a584f2e4e56 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 23 Dec 2019 21:17:04 +1100 Subject: [PATCH 18/29] Use the same Python version to build docs in Travis and GHA --- .travis/install.sh | 4 ++-- .travis/test.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis/install.sh b/.travis/install.sh index 747acb448..926e38303 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -20,8 +20,8 @@ if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then pip install pyqt5 fi -# docs only on Python 3.7 -if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then pip install -r requirements.txt ; fi +# docs only on Python 3.8 +if [ "$TRAVIS_PYTHON_VERSION" == "3.8" ]; then pip install -r requirements.txt ; fi # webp pushd depends && ./install_webp.sh && popd diff --git a/.travis/test.sh b/.travis/test.sh index 91dae9f8d..832d90433 100755 --- a/.travis/test.sh +++ b/.travis/test.sh @@ -5,4 +5,4 @@ set -e python -m pytest -v -x --cov PIL --cov Tests --cov-report term Tests # Docs -if [ "$TRAVIS_PYTHON_VERSION" == "3.7" ]; then make doccheck; fi +if [ "$TRAVIS_PYTHON_VERSION" == "3.8" ]; then make doccheck; fi From fbb14f67a30b612454bc7cf9a5f73d6b35e7eb14 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Mon, 23 Dec 2019 12:26:59 +0200 Subject: [PATCH 19/29] Only check docs on Travis At least whilst there's a problem on GHA: https://github.community/t5/GitHub-Actions/GitHub-Action-for-python-import-of-quot-tkinter-quot-fails/td-p/40644 --- .github/workflows/test.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 78307b7a1..0a4dcc544 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,12 +83,6 @@ jobs: name: errors path: Tests/errors - - name: Docs - if: matrix.python-version == 3.8 - run: | - pip install sphinx-rtd-theme - make doccheck - - name: After success if: success() run: | From 74a80346446e366daa0342df092a02776e8121dc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 24 Dec 2019 14:50:53 +1100 Subject: [PATCH 20/29] Updated draft documentation [ci skip] --- src/PIL/Image.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index b36f64735..770dc3c93 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1127,15 +1127,14 @@ class Image: Configures the image file loader so it returns a version of the image that as closely as possible matches the given mode and size. For example, you can use this method to convert a color - JPEG to greyscale while loading it, or to extract a 128x192 - version from a PCD file. + JPEG to greyscale while loading it. Note that this method modifies the :py:class:`~PIL.Image.Image` object in place. If the image has already been loaded, this method has no effect. Note: This method is not implemented for most images. It is - currently implemented only for JPEG and PCD images. + currently implemented only for JPEG and MPO images. :param mode: The requested mode. :param size: The requested size. From 663fea308b8f5380cc65d0592030cfc40143e8f1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 24 Dec 2019 15:06:47 +1100 Subject: [PATCH 21/29] Updated wording [ci skip] --- docs/releasenotes/7.0.0.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/releasenotes/7.0.0.rst b/docs/releasenotes/7.0.0.rst index 3c223852a..be6d28c04 100644 --- a/docs/releasenotes/7.0.0.rst +++ b/docs/releasenotes/7.0.0.rst @@ -61,14 +61,14 @@ See :ref:`concept-filters` to learn the difference. In short, Image.draft() return value ^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``Image.draft()`` method used to return ``None`` or the image itself. -Unlike other `chain methods`_, ``draft()`` modifies the image in-place -rather than returning a modified version. - -In the new version, ``draft()`` returns ``None`` if it has no effect or -a tuple of new image mode and the box of original coordinates in the -bounds of resulting image otherwise -(the box could be useful in subsequent ``resize()`` call). +If the :py:meth:`~PIL.Image.Image.draft` method has no effect, it returns ``None``. +If it does have an effect, then it previously returned the image itself. +However, unlike other `chain methods`_, :py:meth:`~PIL.Image.Image.draft` does not +return a modified version of the image, but modifies it in-place. So instead, if +:py:meth:`~PIL.Image.Image.draft` has an effect, Pillow will now return a tuple +of the image mode and a co-ordinate box. The box is the original coordinates in the +bounds of resulting image. This may be useful in a subsequent +:py:meth:`~PIL.Image.Image.resize` call. .. _chain methods: https://en.wikipedia.org/wiki/Method_chaining From 1e5c2564b1b7a86efe9d60ed75db3eb6dc4b7f2f Mon Sep 17 00:00:00 2001 From: Hugo Date: Tue, 24 Dec 2019 09:58:25 +0200 Subject: [PATCH 22/29] Move codecov config up a dir to prevent GHA recognising as workflow --- .github/{workflows => }/codecov-upstream.yml | 0 .github/workflows/test-windows.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename .github/{workflows => }/codecov-upstream.yml (100%) diff --git a/.github/workflows/codecov-upstream.yml b/.github/codecov-upstream.yml similarity index 100% rename from .github/workflows/codecov-upstream.yml rename to .github/codecov-upstream.yml diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index a49679a4f..0f05d7b1c 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -369,7 +369,7 @@ jobs: run: | if [ "$GITHUB_REPOSITORY" == "python-pillow/Pillow" ]; then echo "CI on python-pillow/Pillow, copy CodeCov settings" - cp .github/workflows/codecov-upstream.yml .codecov.yml + cp .github/codecov-upstream.yml .codecov.yml fi echo Upload coverage curl -s https://codecov.io/bash | bash diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4419adad4..f98763e85 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -102,7 +102,7 @@ jobs: run: | if [ "$GITHUB_REPOSITORY" == "python-pillow/Pillow" ]; then echo "CI on python-pillow/Pillow, copy CodeCov settings" - cp .github/workflows/codecov-upstream.yml .codecov.yml + cp .github/codecov-upstream.yml .codecov.yml fi bash <(curl -s https://codecov.io/bash) env: From 22ac95a588d49bb4e8a83d5f3db76c2738bdc0a6 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 24 Dec 2019 19:11:46 +1100 Subject: [PATCH 23/29] Keep codecov-action --- .github/workflows/test-windows.yml | 19 ++++++++----------- .github/workflows/test.yml | 17 ++++++++--------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 0f05d7b1c..e97db30c4 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -364,19 +364,16 @@ jobs: name: errors path: Tests/errors + - name: Prepare coverage token + if: success() && github.repository == 'python-pillow/Pillow' + run: cp .github/codecov-upstream.yml .codecov.yml + - name: Upload coverage if: success() - run: | - if [ "$GITHUB_REPOSITORY" == "python-pillow/Pillow" ]; then - echo "CI on python-pillow/Pillow, copy CodeCov settings" - cp .github/codecov-upstream.yml .codecov.yml - fi - echo Upload coverage - curl -s https://codecov.io/bash | bash - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - CODECOV_NAME: ${{ runner.os }} Python ${{ matrix.python-version }} - shell: bash + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + name: ${{ runner.os }} Python ${{ matrix.python-version }} - name: Build wheel id: wheel diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f98763e85..94836fb52 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -97,14 +97,13 @@ jobs: MATRIX_OS: ${{ matrix.os }} COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + - name: Prepare coverage token + if: success() && github.repository == 'python-pillow/Pillow' + run: cp .github/codecov-upstream.yml .codecov.yml + - name: Upload coverage if: success() - run: | - if [ "$GITHUB_REPOSITORY" == "python-pillow/Pillow" ]; then - echo "CI on python-pillow/Pillow, copy CodeCov settings" - cp .github/codecov-upstream.yml .codecov.yml - fi - bash <(curl -s https://codecov.io/bash) - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - CODECOV_NAME: ${{ matrix.os }} Python ${{ matrix.python-version }} + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + name: ${{ matrix.os }} Python ${{ matrix.python-version }} From 7c3076f613a1b6c04c4f3e795c87ac055412f308 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 25 Dec 2019 08:00:08 +1100 Subject: [PATCH 24/29] Updated PyPy3 to 7.3.0 --- .github/workflows/test-windows.yml | 4 ++-- winbuild/appveyor_install_pypy3.cmd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index e97db30c4..4acf55052 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -19,8 +19,8 @@ jobs: platform-vcvars: "x86_amd64" platform-msbuild: "x64" - python-version: "pypy3.6" - pypy-version: "pypy3.6-v7.2.0-win32" - pypy-url: "https://bitbucket.org/pypy/pypy/downloads/pypy3.6-v7.2.0-win32.zip" + pypy-version: "pypy3.6-v7.3.0-win32" + pypy-url: "https://bitbucket.org/pypy/pypy/downloads/pypy3.6-v7.3.0-win32.zip" exclude: - python-version: "pypy3.6" architecture: "x64" diff --git a/winbuild/appveyor_install_pypy3.cmd b/winbuild/appveyor_install_pypy3.cmd index 3622ed6ec..75a22ca59 100644 --- a/winbuild/appveyor_install_pypy3.cmd +++ b/winbuild/appveyor_install_pypy3.cmd @@ -1,3 +1,3 @@ -curl -fsSL -o pypy3.zip https://bitbucket.org/pypy/pypy/downloads/pypy3.6-v7.2.0-win32.zip +curl -fsSL -o pypy3.zip https://bitbucket.org/pypy/pypy/downloads/pypy3.6-v7.3.0-win32.zip 7z x pypy3.zip -oc:\ -c:\Python37\Scripts\virtualenv.exe -p c:\pypy3.6-v7.2.0-win32\pypy3.exe c:\vp\pypy3 +c:\Python37\Scripts\virtualenv.exe -p c:\pypy3.6-v7.3.0-win32\pypy3.exe c:\vp\pypy3 From 1740a1f20e5480b4039355fc79e579c9c60677b0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 25 Dec 2019 15:22:54 +1100 Subject: [PATCH 25/29] Ensure tempfile is unlinked --- src/PIL/GifImagePlugin.py | 66 +++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 7717fc707..5f9ba59c1 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -616,38 +616,42 @@ def _save_netpbm(im, fp, filename): # below for information on how to enable this. tempfile = im._dump() - with open(filename, "wb") as f: - if im.mode != "RGB": - subprocess.check_call( - ["ppmtogif", tempfile], stdout=f, stderr=subprocess.DEVNULL - ) - else: - # Pipe ppmquant output into ppmtogif - # "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename) - quant_cmd = ["ppmquant", "256", tempfile] - togif_cmd = ["ppmtogif"] - quant_proc = subprocess.Popen( - quant_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL - ) - togif_proc = subprocess.Popen( - togif_cmd, stdin=quant_proc.stdout, stdout=f, stderr=subprocess.DEVNULL - ) - - # Allow ppmquant to receive SIGPIPE if ppmtogif exits - quant_proc.stdout.close() - - retcode = quant_proc.wait() - if retcode: - raise subprocess.CalledProcessError(retcode, quant_cmd) - - retcode = togif_proc.wait() - if retcode: - raise subprocess.CalledProcessError(retcode, togif_cmd) - try: - os.unlink(tempfile) - except OSError: - pass + with open(filename, "wb") as f: + if im.mode != "RGB": + subprocess.check_call( + ["ppmtogif", tempfile], stdout=f, stderr=subprocess.DEVNULL + ) + else: + # Pipe ppmquant output into ppmtogif + # "ppmquant 256 %s | ppmtogif > %s" % (tempfile, filename) + quant_cmd = ["ppmquant", "256", tempfile] + togif_cmd = ["ppmtogif"] + quant_proc = subprocess.Popen( + quant_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL + ) + togif_proc = subprocess.Popen( + togif_cmd, + stdin=quant_proc.stdout, + stdout=f, + stderr=subprocess.DEVNULL, + ) + + # Allow ppmquant to receive SIGPIPE if ppmtogif exits + quant_proc.stdout.close() + + retcode = quant_proc.wait() + if retcode: + raise subprocess.CalledProcessError(retcode, quant_cmd) + + retcode = togif_proc.wait() + if retcode: + raise subprocess.CalledProcessError(retcode, togif_cmd) + finally: + try: + os.unlink(tempfile) + except OSError: + pass # Force optimization so that we can test performance against From 9a72ad4fa954c5c5a0160ed28d8d73d60df9df43 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 25 Dec 2019 15:32:26 +1100 Subject: [PATCH 26/29] Removed condition already present from inheritance --- Tests/test_font_leaks.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/test_font_leaks.py b/Tests/test_font_leaks.py index 393ddb0fb..a32cbd81c 100644 --- a/Tests/test_font_leaks.py +++ b/Tests/test_font_leaks.py @@ -2,10 +2,9 @@ import unittest from PIL import Image, ImageDraw, ImageFont, features -from .helper import PillowLeakTestCase, is_win32 +from .helper import PillowLeakTestCase -@unittest.skipIf(is_win32(), "requires Unix or macOS") class TestTTypeFontLeak(PillowLeakTestCase): # fails at iteration 3 in master iterations = 10 From 666b726626def75f70e14ba1002cf4a9785ac28b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 25 Dec 2019 14:13:16 +1100 Subject: [PATCH 27/29] Simplified conditions --- Tests/test_file_msp.py | 2 +- Tests/test_file_sun.py | 2 +- Tests/test_file_webp.py | 2 +- Tests/test_font_leaks.py | 2 +- Tests/test_imagefont_bitmap.py | 2 +- Tests/test_imagetk.py | 2 +- Tests/test_util.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Tests/test_file_msp.py b/Tests/test_file_msp.py index 51189b83b..18c312046 100644 --- a/Tests/test_file_msp.py +++ b/Tests/test_file_msp.py @@ -49,7 +49,7 @@ class TestFileMsp(PillowTestCase): with Image.open(target_path) as target: self.assert_image_equal(im, target) - @unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed") + @unittest.skipUnless(os.path.exists(EXTRA_DIR), "Extra image files not installed") def test_open_windows_v2(self): files = ( diff --git a/Tests/test_file_sun.py b/Tests/test_file_sun.py index 835aead79..6fe9ff29c 100644 --- a/Tests/test_file_sun.py +++ b/Tests/test_file_sun.py @@ -30,7 +30,7 @@ class TestFileSun(PillowTestCase): with Image.open("Tests/images/sunraster.im1.png") as target: self.assert_image_equal(im, target) - @unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed") + @unittest.skipUnless(os.path.exists(EXTRA_DIR), "Extra image files not installed") def test_others(self): files = ( os.path.join(EXTRA_DIR, f) diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index a2fdbc333..00028edb4 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -26,7 +26,7 @@ class TestUnsupportedWebp(PillowTestCase): WebPImagePlugin.SUPPORTED = True -@unittest.skipIf(not HAVE_WEBP, "WebP support not installed") +@unittest.skipUnless(HAVE_WEBP, "WebP support not installed") class TestFileWebp(PillowTestCase): def setUp(self): self.rgb_mode = "RGB" diff --git a/Tests/test_font_leaks.py b/Tests/test_font_leaks.py index a32cbd81c..be0612fa2 100644 --- a/Tests/test_font_leaks.py +++ b/Tests/test_font_leaks.py @@ -19,7 +19,7 @@ class TestTTypeFontLeak(PillowLeakTestCase): ) ) - @unittest.skipIf(not features.check("freetype2"), "Test requires freetype2") + @unittest.skipUnless(features.check("freetype2"), "Test requires freetype2") def test_leak(self): ttype = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20) self._test_font(ttype) diff --git a/Tests/test_imagefont_bitmap.py b/Tests/test_imagefont_bitmap.py index eed0c70b6..6853504f6 100644 --- a/Tests/test_imagefont_bitmap.py +++ b/Tests/test_imagefont_bitmap.py @@ -11,7 +11,7 @@ except ImportError: image_font_installed = False -@unittest.skipIf(not image_font_installed, "image font not installed") +@unittest.skipUnless(image_font_installed, "image font not installed") class TestImageFontBitmap(PillowTestCase): def test_similar(self): text = "EmbeddedBitmap" diff --git a/Tests/test_imagetk.py b/Tests/test_imagetk.py index 5ee994dc7..e6032cc2e 100644 --- a/Tests/test_imagetk.py +++ b/Tests/test_imagetk.py @@ -18,7 +18,7 @@ except (OSError, ImportError): TK_MODES = ("1", "L", "P", "RGB", "RGBA") -@unittest.skipIf(not HAS_TK, "Tk not installed") +@unittest.skipUnless(HAS_TK, "Tk not installed") class TestImageTk(PillowTestCase): def setUp(self): try: diff --git a/Tests/test_util.py b/Tests/test_util.py index 6a111b5b9..c3ef29409 100644 --- a/Tests/test_util.py +++ b/Tests/test_util.py @@ -16,7 +16,7 @@ class TestUtil(PillowTestCase): # Assert self.assertTrue(it_is) - @unittest.skipIf(not _util.py36, "os.path support for Paths added in 3.6") + @unittest.skipUnless(_util.py36, "os.path support for Paths added in 3.6") def test_path_obj_is_path(self): # Arrange from pathlib import Path From 828feceac2f578f12217773c00709aff6e6e267b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 25 Dec 2019 20:29:20 +1100 Subject: [PATCH 28/29] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index fe50b55e0..2e0f10845 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,12 +5,15 @@ Changelog (Pillow) 7.0.0 (unreleased) ------------------ -- Fixed black lines on upscaled images with the BOX filter #4278 - [homm] +- Use default DPI when exif provides invalid x_resolution #4147 + [beipang2, radarhere] - Change default resize resampling filter from NEAREST to BICUBIC #4255 [homm] +- Fixed black lines on upscaled images with the BOX filter #4278 + [homm] + - Better thumbnail aspect ratio preservation #4256 [homm] From 9c2b05848399b1a755e94b37239f9b5782a9aa11 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 25 Dec 2019 15:32:49 +0300 Subject: [PATCH 29/29] update release notes [ci skip] --- docs/releasenotes/7.0.0.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/releasenotes/7.0.0.rst b/docs/releasenotes/7.0.0.rst index be6d28c04..cf88dfa64 100644 --- a/docs/releasenotes/7.0.0.rst +++ b/docs/releasenotes/7.0.0.rst @@ -125,5 +125,5 @@ When calculating the new dimensions in :py:meth:`~PIL.Image.Image.thumbnail`, round to the nearest integer, instead of always rounding down. This better preserves the original aspect ratio. -The last row and column in the image get the correct weight after -JPEG DCT scaling when image size is not divisible by 8. +When the image width or height is not divisible by 8 the last row and column +in the image get the correct weight after JPEG DCT scaling.