diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index 3e8a416a5..2b32bcfce 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -17,6 +17,7 @@ jobs: debian-10-buster-x86, centos-6-amd64, centos-7-amd64, + centos-8-amd64, amazon-1-amd64, amazon-2-amd64, fedora-30-amd64, diff --git a/.travis.yml b/.travis.yml index 9dea5fb14..936e64520 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,7 @@ matrix: - env: DOCKER="debian-10-buster-x86" DOCKER_TAG="master" - env: DOCKER="centos-6-amd64" DOCKER_TAG="master" - env: DOCKER="centos-7-amd64" DOCKER_TAG="master" + - env: DOCKER="centos-8-amd64" DOCKER_TAG="master" - env: DOCKER="amazon-1-amd64" DOCKER_TAG="master" - env: DOCKER="amazon-2-amd64" DOCKER_TAG="master" - env: DOCKER="fedora-30-amd64" DOCKER_TAG="master" diff --git a/CHANGES.rst b/CHANGES.rst index 2e0f10845..8693df466 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,12 @@ Changelog (Pillow) 7.0.0 (unreleased) ------------------ +- Raise ValueError for io.StringIO in Image.open #4302 + [radarhere, hugovk] + +- Fix thumbnail geometry when DCT scaling is used #4231 + [homm, radarhere] + - Use default DPI when exif provides invalid x_resolution #4147 [beipang2, radarhere] diff --git a/Tests/test_image.py b/Tests/test_image.py index 83da76b96..47e7420ef 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -1,3 +1,4 @@ +import io import os import shutil import tempfile @@ -91,6 +92,9 @@ class TestImage(PillowTestCase): def test_bad_mode(self): self.assertRaises(ValueError, Image.open, "filename", "bad mode") + def test_stringio(self): + self.assertRaises(ValueError, Image.open, io.StringIO()) + def test_pathlib(self): from PIL.Image import Path diff --git a/Tests/test_image_reduce.py b/Tests/test_image_reduce.py index 5ed6ccaa3..d8f2ce1ec 100644 --- a/Tests/test_image_reduce.py +++ b/Tests/test_image_reduce.py @@ -94,7 +94,7 @@ class TestImageReduce(PillowTestCase): # rotate previous image band = bands[-1].transpose(Image.ROTATE_90) bands.append(band) - # Correct alpha channel to exclude completely transparent pixels. + # Correct alpha channel by transforming completely transparent pixels. # Low alpha values also emphasize error after alpha multiplication. if mode.endswith("A"): bands[-1] = bands[-1].point(lambda x: int(85 + x / 1.5)) @@ -102,7 +102,7 @@ class TestImageReduce(PillowTestCase): else: assert len(mode_info.bands) == 1 im = self.gradients_image.convert(mode) - # change the height to make a not square image + # change the height to make a not-square image return im.crop((0, 0, im.width, im.height - 5)) def compare_reduce_with_box(self, im, factor): @@ -196,7 +196,7 @@ class TestImageReduce(PillowTestCase): for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor, 0.8, 5) - # With opaque alpha, error should be way smaller + # With opaque alpha, an error should be way smaller. im.putalpha(Image.new("L", im.size, 255)) for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) @@ -219,7 +219,7 @@ class TestImageReduce(PillowTestCase): for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor, 0.8, 5) - # With opaque alpha, error should be way smaller + # With opaque alpha, an error should be way smaller. im.putalpha(Image.new("L", im.size, 255)) for factor in self.remarkable_factors: self.compare_reduce_with_reference(im, factor) diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 91479e343..f9e6e7c4c 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -377,7 +377,7 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack( "RGBA", "RGBa;16L", - b"\x88\x01\x88\x02\x88\x03\x88\x00" b"\x88\x10\x88\x20\x88\x30\x88\xff", + b"\x88\x01\x88\x02\x88\x03\x88\x00\x88\x10\x88\x20\x88\x30\x88\xff", (0, 0, 0, 0), (16, 32, 48, 255), ) @@ -392,7 +392,7 @@ class TestLibUnpack(PillowTestCase): self.assert_unpack( "RGBA", "RGBa;16B", - b"\x01\x88\x02\x88\x03\x88\x00\x88" b"\x10\x88\x20\x88\x30\x88\xff\x88", + b"\x01\x88\x02\x88\x03\x88\x00\x88\x10\x88\x20\x88\x30\x88\xff\x88", (0, 0, 0, 0), (16, 32, 48, 255), ) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dd77f3278..6ddbb08ff 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -51,6 +51,11 @@ jobs: docker: 'centos-7-amd64' name: 'centos_7_amd64' +- template: .azure-pipelines/jobs/test-docker.yml + parameters: + docker: 'centos-8-amd64' + name: 'centos_8_amd64' + - template: .azure-pipelines/jobs/test-docker.yml parameters: docker: 'amazon-1-amd64' diff --git a/docs/installation.rst b/docs/installation.rst index 929bc951a..57c4f8344 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -400,6 +400,8 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | CentOS 7 | 3.6 |x86-64 | +----------------------------------+--------------------------+-----------------------+ +| CentOS 8 | 3.6 |x86-64 | ++----------------------------------+--------------------------+-----------------------+ | Debian 9 Stretch | 3.5 |x86 | +----------------------------------+--------------------------+-----------------------+ | Debian 10 Buster | 3.7 |x86 | diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 3417aeb4a..866c89831 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1797,9 +1797,9 @@ class Image: If the image has mode "1" or "P", it is always set to :py:attr:`PIL.Image.NEAREST`. See: :ref:`concept-filters`. - :param box: An optional 4-tuple of floats giving the region - of the source image which should be scaled. - The values should be within (0, 0, width, height) rectangle. + :param box: An optional 4-tuple of floats providing + the source image region to be scaled. + The values must be within (0, 0, width, height) rectangle. If omitted or None, the entire source is used. :param reducing_gap: Apply optimization by resizing the image in two steps. First, reducing the image in integer times @@ -1874,15 +1874,15 @@ class Image: def reduce(self, factor, box=None): """ - Returns reduced in `factor` times copy of the image. + Returns a copy of the image reduced by `factor` times. If the size of the image is not dividable by the `factor`, the resulting size will be rounded up. :param factor: A greater than 0 integer or tuple of two integers - for width and height separately. - :param box: An optional 4-tuple of ints giving the region - of the source image which should be reduced. - The values should be within (0, 0, width, height) rectangle. + for width and height separately. + :param box: An optional 4-tuple of ints providing + the source image region to be reduced. + The values must be within (0, 0, width, height) rectangle. If omitted or None, the entire source is used. """ if not isinstance(factor, (list, tuple)): @@ -2783,12 +2783,20 @@ def open(fp, mode="r"): and be opened in binary mode. :param mode: The mode. If given, this argument must be "r". :returns: An :py:class:`~PIL.Image.Image` object. - :exception IOError: If the file cannot be found, or the image cannot be - opened and identified. + :exception FileNotFoundError: If the file cannot be found. + :exception PIL.UnidentifiedImageError: If the image cannot be opened and + identified. + :exception ValueError: If the ``mode`` is not "r", or if a ``StringIO`` + instance is used for ``fp``. """ if mode != "r": raise ValueError("bad mode %r" % mode) + elif isinstance(fp, io.StringIO): + raise ValueError( + "StringIO cannot be used to open an image. " + "Binary data must be used instead." + ) exclusive_fp = False filename = "" diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 9f98cd3d7..ee1400d67 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -882,7 +882,6 @@ def _save(im, fp, filename, chunk=putchunk): b"\x01", ) - info = im.encoderinfo.get("pnginfo") if info: chunks = [b"bKGD", b"hIST"] for cid, data in info.chunks: diff --git a/winbuild/build_dep.py b/winbuild/build_dep.py index 5762de5e5..778570139 100644 --- a/winbuild/build_dep.py +++ b/winbuild/build_dep.py @@ -225,8 +225,8 @@ set DefaultPlatformToolset=v100 if bit == 64: script += ( r"copy /Y /B " - + r'"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib\x64\*.Lib" ' - + r"%%FREETYPE%%\builds\windows\vc2010" + r'"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib\x64\*.Lib" ' + r"%%FREETYPE%%\builds\windows\vc2010" ) properties += r" /p:_IsNativeEnvironment=false" script += (