diff --git a/CHANGES.rst b/CHANGES.rst index 45e388625..064497dcf 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,12 +7,27 @@ Changelog (Pillow) - This is the last Pillow release to support Python 2.7 #3642 -- Depends: Update libwebp to 1.0.3 #3983 +- Fix bug when merging identical images to GIF with a list of durations #4003 + [djy0, radarhere] + +- Fix bug in TIFF loading of BufferedReader #3998 + [chadawagner] + +- Added fallback for finding ld on MinGW Cygwin #4019 + [radarhere] + +- Remove indirect dependencies from requirements.txt #3976 + [hugovk] + +- Depends: Update libwebp to 1.0.3 #3983, libimagequant to 2.12.5 #3993, freetype to 2.10.1 #3991 [radarhere] - Change overflow check to use PY_SSIZE_T_MAX #3964 [radarhere] +- Report reason for pytest skips #3942 + [hugovk] + 6.1.0 (2019-07-01) ------------------ diff --git a/Tests/test_file_gif.py b/Tests/test_file_gif.py index 2ba370c3f..4ff9727e1 100644 --- a/Tests/test_file_gif.py +++ b/Tests/test_file_gif.py @@ -495,6 +495,26 @@ class TestFileGif(PillowTestCase): # Assert that the new duration is the total of the identical frames self.assertEqual(reread.info["duration"], 4500) + def test_identical_frames_to_single_frame(self): + for duration in ([1000, 1500, 2000, 4000], (1000, 1500, 2000, 4000), 8500): + out = self.tempfile("temp.gif") + im_list = [ + Image.new("L", (100, 100), "#000"), + Image.new("L", (100, 100), "#000"), + Image.new("L", (100, 100), "#000"), + ] + + im_list[0].save( + out, save_all=True, append_images=im_list[1:], duration=duration + ) + reread = Image.open(out) + + # Assert that all frames were combined + self.assertEqual(reread.n_frames, 1) + + # Assert that the new duration is the total of the identical frames + self.assertEqual(reread.info["duration"], 8500) + def test_number_of_loops(self): number_of_loops = 2 diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index bc5003f5f..6339d878a 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -81,6 +81,19 @@ class TestFileLibTiff(LibTiffTestCase): self.assertEqual(im.size, (500, 500)) self._assert_noerr(im) + def test_g4_non_disk_file_object(self): + """Testing loading from non-disk non-BytesIO file object""" + test_file = "Tests/images/hopper_g4_500.tif" + s = io.BytesIO() + with open(test_file, "rb") as f: + s.write(f.read()) + s.seek(0) + r = io.BufferedReader(s) + im = Image.open(r) + + self.assertEqual(im.size, (500, 500)) + self._assert_noerr(im) + def test_g4_eq_png(self): """ Checking that we're actually getting the data that we expect""" png = Image.open("Tests/images/hopper_bw_500.png") diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index 535eadf1b..fcff8f056 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -286,7 +286,7 @@ class TestFileTiffMetadata(PillowTestCase): reloaded = Image.open(out) self.assertEqual(reloaded.tag_v2[37000], -60000) - def test_expty_values(self): + def test_empty_values(self): data = io.BytesIO( b"II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00" diff --git a/depends/install_imagequant.sh b/depends/install_imagequant.sh index 1813bae09..0120dbc0b 100755 --- a/depends/install_imagequant.sh +++ b/depends/install_imagequant.sh @@ -1,7 +1,7 @@ #!/bin/bash # install libimagequant -archive=libimagequant-2.12.3 +archive=libimagequant-2.12.5 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz diff --git a/docs/installation.rst b/docs/installation.rst index 5add2c35e..35547cb55 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -169,7 +169,7 @@ Many of Pillow's features require external libraries: * **libimagequant** provides improved color quantization - * Pillow has been tested with libimagequant **2.6-2.12.3** + * Pillow has been tested with libimagequant **2.6-2.12.5** * Libimagequant is licensed GPLv3, which is more restrictive than the Pillow license, therefore we will not be distributing binaries with libimagequant support enabled. diff --git a/setup.py b/setup.py index a36e192ec..76bdfb159 100755 --- a/setup.py +++ b/setup.py @@ -432,7 +432,9 @@ class pil_build_ext(build_ext): # pythonX.Y.dll.a is in the /usr/lib/pythonX.Y/config directory _add_directory( library_dirs, - os.path.join("/usr/lib", "python%s" % sys.version[:3], "config"), + os.path.join( + "/usr/lib", "python{}.{}".format(*sys.version_info), "config" + ), ) elif sys.platform == "darwin": diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index bbf6dc9d6..07f5ab683 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -489,6 +489,11 @@ def _write_multiple_frames(im, fp, palette): offset = frame_data["bbox"][:2] _write_frame_data(fp, im_frame, offset, frame_data["encoderinfo"]) return True + elif "duration" in im.encoderinfo and isinstance( + im.encoderinfo["duration"], (list, tuple) + ): + # Since multiple frames will not be written, add together the frame durations + im.encoderinfo["duration"] = sum(im.encoderinfo["duration"]) def _save_all(im, fp, filename): diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py index c4c72e78a..fc728d6fb 100644 --- a/src/PIL/IcoImagePlugin.py +++ b/src/PIL/IcoImagePlugin.py @@ -263,6 +263,9 @@ class IcoImageFile(ImageFile.ImageFile): Handles classic, XP and Vista icon formats. + When saving, PNG compression is used. Support for this was only added in + Windows Vista. + This plugin is a refactored version of Win32IconImagePlugin by Bryan Davis . https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 7d2bb1e7e..8b92aae45 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2110,7 +2110,7 @@ class Image(object): debugging purposes. On Unix platforms, this method saves the image to a temporary - PPM file, and calls the **display**, **eog** or **xv** + PNG file, and calls the **display**, **eog** or **xv** utility, depending on which one can be found. On macOS, this method saves the image to a temporary PNG file, and diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index e2e6af332..16c1052f4 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -546,11 +546,20 @@ def truetype(font=None, size=10, index=0, encoding="", layout_engine=None): This function loads a font object from the given file or file-like object, and creates a font object for a font of the given size. + Pillow uses FreeType to open font files. If you are opening many fonts + simultaneously on Windows, be aware that Windows limits the number of files + that can be open in C at once to 512. If you approach that limit, an + ``OSError`` may be thrown, reporting that FreeType "cannot open resource". + This function requires the _imagingft service. :param font: A filename or file-like object containing a TrueType font. - Under Windows, if the file is not found in this filename, - the loader also looks in Windows :file:`fonts/` directory. + If the file is not found in this filename, the loader may also + search in other directories, such as the :file:`fonts/` + directory on Windows or :file:`/Library/Fonts/`, + :file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/` on + macOS. + :param size: The requested size, in points. :param index: Which font face to load (default is first available face). :param encoding: Which font encoding to use (default is Unicode). Common diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index 29b15351d..13df7dfbe 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -179,7 +179,7 @@ else: with open(path, "r") as f: command = self.get_command_ex(file, **options)[0] subprocess.Popen( - ["im=$(cat);" + command + " $im;" "rm -f $im"], shell=True, stdin=f + ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f ) os.remove(path) return 1 diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 2a3e68b34..9680a5db6 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1191,7 +1191,7 @@ class TiffImageFile(ImageFile.ImageFile): if DEBUG: print("have getvalue. just sending in a string from getvalue") n, err = decoder.decode(self.fp.getvalue()) - elif hasattr(self.fp, "fileno"): + elif fp: # we've got a actual file on disk, pass in the fp. if DEBUG: print("have fileno, calling fileno version of the decoder.") @@ -1202,6 +1202,7 @@ class TiffImageFile(ImageFile.ImageFile): # we have something else. if DEBUG: print("don't have fileno or getvalue. just reading") + self.fp.seek(0) # UNDONE -- so much for that buffer size thing. n, err = decoder.decode(self.fp.read()) diff --git a/winbuild/config.py b/winbuild/config.py index 86a45a3cd..debfe9527 100644 --- a/winbuild/config.py +++ b/winbuild/config.py @@ -35,9 +35,9 @@ libs = { "dir": "tiff-4.0.10", }, "freetype": { - "url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.10.0.tar.gz", # noqa: E501 - "filename": PILLOW_DEPENDS_DIR + "freetype-2.10.0.tar.gz", - "dir": "freetype-2.10.0", + "url": "https://download.savannah.gnu.org/releases/freetype/freetype-2.10.1.tar.gz", # noqa: E501 + "filename": PILLOW_DEPENDS_DIR + "freetype-2.10.1.tar.gz", + "dir": "freetype-2.10.1", }, "lcms": { "url": SF_MIRROR + "/project/lcms/lcms/2.7/lcms2-2.7.zip",