diff -Nru pillow-4.2.1/CHANGES.rst pillow-4.1.1/CHANGES.rst --- pillow-4.2.1/CHANGES.rst 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/CHANGES.rst 2017-04-28 16:48:58.000000000 +0000 @@ -1,141 +1,6 @@ Changelog (Pillow) ================== -4.2.1 (2017-07-06) ------------------- - -- CI: Fix version specification and test on CI for PyPy/Windows #2608 - [wiredfool] - -4.2.0 (2017-07-01) ------------------- - -- Doc: Clarified Image.save:append_images documentation #2604 - [radarhere] - -- CI: Amazon Linux and Centos6 docker images added to TravisCI #2585 - [wiredfool] - -- Image.alpha_composite added #2595 - [wiredfool] - -- Complex Text Support #2576 - [ShamsaHamed, Fahad-Alsaidi, wiredfool] - -- Added threshold parameter to ImageDraw.floodfill #2599 - [nediamond] - -- Added dBATCH parameter to ghostscript command #2588 - [radarhere] - -- JPEG: Adjust buffer size when icc_profile > MAXBLOCK #2596 - [Darou] - -- Specify Pillow Version in one place #2517 - [wiredfool] - -- CI: Change the owner of the TRAVIS_BUILD_DIR, fixing broken docker runs #2587 - [wiredfool] - -- Fix truncated PNG loading for some images, Fix memory leak on truncated PNG images. #2541, #2598 - [homm] - -- Add decompression bomb check to Image.crop #2410 - [wiredfool] - -- ImageFile: Ensure that the `err_code` variable is initialized in case of exception. #2363 - [alexkiro] - -- Tiff: Support append_images for saving multipage TIFFs #2406 - [blochl] - -- Doc: Clarify that draft is only implemented for JPEG and PCD #2409 - [wiredfool] - -- Test: MicImagePlugin #2447 - [hugovk] - -- Use round() instead of floor() to eliminate zero coefficients in resample #2558 - [homm] - -- Remove deprecated code #2549 - [hugovk] - -- Added append_images to PDF saving #2526 - [radarhere] - -- Remove unused function core image function new_array #2548 - [hugovk] - -- Remove unnecessary calls to dict.keys() #2551 - [jdufresne] - -- Add more ImageDraw.py tests and remove unused Draw.c code #2533 - [hugovk] - -- Test: More tests for ImageMorph #2554 - [hugovk] - -- Test: McIDAS area file #2552 - [radarhere] - -- Update Feature Detection #2520 - [wiredfool] - -- CI: Update pypy on TravisCI #2573 - [hugovk] - -- ImageMorph: Fix wrong expected size of MRLs read from disk #2561 - [dov] - -- Docs: Update install docs for FreeBSD #2546 - [wiredfool] - -- Build: Ignore OpenJpeg 1.5 on FreeBSD #2544 - [melvyn-sopacua] - -- Remove 'not yet implemented' methods from PIL 1.1.4 #2538 - [hugovk] - -- Dependencies: Update FreeType to 2.8, LibTIFF to 4.0.8 and libimagequant to 2.9.1 #2535 #2537 #2540 - [radarhere] - -- Raise TypeError and not also UnboundLocalError in ImageFile.Parser() #2525 - [joshblum] - -- Test: Use Codecov for coverage #2528 - [hugovk] - -- Use PNG for Image.show() #2527 - [HinTak, wiredfool] - -- Remove WITH_DEBUG compilation flag #2522 - [wiredfool] - -- Fix return value on parameter parse error in _webp.c #2521 - [adw1n] - -- Set executable flag on scripts with shebang line #2295 - [radarhere] - -- Flake8 #2460 - [radarhere] - -- Doc: Release Process Changes #2516 - [wiredfool] - -- CI: Added region for s3 deployment on appveyor #2515 - [wiredfool] - -- Doc: Updated references to point to existing files #2507 - [radarhere] - -- Return copy on Image crop if crop dimensions match the image #2471 - [radarhere] - -- Test: Optimize CI speed #2464, #2466 - [hugovk] - 4.1.1 (2017-04-28) ------------------ @@ -151,6 +16,7 @@ - Docs: Fixed rst syntax error #2477 [thebjorn] + 4.1.0 (2017-04-03) ------------------ @@ -168,7 +34,7 @@ - Git: Set ContainerIO test file as binary #2469 [cgohlke] - + - Remove superfluous import of FixTk #2455 [cgohlke) @@ -177,7 +43,7 @@ - Pure Python Decoders, including Python decoder to fix for MSP images #1938 [wiredfool, hugovk] - + - Reorganized GifImagePlugin, fixes #2314. #2374 [radarhere, wiredfool] @@ -186,10 +52,10 @@ - Test: Additional tests for BurfStub, Eps, Container, GribStub, IPTC, Wmf, XVThumb, ImageDraw, ImageMorph ImageShow #2425 [radarhere] - + - Health fixes #2437 [radarhere] - + - Test: Correctness tests ContainerIO, XVThumbImagePlugin, BufrStubImagePlugin, GribStubImagePlugin, FitsStubImagePlugin, Hdf5StubImagePlugin, PixarImageFile, PsdImageFile #2443, #2442, #2441, #2440, #2431, #2430, #2428, #2427 [hugovk] @@ -2655,7 +2521,7 @@ import numpy, Image - im = Image.open('hopper.jpg') + im = Image.open('lena.jpg') a = numpy.asarray(im) # a is readonly @@ -3498,7 +3364,7 @@ to any other format, via a lookup table. That table should contain 256 values for each band in the output image. - + Some file drivers (including FLI/FLC, GIF, and IM) accidentally + + Some file drivers (including FLI/FLC, GIF, and IM) accidently overwrote the offset method with an internal attribute. All drivers have been updated to use private attributes where possible. diff -Nru pillow-4.2.1/debian/changelog pillow-4.1.1/debian/changelog --- pillow-4.2.1/debian/changelog 2017-08-03 22:56:22.000000000 +0000 +++ pillow-4.1.1/debian/changelog 2017-08-14 01:28:56.000000000 +0000 @@ -1,8 +1,14 @@ -pillow (4.2.1-1) unstable; urgency=medium +pillow (4.1.1-3build2) artful; urgency=medium - * New upstream version. + * No change rebuild to drop Python 3.5 support. - -- Matthias Klose Thu, 03 Aug 2017 18:56:22 -0400 + -- Michael Hudson-Doyle Mon, 14 Aug 2017 13:28:56 +1200 + +pillow (4.1.1-3build1) artful; urgency=medium + + * No-change rebuild against libwebpmux3 + + -- Steve Langasek Fri, 28 Jul 2017 03:56:21 +0000 pillow (4.1.1-3) unstable; urgency=medium diff -Nru pillow-4.2.1/debian/control pillow-4.1.1/debian/control --- pillow-4.2.1/debian/control 2017-07-01 10:08:50.000000000 +0000 +++ pillow-4.1.1/debian/control 2017-07-28 03:56:21.000000000 +0000 @@ -1,7 +1,8 @@ Source: pillow Section: python Priority: optional -Maintainer: Matthias Klose +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Matthias Klose Build-Depends: debhelper (>= 9), tk-dev, dpkg-dev (>= 1.16.1~), dh-python, python2.7-dev (>= 2.7.8-4), diff -Nru pillow-4.2.1/debian/patches/no-lib64-hack.diff pillow-4.1.1/debian/patches/no-lib64-hack.diff --- pillow-4.2.1/debian/patches/no-lib64-hack.diff 2017-08-03 22:56:22.000000000 +0000 +++ pillow-4.1.1/debian/patches/no-lib64-hack.diff 2017-05-12 19:10:36.000000000 +0000 @@ -2,7 +2,7 @@ =================================================================== --- a/setup.py +++ b/setup.py -@@ -308,61 +308,6 @@ class pil_build_ext(build_ext): +@@ -299,61 +299,6 @@ class pil_build_ext(build_ext): _add_directory(include_dirs, "/usr/X11/include") elif sys.platform.startswith("linux"): diff -Nru pillow-4.2.1/debian/patches/toplevel-setup.py pillow-4.1.1/debian/patches/toplevel-setup.py --- pillow-4.2.1/debian/patches/toplevel-setup.py 2017-08-03 22:56:22.000000000 +0000 +++ pillow-4.1.1/debian/patches/toplevel-setup.py 2017-05-12 19:10:41.000000000 +0000 @@ -17,7 +17,7 @@ from setuptools import Extension, setup, find_packages # monkey patch import hook. Even though flake8 says it's not used, it is. -@@ -192,6 +198,38 @@ class pil_build_ext(build_ext): +@@ -183,6 +189,38 @@ class pil_build_ext(build_ext): _dbg('Requiring %s', x) self.feature.required.add(x) @@ -56,7 +56,7 @@ def build_extensions(self): library_dirs = [] -@@ -263,13 +301,13 @@ class pil_build_ext(build_ext): +@@ -254,13 +292,13 @@ class pil_build_ext(build_ext): if self.disable_platform_guessing: pass @@ -72,7 +72,7 @@ # attempt to make sure we pick freetype2 over other versions _add_directory(include_dirs, "/sw/include/freetype2") _add_directory(include_dirs, "/sw/lib/freetype2/include") -@@ -307,21 +345,21 @@ class pil_build_ext(build_ext): +@@ -298,21 +336,21 @@ class pil_build_ext(build_ext): _add_directory(library_dirs, "/usr/X11/lib") _add_directory(include_dirs, "/usr/X11/include") @@ -99,7 +99,7 @@ _add_directory(library_dirs, "/opt/local/lib") _add_directory(include_dirs, "/opt/local/include") -@@ -339,7 +377,7 @@ class pil_build_ext(build_ext): +@@ -330,7 +368,7 @@ class pil_build_ext(build_ext): # on Windows, look for the OpenJPEG libraries in the location that # the official installer puts them @@ -108,7 +108,7 @@ program_files = os.environ.get('ProgramFiles', '') best_version = (0, 0) best_path = None -@@ -373,7 +411,7 @@ class pil_build_ext(build_ext): +@@ -364,7 +402,7 @@ class pil_build_ext(build_ext): if _find_include_file(self, "zlib.h"): if _find_library_file(self, "z"): feature.zlib = "z" @@ -117,7 +117,7 @@ _find_library_file(self, "zlib")): feature.zlib = "zlib" # alternative name -@@ -382,7 +420,7 @@ class pil_build_ext(build_ext): +@@ -373,7 +411,7 @@ class pil_build_ext(build_ext): if _find_include_file(self, "jpeglib.h"): if _find_library_file(self, "jpeg"): feature.jpeg = "jpeg" @@ -126,7 +126,7 @@ _find_library_file(self, "libjpeg")): feature.jpeg = "libjpeg" # alternative name -@@ -437,9 +475,9 @@ class pil_build_ext(build_ext): +@@ -424,9 +462,9 @@ class pil_build_ext(build_ext): if _find_include_file(self, 'tiff.h'): if _find_library_file(self, "tiff"): feature.tiff = "tiff" @@ -138,7 +138,7 @@ _find_library_file(self, "libtiff")): feature.tiff = "libtiff" -@@ -528,7 +566,7 @@ class pil_build_ext(build_ext): +@@ -507,7 +545,7 @@ class pil_build_ext(build_ext): if feature.jpeg2000: libs.append(feature.jpeg2000) defs.append(("HAVE_OPENJPEG", None)) @@ -147,7 +147,7 @@ defs.append(("OPJ_STATIC", None)) if feature.zlib: libs.append(feature.zlib) -@@ -539,7 +577,7 @@ class pil_build_ext(build_ext): +@@ -518,7 +556,7 @@ class pil_build_ext(build_ext): if feature.tiff: libs.append(feature.tiff) defs.append(("HAVE_LIBTIFF", None)) @@ -156,7 +156,7 @@ libs.extend(["kernel32", "user32", "gdi32"]) if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1: defs.append(("WORDS_BIGENDIAN", None)) -@@ -569,7 +607,7 @@ class pil_build_ext(build_ext): +@@ -538,7 +576,7 @@ class pil_build_ext(build_ext): if feature.lcms: extra = [] @@ -165,7 +165,7 @@ extra.extend(["user32", "gdi32"]) exts.append(Extension("PIL._imagingcms", ["_imagingcms.c"], -@@ -589,7 +627,7 @@ class pil_build_ext(build_ext): +@@ -558,7 +596,7 @@ class pil_build_ext(build_ext): libraries=libs, define_macros=defs)) @@ -174,7 +174,7 @@ exts.append(Extension("PIL._imagingtk", ["_imagingtk.c", "Tk/tkImaging.c"], include_dirs=['Tk'], -@@ -614,7 +652,7 @@ class pil_build_ext(build_ext): +@@ -583,7 +621,7 @@ class pil_build_ext(build_ext): print("-" * 68) print("version Pillow %s" % PILLOW_VERSION) v = sys.version.split("[") diff -Nru pillow-4.2.1/decode.c pillow-4.1.1/decode.c --- pillow-4.2.1/decode.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/decode.c 2017-04-04 18:14:25.000000000 +0000 @@ -779,7 +779,6 @@ return NULL; decoder->decode = ImagingZipDecode; - decoder->cleanup = ImagingZipDecodeCleanup; ((ZIPSTATE*)decoder->state.context)->interlaced = interlaced; diff -Nru pillow-4.2.1/depends/debian_8.2.sh pillow-4.1.1/depends/debian_8.2.sh --- pillow-4.2.1/depends/debian_8.2.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/debian_8.2.sh 2016-10-18 19:11:47.000000000 +0000 @@ -11,8 +11,7 @@ python3-dev python-virtualenv cmake sudo apt-get -y install libtiff5-dev libjpeg62-turbo-dev zlib1g-dev \ libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev \ - python-tk python3-tk libharfbuzz-dev libfribidi-dev + python-tk python3-tk ./install_openjpeg.sh ./install_imagequant.sh -./install_raqm.sh diff -Nru pillow-4.2.1/depends/download-and-extract.sh pillow-4.1.1/depends/download-and-extract.sh --- pillow-4.2.1/depends/download-and-extract.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/download-and-extract.sh 2017-01-02 11:47:11.000000000 +0000 @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Usage: ./download-and-extract.sh something.tar.gz https://example.com/something.tar.gz archive=$1 diff -Nru pillow-4.2.1/depends/fedora_23.sh pillow-4.1.1/depends/fedora_23.sh --- pillow-4.2.1/depends/fedora_23.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/fedora_23.sh 2016-10-18 19:11:47.000000000 +0000 @@ -15,4 +15,4 @@ sudo dnf install libtiff-devel libjpeg-devel zlib-devel freetype-devel \ lcms2-devel libwebp-devel openjpeg2-devel tkinter python3-tkinter \ - tcl-devel tk-devel harfbuzz-devel fribidi-devel libraqm-devel \ No newline at end of file + tcl-devel tk-devel \ No newline at end of file diff -Nru pillow-4.2.1/depends/freebsd_10.sh pillow-4.1.1/depends/freebsd_10.sh --- pillow-4.2.1/depends/freebsd_10.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/freebsd_10.sh 2016-10-18 19:11:47.000000000 +0000 @@ -4,10 +4,8 @@ # Installs all of the dependencies for Pillow for Freebsd 10.x # for both system Pythons 2.7 and 3.4 # -sudo pkg install python2 python3 py27-pip py27-virtualenv wget cmake +sudo pkg install python2 python3 py27-pip py27-virtualenv py27-setuptools27 # Openjpeg fails badly using the openjpeg package. # I can't find a python3.4 version of tkinter -sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 harfbuzz fribidi py27-tkinter - -./install_raqm_cmake.sh +sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 py27-tkinter diff -Nru pillow-4.2.1/depends/install_imagequant.sh pillow-4.1.1/depends/install_imagequant.sh --- pillow-4.2.1/depends/install_imagequant.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/install_imagequant.sh 2017-04-04 18:14:25.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/bash # install libimagequant -archive=libimagequant-2.9.1 +archive=libimagequant-2.9.0 ./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz diff -Nru pillow-4.2.1/depends/install_raqm_cmake.sh pillow-4.1.1/depends/install_raqm_cmake.sh --- pillow-4.2.1/depends/install_raqm_cmake.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/install_raqm_cmake.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -#!/usr/bin/env bash -# install raqm - - -archive=raqm-cmake-b517ba80 - -./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz - -pushd $archive - -mkdir build -cd build -cmake .. -make && sudo make install -cd .. - -popd - diff -Nru pillow-4.2.1/depends/install_raqm.sh pillow-4.1.1/depends/install_raqm.sh --- pillow-4.2.1/depends/install_raqm.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/install_raqm.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,14 +0,0 @@ -#!/usr/bin/env bash -# install raqm - - -archive=raqm-0.2.0 - -./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/master/$archive.tar.gz - -pushd $archive - -./configure --prefix=/usr && make -j4 && sudo make -j4 install - -popd - diff -Nru pillow-4.2.1/depends/ubuntu_14.04.sh pillow-4.1.1/depends/ubuntu_14.04.sh --- pillow-4.2.1/depends/ubuntu_14.04.sh 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/depends/ubuntu_14.04.sh 2016-10-18 19:11:47.000000000 +0000 @@ -4,13 +4,12 @@ # Installs all of the dependencies for Pillow for Ubuntu 14.04 # for both system Pythons 2.7 and 3.4 # -sudo apt-get update + sudo apt-get -y install python-dev python-setuptools \ python3-dev python-virtualenv cmake sudo apt-get -y install libtiff5-dev libjpeg8-dev zlib1g-dev \ libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev \ - python-tk python3-tk libharfbuzz-dev libfribidi-dev + python-tk python3-tk ./install_openjpeg.sh ./install_imagequant.sh -./install_raqm.sh diff -Nru pillow-4.2.1/docs/example/DdsImagePlugin.py pillow-4.1.1/docs/example/DdsImagePlugin.py --- pillow-4.2.1/docs/example/DdsImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/example/DdsImagePlugin.py 2017-04-04 18:14:25.000000000 +0000 @@ -144,7 +144,7 @@ else: r, g, b = 0, 0, 0 - idx = 4 * ((y + j) * width + x + i) + idx = 4 * ((y + j) * width + (x + i)) ret[idx:idx+4] = struct.pack('4B', r, g, b, 255) return bytes(ret) @@ -201,7 +201,7 @@ elif cc == 3: r, g, b = _c3(r0, r1), _c3(g0, g1), _c3(b0, b1) - idx = 4 * ((y + j) * width + x + i) + idx = 4 * ((y + j) * width + (x + i)) ret[idx:idx+4] = struct.pack('4B', r, g, b, alpha) return bytes(ret) @@ -233,6 +233,7 @@ bitcount, rmask, gmask, bmask, amask = struct.unpack("<5I", header.read(20)) + if fourcc == b"DXT1": self.decoder = "DXT1" codec = _dxt1 @@ -240,12 +241,14 @@ self.decoder = "DXT5" codec = _dxt5 else: - raise NotImplementedError("Unimplemented pixel format %r" % fourcc) + raise NotImplementedError("Unimplemented pixel format %r" % + (fourcc)) self.tile = [ (self.decoder, (0, 0) + self.size, 0, (self.mode, 0, 1)) ] + def load_seek(self, pos): pass @@ -258,8 +261,8 @@ self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize)) except struct.error: raise IOError("Truncated DDS file") - return 0, 0 - + + return 0,0 class DXT5Decoder(ImageFile.PyDecoder): _pulls_fd = True @@ -269,7 +272,7 @@ self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize)) except struct.error: raise IOError("Truncated DDS file") - return 0, 0 + return 0,0 Image.register_decoder('DXT1', DXT1Decoder) Image.register_decoder('DXT5', DXT5Decoder) diff -Nru pillow-4.2.1/docs/handbook/concepts.rst pillow-4.1.1/docs/handbook/concepts.rst --- pillow-4.2.1/docs/handbook/concepts.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/handbook/concepts.rst 2017-04-04 18:14:25.000000000 +0000 @@ -45,8 +45,8 @@ PIL also provides limited support for a few special modes, including ``LA`` (L with alpha), ``RGBX`` (true color with padding) and ``RGBa`` (true color with premultiplied alpha). However, PIL doesn’t support user-defined modes; if you -need to handle band combinations that are not listed above, use a sequence of -Image objects. +to handle band combinations that are not listed above, use a sequence of Image +objects. You can read the mode of an image through the :py:attr:`~PIL.Image.Image.mode` attribute. This is a string containing one of the above values. @@ -114,7 +114,7 @@ in the input image is used. ``HAMMING`` - Produces a sharper image than ``BILINEAR``, doesn't have dislocations + Produces more sharp image than ``BILINEAR``, doesn't have dislocations on local level like with ``BOX``. This filter can only be used with the :py:meth:`~PIL.Image.Image.resize` and :py:meth:`~PIL.Image.Image.thumbnail` methods. diff -Nru pillow-4.2.1/docs/handbook/image-file-formats.rst pillow-4.1.1/docs/handbook/image-file-formats.rst --- pillow-4.2.1/docs/handbook/image-file-formats.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/handbook/image-file-formats.rst 2017-04-04 18:14:25.000000000 +0000 @@ -110,7 +110,6 @@ **append_images** A list of images to append as additional frames. Each of the images in the list can be single or multiframe images. - This is currently only supported for GIF, PDF and TIFF. **duration** The display duration of each frame of the multiframe gif, in @@ -125,7 +124,7 @@ eliminating unused colors. This is only useful if the palette can be compressed to the next smaller power of 2 elements. -**palette** +**palette** Use the specified palette for the saved image. The palette should be a bytes or bytearray object containing the palette entries in RGBRGB... form. It should be no more than 768 bytes. Alternately, @@ -790,8 +789,6 @@ first sprite in the file is loaded. You can use :py:meth:`~file.seek` and :py:meth:`~file.tell` to read other sprites from the file. -Note that there may be an embedded gamma of 2.2 in MIC files. - MPO ^^^ diff -Nru pillow-4.2.1/docs/handbook/tutorial.rst pillow-4.1.1/docs/handbook/tutorial.rst --- pillow-4.2.1/docs/handbook/tutorial.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/handbook/tutorial.rst 2016-10-18 19:11:47.000000000 +0000 @@ -13,7 +13,7 @@ in the :py:mod:`~PIL.Image` module:: >>> from PIL import Image - >>> im = Image.open("hopper.ppm") + >>> im = Image.open("lena.ppm") If successful, this function returns an :py:class:`~PIL.Image.Image` object. You can now use instance attributes to examine the file contents:: @@ -276,8 +276,7 @@ :: - from PIL import Image - im = Image.open("hopper.ppm").convert("L") + im = Image.open("lena.ppm").convert("L") The library supports transformations between each supported mode and the “L” and “RGB” modes. To convert between other modes, you may have to use an @@ -436,8 +435,8 @@ from PIL import Image from PIL import PSDraw - im = Image.open("hopper.ppm") - title = "hopper" + im = Image.open("lena.ppm") + title = "lena" box = (1*72, 2*72, 7*72, 10*72) # in points ps = PSDraw.PSDraw() # default is sys.stdout @@ -460,8 +459,7 @@ :py:mod:`~PIL.Image` module is used to open an image file. In most cases, you simply pass it the filename as an argument:: - from PIL import Image - im = Image.open("hopper.ppm") + im = Image.open("lena.ppm") If everything goes well, the result is an :py:class:`PIL.Image.Image` object. Otherwise, an :exc:`IOError` exception is raised. @@ -475,9 +473,8 @@ :: - from PIL import Image - with open("hopper.ppm", "rb") as fp: - im = Image.open(fp) + fp = open("lena.ppm", "rb") + im = Image.open(fp) To read an image from string data, use the :py:class:`~StringIO.StringIO` class: @@ -502,9 +499,9 @@ :: - from PIL import Image, TarIO + from PIL import TarIO - fp = TarIO.TarIO("Tests/images/hopper.tar", "hopper.jpg") + fp = TarIO.TarIO("Imaging.tar", "Imaging/test/lena.ppm") im = Image.open(fp) Controlling the decoder diff -Nru pillow-4.2.1/docs/installation.rst pillow-4.1.1/docs/installation.rst --- pillow-4.2.1/docs/installation.rst 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/docs/installation.rst 2017-04-04 18:14:25.000000000 +0000 @@ -28,6 +28,12 @@ most common image formats. See :ref:`external-libraries` for a full list of external libraries supported. +.. note:: + + The basic installation works on Windows and macOS using the binaries + from PyPI. Other installations require building from source as + detailed below. + Install Pillow with :command:`pip`:: $ pip install Pillow @@ -66,15 +72,11 @@ Linux Installation ^^^^^^^^^^^^^^^^^^ -We provide binaries for Linux for each of the supported Python -versions in the manylinux wheel format. These include support for all -optional libraries except Raqm:: - - $ pip install Pillow - -Most major Linux distributions, including Fedora, Debian/Ubuntu and -ArchLinux also include Pillow in packages that previously contained -PIL e.g. ``python-imaging``. +We do not provide binaries for Linux. Most major Linux distributions, +including Fedora, Debian/Ubuntu and ArchLinux include Pillow in +packages that previously contained PIL e.g. ``python-imaging``. Please +consider using native operating system packages first to avoid +installation problems and/or missing library support later. FreeBSD Installation ^^^^^^^^^^^^^^^^^^^^ @@ -118,9 +120,7 @@ .. note:: There are scripts to install the dependencies for some operating - systems included in the ``depends`` directory. Also see the - Dockerfiles in our `docker images repo - `_. + systems included in the ``depends`` directory. Many of Pillow's features require external libraries: @@ -159,7 +159,7 @@ * Pillow has been tested with openjpeg **2.0.0** and **2.1.0**. * Pillow does **not** support the earlier **1.5** series which ships - with Ubuntu <= 14.04 and Debian Jessie. + with Ubuntu and Debian. * **libimagequant** provides improved color quantization @@ -170,18 +170,6 @@ * Windows support: Libimagequant requires VS2013/MSVC 18 to compile, so it is unlikely to work with any Python prior to 3.5 on Windows. -* **libraqm** provides complex text layout support. - - * libraqm provides bidirectional text support (using FriBiDi), - shaping (using HarfBuzz), and proper script itemization. As a - result, Raqm can support most writing systems covered by Unicode. - * libraqm depends on the following libraries: FreeType, HarfBuzz, - FriBiDi, make sure that you install them before install libraqm - if not available as package in your system. - * setting text direction or font features is not supported without - libraqm. - * Windows support: Raqm support is currently unsupported on Windows. - Once you have installed the prerequisites, run:: $ pip install Pillow @@ -213,16 +201,14 @@ * Build flags: ``--disable-zlib``, ``--disable-jpeg``, ``--disable-tiff``, ``--disable-freetype``, ``--disable-tcl``, ``--disable-tk``, ``--disable-lcms``, ``--disable-webp``, - ``--disable-webpmux``, ``--disable-jpeg2000``, - ``--disable-imagequant``, ``--disable-raqm``. + ``--disable-webpmux``, ``--disable-jpeg2000``, ``--disable-imagequant``. Disable building the corresponding feature even if the development libraries are present on the building machine. * Build flags: ``--enable-zlib``, ``--enable-jpeg``, ``--enable-tiff``, ``--enable-freetype``, ``--enable-tcl``, ``--enable-tk``, ``--enable-lcms``, ``--enable-webp``, - ``--enable-webpmux``, ``--enable-jpeg2000``, - ``--enable-imagequant``, ``--enable-raqm``. + ``--enable-webpmux``, ``--enable-jpeg2000``, ``--enable-imagequant``. Require that the corresponding feature is built. The build will raise an exception if the libraries are not found. Webpmux (WebP metadata) relies on WebP support. Tcl and Tk also must be used together. @@ -261,12 +247,7 @@ $ brew install libtiff libjpeg webp little-cms2 -To install libraqm on macOS use Homebrew to install its dependencies:: - $ brew install freetype harfbuzz fribidi - -Then see ``depends/install_raqm_cmake.sh`` to install libraqm. - -Now install Pillow with:: +Install Pillow with:: $ pip install Pillow @@ -284,7 +265,7 @@ Building on FreeBSD ^^^^^^^^^^^^^^^^^^^ -.. Note:: Only FreeBSD 10 and 11 tested +.. Note:: Only FreeBSD 10 tested Make sure you have Python's development libraries installed.:: @@ -294,11 +275,9 @@ $ 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 +Prerequisites are installed on **FreeBSD 10** with:: -Then see ``depends/install_raqm_cmake.sh`` to install libraqm. + $ sudo pkg install jpeg tiff webp lcms2 freetype2 Building on Linux @@ -325,18 +304,21 @@ .. Note:: ``redhat-rpm-config`` is required on Fedora 23, but not earlier versions. +Prerequisites are installed on **Ubuntu 12.04 LTS** or **Raspian Wheezy +7.0** with:: + + $ sudo apt-get install libtiff4-dev libjpeg8-dev zlib1g-dev \ + libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev python-tk + Prerequisites are installed on **Ubuntu 14.04 LTS** with:: $ sudo apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev \ - libfreetype6-dev liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev \ - tcl8.6-dev tk8.6-dev python-tk - -Then see ``depends/install_raqm.sh`` to install libraqm. + libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk Prerequisites are installed on **Fedora 23** with:: $ sudo dnf install libtiff-devel libjpeg-devel zlib-devel freetype-devel \ - lcms2-devel libwebp-devel tcl-devel tk-devel libraqm-devel + lcms2-devel libwebp-devel tcl-devel tk-devel @@ -362,10 +344,6 @@ +----------------------------------+-------------------------------+-----------------------+ | Arch | 2.7 |x86-64 | +----------------------------------+-------------------------------+-----------------------+ -| Amazon | 2.7 |x86-64 | -+----------------------------------+-------------------------------+-----------------------+ -| Centos 6 | 2.7 |x86-64 | -+----------------------------------+-------------------------------+-----------------------+ | Debian Stretch | 2.7 |x86 | +----------------------------------+-------------------------------+-----------------------+ | Mac OS X 10.10 Yosemite* | 2.7, 3.3, 3.4, 3.5, 3.6 |x86-64 | @@ -379,7 +357,7 @@ +----------------------------------+-------------------------------+-----------------------+ | Ubuntu Linux 12.04 LTS | 2.7 |x86-64 | +----------------------------------+-------------------------------+-----------------------+ -| Windows Server 2012 R2 | 2.7,3.3,3.4,pypy |x86, x86-64 | +| Windows Server 2012 R2 | 2.7,3.3,3.4 |x86, x86-64 | +----------------------------------+-------------------------------+-----------------------+ \* Mac OS X CI is not run for every commit, but is run for every release. @@ -387,7 +365,7 @@ Other Platforms ^^^^^^^^^^^^^^^ -These platforms have been reported to work at the versions mentioned. +These platforms have been reported to work at the versions mentioned. .. note:: @@ -397,7 +375,7 @@ +----------------------------------+------------------------------+--------------------------------+-----------------------+ |**Operating system** |**Tested Python versions** |**Latest tested Pillow version**|**Tested processors** | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| macOS 10.12 Sierra | 2.7,3.4,3.5,3.6 | 4.1.1 |x86-64 | +| macOS 10.12 Sierra | 3.4,3.5,3.6 | 4.0.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Mac OS X 10.11 El Capitan | 2.7,3.3,3.4,3.5 | 4.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ @@ -424,10 +402,6 @@ +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Gentoo Linux | 2.7,3.2 | 2.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| FreeBSD 11.0 | 2.7,3.4,3.5,3.6 | 4.2.0 |x86-64 | -+----------------------------------+------------------------------+--------------------------------+-----------------------+ -| FreeBSD 10.3 | 2.7,3.4,3.5 | 4.2.0 |x86-64 | -+----------------------------------+------------------------------+--------------------------------+-----------------------+ | FreeBSD 10.2 | 2.7,3.4 | 3.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Windows 8.1 Pro | 2.6,2.7,3.2,3.3,3.4 | 2.4.0 |x86,x86-64 | diff -Nru pillow-4.2.1/docs/reference/ImageDraw.rst pillow-4.1.1/docs/reference/ImageDraw.rst --- pillow-4.2.1/docs/reference/ImageDraw.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/reference/ImageDraw.rst 2016-10-18 19:11:47.000000000 +0000 @@ -4,7 +4,7 @@ :py:mod:`ImageDraw` Module ========================== -The :py:mod:`ImageDraw` module provides simple 2D graphics for +The :py:mod:`ImageDraw` module provide simple 2D graphics for :py:class:`~PIL.Image.Image` objects. You can use this module to create new images, annotate or retouch existing images, and to generate graphics on the fly for web use. @@ -20,7 +20,7 @@ from PIL import Image, ImageDraw - im = Image.open("hopper.jpg") + im = Image.open("lena.pgm") draw = ImageDraw.Draw(im) draw.line((0, 0) + im.size, fill=128) @@ -64,7 +64,7 @@ PIL can use bitmap fonts or OpenType/TrueType fonts. Bitmap fonts are stored in PIL’s own format, where each font typically consists -of two files, one named .pil and the other usually named .pbm. The former +of a two files, one named .pil and the other usually named .pbm. The former contains font metrics, the latter raster data. To load a bitmap font, use the load functions in the :py:mod:`~PIL.ImageFont` @@ -81,7 +81,7 @@ from PIL import Image, ImageDraw, ImageFont # get an image - base = Image.open('Pillow/Tests/images/hopper.png').convert('RGBA') + base = Image.open('Pillow/Tests/images/lena.png').convert('RGBA') # make a blank image for the text, initialized to transparent text color txt = Image.new('RGBA', base.size, (255,255,255,0)) @@ -227,7 +227,7 @@ Draw a shape. -.. py:method:: PIL.ImageDraw.Draw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", direction=None, features=None) +.. py:method:: PIL.ImageDraw.Draw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left") Draws the string at the given position. @@ -240,28 +240,9 @@ the number of pixels between lines. :param align: If the text is passed on to multiline_text(), "left", "center" or "right". - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right), 'ttb' (top to - bottom) or 'btt' (bottom to top). Requires - libraqm. - - .. versionadded:: 4.2.0 - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://www.microsoft.com/typography/otspec/featurelist.htm - Requires libraqm. - .. versionadded:: 4.2.0 -.. py:method:: PIL.ImageDraw.Draw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left", - direction=None, features=None) +.. py:method:: PIL.ImageDraw.Draw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left") Draws the string at the given position. @@ -271,28 +252,8 @@ :param font: An :py:class:`~PIL.ImageFont.ImageFont` instance. :param spacing: The number of pixels between lines. :param align: "left", "center" or "right". - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right), 'ttb' (top to - bottom) or 'btt' (bottom to top). Requires - libraqm. - - .. versionadded:: 4.2.0 - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://www.microsoft.com/typography/otspec/featurelist.htm - Requires libraqm. - .. versionadded:: 4.2.0 - -.. py:method:: PIL.ImageDraw.Draw.textsize(text, font=None, spacing=4, direction=None, - features=None) +.. py:method:: PIL.ImageDraw.Draw.textsize(text, font=None, spacing=0) Return the size of the given string, in pixels. @@ -301,51 +262,32 @@ :param font: An :py:class:`~PIL.ImageFont.ImageFont` instance. :param spacing: If the text is passed on to multiline_textsize(), the number of pixels between lines. - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right), 'ttb' (top to - bottom) or 'btt' (bottom to top). Requires - libraqm. - - .. versionadded:: 4.2.0 - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://www.microsoft.com/typography/otspec/featurelist.htm - Requires libraqm. - - .. versionadded:: 4.2.0 - -.. py:method:: PIL.ImageDraw.Draw.multiline_textsize(text, font=None, spacing=4, direction=None, - features=None) +.. py:method:: PIL.ImageDraw.Draw.multiline_textsize(text, font=None, spacing=0) Return the size of the given string, in pixels. :param text: Text to be measured. :param font: An :py:class:`~PIL.ImageFont.ImageFont` instance. :param spacing: The number of pixels between lines. - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right), 'ttb' (top to - bottom) or 'btt' (bottom to top). Requires - libraqm. - - .. versionadded:: 4.2.0 - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://www.microsoft.com/typography/otspec/featurelist.htm - Requires libraqm. - .. versionadded:: 4.2.0 +Legacy API +---------- + +The :py:class:`~PIL.ImageDraw.Draw` class contains a constructor and a number +of methods which are provided for backwards compatibility only. For this to +work properly, you should either use options on the drawing primitives, or +these methods. Do not mix the old and new calling conventions. + + +.. py:function:: PIL.ImageDraw.ImageDraw(image) + + :rtype: :py:class:`~PIL.ImageDraw.Draw` + +.. py:method:: PIL.ImageDraw.Draw.setfont(font) + + .. deprecated:: 1.1.5 + + Sets the default font to use for the text method. + + :param font: An :py:class:`~PIL.ImageFont.ImageFont` instance. diff -Nru pillow-4.2.1/docs/reference/ImageFont.rst pillow-4.1.1/docs/reference/ImageFont.rst --- pillow-4.2.1/docs/reference/ImageFont.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/reference/ImageFont.rst 2017-04-28 16:48:58.000000000 +0000 @@ -51,7 +51,7 @@ :return: (width, height) -.. py:method:: PIL.ImageFont.ImageFont.getmask(text, mode='', direction=None, features=[]) +.. py:method:: PIL.ImageFont.ImageFont.getmask(text, mode='') Create a bitmap for the text. @@ -65,26 +65,5 @@ C-level implementations. .. versionadded:: 1.1.5 - - :param direction: Direction of the text. It can be 'rtl' (right to - left), 'ltr' (left to right), 'ttb' (top to - bottom) or 'btt' (bottom to top). Requires - libraqm. - - .. versionadded:: 4.2.0 - - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional - font features that are not enabled by default, - for example 'dlig' or 'ss01', but can be also - used to turn off default font features for - example '-liga' to disable ligatures or '-kern' - to disable kerning. To get all supported - features, see - https://www.microsoft.com/typography/otspec/featurelist.htm - Requires libraqm. - - .. versionadded:: 4.2.0 - :return: An internal PIL storage memory instance as defined by the :py:mod:`PIL.Image.core` interface module. diff -Nru pillow-4.2.1/docs/reference/Image.rst pillow-4.1.1/docs/reference/Image.rst --- pillow-4.2.1/docs/reference/Image.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/reference/Image.rst 2017-04-04 18:14:25.000000000 +0000 @@ -104,8 +104,6 @@ methods. Unless otherwise stated, all methods return a new instance of the :py:class:`~PIL.Image.Image` class, holding the resulting image. - -.. automethod:: PIL.Image.Image.alpha_composite .. automethod:: PIL.Image.Image.convert The following example converts an RGB image (linearly calibrated according to diff -Nru pillow-4.2.1/docs/reference/limits.rst pillow-4.1.1/docs/reference/limits.rst --- pillow-4.2.1/docs/reference/limits.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/reference/limits.rst 2017-01-02 11:47:11.000000000 +0000 @@ -10,7 +10,7 @@ * Image sizes cannot be negative. These are checked both in ``Storage.c`` and ``Image.py`` -* Image sizes may be 0. (Although not in 3.4) +* Image sizes may be 0. (At least, prior to 3.4) * Maximum pixel dimensions are limited to INT32, or 2^31 by the sizes in the image header. diff -Nru pillow-4.2.1/docs/releasenotes/2.7.0.rst pillow-4.1.1/docs/releasenotes/2.7.0.rst --- pillow-4.2.1/docs/releasenotes/2.7.0.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/2.7.0.rst 2016-10-18 19:11:47.000000000 +0000 @@ -148,7 +148,7 @@ Box filter computation time is constant relative to the radius and depends on source image size only. Because the new Gaussian blur implementation -is based on box filter, its computation time also doesn't depend on the blur +is based on box filter, its computation time also doesn't depends on the blur radius. For example, previously, if the execution time for a given test image was 1 @@ -172,3 +172,4 @@ was difficult to use as kwargs without constructing and passing a dictionary. These parameters now use the underscore character instead of space. (e.g. 'x_resolution') + diff -Nru pillow-4.2.1/docs/releasenotes/3.1.0.rst pillow-4.1.1/docs/releasenotes/3.1.0.rst --- pillow-4.2.1/docs/releasenotes/3.1.0.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/3.1.0.rst 2016-10-18 19:11:47.000000000 +0000 @@ -68,7 +68,7 @@ ++++++++++++++++++++ In Pillow 3.0 and 3.1, images that contain metadata that is internally -consistent, but not in agreement with the TIFF spec, may cause an +consistent but not in agreement with the TIFF spec may cause an exception when reading the metadata. This can happen when a tag that is specified to have a single value is stored with an array of values. diff -Nru pillow-4.2.1/docs/releasenotes/3.3.0.rst pillow-4.1.1/docs/releasenotes/3.3.0.rst --- pillow-4.2.1/docs/releasenotes/3.3.0.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/3.3.0.rst 2016-10-18 19:11:47.000000000 +0000 @@ -29,9 +29,9 @@ ======== Image resampling for 8-bit per channel images was rewritten using only integer -computings. This is faster on most platforms and doesn't introduce precision -errors on the wide range of scales. With other performance improvements, this -makes resampling 60% faster on average. +computings. This is faster on most of the platforms and doesn't introduce +precision errors on the wide range of scales. With other performance +improvements, this makes resampling 60% faster on average. Color calculation for images in the ``LA`` mode on semitransparent pixels was fixed. @@ -41,7 +41,7 @@ ======== Rotation for angles divisible by 90 degrees now always uses transposition. -This greatly improves both quality and performance in this case. +This greatly improve both quality and performance in this cases. Also, the bug with wrong image size calculation when rotating by 90 degrees was fixed. @@ -52,3 +52,4 @@ The return type for binary data in version 2 Exif and Tiff metadata has been changed from a tuple of integers to bytes. This is a change from the behavior since ``3.0.0``. + diff -Nru pillow-4.2.1/docs/releasenotes/3.3.2.rst pillow-4.1.1/docs/releasenotes/3.3.2.rst --- pillow-4.2.1/docs/releasenotes/3.3.2.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/3.3.2.rst 2016-10-18 19:11:47.000000000 +0000 @@ -11,7 +11,7 @@ Specifically, when parameters from the image are passed into ``Image.core.map_buffer``, the size of the image was calculated with -``xsize`` * ``ysize`` * ``bytes_per_pixel``. This will overflow if the +``xsize``*``ysize``*``bytes_per_pixel``. This will overflow if the result is larger than SIZE_MAX. This is possible on a 32-bit system. Furthermore this ``size`` value was added to a potentially attacker diff -Nru pillow-4.2.1/docs/releasenotes/3.4.0.rst pillow-4.1.1/docs/releasenotes/3.4.0.rst --- pillow-4.2.1/docs/releasenotes/3.4.0.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/3.4.0.rst 2017-04-04 18:14:25.000000000 +0000 @@ -8,7 +8,7 @@ Two new filters available for ``Image.resize()`` and ``Image.thumbnail()`` functions: ``BOX`` and ``HAMMING``. ``BOX`` is the high-performance filter with two times shorter window than ``BILINEAR``. It can be used for image reduction -3 and more times and produces a sharper result than ``BILINEAR``. +3 and more times and produces a more sharp result than ``BILINEAR``. ``HAMMING`` filter has the same performance as ``BILINEAR`` filter while providing the image downscaling quality comparable to ``BICUBIC``. @@ -25,7 +25,7 @@ New DDS Decoders ================ -Pillow can now decode DXT3 images, as well as the previously supported +Pillow can now decode DXT3 images, as well as the previously support DXT1 and DXT5 formats. All three formats are now decoded in C code for better performance. @@ -44,7 +44,7 @@ Save multiple frame TIFF ======================== -Multiple frames can now be saved in a TIFF file by using the ``save_all`` option. +Multiple frames can now be saved in a TIFF file by using the ``save_all`` option. e.g.:: im.save("filename.tiff", format="TIFF", save_all=True) diff -Nru pillow-4.2.1/docs/releasenotes/4.2.0.rst pillow-4.1.1/docs/releasenotes/4.2.0.rst --- pillow-4.2.1/docs/releasenotes/4.2.0.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/4.2.0.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -4.2.0 ------ - -Added Complex Text Rendering -============================ - -Pillow now supports complex text rendering for scripts requiring glyph -composition and bidirectional flow. This optional feature adds three -dependencies: harfbuzz, fribidi, and raqm. See the install -documentation for further details. This feature is tested and works on -Unix and Mac, but has not yet been built on Windows platforms. - -New Optional Parameters -======================= - -* :py:meth:`PIL.ImageDraw.floodfill` has a new optional parameter: - threshold. This specifies a tolerance for the color to replace with - the flood fill. - -* The TIFF and PDF image writers now support the ``append_images`` - optional parameter for specifying additional images to create - multipage outputs. - -New DecompressionBomb Warning -============================= - -:py:meth:`PIL.Image.Image.crop` now may raise a DecompressionBomb -warning if the crop region enlarges the image over the threshold -specified by :py:attr:`PIL.Image.MAX_PIXELS`. - -Removed Deprecated Items -======================== - -Several deprecated items have been removed. - -* The methods :py:meth:`PIL.ImageWin.Dib.fromstring`, - :py:meth:`PIL.ImageWin.Dib.tostring` and - :py:meth:`PIL.TiffImagePlugin.ImageFileDirectory_v2.as_dict` have - been removed. - -* Before Pillow 4.2.0, attempting to save an RGBA image as JPEG would - discard the alpha channel. From Pillow 3.4.0, a deprecation warning - was shown. From Pillow 4.2.0, the deprecation warning is removed and - an :py:exc:`IOError` is raised. - -Removed Core Image Function -=========================== - -The unused function ``Image.core.new_array`` was removed. This is an -internal function that should not have been used by user code, but it -was accessible from the python layer. diff -Nru pillow-4.2.1/docs/releasenotes/4.2.1.rst pillow-4.1.1/docs/releasenotes/4.2.1.rst --- pillow-4.2.1/docs/releasenotes/4.2.1.rst 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/4.2.1.rst 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -4.2.1 ------ - -There are no functional changes in this release. - -Fixed Windows PyPy Build -======================== - -A change in the 4.2.0 cycle broke the Windows PyPy build. This has -been fixed, and PyPy is now part of the Windows CI matrix. - diff -Nru pillow-4.2.1/docs/releasenotes/index.rst pillow-4.1.1/docs/releasenotes/index.rst --- pillow-4.2.1/docs/releasenotes/index.rst 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/docs/releasenotes/index.rst 2017-04-28 16:48:58.000000000 +0000 @@ -6,8 +6,6 @@ .. toctree:: :maxdepth: 2 - 4.2.1 - 4.2.0 4.1.1 4.1.0 4.0.0 diff -Nru pillow-4.2.1/_imaging.c pillow-4.1.1/_imaging.c --- pillow-4.2.1/_imaging.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/_imaging.c 2017-04-28 16:48:58.000000000 +0000 @@ -71,6 +71,8 @@ * See the README file for information on usage and redistribution. */ +#define PILLOW_VERSION "4.1.1" + #include "Python.h" #ifdef HAVE_LIBZ @@ -94,6 +96,8 @@ #define WITH_THREADING /* "friendly" threading support */ #define WITH_UNSHARPMASK /* Kevin Cazabon's unsharpmask module */ +#define WITH_DEBUG /* extra debugging interfaces */ + #undef VERBOSE #define CLIP(x) ((x) <= 0 ? 0 : (x) < 256 ? (x) : 255) @@ -630,6 +634,18 @@ } static PyObject* +_new_array(PyObject* self, PyObject* args) +{ + char* mode; + int xsize, ysize; + + if (!PyArg_ParseTuple(args, "s(ii)", &mode, &xsize, &ysize)) + return NULL; + + return PyImagingNew(ImagingNewArray(mode, xsize, ysize)); +} + +static PyObject* _new_block(PyObject* self, PyObject* args) { char* mode; @@ -2906,6 +2922,8 @@ /* -------------------------------------------------------------------- */ +#ifdef WITH_DEBUG + static PyObject* _save_ppm(ImagingObject* self, PyObject* args) { @@ -2921,6 +2939,7 @@ return Py_None; } +#endif /* -------------------------------------------------------------------- */ @@ -3013,9 +3032,12 @@ #endif /* Misc. */ + {"new_array", (PyCFunction)_new_array, 1}, {"new_block", (PyCFunction)_new_block, 1}, +#ifdef WITH_DEBUG {"save_ppm", (PyCFunction)_save_ppm, 1}, +#endif {NULL, NULL} /* sentinel */ }; @@ -3415,7 +3437,6 @@ static int setup_module(PyObject* m) { PyObject* d = PyModule_GetDict(m); - const char* version = (char*)PILLOW_VERSION; /* Ready object types */ if (PyType_Ready(&Imaging_Type) < 0) @@ -3460,7 +3481,7 @@ } #endif - PyDict_SetItemString(d, "PILLOW_VERSION", PyUnicode_FromString(version)); + PyDict_SetItemString(d, "PILLOW_VERSION", PyUnicode_FromString(PILLOW_VERSION)); return 0; } diff -Nru pillow-4.2.1/_imagingft.c pillow-4.1.1/_imagingft.c --- pillow-4.2.1/_imagingft.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/_imagingft.c 2016-10-18 19:11:47.000000000 +0000 @@ -41,18 +41,6 @@ #define FT_ERRORDEF( e, v, s ) { e, s }, #define FT_ERROR_START_LIST { #define FT_ERROR_END_LIST { 0, 0 } }; -#ifdef HAVE_RAQM -#include -#endif - -#define LAYOUT_FALLBACK 0 -#define LAYOUT_RAQM 1 - -typedef struct -{ - int index, x_offset, x_advance, y_offset; - unsigned int cluster; -} GlyphInfo; struct { int code; @@ -70,7 +58,6 @@ PyObject_HEAD FT_Face face; unsigned char *font_bytes; - int layout_engine; } FontObject; static PyTypeObject Font_Type; @@ -104,13 +91,11 @@ char* filename = NULL; int size; int index = 0; - int layout_engine = 0; unsigned char* encoding; unsigned char* font_bytes; int font_bytes_size = 0; static char* kwlist[] = { - "filename", "size", "index", "encoding", "font_bytes", - "layout_engine", NULL + "filename", "size", "index", "encoding", "font_bytes", NULL }; if (!library) { @@ -121,10 +106,10 @@ return NULL; } - if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|iss#i", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kw, "eti|iss#", kwlist, Py_FileSystemDefaultEncoding, &filename, &size, &index, &encoding, &font_bytes, - &font_bytes_size, &layout_engine)) { + &font_bytes_size)) { return NULL; } @@ -136,7 +121,6 @@ } self->face = NULL; - self->layout_engine = layout_engine; if (filename && font_bytes_size <= 0) { self->font_bytes = NULL; @@ -204,288 +188,60 @@ return 0; } -#ifdef HAVE_RAQM -static size_t -text_layout_raqm(PyObject* string, FontObject* self, const char* dir, - PyObject *features ,GlyphInfo **glyph_info, int mask) -{ - int i = 0; - raqm_t *rq; - size_t count = 0; - raqm_glyph_t *glyphs; - raqm_direction_t direction; - - rq = raqm_create(); - if (rq == NULL) { - PyErr_SetString(PyExc_ValueError, "raqm_create() failed."); - goto failed; - } - - if (PyUnicode_Check(string)) { - Py_UNICODE *text = PyUnicode_AS_UNICODE(string); - Py_ssize_t size = PyUnicode_GET_SIZE(string); - if (!raqm_set_text(rq, (const uint32_t *)(text), size)) { - PyErr_SetString(PyExc_ValueError, "raqm_set_text() failed"); - goto failed; - } - } -#if PY_VERSION_HEX < 0x03000000 - else if (PyString_Check(string)) { - char *text = PyString_AS_STRING(string); - int size = PyString_GET_SIZE(string); - if (!raqm_set_text_utf8(rq, text, size)) { - PyErr_SetString(PyExc_ValueError, "raqm_set_text_utf8() failed"); - goto failed; - } - } -#endif - else { - PyErr_SetString(PyExc_TypeError, "expected string"); - goto failed; - } - - direction = RAQM_DIRECTION_DEFAULT; - if (dir) { - if (strcmp(dir, "rtl") == 0) - direction = RAQM_DIRECTION_RTL; - else if (strcmp(dir, "ltr") == 0) - direction = RAQM_DIRECTION_LTR; - else if (strcmp(dir, "ttb") == 0) - direction = RAQM_DIRECTION_TTB; - else { - PyErr_SetString(PyExc_ValueError, "direction must be either 'rtl', 'ltr' or 'ttb'"); - goto failed; - } - } - - if (!raqm_set_par_direction(rq, direction)) { - PyErr_SetString(PyExc_ValueError, "raqm_set_par_direction() failed"); - goto failed; - } - - if (features != Py_None) { - int len; - PyObject *seq = PySequence_Fast(features, "expected a sequence"); - if (!seq) { - goto failed; - } - - len = PySequence_Size(seq); - for (i = 0; i < len; i++) { - PyObject *item = PySequence_Fast_GET_ITEM(seq, i); - char *feature = NULL; - Py_ssize_t size = 0; - PyObject *bytes; - -#if PY_VERSION_HEX >= 0x03000000 - if (!PyUnicode_Check(item)) { -#else - if (!PyUnicode_Check(item) && !PyString_Check(item)) { -#endif - PyErr_SetString(PyExc_TypeError, "expected a string"); - goto failed; - } - - if (PyUnicode_Check(item)) { - bytes = PyUnicode_AsUTF8String(item); - if (bytes == NULL) - goto failed; - feature = PyBytes_AS_STRING(bytes); - size = PyBytes_GET_SIZE(bytes); - } -#if PY_VERSION_HEX < 0x03000000 - else { - feature = PyString_AsString(item); - size = PyString_GET_SIZE(item); - } -#endif - if (!raqm_add_font_feature(rq, feature, size)) { - PyErr_SetString(PyExc_ValueError, "raqm_add_font_feature() failed"); - goto failed; - } - } - } - - if (!raqm_set_freetype_face(rq, self->face)) { - PyErr_SetString(PyExc_RuntimeError, "raqm_set_freetype_face() failed."); - goto failed; - } - - if (!raqm_layout (rq)) { - PyErr_SetString(PyExc_RuntimeError, "raqm_layout() failed."); - goto failed; - } - - glyphs = raqm_get_glyphs(rq, &count); - if (glyphs == NULL) { - PyErr_SetString(PyExc_ValueError, "raqm_get_glyphs() failed."); - count = 0; - goto failed; - } - - (*glyph_info) = PyMem_New(GlyphInfo, count); - if ((*glyph_info) == NULL) { - PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed"); - count = 0; - goto failed; - } - - for (i = 0; i < count; i++) { - (*glyph_info)[i].index = glyphs[i].index; - (*glyph_info)[i].x_offset = glyphs[i].x_offset; - (*glyph_info)[i].x_advance = glyphs[i].x_advance; - (*glyph_info)[i].y_offset = glyphs[i].y_offset; - (*glyph_info)[i].cluster = glyphs[i].cluster; - } - -failed: - raqm_destroy (rq); - return count; -} -#endif - -static size_t -text_layout_fallback(PyObject* string, FontObject* self, const char* dir, - PyObject *features ,GlyphInfo **glyph_info, int mask) +static PyObject* +font_getsize(FontObject* self, PyObject* args) { - int error, load_flags; + int i, x, y_max, y_min; FT_ULong ch; - Py_ssize_t count; - FT_GlyphSlot glyph; + FT_Face face; + int xoffset, yoffset; FT_Bool kerning = FT_HAS_KERNING(self->face); FT_UInt last_index = 0; - int i; - if (features != Py_None || dir != NULL) { - PyErr_SetString(PyExc_KeyError, "setting text direction or font features is not supported without libraqm"); - } + /* calculate size and bearing for a given string */ + + PyObject* string; + if (!PyArg_ParseTuple(args, "O:getsize", &string)) + return NULL; + #if PY_VERSION_HEX >= 0x03000000 if (!PyUnicode_Check(string)) { #else if (!PyUnicode_Check(string) && !PyString_Check(string)) { #endif PyErr_SetString(PyExc_TypeError, "expected string"); - return 0; - } - - count = 0; - while (font_getchar(string, count, &ch)) { - count++; - } - if (count == 0) { - return 0; - } - - (*glyph_info) = PyMem_New(GlyphInfo, count); - if ((*glyph_info) == NULL) { - PyErr_SetString(PyExc_MemoryError, "PyMem_New() failed"); - return 0; - } - - load_flags = FT_LOAD_RENDER|FT_LOAD_NO_BITMAP; - if (mask) { - load_flags |= FT_LOAD_TARGET_MONO; - } - for (i = 0; font_getchar(string, i, &ch); i++) { - (*glyph_info)[i].index = FT_Get_Char_Index(self->face, ch); - error = FT_Load_Glyph(self->face, (*glyph_info)[i].index, load_flags); - if (error) { - geterror(error); - return 0; - } - glyph = self->face->glyph; - (*glyph_info)[i].x_offset=0; - (*glyph_info)[i].y_offset=0; - if (kerning && last_index && (*glyph_info)[i].index) { - FT_Vector delta; - if (FT_Get_Kerning(self->face, last_index, (*glyph_info)[i].index, - ft_kerning_default,&delta) == 0) - (*glyph_info)[i-1].x_advance += PIXEL(delta.x); - } - - (*glyph_info)[i].x_advance = glyph->metrics.horiAdvance; - last_index = (*glyph_info)[i].index; - (*glyph_info)[i].cluster = ch; - } - return count; -} - -static size_t -text_layout(PyObject* string, FontObject* self, const char* dir, - PyObject *features, GlyphInfo **glyph_info, int mask) -{ - size_t count; -#ifdef HAVE_RAQM - if (self->layout_engine == LAYOUT_RAQM) { - count = text_layout_raqm(string, self, dir, features, glyph_info, mask); - } else { - count = text_layout_fallback(string, self, dir, features, glyph_info, mask); - } -#else - count = text_layout_fallback(string, self, dir, features, glyph_info, mask); -#endif - return count; -} - -static PyObject* -font_getsize(FontObject* self, PyObject* args) -{ - int i, x, y_max, y_min; - FT_Face face; - int xoffset, yoffset; - const char *dir = NULL; - size_t count; - GlyphInfo *glyph_info = NULL; - PyObject *features = Py_None; - - /* calculate size and bearing for a given string */ - - PyObject* string; - if (!PyArg_ParseTuple(args, "O|zO:getsize", &string, &dir, &features)) return NULL; + } face = NULL; xoffset = yoffset = 0; y_max = y_min = 0; - count = text_layout(string, self, dir, features, &glyph_info, 0); - if (count == 0) - return NULL; - - for (x = i = 0; i < count; i++) { + for (x = i = 0; font_getchar(string, i, &ch); i++) { int index, error; FT_BBox bbox; FT_Glyph glyph; face = self->face; - index = glyph_info[i].index; - /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 - * Yifu Yu, 2014-10-15 - */ + index = FT_Get_Char_Index(face, ch); + if (kerning && last_index && index) { + FT_Vector delta; + FT_Get_Kerning(self->face, last_index, index, ft_kerning_default, + &delta); + x += delta.x; + } + + /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 + * Yifu Yu, 2014-10-15 + */ error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP); if (error) return geterror(error); - - if (i == 0 && face->glyph->metrics.horiBearingX < 0) { + if (i == 0) xoffset = face->glyph->metrics.horiBearingX; - x -= xoffset; - } - - x += glyph_info[i].x_advance; - - if (i == count - 1) - { - int offset; - offset = glyph_info[i].x_advance - - face->glyph->metrics.width - - face->glyph->metrics.horiBearingX; - if (offset < 0) - x -= offset; - } + x += face->glyph->metrics.horiAdvance; FT_Get_Glyph(face->glyph, &glyph); FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_SUBPIXELS, &bbox); - bbox.yMax -= glyph_info[i].y_offset; - bbox.yMin -= glyph_info[i].y_offset; if (bbox.yMax > y_max) y_max = bbox.yMax; if (bbox.yMin < y_min) @@ -495,16 +251,23 @@ if (face->glyph->metrics.horiBearingY > yoffset) yoffset = face->glyph->metrics.horiBearingY; + last_index = index; FT_Done_Glyph(glyph); } if (face) { - + int offset; /* left bearing */ if (xoffset < 0) x -= xoffset; else xoffset = 0; + /* right bearing */ + offset = face->glyph->metrics.horiAdvance - + face->glyph->metrics.width - + face->glyph->metrics.horiBearingX; + if (offset < 0) + x -= offset; /* difference between the font ascender and the distance of * the baseline from the top */ yoffset = PIXEL(self->face->size->metrics.ascender - yoffset); @@ -543,7 +306,7 @@ int index, error; face = self->face; index = FT_Get_Char_Index(face, ch); - /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */ + /* Note: bitmap fonts within ttf fonts do not work, see #891/pr#960 */ error = FT_Load_Glyph(face, index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP); if (error) return geterror(error); @@ -566,7 +329,11 @@ int index, error, ascender; int load_flags; unsigned char *source; + FT_ULong ch; FT_GlyphSlot glyph; + FT_Bool kerning = FT_HAS_KERNING(self->face); + FT_UInt last_index = 0; + /* render string into given buffer (the buffer *must* have the right size, or this will crash) */ PyObject* string; @@ -574,18 +341,15 @@ int mask = 0; int temp; int xx, x0, x1; - const char *dir = NULL; - size_t count; - GlyphInfo *glyph_info; - PyObject *features = NULL; - - if (!PyArg_ParseTuple(args, "On|izO:render", &string, &id, &mask, &dir, &features)) { + if (!PyArg_ParseTuple(args, "On|i:render", &string, &id, &mask)) return NULL; - } - glyph_info = NULL; - count = text_layout(string, self, dir, features, &glyph_info, mask); - if (count == 0) { +#if PY_VERSION_HEX >= 0x03000000 + if (!PyUnicode_Check(string)) { +#else + if (!PyUnicode_Check(string) && !PyString_Check(string)) { +#endif + PyErr_SetString(PyExc_TypeError, "expected string"); return NULL; } @@ -596,37 +360,36 @@ load_flags |= FT_LOAD_TARGET_MONO; ascender = 0; - for (i = 0; i < count; i++) { - index = glyph_info[i].index; + for (i = 0; font_getchar(string, i, &ch); i++) { + index = FT_Get_Char_Index(self->face, ch); error = FT_Load_Glyph(self->face, index, load_flags); if (error) return geterror(error); - glyph = self->face->glyph; temp = (glyph->bitmap.rows - glyph->bitmap_top); - temp -= PIXEL(glyph_info[i].y_offset); if (temp > ascender) ascender = temp; } - for (x = i = 0; i < count; i++) { + for (x = i = 0; font_getchar(string, i, &ch); i++) { if (i == 0 && self->face->glyph->metrics.horiBearingX < 0) - x = -self->face->glyph->metrics.horiBearingX; + x = -PIXEL(self->face->glyph->metrics.horiBearingX); + index = FT_Get_Char_Index(self->face, ch); + if (kerning && last_index && index) { + FT_Vector delta; + FT_Get_Kerning(self->face, last_index, index, ft_kerning_default, + &delta); + x += delta.x >> 6; + } - index = glyph_info[i].index; error = FT_Load_Glyph(self->face, index, load_flags); if (error) return geterror(error); - if (i == 0 && self->face->glyph->metrics.horiBearingX < 0) { - x = -self->face->glyph->metrics.horiBearingX; - } - glyph = self->face->glyph; source = (unsigned char*) glyph->bitmap.buffer; - xx = PIXEL(x) + glyph->bitmap_left; - xx += PIXEL(glyph_info[i].x_offset); + xx = x + glyph->bitmap_left; x0 = 0; x1 = glyph->bitmap.width; if (xx < 0) @@ -638,7 +401,6 @@ /* use monochrome mask (on palette images, etc) */ for (y = 0; y < glyph->bitmap.rows; y++) { int yy = y + im->ysize - (PIXEL(glyph->metrics.horiBearingY) + ascender); - yy -= PIXEL(glyph_info[i].y_offset); if (yy >= 0 && yy < im->ysize) { /* blend this glyph into the buffer */ unsigned char *target = im->image8[yy] + xx; @@ -658,10 +420,8 @@ /* use antialiased rendering */ for (y = 0; y < glyph->bitmap.rows; y++) { int yy = y + im->ysize - (PIXEL(glyph->metrics.horiBearingY) + ascender); - yy -= PIXEL(glyph_info[i].y_offset); if (yy >= 0 && yy < im->ysize) { /* blend this glyph into the buffer */ - int i; unsigned char *target = im->image8[yy] + xx; for (i = x0; i < x1; i++) { @@ -672,10 +432,10 @@ source += glyph->bitmap.pitch; } } - x += glyph_info[i].x_advance; + x += PIXEL(glyph->metrics.horiAdvance); + last_index = index; } - PyMem_Del(glyph_info); Py_RETURN_NONE; } @@ -833,14 +593,6 @@ #endif PyDict_SetItemString(d, "freetype2_version", v); - -#ifdef HAVE_RAQM - v = PyBool_FromLong(1); -#else - v = PyBool_FromLong(0); -#endif - PyDict_SetItemString(d, "HAVE_RAQM", v); - return 0; } diff -Nru pillow-4.2.1/libImaging/Draw.c pillow-4.1.1/libImaging/Draw.c --- pillow-4.2.1/libImaging/Draw.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/libImaging/Draw.c 2016-10-18 19:11:47.000000000 +0000 @@ -605,6 +605,11 @@ DRAWINIT(); + if (width <= 1) { + draw->line(im, x0, y0, x1, y1, ink); + return 0; + } + dx = x1-x0; dy = y1-y0; if (dx == 0 && dy == 0) { @@ -1026,6 +1031,20 @@ } int +ImagingOutlineCurve2(ImagingOutline outline, float cx, float cy, + float x3, float y3) +{ + /* add bezier curve based on three control points (as + in the Flash file format) */ + + return ImagingOutlineCurve( + outline, + (outline->x + cx + cx)/3, (outline->y + cy + cy)/3, + (cx + cx + x3)/3, (cy + cy + y3)/3, + x3, y3); +} + +int ImagingOutlineClose(ImagingOutline outline) { if (outline->x == outline->x0 && outline->y == outline->y0) diff -Nru pillow-4.2.1/libImaging/Imaging.h pillow-4.1.1/libImaging/Imaging.h --- pillow-4.2.1/libImaging/Imaging.h 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/libImaging/Imaging.h 2016-10-18 19:11:47.000000000 +0000 @@ -455,7 +455,6 @@ #ifdef HAVE_LIBZ extern int ImagingZipDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); -extern int ImagingZipDecodeCleanup(ImagingCodecState state); extern int ImagingZipEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); extern int ImagingZipEncodeCleanup(ImagingCodecState state); diff -Nru pillow-4.2.1/libImaging/JpegDecode.c pillow-4.1.1/libImaging/JpegDecode.c --- pillow-4.2.1/libImaging/JpegDecode.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/libImaging/JpegDecode.c 2016-10-18 19:11:47.000000000 +0000 @@ -268,7 +268,7 @@ /* -------------------------------------------------------------------- */ int ImagingJpegDecodeCleanup(ImagingCodecState state){ - /* called to free the decompression engine when the decode terminates + /* called to fee the decompression engine when the decode terminates due to a corrupt or truncated image */ JPEGSTATE* context = (JPEGSTATE*) state->context; diff -Nru pillow-4.2.1/libImaging/Resample.c pillow-4.1.1/libImaging/Resample.c --- pillow-4.2.1/libImaging/Resample.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/libImaging/Resample.c 2016-10-18 19:11:47.000000000 +0000 @@ -32,8 +32,6 @@ x = -x; if (x == 0.0) return 1.0; - if (x >= 1.0) - return 0.0; x = x * M_PI; return sin(x) / x * (0.54f + 0.46f * cos(x)); } @@ -168,12 +166,10 @@ center = (xx + 0.5) * scale; ww = 0.0; ss = 1.0 / filterscale; - // Round the value - xmin = (int) (center - support + 0.5); + xmin = (int) floor(center - support); if (xmin < 0) xmin = 0; - // Round the value - xmax = (int) (center + support + 0.5); + xmax = (int) ceil(center + support); if (xmax > inSize) xmax = inSize; xmax -= xmin; @@ -182,6 +178,21 @@ double w = filterp->filter((x + xmin - center + 0.5) * ss); k[x] = w; ww += w; + + // We can skip extreme coefficients if they are zeroes. + if (w == 0) { + // Skip from the start. + if (x == 0) { + // At next loop `x` will be 0. + x -= 1; + // But `w` will not be 0, because it based on `xmin`. + xmin += 1; + xmax -= 1; + } else if (x == xmax - 1) { + // Truncate the last coefficient for current `xx`. + xmax -= 1; + } + } } for (x = 0; x < xmax; x++) { if (ww != 0.0) diff -Nru pillow-4.2.1/libImaging/ZipDecode.c pillow-4.1.1/libImaging/ZipDecode.c --- pillow-4.2.1/libImaging/ZipDecode.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/libImaging/ZipDecode.c 2016-10-18 19:11:47.000000000 +0000 @@ -85,8 +85,6 @@ err = inflateInit(&context->z_stream); if (err < 0) { state->errcode = IMAGING_CODEC_CONFIG; - free(context->previous); - context->previous = NULL; return -1; } @@ -128,7 +126,6 @@ else state->errcode = IMAGING_CODEC_CONFIG; free(context->previous); - context->previous = NULL; inflateEnd(&context->z_stream); return -1; } @@ -194,7 +191,6 @@ default: state->errcode = IMAGING_CODEC_UNKNOWN; free(context->previous); - context->previous = NULL; inflateEnd(&context->z_stream); return -1; } @@ -262,7 +258,6 @@ state->errcode = IMAGING_CODEC_BROKEN; */ free(context->previous); - context->previous = NULL; inflateEnd(&context->z_stream); return -1; /* end of file (errcode=0) */ @@ -279,20 +274,4 @@ } - -int ImagingZipDecodeCleanup(ImagingCodecState state){ - /* called to free the decompression engine when the decode terminates - due to a corrupt or truncated image - */ - ZIPSTATE* context = (ZIPSTATE*) state->context; - - /* Clean up */ - if (context->previous) { - inflateEnd(&context->z_stream); - free(context->previous); - context->previous = NULL; - } - return -1; -} - #endif diff -Nru pillow-4.2.1/Makefile pillow-4.1.1/Makefile --- pillow-4.2.1/Makefile 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Makefile 2017-01-02 11:47:11.000000000 +0000 @@ -84,7 +84,7 @@ viewdoc sdist: - python setup.py sdist --format=gztar + python setup.py sdist --format=gztar,zip test: python test-installed.py @@ -95,10 +95,10 @@ # username: # password: # repository = http://test.pythonpackages.com - python setup.py sdist --format=gztar upload -r test + python setup.py sdist --format=gztar,zip upload -r test upload: - python setup.py sdist --format=gztar upload + python setup.py sdist --format=gztar,zip upload readme: viewdoc diff -Nru pillow-4.2.1/mp_compile.py pillow-4.1.1/mp_compile.py --- pillow-4.2.1/mp_compile.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/mp_compile.py 2017-04-04 18:14:25.000000000 +0000 @@ -54,8 +54,7 @@ def install(): - fl_pypy3 = (hasattr(sys, 'pypy_version_info') and - (3, 0) < sys.version_info < (3, 3)) + fl_pypy3 = hasattr(sys, 'pypy_version_info') and sys.version_info > (3, 0) fl_win = sys.platform.startswith('win') fl_cygwin = sys.platform.startswith('cygwin') @@ -74,7 +73,7 @@ try: # bug, only enable if we can make a Pool. see issue #790 and # https://stackoverflow.com/questions/6033599/oserror-38-errno-38-with-multiprocessing - Pool(2) + pool = Pool(2) CCompiler.compile = _mp_compile except Exception as msg: print("Exception installing mp_compile, proceeding without:" @@ -83,5 +82,4 @@ print("Single threaded build, not installing mp_compile:" "%s processes" % MAX_PROCS) - install() diff -Nru pillow-4.2.1/path.c pillow-4.1.1/path.c --- pillow-4.2.1/path.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/path.c 2017-04-28 16:48:58.000000000 +0000 @@ -314,6 +314,22 @@ } static PyObject* +path_clip_polygon(PyPathObject* self, PyObject* args) +{ + /* Clip path representing a single polygon */ + PyErr_SetString(PyExc_RuntimeError, "not yet implemented"); + return NULL; +} + +static PyObject* +path_clip_polyline(PyPathObject* self, PyObject* args) +{ + /* Clip path representing a single polyline (outline) */ + PyErr_SetString(PyExc_RuntimeError, "not yet implemented"); + return NULL; +} + +static PyObject* path_getbbox(PyPathObject* self, PyObject* args) { /* Find bounding box */ @@ -518,6 +534,8 @@ static struct PyMethodDef methods[] = { {"getbbox", (PyCFunction)path_getbbox, 1}, {"tolist", (PyCFunction)path_tolist, 1}, + {"clip_polygon", (PyCFunction)path_clip_polygon, 1}, + {"clip_polyline", (PyCFunction)path_clip_polyline, 1}, {"compact", (PyCFunction)path_compact, 1}, {"map", (PyCFunction)path_map, 1}, {"transform", (PyCFunction)path_transform, 1}, diff -Nru pillow-4.2.1/PIL/_binary.py pillow-4.1.1/PIL/_binary.py --- pillow-4.2.1/PIL/_binary.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/_binary.py 2017-04-04 18:14:24.000000000 +0000 @@ -37,7 +37,6 @@ """ return unpack(" 1: @@ -444,7 +441,6 @@ _write_frame_data(fp, im_frame, offset, frame_data['encoderinfo']) return True - def _save_all(im, fp, filename): _save(im, fp, filename, save_all=True) @@ -597,7 +593,6 @@ # cases where it took lots of memory and time previously. _FORCE_OPTIMIZE = False - def _get_optimize(im, info): """ Palette optimization is a potentially expensive operation. @@ -629,10 +624,9 @@ used_palette_colors.append(i) if optimise or (len(used_palette_colors) <= 128 and - max(used_palette_colors) > len(used_palette_colors)): + max(used_palette_colors) > len(used_palette_colors)): return used_palette_colors - def _get_color_table_size(palette_bytes): # calculate the palette size for the header import math @@ -641,7 +635,6 @@ color_table_size = 0 return color_table_size - def _get_header_palette(palette_bytes): """ Returns the palette, null padded to the next power of 2 (*3) bytes @@ -659,16 +652,14 @@ palette_bytes += o8(0) * 3 * actual_target_size_diff return palette_bytes - def _get_palette_bytes(im): - """ - Gets the palette for inclusion in the gif header - - :param im: Image object - :returns: Bytes, len<=768 suitable for inclusion in gif header - """ - return im.palette.palette + """ + Gets the palette for inclusion in the gif header + :param im: Image object + :returns: Bytes, len<=768 suitable for inclusion in gif header + """ + return im.palette.palette def _get_global_header(im, info): """Return a list of strings representing a GIF header""" @@ -680,7 +671,7 @@ for extensionKey in ["transparency", "duration", "loop", "comment"]: if info and extensionKey in info: if ((extensionKey == "duration" and info[extensionKey] == 0) or - (extensionKey == "comment" and not (1 <= len(info[extensionKey]) <= 255))): + (extensionKey == "comment" and not (1 <= len(info[extensionKey]) <= 255))): continue version = b"89a" break @@ -702,13 +693,12 @@ # size of global color table + global color table flag o8(color_table_size + 128), # packed fields # background + reserved/aspect - o8(background) + o8(0), + o8(background) + o8(0), # Global Color Table _get_header_palette(palette_bytes) ] - def _write_frame_data(fp, im_frame, offset, params): try: im_frame.encoderinfo = params @@ -726,7 +716,6 @@ # -------------------------------------------------------------------- # Legacy GIF utilities - def getheader(im, palette=None, info=None): """ Legacy Method to get Gif data from image. @@ -735,7 +724,7 @@ :param im: Image object :param palette: bytes object containing the source palette, or .... - :param info: encoderinfo + :param info: encoderinfo :returns: tuple of(list of header items, optimized palette) """ @@ -744,7 +733,7 @@ if info is None: info = {} - if "background" not in info and "background" in im.info: + if not "background" in info and "background" in im.info: info["background"] = im.info["background"] im_mod = _normalize_palette(im, palette, info) @@ -754,7 +743,6 @@ return header, used_palette_colors - # To specify duration, add the time in milliseconds to getdata(), # e.g. getdata(im_frame, duration=1000) def getdata(im, offset=(0, 0), **params): diff -Nru pillow-4.2.1/PIL/IcoImagePlugin.py pillow-4.1.1/PIL/IcoImagePlugin.py --- pillow-4.2.1/PIL/IcoImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/IcoImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -176,8 +176,8 @@ # figure out where AND mask image starts mode = a[0] bpp = 8 - for k, v in BmpImagePlugin.BIT2MODE.items(): - if mode == v[1]: + for k in BmpImagePlugin.BIT2MODE.keys(): + if mode == BmpImagePlugin.BIT2MODE[k][1]: bpp = k break diff -Nru pillow-4.2.1/PIL/ImageCms.py pillow-4.1.1/PIL/ImageCms.py --- pillow-4.2.1/PIL/ImageCms.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageCms.py 2016-10-18 19:11:47.000000000 +0000 @@ -166,6 +166,7 @@ self._set(profile) else: raise TypeError("Invalid type for Profile") + def _set(self, profile, filename=None): self.profile = profile diff -Nru pillow-4.2.1/PIL/ImageDraw.py pillow-4.1.1/PIL/ImageDraw.py --- pillow-4.2.1/PIL/ImageDraw.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageDraw.py 2017-04-04 18:14:24.000000000 +0000 @@ -207,6 +207,7 @@ if self._multiline_check(text): return self.multiline_text(xy, text, fill, font, anchor, *args, **kwargs) + ink, fill = self._getink(fill) if font is None: font = self.getfont() @@ -214,17 +215,17 @@ ink = fill if ink is not None: try: - mask, offset = font.getmask2(text, self.fontmode, *args, **kwargs) + mask, offset = font.getmask2(text, self.fontmode) xy = xy[0] + offset[0], xy[1] + offset[1] except AttributeError: try: - mask = font.getmask(text, self.fontmode, *args, **kwargs) + mask = font.getmask(text, self.fontmode) except TypeError: mask = font.getmask(text) self.draw.draw_bitmap(xy, mask, ink) def multiline_text(self, xy, text, fill=None, font=None, anchor=None, - spacing=4, align="left", direction=None, features=None): + spacing=4, align="left"): widths = [] max_width = 0 lines = self._multiline_split(text) @@ -243,30 +244,25 @@ left += (max_width - widths[idx]) else: assert False, 'align must be "left", "center" or "right"' - self.text((left, top), line, fill, font, anchor, - direction=direction, features=features) + self.text((left, top), line, fill, font, anchor) top += line_spacing left = xy[0] - def textsize(self, text, font=None, spacing=4, direction=None, - features=None): + def textsize(self, text, font=None, *args, **kwargs): """Get the size of a given string, in pixels.""" if self._multiline_check(text): - return self.multiline_textsize(text, font, spacing, - direction, features) + return self.multiline_textsize(text, font, *args, **kwargs) if font is None: font = self.getfont() - return font.getsize(text, direction, features) + return font.getsize(text) - def multiline_textsize(self, text, font=None, spacing=4, direction=None, - features=None): + def multiline_textsize(self, text, font=None, spacing=4): max_width = 0 lines = self._multiline_split(text) line_spacing = self.textsize('A', font=font)[1] + spacing for line in lines: - line_width, line_height = self.textsize(line, font, spacing, - direction, features) + line_width, line_height = self.textsize(line, font) max_width = max(max_width, line_width) return max_width, len(lines)*line_spacing @@ -287,7 +283,6 @@ except AttributeError: return ImageDraw(im, mode) - # experimental access to the outline API try: Outline = Image.core.outline @@ -319,7 +314,7 @@ return im, handler -def floodfill(image, xy, value, border=None, thresh=0): +def floodfill(image, xy, value, border=None): """ (experimental) Fills a bounded region with a given color. @@ -330,17 +325,13 @@ pixels with a color different from the border color. If not given, the region consists of pixels having the same color as the seed pixel. - :param thresh: Optional threshold value which specifies a maximum - tolerable difference of a pixel value from the 'background' in - order for it to be replaced. Useful for filling regions of non- - homogeneous, but similar, colors. """ # based on an implementation by Eric S. Raymond pixel = image.load() x, y = xy try: background = pixel[x, y] - if _color_diff(value, background) <= thresh: + if background == value: return # seed point already has fill color pixel[x, y] = value except (ValueError, IndexError): @@ -356,7 +347,7 @@ except IndexError: pass else: - if _color_diff(p, background) <= thresh: + if p == background: pixel[s, t] = value newedge.append((s, t)) edge = newedge @@ -374,10 +365,3 @@ pixel[s, t] = value newedge.append((s, t)) edge = newedge - - -def _color_diff(rgb1, rgb2): - """ - Uses 1-norm distance to calculate difference between two rgb values. - """ - return abs(rgb1[0]-rgb2[0]) + abs(rgb1[1]-rgb2[1]) + abs(rgb1[2]-rgb2[2]) diff -Nru pillow-4.2.1/PIL/ImageFile.py pillow-4.1.1/PIL/ImageFile.py --- pillow-4.2.1/PIL/ImageFile.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageFile.py 2017-04-04 18:14:24.000000000 +0000 @@ -160,7 +160,7 @@ # try memory mapping decoder_name, extents, offset, args = self.tile[0] if decoder_name == "raw" and len(args) >= 3 and args[0] == self.mode \ - and args[0] in Image._MAPMODES: + and args[0] in Image._MAPMODES: try: if hasattr(Image.core, "map"): # use built-in mapper WIN32 only @@ -186,7 +186,7 @@ self.map = None self.load_prepare() - err_code = -3 # initialize to unknown error + if not self.map: # sort tiles in file order self.tile.sort(key=_tilesort) @@ -199,7 +199,7 @@ for decoder_name, extents, offset, args in self.tile: decoder = Image._getdecoder(self.mode, decoder_name, - args, self.decoderconfig) + args, self.decoderconfig) seek(offset) decoder.setimage(self.im, extents) if decoder.pulls_fd: @@ -380,8 +380,11 @@ # attempt to open this file try: - with io.BytesIO(self.data) as fp: + try: + fp = io.BytesIO(self.data) im = Image.open(fp) + finally: + fp.close() # explicitly close the virtual file except IOError: # traceback.print_exc() pass # not enough data @@ -429,11 +432,12 @@ if self.data: # incremental parsing not possible; reopen the file # not that we have all data - with io.BytesIO(self.data) as fp: - try: - self.image = Image.open(fp) - finally: - self.image.load() + try: + fp = io.BytesIO(self.data) + self.image = Image.open(fp) + finally: + self.image.load() + fp.close() # explicitly close the virtual file return self.image @@ -536,7 +540,6 @@ return (self.xoff, self.yoff, self.xoff+self.xsize, self.yoff+self.ysize) - class PyDecoder(object): """ Python implementation of a format decoder. Override this class and @@ -562,7 +565,7 @@ :returns: None """ self.args = args - + @property def pulls_fd(self): return self._pulls_fd @@ -594,7 +597,7 @@ :returns: None """ self.fd = fd - + def setimage(self, im, extents=None): """ Called from ImageFile to set the core output image for the decoder @@ -604,7 +607,7 @@ for this tile :returns: None """ - + # following c code self.im = im @@ -613,6 +616,7 @@ else: (x0, y0, x1, y1) = (0, 0, 0, 0) + if x0 == 0 and x1 == 0: self.state.xsize, self.state.ysize = self.im.size else: @@ -623,11 +627,11 @@ if self.state.xsize <= 0 or self.state.ysize <= 0: raise ValueError("Size cannot be negative") - + if (self.state.xsize + self.state.xoff > self.im.size[0] or - self.state.ysize + self.state.yoff > self.im.size[1]): + self.state.ysize + self.state.yoff > self.im.size[1]): raise ValueError("Tile cannot extend outside image") - + def set_as_raw(self, data, rawmode=None): """ Convenience method to set the internal image from a stream of raw data @@ -637,13 +641,13 @@ it will default to the mode of the image :returns: None """ - + if not rawmode: rawmode = self.mode d = Image._getdecoder(self.mode, 'raw', (rawmode)) d.setimage(self.im, self.state.extents()) s = d.decode(data) - + if s[0] >= 0: raise ValueError("not enough image data") if s[1] != 0: diff -Nru pillow-4.2.1/PIL/ImageFont.py pillow-4.1.1/PIL/ImageFont.py --- pillow-4.2.1/PIL/ImageFont.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageFont.py 2017-04-04 18:14:24.000000000 +0000 @@ -41,9 +41,6 @@ except ImportError: core = _imagingft_not_installed() -LAYOUT_BASIC = 0 -LAYOUT_RAQM = 1 - # FIXME: add support for pilfont2 format (see FontFile.py) # -------------------------------------------------------------------- @@ -106,12 +103,9 @@ self.font = Image.core.font(image.im, data) - def getsize(self, text, *args, **kwargs): - return self.font.getsize(text) - - def getmask(self, text, mode="", *args, **kwargs): - return self.font.getmask(text, mode) - + # delegate critical operations to internal type + self.getsize = self.font.getsize + self.getmask = self.font.getmask ## @@ -121,8 +115,7 @@ class FreeTypeFont(object): "FreeType font wrapper (requires _imagingft service)" - def __init__(self, font=None, size=10, index=0, encoding="", - layout_engine=None): + def __init__(self, font=None, size=10, index=0, encoding=""): # FIXME: use service provider instead self.path = font @@ -130,21 +123,12 @@ self.index = index self.encoding = encoding - if layout_engine not in (LAYOUT_BASIC, LAYOUT_RAQM): - layout_engine = LAYOUT_BASIC - if core.HAVE_RAQM: - layout_engine = LAYOUT_RAQM - if layout_engine == LAYOUT_RAQM and not core.HAVE_RAQM: - layout_engine = LAYOUT_BASIC - - self.layout_engine = layout_engine - if isPath(font): - self.font = core.getfont(font, size, index, encoding, layout_engine=layout_engine) + self.font = core.getfont(font, size, index, encoding) else: self.font_bytes = font.read() self.font = core.getfont( - "", size, index, encoding, self.font_bytes, layout_engine) + "", size, index, encoding, self.font_bytes) def getname(self): return self.font.family, self.font.style @@ -152,24 +136,23 @@ def getmetrics(self): return self.font.ascent, self.font.descent - def getsize(self, text, direction=None, features=None): - size, offset = self.font.getsize(text, direction, features) + def getsize(self, text): + size, offset = self.font.getsize(text) return (size[0] + offset[0], size[1] + offset[1]) def getoffset(self, text): return self.font.getsize(text)[1] - def getmask(self, text, mode="", direction=None, features=None): - return self.getmask2(text, mode, direction=direction, features=features)[0] + def getmask(self, text, mode=""): + return self.getmask2(text, mode)[0] - def getmask2(self, text, mode="", fill=Image.core.fill, direction=None, features=None): - size, offset = self.font.getsize(text, direction, features) + def getmask2(self, text, mode="", fill=Image.core.fill): + size, offset = self.font.getsize(text) im = fill("L", size, 0) - self.font.render(text, im.id, mode == "1", direction, features) + self.font.render(text, im.id, mode == "1") return im, offset - def font_variant(self, font=None, size=None, index=None, encoding=None, - layout_engine=None): + def font_variant(self, font=None, size=None, index=None, encoding=None): """ Create a copy of this FreeTypeFont object, using any specified arguments to override the settings. @@ -182,9 +165,8 @@ return FreeTypeFont(font=self.path if font is None else font, size=self.size if size is None else size, index=self.index if index is None else index, - encoding=self.encoding if encoding is None else encoding, - layout_engine=self.layout_engine if layout_engine is None else layout_engine - ) + encoding=self.encoding if encoding is None else + encoding) class TransposedFont(object): @@ -203,14 +185,14 @@ self.font = font self.orientation = orientation # any 'transpose' argument, or None - def getsize(self, text, *args, **kwargs): + def getsize(self, text): w, h = self.font.getsize(text) if self.orientation in (Image.ROTATE_90, Image.ROTATE_270): return h, w return w, h - def getmask(self, text, mode="", *args, **kwargs): - im = self.font.getmask(text, mode, *args, **kwargs) + def getmask(self, text, mode=""): + im = self.font.getmask(text, mode) if self.orientation is not None: return im.transpose(self.orientation) return im @@ -230,8 +212,7 @@ return f -def truetype(font=None, size=10, index=0, encoding="", - layout_engine=None): +def truetype(font=None, size=10, index=0, encoding=""): """ Load a TrueType or OpenType font file, and create a font object. This function loads a font object from the given file, and creates @@ -249,14 +230,12 @@ Symbol), "ADOB" (Adobe Standard), "ADBE" (Adobe Expert), and "armn" (Apple Roman). See the FreeType documentation for more information. - :param layout_engine: Which layout engine to use, if available: - `ImageFont.LAYOUT_BASIC` or `ImageFont.LAYOUT_RAQM`. :return: A font object. :exception IOError: If the file could not be read. """ try: - return FreeTypeFont(font, size, index, encoding, layout_engine) + return FreeTypeFont(font, size, index, encoding) except IOError: ttf_filename = os.path.basename(font) @@ -287,16 +266,16 @@ for walkfilename in walkfilenames: if ext and walkfilename == ttf_filename: fontpath = os.path.join(walkroot, walkfilename) - return FreeTypeFont(fontpath, size, index, encoding, layout_engine) + return FreeTypeFont(fontpath, size, index, encoding) elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename: fontpath = os.path.join(walkroot, walkfilename) if os.path.splitext(fontpath)[1] == '.ttf': - return FreeTypeFont(fontpath, size, index, encoding, layout_engine) + return FreeTypeFont(fontpath, size, index, encoding) if not ext and first_font_with_a_different_extension is None: first_font_with_a_different_extension = fontpath if first_font_with_a_different_extension: return FreeTypeFont(first_font_with_a_different_extension, size, - index, encoding, layout_engine) + index, encoding) raise diff -Nru pillow-4.2.1/PIL/ImageMorph.py pillow-4.1.1/PIL/ImageMorph.py --- pillow-4.2.1/PIL/ImageMorph.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageMorph.py 2017-04-04 18:14:24.000000000 +0000 @@ -123,7 +123,7 @@ .replace('0', 'Z') .replace('1', '0') .replace('Z', '1')) - res = 1-int(res) + res = '%d' % (1-int(res)) patterns.append((pattern, res)) return patterns @@ -152,8 +152,8 @@ patterns += self._pattern_permute(pattern, options, result) # # Debugging -# for p, r in patterns: -# print(p, r) +# for p,r in patterns: +# print(p,r) # print('--') # compile the patterns into regular expressions for speed @@ -234,7 +234,7 @@ with open(filename, 'rb') as f: self.lut = bytearray(f.read()) - if len(self.lut) != LUT_SIZE: + if len(self.lut) != 8192: self.lut = None raise Exception('Wrong size operator file!') diff -Nru pillow-4.2.1/PIL/Image.py pillow-4.1.1/PIL/Image.py --- pillow-4.2.1/PIL/Image.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/Image.py 2017-04-04 18:14:24.000000000 +0000 @@ -56,10 +56,7 @@ from . import _imaging as core if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None): raise ImportError("The _imaging extension was built for another " - "version of Pillow or PIL: Core Version: %s" - "Pillow Version: %s" % - (getattr(core, 'PILLOW_VERSION', None), - PILLOW_VERSION)) + "version of Pillow or PIL") except ImportError as v: core = _imaging_not_installed() @@ -277,7 +274,7 @@ return shape+(extra,), typ -MODES = sorted(_MODEINFO) +MODES = sorted(_MODEINFO.keys()) # raw modes that may be memory mapped. NOTE: if you change this, you # may have to modify the stride calculation in map.c too! @@ -561,16 +558,16 @@ if getattr(self, 'map', None): self.map = None - + # Instead of simply setting to None, we're setting up a # deferred error that will better explain that the core image # object is gone. self.im = deferred_error(ValueError("Operation on closed image")) - if sys.version_info >= (3, 4, 0): + if sys.version_info >= (3,4,0): def __del__(self): - if (hasattr(self, 'fp') and hasattr(self, '_exclusive_fp') - and self.fp and self._exclusive_fp): + if (hasattr(self, 'fp') and hasattr(self, '_exclusive_fp') + and self.fp and self._exclusive_fp): self.fp.close() self.fp = None @@ -580,7 +577,7 @@ self.pyaccess = None self.readonly = 0 - def _dump(self, file=None, format=None, **options): + def _dump(self, file=None, format=None): import tempfile suffix = '' if format: @@ -595,7 +592,7 @@ else: if not file.endswith(format): file = file + "." + format - self.save(file, format, **options) + self.save(file, format) return file def __eq__(self, other): @@ -1045,20 +1042,6 @@ if box is None: return self.copy() - return self._new(self._crop(self.im, box)) - - def _crop(self, im, box): - """ - Returns a rectangular region from the core image object im. - - This is equivalent to calling im.crop((x0, y0, x1, y1)), but - includes additional sanity checks. - - :param im: a core image object - :param box: The crop rectangle, as a (left, upper, right, lower)-tuple. - :returns: A core image object. - """ - x0, y0, x1, y1 = map(int, map(round, box)) if x1 < x0: @@ -1066,10 +1049,8 @@ if y1 < y0: y1 = y0 - _decompression_bomb_check((x1, y1)) + return self._new(self.im.crop((x0, y0, x1, y1))) - return im.crop((x0, y0, x1, y1)) - def draft(self, mode, size): """ Configures the image file loader so it returns a version of the @@ -1082,9 +1063,6 @@ 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. - :param mode: The requested mode. :param size: The requested size. """ @@ -1376,54 +1354,6 @@ else: self.im.paste(im, box) - def alpha_composite(self, im, dest=(0,0), source=(0,0)): - """ 'In-place' analog of Image.alpha_composite. Composites an image - onto this image. - - :param im: image to composite over this one - :param dest: Optional 2 tuple (top, left) specifying the upper - left corner in this (destination) image. - :param source: Optional 2 (top, left) tuple for the upper left - corner in the overlay source image, or 4 tuple (top, left, bottom, - right) for the bounds of the source rectangle - - Performance Note: Not currently implemented in-place in the core layer. - """ - - if not isinstance(source, tuple): - raise ValueError("Source must be a tuple") - if not isinstance(dest, tuple): - raise ValueError("Destination must be a tuple") - if not len(source) in (2, 4): - raise ValueError("Source must be a 2 or 4-tuple") - if not len(dest) == 2: - raise ValueError("Destination must be a 2-tuple") - if min(source) < 0: - raise ValueError("Source must be non-negative") - if min(dest) < 0: - raise ValueError("Destination must be non-negative") - - if len(source) == 2: - source = source + im.size - - # over image, crop if it's not the whole thing. - if source == (0,0) + im.size: - overlay = im - else: - overlay = im.crop(source) - - # target for the paste - box = dest + (dest[0] + overlay.width, dest[1] + overlay.height) - - # destination image. don't copy if we're using the whole image. - if dest == (0,0) + self.size: - background = self - else: - background = self.crop(box) - - result = alpha_composite(background, overlay) - self.paste(result, box) - def point(self, lut, mode=None): """ Maps this image through a lookup table or function. @@ -1602,16 +1532,16 @@ def remap_palette(self, dest_map, source_palette=None): """ Rewrites the image to reorder the palette. - + :param dest_map: A list of indexes into the original palette. e.g. [1,0] would swap a two item palette, and list(range(255)) is the identity transform. :param source_palette: Bytes or None. - :returns: An :py:class:`~PIL.Image.Image` object. - + :returns: An :py:class:`~PIL.Image.Image` object. + """ from . import ImagePalette - + if self.mode not in ("L", "P"): raise ValueError("illegal image mode") @@ -1620,6 +1550,7 @@ source_palette = self.im.getpalette("RGB")[:768] else: # L-mode source_palette = bytearray(i//3 for i in range(768)) + palette_bytes = b"" new_positions = [0]*256 @@ -1655,8 +1586,8 @@ m_im.palette = ImagePalette.ImagePalette("RGB", palette=mapping_palette*3, size=768) - # possibly set palette dirty, then - # m_im.putpalette(mapping_palette, 'L') # converts to 'P' + #possibly set palette dirty, then + #m_im.putpalette(mapping_palette, 'L') # converts to 'P' # or just force it. # UNDONE -- this is part of the general issue with palettes m_im.im.putpalette(*m_im.palette.getdata()) @@ -1672,6 +1603,8 @@ size=len(palette_bytes)) return m_im + + def resize(self, size, resample=NEAREST): """ @@ -2691,7 +2624,6 @@ init() return EXTENSION - def register_decoder(name, decoder): """ Registers an image decoder. This function should not be @@ -2701,7 +2633,7 @@ :param decoder: A callable(mode, args) that returns an ImageFile.PyDecoder object - .. versionadded:: 4.1.0 + .. versionadded:: 4.1.0 """ DECODERS[name] = decoder diff -Nru pillow-4.2.1/PIL/ImageShow.py pillow-4.1.1/PIL/ImageShow.py --- pillow-4.2.1/PIL/ImageShow.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageShow.py 2016-10-18 19:11:47.000000000 +0000 @@ -69,7 +69,7 @@ # FIXME: auto-contrast if max() > 255? else: base = Image.getmodebase(image.mode) - if base != image.mode and image.mode != "1" and image.mode != "RGBA": + if base != image.mode and image.mode != "1": image = image.convert(base) return self.show_image(image, **options) @@ -77,7 +77,6 @@ # hook methods format = None - options = {} def get_format(self, image): """Return format name, or None to save as PGM/PPM""" @@ -88,7 +87,7 @@ def save_image(self, image): """Save to temporary file, and return filename""" - return image._dump(format=self.get_format(image), **self.options) + return image._dump(format=self.get_format(image)) def show_image(self, image, **options): """Display given image""" @@ -116,8 +115,7 @@ elif sys.platform == "darwin": class MacViewer(Viewer): - format = "PNG" - options = {'compress_level': 1} + format = "BMP" def get_command(self, file, **options): # on darwin open returns immediately resulting in the temp @@ -144,9 +142,6 @@ return None class UnixViewer(Viewer): - format = "PNG" - options = {'compress_level': 1} - def show_file(self, file, **options): command, executable = self.get_command_ex(file, **options) command = "(%s %s; rm -f %s)&" % (command, quote(file), diff -Nru pillow-4.2.1/PIL/ImageWin.py pillow-4.1.1/PIL/ImageWin.py --- pillow-4.2.1/PIL/ImageWin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/ImageWin.py 2017-04-04 18:14:24.000000000 +0000 @@ -182,6 +182,14 @@ """ return self.image.tobytes() + def fromstring(self, *args, **kw): + raise NotImplementedError("fromstring() has been removed. " + + "Please use frombytes() instead.") + + def tostring(self, *args, **kw): + raise NotImplementedError("tostring() has been removed. " + + "Please use tobytes() instead.") + class Window(object): """Create a Window with the given title size.""" diff -Nru pillow-4.2.1/PIL/__init__.py pillow-4.1.1/PIL/__init__.py --- pillow-4.2.1/PIL/__init__.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/__init__.py 2017-04-28 16:48:58.000000000 +0000 @@ -11,10 +11,8 @@ # ;-) -from . import version - -VERSION = '1.1.7' # PIL Version -PILLOW_VERSION = version.__version__ +VERSION = '1.1.7' # PIL version +PILLOW_VERSION = '4.1.1' # Pillow __version__ = PILLOW_VERSION diff -Nru pillow-4.2.1/PIL/IptcImagePlugin.py pillow-4.1.1/PIL/IptcImagePlugin.py --- pillow-4.2.1/PIL/IptcImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/IptcImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -95,7 +95,7 @@ tagdata = self.fp.read(size) else: tagdata = None - if tag in self.info: + if tag in list(self.info.keys()): if isinstance(self.info[tag], list): self.info[tag].append(tagdata) else: diff -Nru pillow-4.2.1/PIL/JpegImagePlugin.py pillow-4.1.1/PIL/JpegImagePlugin.py --- pillow-4.2.1/PIL/JpegImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/JpegImagePlugin.py 2017-04-28 16:48:58.000000000 +0000 @@ -127,7 +127,7 @@ dpi = x_resolution[0] / x_resolution[1] except TypeError: dpi = x_resolution - if resolution_unit == 3: # cm + if resolution_unit == 3: # cm # 1 dpcm = 2.54 dpi dpi *= 2.54 self.info["dpi"] = dpi, dpi @@ -423,8 +423,7 @@ try: if len(value) == 1 and not isinstance(value, dict): return value[0] - except: - pass + except: pass return value return {k: _fixup(v) for k, v in src_dict.items()} @@ -555,6 +554,7 @@ "1": "L", "L": "L", "RGB": "RGB", + "RGBA": "RGB", "RGBX": "RGB", "CMYK": "CMYK;I", # assume adobe conventions "YCbCr": "YCbCr", @@ -603,6 +603,14 @@ except KeyError: raise IOError("cannot write mode %s as JPEG" % im.mode) + if im.mode == 'RGBA': + warnings.warn( + 'You are saving RGBA image as JPEG. The alpha channel will be ' + 'discarded. This conversion is deprecated and will be disabled ' + 'in Pillow 3.7. Please, convert the image to RGB explicitly.', + DeprecationWarning + ) + info = im.encoderinfo dpi = [int(round(x)) for x in info.get("dpi", (0, 0))] @@ -697,8 +705,8 @@ # "progressive" is the official name, but older documentation # says "progression" # FIXME: issue a warning if the wrong form is used (post-1.1.7) - progressive = (info.get("progressive", False) or - info.get("progression", False)) + progressive = info.get("progressive", False) or\ + info.get("progression", False) optimize = info.get("optimize", False) @@ -732,9 +740,8 @@ bufsize = im.size[0] * im.size[1] # The exif info needs to be written as one block, + APP1, + one spare byte. - # Ensure that our buffer is big enough. Same with the icc_profile block. - bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5, - len(extra) + 1) + # Ensure that our buffer is big enough + bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5) ImageFile._save(im, fp, [("jpeg", (0, 0)+im.size, 0, rawmode)], bufsize) diff -Nru pillow-4.2.1/PIL/McIdasImagePlugin.py pillow-4.1.1/PIL/McIdasImagePlugin.py --- pillow-4.2.1/PIL/McIdasImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/McIdasImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -66,7 +66,6 @@ self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))] - # -------------------------------------------------------------------- # registry diff -Nru pillow-4.2.1/PIL/MicImagePlugin.py pillow-4.1.1/PIL/MicImagePlugin.py --- pillow-4.2.1/PIL/MicImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/MicImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -97,7 +97,6 @@ return self.frame - # # -------------------------------------------------------------------- diff -Nru pillow-4.2.1/PIL/MspImagePlugin.py pillow-4.1.1/PIL/MspImagePlugin.py --- pillow-4.2.1/PIL/MspImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/MspImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -25,8 +25,7 @@ from . import Image, ImageFile from ._binary import i16le as i16, o16le as o16, i8 -import struct -import io +import struct, io __version__ = "0.1" @@ -98,7 +97,7 @@ # If the RunType value is non-zero # Use this value as the RunCount # Read and write the next RunCount bytes literally - # + # # e.g.: # 0x00 03 ff 05 00 01 02 03 04 # would yield the bytes: @@ -106,10 +105,11 @@ # # which are then interpreted as a bit packed mode '1' image + _pulls_fd = True def decode(self, buffer): - + img = io.BytesIO() blank_line = bytearray((0xff,)*((self.state.xsize+7)//8)) try: @@ -140,17 +140,17 @@ runcount = runtype img.write(row[idx:idx+runcount]) idx += runcount - + except struct.error: - raise IOError("Corrupted MSP file in row %d" % x) - + raise IOError("Corrupted MSP file in row %d" %x) + self.set_as_raw(img.getvalue(), ("1", 0, 1)) - - return 0, 0 + + return 0,0 Image.register_decoder('MSP', MspDecoder) - + # # write MSP files (uncompressed only) diff -Nru pillow-4.2.1/PIL/PdfImagePlugin.py pillow-4.1.1/PIL/PdfImagePlugin.py --- pillow-4.2.1/PIL/PdfImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/PdfImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -20,7 +20,7 @@ # Image plugin for PDF images (output only). ## -from . import Image, ImageFile, ImageSequence +from . import Image, ImageFile from ._binary import i8 import io @@ -133,24 +133,13 @@ # # pages - ims = [im] + numberOfPages = 1 if save_all: - append_images = im.encoderinfo.get("append_images", []) - for append_im in append_images: - if append_im.mode != im.mode: - append_im = append_im.convert(im.mode) - append_im.encoderinfo = im.encoderinfo.copy() - ims.append(append_im) - numberOfPages = 0 - for im in ims: - im_numberOfPages = 1 - if save_all: - try: - im_numberOfPages = im.n_frames - except AttributeError: - # Image format does not have n_frames. It is a single frame image - pass - numberOfPages += im_numberOfPages + try: + numberOfPages = im.n_frames + except AttributeError: + # Image format does not have n_frames. It is a single frame image + pass pages = [str(pageNumber*3+4)+" 0 R" for pageNumber in range(0, numberOfPages)] @@ -162,92 +151,90 @@ Kids="["+"\n".join(pages)+"]") _endobj(fp) - pageNumber = 0 - for imSequence in ims: - for im in ImageSequence.Iterator(imSequence): - # - # image - - op = io.BytesIO() - - if filter == "/ASCIIHexDecode": - if bits == 1: - # FIXME: the hex encoder doesn't support packed 1-bit - # images; do things the hard way... - data = im.tobytes("raw", "1") - im = Image.new("L", (len(data), 1), None) - im.putdata(data) - ImageFile._save(im, op, [("hex", (0, 0)+im.size, 0, im.mode)]) - elif filter == "/DCTDecode": - Image.SAVE["JPEG"](im, op, filename) - elif filter == "/FlateDecode": - ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)]) - elif filter == "/RunLengthDecode": - ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)]) - else: - raise ValueError("unsupported PDF filter (%s)" % filter) - - # - # Get image characteristics - - width, height = im.size - - xref.append(fp.tell()) - _obj( - fp, pageNumber*3+3, - Type="/XObject", - Subtype="/Image", - Width=width, # * 72.0 / resolution, - Height=height, # * 72.0 / resolution, - Length=len(op.getvalue()), - Filter=filter, - BitsPerComponent=bits, - DecodeParams=params, - ColorSpace=colorspace) - - fp.write("stream\n") - fp.fp.write(op.getvalue()) - fp.write("\nendstream\n") - - _endobj(fp) - - # - # page - - xref.append(fp.tell()) - _obj(fp, pageNumber*3+4) - fp.write( - "<<\n/Type /Page\n/Parent 2 0 R\n" - "/Resources <<\n/ProcSet [ /PDF %s ]\n" - "/XObject << /image %d 0 R >>\n>>\n" - "/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\n" % ( - procset, - pageNumber*3+3, - int(width * 72.0 / resolution), - int(height * 72.0 / resolution), - pageNumber*3+5)) - _endobj(fp) - - # - # page contents - - op = TextWriter(io.BytesIO()) - - op.write( - "q %d 0 0 %d 0 0 cm /image Do Q\n" % ( - int(width * 72.0 / resolution), - int(height * 72.0 / resolution))) - - xref.append(fp.tell()) - _obj(fp, pageNumber*3+5, Length=len(op.fp.getvalue())) - - fp.write("stream\n") - fp.fp.write(op.fp.getvalue()) - fp.write("\nendstream\n") + for pageNumber in range(0, numberOfPages): + im.seek(pageNumber) - _endobj(fp) + # + # image - pageNumber += 1 + op = io.BytesIO() + + if filter == "/ASCIIHexDecode": + if bits == 1: + # FIXME: the hex encoder doesn't support packed 1-bit + # images; do things the hard way... + data = im.tobytes("raw", "1") + im = Image.new("L", (len(data), 1), None) + im.putdata(data) + ImageFile._save(im, op, [("hex", (0, 0)+im.size, 0, im.mode)]) + elif filter == "/DCTDecode": + Image.SAVE["JPEG"](im, op, filename) + elif filter == "/FlateDecode": + ImageFile._save(im, op, [("zip", (0, 0)+im.size, 0, im.mode)]) + elif filter == "/RunLengthDecode": + ImageFile._save(im, op, [("packbits", (0, 0)+im.size, 0, im.mode)]) + else: + raise ValueError("unsupported PDF filter (%s)" % filter) + + # + # Get image characteristics + + width, height = im.size + + xref.append(fp.tell()) + _obj( + fp, pageNumber*3+3, + Type="/XObject", + Subtype="/Image", + Width=width, # * 72.0 / resolution, + Height=height, # * 72.0 / resolution, + Length=len(op.getvalue()), + Filter=filter, + BitsPerComponent=bits, + DecodeParams=params, + ColorSpace=colorspace) + + fp.write("stream\n") + fp.fp.write(op.getvalue()) + fp.write("\nendstream\n") + + _endobj(fp) + + # + # page + + xref.append(fp.tell()) + _obj(fp, pageNumber*3+4) + fp.write( + "<<\n/Type /Page\n/Parent 2 0 R\n" + "/Resources <<\n/ProcSet [ /PDF %s ]\n" + "/XObject << /image %d 0 R >>\n>>\n" + "/MediaBox [ 0 0 %d %d ]\n/Contents %d 0 R\n>>\n" % ( + procset, + pageNumber*3+3, + int(width * 72.0 / resolution), + int(height * 72.0 / resolution), + pageNumber*3+5)) + _endobj(fp) + + # + # page contents + + op = TextWriter(io.BytesIO()) + + op.write( + "q %d 0 0 %d 0 0 cm /image Do Q\n" % ( + int(width * 72.0 / resolution), + int(height * 72.0 / resolution))) + + xref.append(fp.tell()) + _obj(fp, pageNumber*3+5, Length=len(op.fp.getvalue())) + + fp.write("stream\n") + fp.fp.write(op.fp.getvalue()) + fp.write("\nendstream\n") + + _endobj(fp) # # trailer diff -Nru pillow-4.2.1/PIL/PngImagePlugin.py pillow-4.1.1/PIL/PngImagePlugin.py --- pillow-4.2.1/PIL/PngImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/PngImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -113,8 +113,7 @@ length = i32(s) if not is_cid(cid): - if not ImageFile.LOAD_TRUNCATED_IMAGES: - raise SyntaxError("broken PNG file (chunk %s)" % repr(cid)) + raise SyntaxError("broken PNG file (chunk %s)" % repr(cid)) return cid, pos, length diff -Nru pillow-4.2.1/PIL/SgiImagePlugin.py pillow-4.1.1/PIL/SgiImagePlugin.py --- pillow-4.2.1/PIL/SgiImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/SgiImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -124,14 +124,14 @@ fp.write(struct.pack('>l', pinmin)) fp.write(struct.pack('>l', pinmax)) - fp.write(struct.pack('4s', b'')) # dummy - fp.write(struct.pack('79s', imgName)) # truncates to 79 chars - fp.write(struct.pack('s', b'')) # force null byte after imgname + fp.write(struct.pack('4s', b'')) # dummy + fp.write(struct.pack('79s', imgName)) # truncates to 79 chars + fp.write(struct.pack('s', b'')) # force null byte after imgname fp.write(struct.pack('>l', colormap)) - fp.write(struct.pack('404s', b'')) # dummy + fp.write(struct.pack('404s', b'')) # dummy - # assert we've got the right number of bands. + #assert we've got the right number of bands. if len(im.getbands()) != z: raise ValueError("incorrect number of bands in SGI write: %s vs %s" % (z, len(im.getbands()))) diff -Nru pillow-4.2.1/PIL/SunImagePlugin.py pillow-4.1.1/PIL/SunImagePlugin.py --- pillow-4.2.1/PIL/SunImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/SunImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -52,6 +52,7 @@ # DWORD ColorMapLength; /* Size of the color map in bytes */ # } SUNRASTER; + # HEAD s = self.fp.read(32) if i32(s) != 0x59a66a95: @@ -62,9 +63,9 @@ self.size = i32(s[4:8]), i32(s[8:12]) depth = i32(s[12:16]) - data_length = i32(s[16:20]) # unreliable, ignore. + data_length = i32(s[16:20]) # unreliable, ignore. file_type = i32(s[20:24]) - palette_type = i32(s[24:28]) # 0: None, 1: RGB, 2: Raw/arbitrary + palette_type = i32(s[24:28]) # 0: None, 1: RGB, 2: Raw/arbitrary palette_length = i32(s[28:32]) if depth == 1: diff -Nru pillow-4.2.1/PIL/TiffImagePlugin.py pillow-4.1.1/PIL/TiffImagePlugin.py --- pillow-4.2.1/PIL/TiffImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/TiffImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -242,7 +242,6 @@ n_d = IFDRational(1 / val if inv else val).limit_rational(max_val) return n_d[::-1] if inv else n_d - ## # Wrapper for TIFF IFDs. @@ -463,6 +462,15 @@ def __str__(self): return str(dict(self)) + def as_dict(self): + """Return a dictionary of the image's tags. + + .. deprecated:: 3.0.0 + """ + warnings.warn("as_dict() is deprecated. " + + "Please use dict(ifd) instead.", DeprecationWarning) + return dict(self) + def named(self): """ :returns: dict of name|key: value @@ -527,8 +535,7 @@ self.tagtype[tag] = 2 if self.tagtype[tag] == 7 and bytes is not str: - values = [value.encode("ascii", 'replace') if isinstance( - value, str) else value] + values = [value.encode("ascii", 'replace') if isinstance(value, str) else value] values = tuple(info.cvt_enum(value) for value in values) @@ -581,13 +588,9 @@ b"".join(self._pack(fmt, value) for value in values)) list(map(_register_basic, - [(3, "H", "short"), - (4, "L", "long"), - (6, "b", "signed byte"), - (8, "h", "signed short"), - (9, "l", "signed long"), - (11, "f", "float"), - (12, "d", "double")])) + [(3, "H", "short"), (4, "L", "long"), + (6, "b", "signed byte"), (8, "h", "signed short"), + (9, "l", "signed long"), (11, "f", "float"), (12, "d", "double")])) @_register_loader(1, 1) # Basic type, except for the legacy API. def load_byte(self, data, legacy_api=True): @@ -613,8 +616,7 @@ @_register_loader(5, 8) def load_rational(self, data, legacy_api=True): vals = self._unpack("{}L".format(len(data) // 4), data) - - def combine(a, b): return (a, b) if legacy_api else IFDRational(a, b) + combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b) return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) @@ -634,8 +636,7 @@ @_register_loader(10, 8) def load_signed_rational(self, data, legacy_api=True): vals = self._unpack("{}l".format(len(data) // 4), data) - - def combine(a, b): return (a, b) if legacy_api else IFDRational(a, b) + combine = lambda a, b: (a, b) if legacy_api else IFDRational(a, b) return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) @@ -659,8 +660,7 @@ try: for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]): - tag, typ, count, data = self._unpack("HHL4s", - self._ensure_read(fp, 12)) + tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12)) if DEBUG: tagname = TiffTags.lookup(tag).name typname = TYPES.get(typ, "unknown") @@ -688,8 +688,8 @@ if len(data) != size: warnings.warn("Possibly corrupt EXIF data. " - "Expecting to read %d bytes but only got %d." - " Skipping tag %s" % (size, len(data), tag)) + "Expecting to read %d bytes but only got %d. " + "Skipping tag %s" % (size, len(data), tag)) continue if not data: @@ -748,8 +748,7 @@ if len(data) <= 4: entries.append((tag, typ, count, data.ljust(4, b"\0"), b"")) else: - entries.append((tag, typ, count, self._pack("L", offset), - data)) + entries.append((tag, typ, count, self._pack("L", offset), data)) offset += (len(data) + 1) // 2 * 2 # pad to word # update strip offset data to point beyond auxiliary data @@ -778,7 +777,6 @@ return offset - ImageFileDirectory_v2._load_dispatch = _load_dispatch ImageFileDirectory_v2._write_dispatch = _write_dispatch for idx, name in TYPES.items(): @@ -1138,7 +1136,7 @@ sampleFormat = self.tag_v2.get(SAMPLEFORMAT, (1,)) if (len(sampleFormat) > 1 - and max(sampleFormat) == min(sampleFormat) == 1): + and max(sampleFormat) == min(sampleFormat) == 1): # SAMPLEFORMAT is properly per band, so an RGB image will # be (1,1,1). But, we don't support per band pixel types, # and anything more than one band is a uint8. So, just @@ -1176,10 +1174,9 @@ self.info["dpi"] = xres, yres elif resunit == 3: # dots per centimeter. convert to dpi self.info["dpi"] = xres * 2.54, yres * 2.54 - elif resunit is None: # used to default to 1, but now 2) + elif resunit is None: # used to default to 1, but now 2) self.info["dpi"] = xres, yres - # For backward compatibility, - # we also preserve the old behavior + # For backward compatibility, we also preserve the old behavior. self.info["resolution"] = xres, yres else: # No absolute unit of measurement self.info["resolution"] = xres, yres @@ -1295,8 +1292,6 @@ if self.mode == "P": palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]] self.palette = ImagePalette.raw("RGB;L", b"".join(palette)) - - # # -------------------------------------------------------------------- # Write TIFF files @@ -1497,7 +1492,6 @@ # just to access o32 and o16 (using correct byte order) im._debug_multipage = ifd - class AppendingTiffWriter: fieldSizes = [ 0, # None @@ -1685,10 +1679,13 @@ def fixIFD(self): numTags = self.readShort() + #trace("fixing IFD at %X; number of tags: %u (0x%X)", self.f.tell()-2, + # numTags, numTags) for i in range(numTags): - tag, fieldType, count = struct.unpack(self.tagFormat, - self.f.read(8)) + tag, fieldType, count = struct.unpack(self.tagFormat, self.f.read(8)) + #trace(" at %X: tag %u (0x%X), type %u, count %u", self.f.tell()-8, + # tag, tag, fieldType, count) fieldSize = self.fieldSizes[fieldType] totalSize = fieldSize * count @@ -1740,34 +1737,21 @@ else: self.rewriteLastLong(offset) - def _save_all(im, fp, filename): - encoderinfo = im.encoderinfo.copy() - encoderconfig = im.encoderconfig - append_images = encoderinfo.get("append_images", []) - if not hasattr(im, "n_frames") and not len(append_images): + if not hasattr(im, "n_frames"): return _save(im, fp, filename) cur_idx = im.tell() try: with AppendingTiffWriter(fp) as tf: - for ims in [im]+append_images: - ims.encoderinfo = encoderinfo - ims.encoderconfig = encoderconfig - if not hasattr(ims, "n_frames"): - nfr = 1 - else: - nfr = ims.n_frames - - for idx in range(nfr): - ims.seek(idx) - ims.load() - _save(ims, tf, filename) - tf.newFrame() + for idx in range(im.n_frames): + im.seek(idx) + im.load() + _save(im, tf, filename) + tf.newFrame() finally: im.seek(cur_idx) - # # -------------------------------------------------------------------- # Register diff -Nru pillow-4.2.1/PIL/version.py pillow-4.1.1/PIL/version.py --- pillow-4.2.1/PIL/version.py 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/PIL/version.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -# Master version for Pillow -__version__ = '4.2.1' diff -Nru pillow-4.2.1/PIL/WmfImagePlugin.py pillow-4.1.1/PIL/WmfImagePlugin.py --- pillow-4.2.1/PIL/WmfImagePlugin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/PIL/WmfImagePlugin.py 2017-04-04 18:14:24.000000000 +0000 @@ -25,6 +25,7 @@ from ._binary import i16le as word, si16le as short, i32le as dword, si32le as _long + __version__ = "0.2" _handler = None @@ -65,7 +66,6 @@ # -------------------------------------------------------------------- # Read WMF file - def _accept(prefix): return ( prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or diff -Nru pillow-4.2.1/Pillow.egg-info/PKG-INFO pillow-4.1.1/Pillow.egg-info/PKG-INFO --- pillow-4.2.1/Pillow.egg-info/PKG-INFO 2017-07-06 20:47:09.000000000 +0000 +++ pillow-4.1.1/Pillow.egg-info/PKG-INFO 2017-04-28 16:49:31.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: Pillow -Version: 4.2.1 +Version: 4.1.1 Summary: Python Imaging Library (Fork) Home-page: https://python-pillow.org Author: Alex Clark (Fork Author) @@ -22,7 +22,7 @@ * - docs - |docs| * - tests - - | |linux| |macos| |windows| |coverage| + - | |linux| |macos| |windows| |coverage| |health| * - package - |zenodo| |version| @@ -46,6 +46,10 @@ :target: https://coveralls.io/github/python-pillow/Pillow?branch=master :alt: Code coverage + .. |health| image:: https://landscape.io/github/python-pillow/Pillow/master/landscape.svg + :target: https://landscape.io/github/python-pillow/Pillow/master + :alt: Code health + .. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg :target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow diff -Nru pillow-4.2.1/Pillow.egg-info/requires.txt pillow-4.1.1/Pillow.egg-info/requires.txt --- pillow-4.2.1/Pillow.egg-info/requires.txt 2017-07-06 20:47:09.000000000 +0000 +++ pillow-4.1.1/Pillow.egg-info/requires.txt 2017-04-28 16:49:31.000000000 +0000 @@ -1 +1 @@ -olefile +olefile \ No newline at end of file diff -Nru pillow-4.2.1/Pillow.egg-info/SOURCES.txt pillow-4.1.1/Pillow.egg-info/SOURCES.txt --- pillow-4.2.1/Pillow.egg-info/SOURCES.txt 2017-07-06 20:47:09.000000000 +0000 +++ pillow-4.1.1/Pillow.egg-info/SOURCES.txt 2017-04-28 16:49:31.000000000 +0000 @@ -113,7 +113,6 @@ PIL/_tkinter_finder.py PIL/_util.py PIL/features.py -PIL/version.py Pillow.egg-info/PKG-INFO Pillow.egg-info/SOURCES.txt Pillow.egg-info/dependency_links.txt @@ -262,7 +261,6 @@ Tests/test_imagefile.py Tests/test_imagefont.py Tests/test_imagefont_bitmap.py -Tests/test_imagefontctl.py Tests/test_imagegrab.py Tests/test_imagemath.py Tests/test_imagemorph.py @@ -295,8 +293,6 @@ Tests/fonts/DejaVuSans-bitmap.ttf Tests/fonts/DejaVuSans.ttf Tests/fonts/FreeMono.ttf -Tests/fonts/LICENSE.txt -Tests/fonts/NotoNastaliqUrdu-Regular.ttf Tests/fonts/helvO18.pcf Tests/icc/LICENSE.txt Tests/icc/sRGB_IEC61966-2-1_black_scaled.icc @@ -325,8 +321,6 @@ Tests/images/chi.gif Tests/images/clipboard.dib Tests/images/clipboard_target.png -Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara -Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png Tests/images/color_snakes.png Tests/images/compression.tif Tests/images/copyleft.tiff @@ -398,7 +392,6 @@ Tests/images/hopper.ico Tests/images/hopper.im Tests/images/hopper.jpg -Tests/images/hopper.mic Tests/images/hopper.msp Tests/images/hopper.p7 Tests/images/hopper.pcd @@ -432,21 +425,15 @@ Tests/images/hopper_webp_bits.ppm Tests/images/hopper_webp_write.ppm Tests/images/icc_profile.png -Tests/images/icc_profile_big.jpg Tests/images/icc_profile_none.png Tests/images/illu10_no_preview.eps Tests/images/illu10_preview.eps Tests/images/illuCS6_no_preview.eps Tests/images/illuCS6_preview.eps Tests/images/imagedraw_arc.png -Tests/images/imagedraw_arc_end_le_start.png -Tests/images/imagedraw_arc_no_loops.png -Tests/images/imagedraw_big_rectangle.png Tests/images/imagedraw_bitmap.png -Tests/images/imagedraw_chord_L.png -Tests/images/imagedraw_chord_RGB.png -Tests/images/imagedraw_ellipse_L.png -Tests/images/imagedraw_ellipse_RGB.png +Tests/images/imagedraw_chord.png +Tests/images/imagedraw_ellipse.png Tests/images/imagedraw_ellipse_edge.png Tests/images/imagedraw_floodfill.png Tests/images/imagedraw_floodfill2.png @@ -454,12 +441,9 @@ Tests/images/imagedraw_pieslice.png Tests/images/imagedraw_point.png Tests/images/imagedraw_polygon.png -Tests/images/imagedraw_polygon_kite_L.png -Tests/images/imagedraw_polygon_kite_RGB.png Tests/images/imagedraw_rectangle.png Tests/images/imagedraw_shape1.png Tests/images/imagedraw_shape2.png -Tests/images/imagedraw_wide_line_dot.png Tests/images/invalid.spider Tests/images/iptc.jpg Tests/images/iss634.gif @@ -523,15 +507,6 @@ Tests/images/test-ole-file.doc Tests/images/test.colors.gif Tests/images/test.gpl -Tests/images/test_Nastalifont_text.png -Tests/images/test_arabictext_features.png -Tests/images/test_complex_unicode_text.png -Tests/images/test_direction_ltr.png -Tests/images/test_direction_rtl.png -Tests/images/test_kerning_features.png -Tests/images/test_ligature_features.png -Tests/images/test_text.png -Tests/images/test_y_offset.png Tests/images/tga_id_field.tga Tests/images/tiff_adobe_deflate.tif Tests/images/total-pages-zero.tif @@ -665,8 +640,6 @@ depends/install_extra_test_images.sh depends/install_imagequant.sh depends/install_openjpeg.sh -depends/install_raqm.sh -depends/install_raqm_cmake.sh depends/install_webp.sh depends/ubuntu_12.04.sh depends/ubuntu_14.04.sh @@ -732,8 +705,6 @@ docs/releasenotes/4.0.0.rst docs/releasenotes/4.1.0.rst docs/releasenotes/4.1.1.rst -docs/releasenotes/4.2.0.rst -docs/releasenotes/4.2.1.rst docs/releasenotes/index.rst libImaging/Access.c libImaging/AlphaComposite.c @@ -818,7 +789,6 @@ libImaging/ZipEncode.c libImaging/codec_fd.c winbuild/README.md -winbuild/appveyor_install_pypy.cmd winbuild/build.py winbuild/build.rst winbuild/build_dep.py diff -Nru pillow-4.2.1/PKG-INFO pillow-4.1.1/PKG-INFO --- pillow-4.2.1/PKG-INFO 2017-07-06 20:47:09.000000000 +0000 +++ pillow-4.1.1/PKG-INFO 2017-04-28 16:49:31.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: Pillow -Version: 4.2.1 +Version: 4.1.1 Summary: Python Imaging Library (Fork) Home-page: https://python-pillow.org Author: Alex Clark (Fork Author) @@ -22,7 +22,7 @@ * - docs - |docs| * - tests - - | |linux| |macos| |windows| |coverage| + - | |linux| |macos| |windows| |coverage| |health| * - package - |zenodo| |version| @@ -46,6 +46,10 @@ :target: https://coveralls.io/github/python-pillow/Pillow?branch=master :alt: Code coverage + .. |health| image:: https://landscape.io/github/python-pillow/Pillow/master/landscape.svg + :target: https://landscape.io/github/python-pillow/Pillow/master + :alt: Code health + .. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg :target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow diff -Nru pillow-4.2.1/README.rst pillow-4.1.1/README.rst --- pillow-4.2.1/README.rst 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/README.rst 2017-04-04 18:14:24.000000000 +0000 @@ -14,7 +14,7 @@ * - docs - |docs| * - tests - - | |linux| |macos| |windows| |coverage| + - | |linux| |macos| |windows| |coverage| |health| * - package - |zenodo| |version| @@ -38,6 +38,10 @@ :target: https://coveralls.io/github/python-pillow/Pillow?branch=master :alt: Code coverage +.. |health| image:: https://landscape.io/github/python-pillow/Pillow/master/landscape.svg + :target: https://landscape.io/github/python-pillow/Pillow/master + :alt: Code health + .. |zenodo| image:: https://zenodo.org/badge/17549/python-pillow/Pillow.svg :target: https://zenodo.org/badge/latestdoi/17549/python-pillow/Pillow diff -Nru pillow-4.2.1/RELEASING.md pillow-4.1.1/RELEASING.md --- pillow-4.2.1/RELEASING.md 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/RELEASING.md 2016-10-18 19:11:47.000000000 +0000 @@ -7,8 +7,10 @@ * [ ] Open a release ticket e.g. https://github.com/python-pillow/Pillow/issues/1174 * [ ] Develop and prepare release in ``master`` branch. * [ ] Check [Travis CI](https://travis-ci.org/python-pillow/Pillow) and [AppVeyor CI](https://ci.appveyor.com/project/python-pillow/Pillow) to confirm passing tests in ``master`` branch. -* [ ] Check that all of the wheel builds [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels) pass the tests in TravisCI. -* [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in `PIL/version.py` +* [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in: +``` + PIL/__init__.py setup.py _imaging.c appveyor.yml +``` * [ ] Update `CHANGES.rst`. * [ ] Run pre-release check via `make release-test` in a freshly cloned repo. * [ ] Create branch and tag for release e.g.: @@ -18,12 +20,12 @@ $ git push --all $ git push --tags ``` -* [ ] Create source distributions e.g.: +* [ ] Create and upload source distributions e.g.: ``` $ make sdist + $ make upload ``` -* [ ] Create binary distributions [binary distributions](#binary-distributions) -* [ ] Upload all binaries and source distributions with ``twine upload dist/Pillow-4.1.0-*`` +* [ ] Create and upload [binary distributions](#binary-distributions) * [ ] Manually hide old versions on PyPI such that only the latest major release is visible when viewing https://pypi.python.org/pypi/Pillow (https://pypi.python.org/pypi?:action=pkg_edit&name=Pillow) ## Point Release @@ -38,18 +40,24 @@ ``` git checkout -t remotes/origin/2.9.x ``` -* [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in `PIL/version.py` +* [ ] In compliance with https://www.python.org/dev/peps/pep-0440/, update version identifier in: +``` + PIL/__init__.py + setup.py + _imaging.c + appveyor.yml +``` * [ ] Run pre-release check via `make release-test`. * [ ] Create tag for release e.g.: ``` $ git tag 2.9.1 $ git push --tags ``` -* [ ] Create source distributions e.g.: +* [ ] Create and upload source distributions e.g.: ``` - $ make sdist + $ make sdistup ``` -* [ ] Create [binary distributions](#binary-distributions) +* [ ] Create and upload [binary distributions](#binary-distributions) ## Embargoed Release @@ -68,11 +76,11 @@ git push origin 2.5.x git push origin --tags ``` -* [ ] Create source distributions e.g.: +* [ ] Create and upload source distributions e.g.: ``` - $ make sdist + $ make sdistup ``` -* [ ] Create [binary distributions](#binary-distributions) +* [ ] Create and upload [binary distributions](#binary-distributions) ## Binary Distributions @@ -80,8 +88,8 @@ * [ ] Contact @cgohlke for Windows binaries via release ticket e.g. https://github.com/python-pillow/Pillow/issues/1174. * [ ] Download and extract tarball from @cgohlke and ``twine upload *``. -### Mac and Linux -* [ ] Use the [Pillow Wheel Builder](https://github.com/python-pillow/pillow-wheels): +### macOS +* [ ] Use the [Pillow macOS Wheel Builder](https://github.com/python-pillow/pillow-wheels): ``` $ git checkout https://github.com/python-pillow/pillow-wheels $ cd pillow-wheels @@ -89,13 +97,12 @@ $ git submodule update $ cd Pillow $ git fetch --all - $ git checkout [[release tag]] - $ cd .. - $ git commit -m "Pillow -> 2.9.0" Pillow - $ git push + $ git commit -a -m "Pillow -> 2.9.0" + $ git push ``` -* [ ] Download distributions from the [Pillow Wheel Builder container](http://a365fff413fe338398b6-1c8a9b3114517dc5fe17b7c3f8c63a43.r19.cf2.rackcdn.com/). +* [ ] Download distributions from the [Pillow macOS Wheel Builder container](http://cdf58691c5cf45771290-6a3b6a0f5f6ab91aadc447b2a897dd9a.r50.cf2.rackcdn.com/) and ``twine upload *``. +### Linux ## Publicize Release diff -Nru pillow-4.2.1/selftest.py pillow-4.1.1/selftest.py --- pillow-4.2.1/selftest.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/selftest.py 2017-01-02 11:47:11.000000000 +0000 @@ -178,15 +178,25 @@ ("freetype2", "FREETYPE2"), ("littlecms2", "LITTLECMS2"), ("webp", "WEBP"), - ("transp_webp", "Transparent WEBP"), - ("webp_mux", "WEBPMUX"), + ("transp_webp", "Transparent WEBP") + ]: + supported = features.check_module(name) + + if supported is None: + # A method was being tested, but the module required + # for the method could not be correctly imported + pass + elif supported: + print("---", feature, "support ok") + else: + print("***", feature, "support not installed") + for name, feature in [ ("jpg", "JPEG"), ("jpg_2000", "OPENJPEG (JPEG2000)"), ("zlib", "ZLIB (PNG/ZIP)"), - ("libtiff", "LIBTIFF"), - ("raqm", "RAQM (Bidirectional Text)") + ("libtiff", "LIBTIFF") ]: - if features.check(name): + if features.check_codec(name): print("---", feature, "support ok") else: print("***", feature, "support not installed") diff -Nru pillow-4.2.1/setup.py pillow-4.1.1/setup.py --- pillow-4.2.1/setup.py 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/setup.py 2017-04-28 16:48:58.000000000 +0000 @@ -63,9 +63,6 @@ else: _dbg('Inserting path %s', subdir) path.insert(where, subdir) - elif subdir in path and where is not None: - path.remove(subdir) - path.insert(where, subdir) def _find_include_file(self, include): @@ -98,12 +95,6 @@ return fp.read() -def get_version(): - version_file = 'PIL/version.py' - with open(version_file, 'r') as f: - exec(compile(f.read(), version_file, 'exec')) - return locals()['__version__'] - try: import _tkinter except (ImportError, OSError): @@ -111,7 +102,7 @@ _tkinter = None NAME = 'Pillow' -PILLOW_VERSION = get_version() +PILLOW_VERSION = '4.1.1' JPEG_ROOT = None JPEG2K_ROOT = None ZLIB_ROOT = None @@ -119,7 +110,7 @@ TIFF_ROOT = None FREETYPE_ROOT = None LCMS_ROOT = None -RAQM_ROOT = None + def _pkg_config(name): try: @@ -137,7 +128,7 @@ class pil_build_ext(build_ext): class feature: - features = ['zlib', 'jpeg', 'tiff', 'freetype', 'raqm', 'lcms', 'webp', + features = ['zlib', 'jpeg', 'tiff', 'freetype', 'lcms', 'webp', 'webpmux', 'jpeg2000', 'imagequant'] required = {'jpeg', 'zlib'} @@ -471,10 +462,6 @@ # Add the directory to the include path so we can include # rather than having to cope with the versioned # include path - # FIXME (melvyn-sopacua): - # At this point it's possible that best_path is already in - # self.compiler.include_dirs. Should investigate how that is - # possible. _add_directory(self.compiler.include_dirs, best_path, 0) feature.jpeg2000 = 'openjp2' feature.openjpeg_version = '.'.join(str(x) for x in best_version) @@ -522,14 +509,6 @@ if subdir: _add_directory(self.compiler.include_dirs, subdir, 0) - if feature.want('raqm'): - _dbg('Looking for raqm') - if _find_include_file(self, "raqm.h"): - if _find_library_file(self, "raqm") and \ - _find_library_file(self, "harfbuzz") and \ - _find_library_file(self, "fribidi"): - feature.raqm = ["raqm", "harfbuzz", "fribidi"] - if feature.want('lcms'): _dbg('Looking for lcms') if _find_include_file(self, "lcms2.h"): @@ -599,11 +578,6 @@ if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1: defs.append(("WORDS_BIGENDIAN", None)) - if sys.platform == "win32" and not hasattr(sys, 'pypy_version_info'): - defs.append(("PILLOW_VERSION", '"\\"%s\\""'%PILLOW_VERSION)) - else: - defs.append(("PILLOW_VERSION", '"%s"'%PILLOW_VERSION)) - exts = [(Extension("PIL._imaging", files, libraries=libs, @@ -613,14 +587,9 @@ # additional libraries if feature.freetype: - libs = ["freetype"] - defs = [] - if feature.raqm: - libs.extend(feature.raqm) - defs.append(('HAVE_RAQM', None)) - exts.append(Extension( - "PIL._imagingft", ["_imagingft.c"], libraries=libs, - define_macros=defs)) + exts.append(Extension("PIL._imagingft", + ["_imagingft.c"], + libraries=["freetype"])) if feature.lcms: extra = [] @@ -682,7 +651,6 @@ (feature.imagequant, "LIBIMAGEQUANT"), (feature.tiff, "LIBTIFF"), (feature.freetype, "FREETYPE2"), - (feature.raqm, "RAQM"), (feature.lcms, "LITTLECMS2"), (feature.webp, "WEBP"), (feature.webpmux, "WEBPMUX"), diff -Nru pillow-4.2.1/Tests/fonts/LICENSE.txt pillow-4.1.1/Tests/fonts/LICENSE.txt --- pillow-4.2.1/Tests/fonts/LICENSE.txt 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/fonts/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ - -NotoNastaliqUrdu-Regular.ttf: - -(from https://github.com/googlei18n/noto-fonts) - -All Noto fonts are published under the SIL Open Font License (OFL) v1.1 (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL), which allows you to copy, modify, and redistribute them if you need to. Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/fonts/NotoNastaliqUrdu-Regular.ttf and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/fonts/NotoNastaliqUrdu-Regular.ttf differ diff -Nru pillow-4.2.1/Tests/helper.py pillow-4.1.1/Tests/helper.py --- pillow-4.2.1/Tests/helper.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/helper.py 2017-04-04 18:14:24.000000000 +0000 @@ -250,7 +250,6 @@ else: IMCONVERT = 'convert' - def distro(): if os.path.exists('/etc/os-release'): with open('/etc/os-release', 'r') as f: @@ -258,7 +257,6 @@ if 'ID=' in line: return line.strip().split('=')[1] - class cached_property(object): def __init__(self, func): self.func = func Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/hopper.mic and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/hopper.mic differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/icc_profile_big.jpg and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/icc_profile_big.jpg differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_arc_end_le_start.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_arc_end_le_start.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_arc_no_loops.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_arc_no_loops.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_big_rectangle.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_big_rectangle.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_chord_L.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_chord_L.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_chord.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_chord.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_chord_RGB.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_chord_RGB.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_ellipse_L.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_ellipse_L.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_ellipse.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_ellipse.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_ellipse_RGB.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_ellipse_RGB.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_polygon_kite_L.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_polygon_kite_L.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_polygon_kite_RGB.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_polygon_kite_RGB.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/imagedraw_wide_line_dot.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/imagedraw_wide_line_dot.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_arabictext_features.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_arabictext_features.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_complex_unicode_text.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_complex_unicode_text.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_direction_ltr.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_direction_ltr.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_direction_rtl.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_direction_rtl.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_kerning_features.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_kerning_features.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_ligature_features.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_ligature_features.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_Nastalifont_text.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_Nastalifont_text.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_text.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_text.png differ Binary files /tmp/tmp2B58Pk/r_qcVCy5hv/pillow-4.2.1/Tests/images/test_y_offset.png and /tmp/tmp2B58Pk/Ozn7o0yV4S/pillow-4.1.1/Tests/images/test_y_offset.png differ diff -Nru pillow-4.2.1/Tests/test_bmp_reference.py pillow-4.1.1/Tests/test_bmp_reference.py --- pillow-4.2.1/Tests/test_bmp_reference.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_bmp_reference.py 2017-01-02 11:47:11.000000000 +0000 @@ -99,7 +99,8 @@ os.path.join(base, 'g', 'pal8rle.bmp'), os.path.join(base, 'g', 'pal4rle.bmp')) if f not in unsupported: - self.fail("Unsupported Image %s: %s" % (f, msg)) + self.assertTrue( + False, "Unsupported Image %s: %s" % (f, msg)) if __name__ == '__main__': diff -Nru pillow-4.2.1/Tests/test_decompression_bomb.py pillow-4.1.1/Tests/test_decompression_bomb.py --- pillow-4.2.1/Tests/test_decompression_bomb.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_decompression_bomb.py 2016-10-18 19:11:47.000000000 +0000 @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase from PIL import Image @@ -21,7 +21,7 @@ # Arrange # Turn limit off Image.MAX_IMAGE_PIXELS = None - self.assertIsNone(Image.MAX_IMAGE_PIXELS) + self.assertEqual(Image.MAX_IMAGE_PIXELS, None) # Act / Assert # Implicit assert: no warning. @@ -35,24 +35,9 @@ self.assertEqual(Image.MAX_IMAGE_PIXELS, 10) # Act / Assert - self.assert_warning(Image.DecompressionBombWarning, - lambda: Image.open(TEST_FILE)) - -class TestDecompressionCrop(PillowTestCase): - - def setUp(self): - self.src = hopper() - Image.MAX_IMAGE_PIXELS = self.src.height * self.src.width - - def tearDown(self): - Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT - - def testEnlargeCrop(self): - # Crops can extend the extents, therefore we should have the - # same decompression bomb warnings on them. - box = (0, 0, self.src.width * 2, self.src.height * 2) - self.assert_warning(Image.DecompressionBombWarning, - lambda: self.src.crop(box)) + self.assert_warning( + Image.DecompressionBombWarning, + lambda: Image.open(TEST_FILE)) if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_features.py pillow-4.1.1/Tests/test_features.py --- pillow-4.2.1/Tests/test_features.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_features.py 2017-01-02 11:47:11.000000000 +0000 @@ -2,50 +2,19 @@ from PIL import features -try: - from PIL import _webp - HAVE_WEBP = True -except: - HAVE_WEBP = False - class TestFeatures(PillowTestCase): - def test_check(self): - # Check the correctness of the convenience function - for module in features.modules: - self.assertEqual(features.check_module(module), - features.check(module)) - for codec in features.codecs: - self.assertEqual(features.check_codec(codec), - features.check(codec)) - for feature in features.features: - self.assertEqual(features.check_feature(feature), - features.check(feature)) - - @unittest.skipUnless(HAVE_WEBP, True) - def check_webp_transparency(self): - self.assertEqual(features.check('transp_webp'), - not _webp.WebPDecoderBuggyAlpha()) - self.assertEqual(features.check('transp_webp'), - _webp.HAVE_TRANSPARENCY) - - @unittest.skipUnless(HAVE_WEBP, True) - def check_webp_mux(self): - self.assertEqual(features.check('webp_mux'), - _webp.HAVE_WEBPMUX) - - def test_check_modules(self): + def test_check_features(self): for feature in features.modules: - self.assertIn(features.check_module(feature), [True, False]) + self.assertTrue( + features.check_module(feature) in [True, False, None]) for feature in features.codecs: - self.assertIn(features.check_codec(feature), [True, False]) + self.assertTrue(features.check_codec(feature) in [True, False]) - def test_supported_modules(self): + def test_supported_features(self): self.assertIsInstance(features.get_supported_modules(), list) self.assertIsInstance(features.get_supported_codecs(), list) - self.assertIsInstance(features.get_supported_features(), list) - self.assertIsInstance(features.get_supported(), list) def test_unsupported_codec(self): # Arrange diff -Nru pillow-4.2.1/Tests/test_file_cur.py pillow-4.1.1/Tests/test_file_cur.py --- pillow-4.2.1/Tests/test_file_cur.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_cur.py 2016-10-18 19:11:47.000000000 +0000 @@ -26,8 +26,8 @@ no_cursors_file = "Tests/images/no_cursors.cur" cur = CurImagePlugin.CurImageFile(TEST_FILE) - with open(no_cursors_file, "rb") as cur.fp: - self.assertRaises(TypeError, cur._open) + cur.fp = open(no_cursors_file, "rb") + self.assertRaises(TypeError, cur._open) if __name__ == '__main__': diff -Nru pillow-4.2.1/Tests/test_file_dcx.py pillow-4.1.1/Tests/test_file_dcx.py --- pillow-4.2.1/Tests/test_file_dcx.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_dcx.py 2016-10-18 19:11:47.000000000 +0000 @@ -50,7 +50,7 @@ im.seek(n_frames) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) def test_seek_too_far(self): # Arrange diff -Nru pillow-4.2.1/Tests/test_file_fli.py pillow-4.1.1/Tests/test_file_fli.py --- pillow-4.2.1/Tests/test_file_fli.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_fli.py 2017-01-02 11:47:11.000000000 +0000 @@ -2,6 +2,7 @@ from PIL import Image, FliImagePlugin +# sample ppm stream # created as an export of a palette image from Gimp2.6 # save as...-> hopper.fli, default options. test_file = "Tests/images/hopper.fli" @@ -37,7 +38,7 @@ im.seek(n_frames) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) if __name__ == '__main__': diff -Nru pillow-4.2.1/Tests/test_file_gif.py pillow-4.1.1/Tests/test_file_gif.py --- pillow-4.2.1/Tests/test_file_gif.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_gif.py 2017-04-04 18:14:25.000000000 +0000 @@ -58,20 +58,21 @@ # Check for correctness after conversion back to RGB def check(colors, size, expected_palette_length): # make an image with empty colors in the start of the palette range - im = Image.frombytes('P', (colors, colors), - bytes(bytearray(range(256-colors, 256))*colors)) - im = im.resize((size, size)) + im = Image.frombytes('P', (colors,colors), + bytes(bytearray(range(256-colors,256))*colors)) + im = im.resize((size,size)) outfile = BytesIO() im.save(outfile, 'GIF') outfile.seek(0) reloaded = Image.open(outfile) # check palette length - palette_length = max(i+1 for i, v in enumerate(reloaded.histogram()) if v) + palette_length = max(i+1 for i,v in enumerate(reloaded.histogram()) if v) self.assertEqual(expected_palette_length, palette_length) self.assert_image_equal(im.convert('RGB'), reloaded.convert('RGB')) + # These do optimize the palette check(128, 511, 128) check(64, 511, 64) @@ -226,7 +227,7 @@ im.seek(n_frames) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) def test_dispose_none(self): img = Image.open("Tests/images/dispose_none.gif") @@ -283,7 +284,7 @@ Image.new('L', (100, 100), '#222') ] - # duration as list + #duration as list im_list[0].save( out, save_all=True, @@ -326,7 +327,7 @@ Image.new('L', (100, 100), '#111') ] - # duration as list + #duration as list im_list[0].save( out, save_all=True, @@ -427,10 +428,10 @@ from PIL import ImagePalette - data = bytes(bytearray(range(1, 254))) + data = bytes(bytearray(range(1,254))) palette = ImagePalette.ImagePalette("RGB", list(range(256))*3) - im = Image.new('L', (253, 1)) + im = Image.new('L', (253,1)) im.frombytes(data) im.putpalette(palette) @@ -443,8 +444,8 @@ def test_bbox(self): out = self.tempfile('temp.gif') - im = Image.new('RGB', (100, 100), '#fff') - ims = [Image.new("RGB", (100, 100), '#000')] + im = Image.new('RGB', (100,100), '#fff') + ims = [Image.new("RGB", (100,100), '#000')] im.save(out, save_all=True, append_images=ims) reread = Image.open(out) @@ -452,7 +453,7 @@ def test_palette_save_L(self): # generate an L mode image with a separate palette - + im = hopper('P') im_l = Image.frombytes('L', im.size, im.tobytes()) palette = bytes(bytearray(im.getpalette())) @@ -463,7 +464,7 @@ reloaded = Image.open(out) self.assert_image_equal(reloaded.convert('RGB'), im.convert('RGB')) - + def test_palette_save_P(self): # pass in a different palette, then construct what the image # would look like. @@ -510,7 +511,7 @@ im = Image._wedge().resize((16, 16)) im.putpalette(ImagePalette.ImagePalette('RGB')) im.info = {'background': 0} - + passed_palette = bytes(bytearray([255-i//3 for i in range(768)])) GifImagePlugin._FORCE_OPTIMIZE = True @@ -520,16 +521,19 @@ import pickle # Enable to get target values on pre-refactor version - # with open('Tests/images/gif_header_data.pkl', 'wb') as f: + #with open('Tests/images/gif_header_data.pkl', 'wb') as f: # pickle.dump((h, d), f, 1) with open('Tests/images/gif_header_data.pkl', 'rb') as f: (h_target, d_target) = pickle.load(f) - + self.assertEqual(h, h_target) self.assertEqual(d, d_target) finally: GifImagePlugin._FORCE_OPTIMIZE = False + + + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_ico.py pillow-4.1.1/Tests/test_file_ico.py --- pillow-4.2.1/Tests/test_file_ico.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_ico.py 2017-01-02 11:47:11.000000000 +0000 @@ -3,6 +3,7 @@ import io from PIL import Image, IcoImagePlugin +# sample ppm stream TEST_ICO_FILE = "Tests/images/hopper.ico" diff -Nru pillow-4.2.1/Tests/test_file_im.py pillow-4.1.1/Tests/test_file_im.py --- pillow-4.2.1/Tests/test_file_im.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_im.py 2016-10-18 19:11:47.000000000 +0000 @@ -30,7 +30,7 @@ im.seek(n_frames) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) def test_roundtrip(self): out = self.tempfile('temp.im') diff -Nru pillow-4.2.1/Tests/test_file_jpeg.py pillow-4.1.1/Tests/test_file_jpeg.py --- pillow-4.2.1/Tests/test_file_jpeg.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_jpeg.py 2017-04-28 16:48:58.000000000 +0000 @@ -93,7 +93,7 @@ self.assertEqual(test(72), (72, 72)) self.assertEqual(test(300), (300, 300)) self.assertEqual(test(100, 200), (100, 200)) - self.assertIsNone(test(0)) # square pixels + self.assertEqual(test(0), None) # square pixels def test_icc(self): # Test ICC support @@ -133,19 +133,6 @@ test(ImageFile.MAXBLOCK+1) # full buffer block plus one byte test(ImageFile.MAXBLOCK*4+3) # large block - def test_large_icc_meta(self): - # https://github.com/python-pillow/Pillow/issues/148 - # Sometimes the meta data on the icc_profile block is bigger than - # Image.MAXBLOCK or the image size. - im = Image.open('Tests/images/icc_profile_big.jpg') - f = self.tempfile("temp.jpg") - icc_profile = im.info["icc_profile"] - try: - im.save(f, format='JPEG', progressive=True,quality=95, - icc_profile=icc_profile, optimize=True) - except IOError: - self.fail("Failed saving image with icc larger than image size") - def test_optimize(self): im1 = self.roundtrip(hopper()) im2 = self.roundtrip(hopper(), optimize=0) @@ -452,7 +439,7 @@ def test_no_duplicate_0x1001_tag(self): # Arrange from PIL import ExifTags - tag_ids = {v: k for k, v in ExifTags.TAGS.items()} + tag_ids = dict(zip(ExifTags.TAGS.values(), ExifTags.TAGS.keys())) # Assert self.assertEqual(tag_ids['RelatedImageWidth'], 0x1001) @@ -489,12 +476,18 @@ img.save(out, "JPEG") def test_save_wrong_modes(self): - # ref https://github.com/python-pillow/Pillow/issues/2005 out = BytesIO() - for mode in ['LA', 'La', 'RGBA', 'RGBa', 'P']: + for mode in ['LA', 'La', 'RGBa', 'P']: img = Image.new(mode, (20, 20)) self.assertRaises(IOError, img.save, out, "JPEG") + def test_save_modes_with_warnings(self): + # ref https://github.com/python-pillow/Pillow/issues/2005 + out = BytesIO() + for mode in ['RGBA']: + img = Image.new(mode, (20, 20)) + self.assert_warning(DeprecationWarning, img.save, out, "JPEG") + def test_save_tiff_with_dpi(self): # Arrange outfile = self.tempfile("temp.tif") diff -Nru pillow-4.2.1/Tests/test_file_libtiff.py pillow-4.1.1/Tests/test_file_libtiff.py --- pillow-4.2.1/Tests/test_file_libtiff.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_libtiff.py 2017-04-04 18:14:25.000000000 +0000 @@ -42,7 +42,6 @@ out_bytes = io.BytesIO() im.save(out_bytes, format='tiff', compression='group4') - class TestFileLibTiff(LibTiffTestCase): def test_g4_tiff(self): @@ -173,7 +172,8 @@ 'RowsPerStrip', 'StripOffsets'] for field in requested_fields: - self.assertIn(field, reloaded, "%s not in metadata" % field) + self.assertTrue(field in reloaded, + "%s not in metadata" % field) def test_additional_metadata(self): # these should not crash. Seriously dummy data, most of it doesn't make @@ -189,7 +189,7 @@ # Exclude ones that have special meaning # that we're already testing them im = Image.open('Tests/images/hopper_g4.tif') - for tag in im.tag_v2: + for tag in im.tag_v2.keys(): try: del(core_items[tag]) except: @@ -532,7 +532,7 @@ count = im.n_frames im.close() try: - os.remove(tmpfile) # Windows PermissionError here! + os.remove(tmpfile) # Windows PermissionError here! except: self.fail("Should not get permission error here") diff -Nru pillow-4.2.1/Tests/test_file_mcidas.py pillow-4.1.1/Tests/test_file_mcidas.py --- pillow-4.2.1/Tests/test_file_mcidas.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_mcidas.py 2016-10-18 19:11:47.000000000 +0000 @@ -1,6 +1,6 @@ from helper import unittest, PillowTestCase -from PIL import Image, McIdasImagePlugin +from PIL import McIdasImagePlugin class TestFileMcIdas(PillowTestCase): @@ -12,24 +12,6 @@ lambda: McIdasImagePlugin.McIdasImageFile(invalid_file)) - def test_valid_file(self): - # Arrange - # https://ghrc.nsstc.nasa.gov/hydro/details/cmx3g8 - # https://ghrc.nsstc.nasa.gov/pub/fieldCampaigns/camex3/cmx3g8/browse/ - test_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.ara" - saved_file = "Tests/images/cmx3g8_wv_1998.260_0745_mcidas.png" - - # Act - im = Image.open(test_file) - im.load() - - # Assert - self.assertEqual(im.format, "MCIDAS") - self.assertEqual(im.mode, "I") - self.assertEqual(im.size, (1800, 400)) - im2 = Image.open(saved_file) - self.assert_image_equal(im, im2) - if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_mic.py pillow-4.1.1/Tests/test_file_mic.py --- pillow-4.2.1/Tests/test_file_mic.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_mic.py 2016-10-18 19:11:47.000000000 +0000 @@ -1,50 +1,10 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase -from PIL import Image, ImagePalette, MicImagePlugin - -TEST_FILE = "Tests/images/hopper.mic" +from PIL import MicImagePlugin class TestFileMic(PillowTestCase): - def test_sanity(self): - im = Image.open(TEST_FILE) - im.load() - self.assertEqual(im.mode, "RGBA") - self.assertEqual(im.size, (128, 128)) - self.assertEqual(im.format, "MIC") - - # Adjust for the gamma of 2.2 encoded into the file - lut = ImagePalette.make_gamma_lut(1/2.2) - im = Image.merge('RGBA', [chan.point(lut) for chan in im.split()]) - - im2 = hopper("RGBA") - self.assert_image_similar(im, im2, 10) - - def test_n_frames(self): - im = Image.open(TEST_FILE) - - self.assertEqual(im.n_frames, 1) - - def test_is_animated(self): - im = Image.open(TEST_FILE) - - self.assertFalse(im.is_animated) - - def test_tell(self): - im = Image.open(TEST_FILE) - - self.assertEqual(im.tell(), 0) - - def test_seek(self): - im = Image.open(TEST_FILE) - - im.seek(0) - self.assertEqual(im.tell(), 0) - - self.assertRaises(EOFError, lambda: im.seek(99)) - self.assertEqual(im.tell(), 0) - def test_invalid_file(self): # Test an invalid OLE file invalid_file = "Tests/images/flower.jpg" diff -Nru pillow-4.2.1/Tests/test_file_mpo.py pillow-4.1.1/Tests/test_file_mpo.py --- pillow-4.2.1/Tests/test_file_mpo.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_mpo.py 2016-10-18 19:11:47.000000000 +0000 @@ -110,7 +110,7 @@ im.seek(n_frames) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) def test_image_grab(self): for test_file in test_files: diff -Nru pillow-4.2.1/Tests/test_file_msp.py pillow-4.1.1/Tests/test_file_msp.py --- pillow-4.2.1/Tests/test_file_msp.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_msp.py 2017-04-04 18:14:25.000000000 +0000 @@ -59,17 +59,17 @@ if os.path.splitext(f)[1] == '.msp') for path in files: self._assert_file_image_equal(path, - path.replace('.msp', '.png')) + path.replace('.msp','.png')) @unittest.skipIf(not os.path.exists(YA_EXTRA_DIR), "Even More Extra image files not installed") def test_msp_v2(self): for f in os.listdir(YA_EXTRA_DIR): - if '.MSP' not in f: - continue + if not '.MSP' in f: continue path = os.path.join(YA_EXTRA_DIR, f) self._assert_file_image_equal(path, - path.replace('.MSP', '.png')) + path.replace('.MSP','.png')) + def test_cannot_save_wrong_mode(self): # Arrange diff -Nru pillow-4.2.1/Tests/test_file_pdf.py pillow-4.1.1/Tests/test_file_pdf.py --- pillow-4.2.1/Tests/test_file_pdf.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_pdf.py 2016-10-18 19:11:47.000000000 +0000 @@ -74,12 +74,6 @@ self.assertTrue(os.path.isfile(outfile)) self.assertGreater(os.path.getsize(outfile), 0) - # Append images - im.save(outfile, save_all=True, append_images=[hopper()]) - - self.assertTrue(os.path.isfile(outfile)) - self.assertGreater(os.path.getsize(outfile), 0) - if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_pixar.py pillow-4.1.1/Tests/test_file_pixar.py --- pillow-4.2.1/Tests/test_file_pixar.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_pixar.py 2017-04-04 18:14:25.000000000 +0000 @@ -2,10 +2,11 @@ from PIL import Image, PixarImagePlugin +# sample ppm stream TEST_FILE = "Tests/images/hopper.pxr" -class TestFilePixar(PillowTestCase): +class TestImagePsd(PillowTestCase): def test_sanity(self): im = Image.open(TEST_FILE) diff -Nru pillow-4.2.1/Tests/test_file_png.py pillow-4.1.1/Tests/test_file_png.py --- pillow-4.2.1/Tests/test_file_png.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_png.py 2017-04-04 18:14:25.000000000 +0000 @@ -1,16 +1,14 @@ from helper import unittest, PillowTestCase, hopper -from PIL import Image, ImageFile, PngImagePlugin from io import BytesIO + +from PIL import Image +from PIL import ImageFile +from PIL import PngImagePlugin import zlib -import sys codecs = dir(Image.core) -# For Truncated phng memory leak -MEM_LIMIT = 2 # max increase in MB -ITERATIONS = 100 # Leak is 56k/iteration, this will leak 5.6megs - # sample png stream TEST_PNG_FILE = "Tests/images/hopper.png" @@ -318,7 +316,7 @@ test_file = f.read()[:offset] im = Image.open(BytesIO(test_file)) - self.assertIsNotNone(im.fp) + self.assertTrue(im.fp is not None) self.assertRaises((IOError, SyntaxError), im.verify) def test_verify_ignores_crc_error(self): @@ -333,7 +331,7 @@ ImageFile.LOAD_TRUNCATED_IMAGES = True try: im = load(image_data) - self.assertIsNotNone(im) + self.assertTrue(im is not None) finally: ImageFile.LOAD_TRUNCATED_IMAGES = False @@ -464,7 +462,7 @@ def test_save_icc_profile(self): im = Image.open("Tests/images/icc_profile_none.png") - self.assertIsNone(im.info['icc_profile']) + self.assertEqual(im.info['icc_profile'], None) with_icc = Image.open("Tests/images/icc_profile.png") expected_icc = with_icc.info['icc_profile'] @@ -487,7 +485,7 @@ def test_roundtrip_no_icc_profile(self): im = Image.open("Tests/images/icc_profile_none.png") - self.assertIsNone(im.info['icc_profile']) + self.assertEqual(im.info['icc_profile'], None) im = roundtrip(im) self.assertNotIn('icc_profile', im.info) @@ -532,44 +530,5 @@ self.assertLess(chunks.index(b"pHYs"), chunks.index(b"IDAT")) -@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or MacOS") -class TestTruncatedPngPLeaks(PillowTestCase): - - def setUp(self): - if "zip_encoder" not in codecs or "zip_decoder" not in codecs: - self.skipTest("zip/deflate support not available") - - def _get_mem_usage(self): - from resource import getpagesize, getrusage, RUSAGE_SELF - mem = getrusage(RUSAGE_SELF).ru_maxrss - if sys.platform == 'darwin': - # man 2 getrusage: - # ru_maxrss the maximum resident set size utilized (in bytes). - return mem / 1024 / 1024 # megs - else: - # linux - # man 2 getrusage - # ru_maxrss (since Linux 2.6.32) - # This is the maximum resident set size used (in kilobytes). - return mem / 1024 # megs - - def test_leak_load(self): - with open('Tests/images/hopper.png', 'rb') as f: - DATA = BytesIO(f.read(16 * 1024)) - - ImageFile.LOAD_TRUNCATED_IMAGES = True - with Image.open(DATA) as im: - im.load() - start_mem = self._get_mem_usage() - try: - for _ in range(ITERATIONS): - with Image.open(DATA) as im: - im.load() - mem = (self._get_mem_usage() - start_mem) - self.assertLess(mem, MEM_LIMIT, msg='memory usage limit exceeded') - finally: - ImageFile.LOAD_TRUNCATED_IMAGES = False - - if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_ppm.py pillow-4.1.1/Tests/test_file_ppm.py --- pillow-4.2.1/Tests/test_file_ppm.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_ppm.py 2017-04-04 18:14:25.000000000 +0000 @@ -41,6 +41,7 @@ self.assertRaises(ValueError, lambda: Image.open(path)) + def test_neg_ppm(self): # Storage.c accepted negative values for xsize, ysize. the # internal open_ppm function didn't check for sanity but it diff -Nru pillow-4.2.1/Tests/test_file_psd.py pillow-4.1.1/Tests/test_file_psd.py --- pillow-4.2.1/Tests/test_file_psd.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_psd.py 2017-04-04 18:14:25.000000000 +0000 @@ -2,6 +2,7 @@ from PIL import Image, PsdImagePlugin +# sample ppm stream test_file = "Tests/images/hopper.psd" @@ -43,7 +44,7 @@ im.seek(n_frames+1) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) def test_seek_tell(self): im = Image.open(test_file) diff -Nru pillow-4.2.1/Tests/test_file_sgi.py pillow-4.1.1/Tests/test_file_sgi.py --- pillow-4.2.1/Tests/test_file_sgi.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_sgi.py 2017-01-02 11:47:11.000000000 +0000 @@ -25,7 +25,7 @@ # Created with ImageMagick: # convert transparent.png -compress None transparent.sgi test_file = "Tests/images/transparent.sgi" - + im = Image.open(test_file) target = Image.open('Tests/images/transparent.png') self.assert_image_equal(im, target) @@ -56,5 +56,6 @@ roundtrip(hopper(mode)) + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_spider.py pillow-4.1.1/Tests/test_file_spider.py --- pillow-4.2.1/Tests/test_file_spider.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_spider.py 2016-10-18 19:11:47.000000000 +0000 @@ -69,7 +69,7 @@ img_list = SpiderImagePlugin.loadImageSeries(file_list) # Assert - self.assertIsNone(img_list) + self.assertEqual(img_list, None) def test_isInt_not_a_number(self): # Arrange diff -Nru pillow-4.2.1/Tests/test_file_sun.py pillow-4.1.1/Tests/test_file_sun.py --- pillow-4.2.1/Tests/test_file_sun.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_sun.py 2017-01-02 11:47:11.000000000 +0000 @@ -6,7 +6,6 @@ EXTRA_DIR = 'Tests/images/sunraster' - class TestFileSun(PillowTestCase): def test_sanity(self): @@ -20,8 +19,8 @@ # Assert self.assertEqual(im.size, (128, 128)) - self.assert_image_similar(im, hopper(), 5) # visually verified - + self.assert_image_similar(im, hopper(), 5) # visually verified + invalid_file = "Tests/images/flower.jpg" self.assertRaises(SyntaxError, lambda: SunImagePlugin.SunImageFile(invalid_file)) @@ -31,20 +30,21 @@ target = Image.open('Tests/images/sunraster.im1.png') self.assert_image_equal(im, target) + @unittest.skipIf(not os.path.exists(EXTRA_DIR), "Extra image files not installed") def test_others(self): files = (os.path.join(EXTRA_DIR, f) for f in - os.listdir(EXTRA_DIR) if os.path.splitext(f)[1] - in ('.sun', '.SUN', '.ras')) + os.listdir(EXTRA_DIR) if os.path.splitext(f)[1] + in ('.sun', '.SUN', '.ras')) for path in files: with Image.open(path) as im: - im.load() + im.load() self.assertIsInstance(im, SunImagePlugin.SunImageFile) target_path = "%s.png" % os.path.splitext(path)[0] - # im.save(target_file) + #im.save(target_file) with Image.open(target_path) as target: self.assert_image_equal(im, target) - + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_tiff.py pillow-4.1.1/Tests/test_file_tiff.py --- pillow-4.2.1/Tests/test_file_tiff.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_tiff.py 2017-04-04 18:14:25.000000000 +0000 @@ -6,7 +6,6 @@ from helper import unittest, PillowTestCase, hopper, py3 from PIL import Image, TiffImagePlugin -from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION, RESOLUTION_UNIT logger = logging.getLogger(__name__) @@ -78,6 +77,7 @@ self.assertEqual(im.mode, 'RGB') def test_xyres_tiff(self): + from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION filename = "Tests/images/pil168.tif" im = Image.open(filename) @@ -94,6 +94,7 @@ self.assertEqual(im.info['dpi'], (72., 72.)) def test_xyres_fallback_tiff(self): + from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION, RESOLUTION_UNIT filename = "Tests/images/compression.tif" im = Image.open(filename) @@ -111,6 +112,7 @@ self.assertEqual(im.info['dpi'], (100., 100.)) def test_int_resolution(self): + from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION filename = "Tests/images/pil168.tif" im = Image.open(filename) @@ -121,6 +123,7 @@ self.assertEqual(im.info['dpi'], (71., 71.)) def test_save_setting_missing_resolution(self): + from PIL.TiffImagePlugin import X_RESOLUTION, Y_RESOLUTION b = BytesIO() Image.open("Tests/images/10ct_32bit_128.tiff").save( b, format="tiff", resolution=123.45) @@ -234,7 +237,7 @@ im.seek(n_frames) break except EOFError: - self.assertLess(im.tell(), n_frames) + self.assertTrue(im.tell() < n_frames) def test_multipage(self): # issue #862 @@ -271,6 +274,16 @@ # Assert self.assertIsInstance(ret, str) + def test_as_dict_deprecation(self): + # Arrange + filename = "Tests/images/pil136.tiff" + im = Image.open(filename) + + self.assert_warning(DeprecationWarning, im.tag_v2.as_dict) + self.assert_warning(DeprecationWarning, im.tag.as_dict) + self.assertEqual(dict(im.tag_v2), im.tag_v2.as_dict()) + self.assertEqual(dict(im.tag), im.tag.as_dict()) + def test_dict(self): # Arrange filename = "Tests/images/pil136.tiff" @@ -441,23 +454,11 @@ with Image.open(mp) as im: self.assertEqual(im.n_frames, 3) - # Test appending images - mp = io.BytesIO() - im = Image.new('RGB', (100, 100), '#f00') - ims = [Image.new('RGB', (100, 100), color) for color - in ['#0f0', '#00f']] - im.save(mp, format="TIFF", save_all=True, append_images=ims) - - mp.seek(0, os.SEEK_SET) - reread = Image.open(mp) - self.assertEqual(reread.n_frames, 3) - - def test_saving_icc_profile(self): # Tests saving TIFF with icc_profile set. # At the time of writing this will only work for non-compressed tiffs - # as libtiff does not support embedded ICC profiles, - # ImageFile._save(..) however does. + # as libtiff does not support embedded ICC profiles, ImageFile._save(..) + # however does. im = Image.new('RGB', (1, 1)) im.info['icc_profile'] = 'Dummy value' @@ -483,7 +484,7 @@ def test_close_on_load_nonexclusive(self): tmpfile = self.tempfile("temp.tif") - + with Image.open("Tests/images/uint16_1_4660.tif") as im: im.save(tmpfile) @@ -494,13 +495,15 @@ im.load() self.assertFalse(fp.closed) + + @unittest.skipUnless(sys.platform.startswith('win32'), "Windows only") class TestFileTiffW32(PillowTestCase): def test_fd_leak(self): tmpfile = self.tempfile("temp.tif") import os - # this is an mmaped file. + # this is an mmaped file. with Image.open("Tests/images/uint16_1_4660.tif") as im: im.save(tmpfile) @@ -513,11 +516,10 @@ # this closes the mmap im.close() - + # this should not fail, as load should have closed the file pointer, # and close should have closed the mmap os.remove(tmpfile) - if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_webp_metadata.py pillow-4.1.1/Tests/test_file_webp_metadata.py --- pillow-4.2.1/Tests/test_file_webp_metadata.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_webp_metadata.py 2016-10-18 19:11:47.000000000 +0000 @@ -96,7 +96,7 @@ file_path = "Tests/images/flower.jpg" image = Image.open(file_path) - self.assertIn('exif', image.info) + self.assertTrue('exif' in image.info) test_buffer = BytesIO() diff -Nru pillow-4.2.1/Tests/test_file_webp.py pillow-4.1.1/Tests/test_file_webp.py --- pillow-4.2.1/Tests/test_file_webp.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_webp.py 2016-10-18 19:11:47.000000000 +0000 @@ -77,11 +77,6 @@ self.assertRaises(IOError, lambda: hopper("L").save(temp_file)) - def test_WebPEncode_with_invalid_args(self): - self.assertRaises(TypeError, _webp.WebPEncode) - - def test_WebPDecode_with_invalid_args(self): - self.assertRaises(TypeError, _webp.WebPDecode) if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_file_wmf.py pillow-4.1.1/Tests/test_file_wmf.py --- pillow-4.2.1/Tests/test_file_wmf.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_wmf.py 2017-04-04 18:14:25.000000000 +0000 @@ -1,7 +1,6 @@ from helper import unittest, PillowTestCase, hopper from PIL import Image - class TestFileWmf(PillowTestCase): def test_load_raw(self): diff -Nru pillow-4.2.1/Tests/test_file_xpm.py pillow-4.1.1/Tests/test_file_xpm.py --- pillow-4.2.1/Tests/test_file_xpm.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_file_xpm.py 2016-10-18 19:11:47.000000000 +0000 @@ -2,6 +2,7 @@ from PIL import Image, XpmImagePlugin +# sample ppm stream TEST_FILE = "Tests/images/hopper.xpm" diff -Nru pillow-4.2.1/Tests/test_image_access.py pillow-4.1.1/Tests/test_image_access.py --- pillow-4.2.1/Tests/test_image_access.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_access.py 2017-04-04 18:14:25.000000000 +0000 @@ -97,6 +97,7 @@ with self.assertRaises(IndexError): im.getpixel((0, 0)) + def test_basic(self): for mode in ("1", "L", "LA", "I", "I;16", "I;16B", "F", "P", "PA", "RGB", "RGBA", "RGBX", "CMYK", "YCbCr"): diff -Nru pillow-4.2.1/Tests/test_imagecms.py pillow-4.1.1/Tests/test_imagecms.py --- pillow-4.2.1/Tests/test_imagecms.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagecms.py 2017-04-04 18:14:25.000000000 +0000 @@ -222,7 +222,7 @@ self.assertTrue(img_srgb.info['icc_profile']) profile = ImageCmsProfile(BytesIO(img_srgb.info['icc_profile'])) - self.assertIn('sRGB', ImageCms.getProfileDescription(profile)) + self.assertTrue('sRGB' in ImageCms.getProfileDescription(profile)) def test_lab_roundtrip(self): # check to see if we're at least internally consistent. @@ -275,12 +275,12 @@ assert_truncated_tuple_equal(p.blue_colorant, ((0.14306640625, 0.06060791015625, 0.7140960693359375), (0.1558847490315394, 0.06603820639433387, 0.06060791015625))) assert_truncated_tuple_equal(p.blue_primary, ((0.14306641366715667, 0.06060790921083026, 0.7140960805782015), (0.15588475410450106, 0.06603820408959558, 0.06060790921083026))) assert_truncated_tuple_equal(p.chromatic_adaptation, (((1.04791259765625, 0.0229339599609375, -0.050201416015625), (0.02960205078125, 0.9904632568359375, -0.0170745849609375), (-0.009246826171875, 0.0150604248046875, 0.7517852783203125)), ((1.0267159024652783, 0.022470062342089134, 0.0229339599609375), (0.02951378324103937, 0.9875098886387147, 0.9904632568359375), (-0.012205438066465256, 0.01987915407854985, 0.0150604248046875)))) - self.assertIsNone(p.chromaticity) + self.assertEqual(p.chromaticity, None) self.assertEqual(p.clut, {0: (False, False, True), 1: (False, False, True), 2: (False, False, True), 3: (False, False, True)}) self.assertEqual(p.color_space, 'RGB') - self.assertIsNone(p.colorant_table) - self.assertIsNone(p.colorant_table_out) - self.assertIsNone(p.colorimetric_intent) + self.assertEqual(p.colorant_table, None) + self.assertEqual(p.colorant_table_out, None) + self.assertEqual(p.colorimetric_intent, None) self.assertEqual(p.connection_space, 'XYZ ') self.assertEqual(p.copyright, 'Copyright International Color Consortium, 2009') self.assertEqual(p.creation_date, datetime.datetime(2009, 2, 27, 21, 36, 31)) @@ -292,17 +292,17 @@ self.assertEqual(p.header_model, '\x00\x00\x00\x00') self.assertEqual(p.icc_measurement_condition, {'backing': (0.0, 0.0, 0.0), 'flare': 0.0, 'geo': 'unknown', 'observer': 1, 'illuminant_type': 'D65'}) self.assertEqual(p.icc_version, 33554432) - self.assertIsNone(p.icc_viewing_condition) + self.assertEqual(p.icc_viewing_condition, None) self.assertEqual(p.intent_supported, {0: (True, True, True), 1: (True, True, True), 2: (True, True, True), 3: (True, True, True)}) - self.assertTrue(p.is_matrix_shaper) + self.assertEqual(p.is_matrix_shaper, True) self.assertEqual(p.luminance, ((0.0, 80.0, 0.0), (0.0, 1.0, 80.0))) - self.assertIsNone(p.manufacturer) + self.assertEqual(p.manufacturer, None) assert_truncated_tuple_equal(p.media_black_point, ((0.012054443359375, 0.0124969482421875, 0.01031494140625), (0.34573304157549234, 0.35842450765864337, 0.0124969482421875))) assert_truncated_tuple_equal(p.media_white_point, ((0.964202880859375, 1.0, 0.8249053955078125), (0.3457029219802284, 0.3585375327567059, 1.0))) assert_truncated_tuple_equal((p.media_white_point_temperature,), (5000.722328847392,)) self.assertEqual(p.model, 'IEC 61966-2-1 Default RGB Colour Space - sRGB') self.assertEqual(p.pcs, 'XYZ') - self.assertIsNone(p.perceptual_rendering_intent_gamut) + self.assertEqual(p.perceptual_rendering_intent_gamut, None) self.assertEqual(p.product_copyright, 'Copyright International Color Consortium, 2009') self.assertEqual(p.product_desc, 'sRGB IEC61966-2-1 black scaled') self.assertEqual(p.product_description, 'sRGB IEC61966-2-1 black scaled') @@ -313,9 +313,9 @@ assert_truncated_tuple_equal(p.red_colorant, ((0.436065673828125, 0.2224884033203125, 0.013916015625), (0.6484536316398539, 0.3308524880306778, 0.2224884033203125))) assert_truncated_tuple_equal(p.red_primary, ((0.43606566581047446, 0.22248840582960838, 0.013916015621759925), (0.6484536250319214, 0.3308524944738204, 0.22248840582960838))) self.assertEqual(p.rendering_intent, 0) - self.assertIsNone(p.saturation_rendering_intent_gamut) - self.assertIsNone(p.screening_description) - self.assertIsNone(p.target) + self.assertEqual(p.saturation_rendering_intent_gamut, None) + self.assertEqual(p.screening_description, None) + self.assertEqual(p.target, None) self.assertEqual(p.technology, 'CRT ') self.assertEqual(p.version, 2.0) self.assertEqual(p.viewing_condition, 'Reference Viewing Condition in IEC 61966-2-1') @@ -344,7 +344,7 @@ chans = [] bands = ImageMode.getmode(mode).bands for band_ndx in range(len(bands)): - channel_type = 'L' # 8-bit unorm + channel_type = 'L' # 8-bit unorm channel_pattern = hopper(channel_type) # paste pattern with varying offsets to avoid correlation diff -Nru pillow-4.2.1/Tests/test_imagecolor.py pillow-4.1.1/Tests/test_imagecolor.py --- pillow-4.2.1/Tests/test_imagecolor.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagecolor.py 2016-10-18 19:11:47.000000000 +0000 @@ -119,7 +119,7 @@ # look for rounding errors (based on code by Tim Hatch) def test_rounding_errors(self): - for color in ImageColor.colormap: + for color in list(ImageColor.colormap.keys()): expected = Image.new( "RGB", (1, 1), color).convert("L").getpixel((0, 0)) actual = ImageColor.getcolor(color, 'L') diff -Nru pillow-4.2.1/Tests/test_image_convert.py pillow-4.1.1/Tests/test_image_convert.py --- pillow-4.2.1/Tests/test_image_convert.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_convert.py 2017-04-04 18:14:25.000000000 +0000 @@ -187,6 +187,7 @@ else: self.assert_image_similar(converted_im, target.split()[0], 1) + matrix_convert('RGB') matrix_convert('L') diff -Nru pillow-4.2.1/Tests/test_image_copy.py pillow-4.1.1/Tests/test_image_copy.py --- pillow-4.2.1/Tests/test_image_copy.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_copy.py 2017-01-02 11:47:11.000000000 +0000 @@ -36,7 +36,7 @@ self.assertEqual(out.size, croppedSize) def test_copy_zero(self): - im = Image.new('RGB', (0, 0)) + im = Image.new('RGB', (0,0)) out = im.copy() self.assertEqual(out.mode, im.mode) self.assertEqual(out.size, im.size) diff -Nru pillow-4.2.1/Tests/test_image_crop.py pillow-4.1.1/Tests/test_image_crop.py --- pillow-4.2.1/Tests/test_image_crop.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_crop.py 2017-04-04 18:14:25.000000000 +0000 @@ -70,13 +70,13 @@ self.assertEqual(cropped.size, (3, 5)) def test_crop_crash(self): - # Image.crop crashes prepatch with an access violation - # apparently a use after free on windows, see - # https://github.com/python-pillow/Pillow/issues/1077 + #Image.crop crashes prepatch with an access violation + #apparently a use after free on windows, see + #https://github.com/python-pillow/Pillow/issues/1077 test_img = 'Tests/images/bmp/g/pal8-0.bmp' - extents = (1, 1, 10, 10) - # works prepatch + extents = (1,1,10,10) + #works prepatch img = Image.open(test_img) img2 = img.crop(extents) img2.load() @@ -104,5 +104,6 @@ self.assertEqual(cropped.getdata()[2], (0, 0, 0)) + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_imagedraw.py pillow-4.1.1/Tests/test_imagedraw.py --- pillow-4.2.1/Tests/test_imagedraw.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagedraw.py 2017-04-04 18:14:25.000000000 +0000 @@ -30,8 +30,6 @@ POINTS1 = [(10, 10), (20, 40), (30, 30)] POINTS2 = [10, 10, 20, 40, 30, 30] -KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)] - class TestImageDraw(PillowTestCase): @@ -80,37 +78,6 @@ self.helper_arc(BBOX2, 0, 180) self.helper_arc(BBOX2, 0.5, 180.4) - def test_arc_end_le_start(self): - # Arrange - im = Image.new("RGB", (W, H)) - draw = ImageDraw.Draw(im) - start = 270.5 - end = 0 - - # Act - draw.arc(BBOX1, start=start, end=end) - del draw - - # Assert - self.assert_image_equal( - im, Image.open("Tests/images/imagedraw_arc_end_le_start.png")) - - def test_arc_no_loops(self): - # No need to go in loops - # Arrange - im = Image.new("RGB", (W, H)) - draw = ImageDraw.Draw(im) - start = 5 - end = 370 - - # Act - draw.arc(BBOX1, start=start, end=end) - del draw - - # Assert - self.assert_image_similar( - im, Image.open("Tests/images/imagedraw_arc_no_loops.png"), 1) - def test_bitmap(self): # Arrange small = Image.open("Tests/images/pil123rgba.png").resize((50, 50)) @@ -125,49 +92,45 @@ self.assert_image_equal( im, Image.open("Tests/images/imagedraw_bitmap.png")) - def helper_chord(self, mode, bbox, start, end): + def helper_chord(self, bbox, start, end): # Arrange - im = Image.new(mode, (W, H)) + im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) - expected = "Tests/images/imagedraw_chord_{}.png".format(mode) # Act draw.chord(bbox, start, end, fill="red", outline="yellow") del draw # Assert - self.assert_image_similar(im, Image.open(expected), 1) + self.assert_image_similar( + im, Image.open("Tests/images/imagedraw_chord.png"), 1) def test_chord1(self): - for mode in ["RGB", "L"]: - self.helper_chord(mode, BBOX1, 0, 180) - self.helper_chord(mode, BBOX1, 0.5, 180.4) + self.helper_chord(BBOX1, 0, 180) + self.helper_chord(BBOX1, 0.5, 180.4) def test_chord2(self): - for mode in ["RGB", "L"]: - self.helper_chord(mode, BBOX2, 0, 180) - self.helper_chord(mode, BBOX2, 0.5, 180.4) + self.helper_chord(BBOX2, 0, 180) + self.helper_chord(BBOX2, 0.5, 180.4) - def helper_ellipse(self, mode, bbox): + def helper_ellipse(self, bbox): # Arrange - im = Image.new(mode, (W, H)) + im = Image.new("RGB", (W, H)) draw = ImageDraw.Draw(im) - expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode) # Act draw.ellipse(bbox, fill="green", outline="blue") del draw # Assert - self.assert_image_similar(im, Image.open(expected), 1) + self.assert_image_similar( + im, Image.open("Tests/images/imagedraw_ellipse.png"), 1) def test_ellipse1(self): - for mode in ["RGB", "L"]: - self.helper_ellipse(mode, BBOX1) + self.helper_ellipse(BBOX1) def test_ellipse2(self): - for mode in ["RGB", "L"]: - self.helper_ellipse(mode, BBOX2) + self.helper_ellipse(BBOX2) def test_ellipse_edge(self): # Arrange @@ -304,23 +267,6 @@ def test_polygon2(self): self.helper_polygon(POINTS2) - def test_polygon_kite(self): - # Test drawing lines of different gradients (dx>dy, dy>dx) and - # vertical (dx==0) and horizontal (dy==0) lines - for mode in ["RGB", "L"]: - # Arrange - im = Image.new(mode, (W, H)) - draw = ImageDraw.Draw(im) - expected = "Tests/images/imagedraw_polygon_kite_{}.png".format( - mode) - - # Act - draw.polygon(KITE_POINTS, fill="blue", outline="yellow") - del draw - - # Assert - self.assert_image_equal(im, Image.open(expected)) - def helper_rectangle(self, bbox): # Arrange im = Image.new("RGB", (W, H)) @@ -340,21 +286,6 @@ def test_rectangle2(self): self.helper_rectangle(BBOX2) - def test_big_rectangle(self): - # Test drawing a rectangle bigger than the image - # Arrange - im = Image.new("RGB", (W, H)) - bbox = [(-1, -1), (W+1, H+1)] - draw = ImageDraw.Draw(im) - expected = "Tests/images/imagedraw_big_rectangle.png" - - # Act - draw.rectangle(bbox, fill="orange") - del draw - - # Assert - self.assert_image_similar(im, Image.open(expected), 1) - def test_floodfill(self): # Arrange im = Image.new("RGB", (W, H)) @@ -379,6 +310,7 @@ self.assert_image_equal(im, im_floodfill) del draw + @unittest.skipIf(hasattr(sys, 'pypy_version_info'), "Causes fatal RPython error on PyPy") def test_floodfill_border(self): @@ -400,26 +332,6 @@ self.assert_image_equal( im, Image.open("Tests/images/imagedraw_floodfill2.png")) - - def test_floodfill_thresh(self): - # floodfill() is experimental - - # Arrange - im = Image.new("RGB", (W, H)) - draw = ImageDraw.Draw(im) - draw.rectangle(BBOX2, outline="darkgreen", fill="green") - centre_point = (int(W/2), int(H/2)) - - # Act - ImageDraw.floodfill( - im, centre_point, ImageColor.getrgb("red"), - thresh=30) - del draw - - # Assert - self.assert_image_equal( - im, Image.open("Tests/images/imagedraw_floodfill2.png")) - def create_base_image_draw(self, size, mode=DEFAULT_MODE, background1=WHITE, @@ -567,21 +479,6 @@ self.assert_image_equal(img, expected, 'line oblique 45 inverted 3px wide B failed') - def test_wide_line_dot(self): - # Test drawing a wide "line" from one point to another just draws - # a single point - # Arrange - im = Image.new("RGB", (W, H)) - draw = ImageDraw.Draw(im) - expected = "Tests/images/imagedraw_wide_line_dot.png" - - # Act - draw.line([(50, 50), (50, 50)], width=3) - del draw - - # Assert - self.assert_image_similar(im, Image.open(expected), 1) - if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_imagefile.py pillow-4.1.1/Tests/test_imagefile.py --- pillow-4.2.1/Tests/test_imagefile.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagefile.py 2017-04-04 18:14:25.000000000 +0000 @@ -95,11 +95,6 @@ def test_raise_ioerror(self): self.assertRaises(IOError, lambda: ImageFile.raise_ioerror(1)) - def test_raise_typeerror(self): - with self.assertRaises(TypeError): - parser = ImageFile.Parser() - parser.feed(1) - def test_truncated_with_errors(self): if "zip_encoder" not in codecs: self.skipTest("PNG (zlib) encoder not available") @@ -143,12 +138,10 @@ class MockPyDecoder(ImageFile.PyDecoder): def decode(self, buffer): - # eof + #eof return (-1, 0) xoff, yoff, xsize, ysize = 10, 20, 100, 100 - - class MockImageFile(ImageFile.ImageFile): def _open(self): self.rawmode = 'RGBA' @@ -156,7 +149,6 @@ self.size = (200, 200) self.tile = [("MOCK", (xoff, yoff, xoff+xsize, yoff+ysize), 32, None)] - class TestPyDecoder(PillowTestCase): def get_decoder(self): diff -Nru pillow-4.2.1/Tests/test_imagefontctl.py pillow-4.1.1/Tests/test_imagefontctl.py --- pillow-4.2.1/Tests/test_imagefontctl.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagefontctl.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -# -*- coding: utf-8 -*- -from helper import unittest, PillowTestCase -from PIL import Image, ImageDraw, ImageFont, features - - -FONT_SIZE = 20 -FONT_PATH = "Tests/fonts/DejaVuSans.ttf" - -@unittest.skipUnless(features.check('raqm'), "Raqm Library is not installed.") -class TestImagecomplextext(PillowTestCase): - - def test_english(self): - #smoke test, this should not fail - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'TEST', font=ttf, fill=500, direction='ltr') - - - def test_complex_text(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'اهلا عمان', font=ttf, fill=500) - - target = 'Tests/images/test_text.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - def test_y_offset(self): - ttf = ImageFont.truetype("Tests/fonts/NotoNastaliqUrdu-Regular.ttf", FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'العالم العربي', font=ttf, fill=500) - - target = 'Tests/images/test_y_offset.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, 1.7) - - def test_complex_unicode_text(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'السلام عليكم', font=ttf, fill=500) - - target = 'Tests/images/test_complex_unicode_text.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - def test_text_direction_rtl(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'English عربي', font=ttf, fill=500, direction='rtl') - - target = 'Tests/images/test_direction_rtl.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - def test_text_direction_ltr(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'سلطنة عمان Oman', font=ttf, fill=500, direction='ltr') - - target = 'Tests/images/test_direction_ltr.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - def test_text_direction_rtl2(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'Oman سلطنة عمان', font=ttf, fill=500, direction='rtl') - - target = 'Tests/images/test_direction_ltr.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - def test_ligature_features(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'filling', font=ttf, fill=500, features=['-liga']) - target = 'Tests/images/test_ligature_features.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - liga_size = ttf.getsize('fi', features=['-liga']) - self.assertEqual(liga_size,(13,19)) - - def test_kerning_features(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'TeToAV', font=ttf, fill=500, features=['-kern']) - - target = 'Tests/images/test_kerning_features.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - - def test_arabictext_features(self): - ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), 'اللغة العربية', font=ttf, fill=500, features=['-fina','-init','-medi']) - - target = 'Tests/images/test_arabictext_features.png' - target_img = Image.open(target) - - self.assert_image_similar(im, target_img, .5) - -if __name__ == '__main__': - unittest.main() - -# End of file diff -Nru pillow-4.2.1/Tests/test_imagefont.py pillow-4.1.1/Tests/test_imagefont.py --- pillow-4.2.1/Tests/test_imagefont.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagefont.py 2017-01-02 11:47:11.000000000 +0000 @@ -1,6 +1,7 @@ from helper import unittest, PillowTestCase -from PIL import Image, ImageDraw, ImageFont, features +from PIL import Image +from PIL import ImageDraw from io import BytesIO import os import sys @@ -11,485 +12,466 @@ TEST_TEXT = "hey you\nyou are awesome\nthis looks awkward" -HAS_FREETYPE = features.check('freetype2') -HAS_RAQM = features.check('raqm') - -class SimplePatcher(object): - def __init__(self, parent_obj, attr_name, value): - self._parent_obj = parent_obj - self._attr_name = attr_name - self._saved = None - self._is_saved = False - self._value = value - - def __enter__(self): - # Patch the attr on the object - if hasattr(self._parent_obj, self._attr_name): - self._saved = getattr(self._parent_obj, self._attr_name) - setattr(self._parent_obj, self._attr_name, self._value) - self._is_saved = True - else: - setattr(self._parent_obj, self._attr_name, self._value) +try: + from PIL import ImageFont + ImageFont.core.getfont # check if freetype is available + + class SimplePatcher(object): + def __init__(self, parent_obj, attr_name, value): + self._parent_obj = parent_obj + self._attr_name = attr_name + self._saved = None self._is_saved = False + self._value = value + + def __enter__(self): + # Patch the attr on the object + if hasattr(self._parent_obj, self._attr_name): + self._saved = getattr(self._parent_obj, self._attr_name) + setattr(self._parent_obj, self._attr_name, self._value) + self._is_saved = True + else: + setattr(self._parent_obj, self._attr_name, self._value) + self._is_saved = False + + def __exit__(self, type, value, traceback): + # Restore the original value + if self._is_saved: + setattr(self._parent_obj, self._attr_name, self._saved) + else: + delattr(self._parent_obj, self._attr_name) + + class TestImageFont(PillowTestCase): + + def test_sanity(self): + self.assertRegexpMatches( + ImageFont.core.freetype2_version, r"\d+\.\d+\.\d+$") + + def test_font_properties(self): + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + self.assertEqual(ttf.path, FONT_PATH) + self.assertEqual(ttf.size, FONT_SIZE) + + ttf_copy = ttf.font_variant() + self.assertEqual(ttf_copy.path, FONT_PATH) + self.assertEqual(ttf_copy.size, FONT_SIZE) + + ttf_copy = ttf.font_variant(size=FONT_SIZE+1) + self.assertEqual(ttf_copy.size, FONT_SIZE+1) + + second_font_path = "Tests/fonts/DejaVuSans.ttf" + ttf_copy = ttf.font_variant(font=second_font_path) + self.assertEqual(ttf_copy.path, second_font_path) + + def test_font_with_name(self): + ImageFont.truetype(FONT_PATH, FONT_SIZE) + self._render(FONT_PATH) + self._clean() + + def _font_as_bytes(self): + with open(FONT_PATH, 'rb') as f: + font_bytes = BytesIO(f.read()) + return font_bytes + + def test_font_with_filelike(self): + ImageFont.truetype(self._font_as_bytes(), FONT_SIZE) + self._render(self._font_as_bytes()) + # Usage note: making two fonts from the same buffer fails. + # shared_bytes = self._font_as_bytes() + # self._render(shared_bytes) + # self.assertRaises(Exception, lambda: _render(shared_bytes)) + self._clean() + + def test_font_with_open_file(self): + with open(FONT_PATH, 'rb') as f: + self._render(f) + self._clean() + + def _render(self, font): + txt = "Hello World!" + ttf = ImageFont.truetype(font, FONT_SIZE) + ttf.getsize(txt) + + img = Image.new("RGB", (256, 64), "white") + d = ImageDraw.Draw(img) + d.text((10, 10), txt, font=ttf, fill='black') + + img.save('font.png') + return img + + def _clean(self): + os.unlink('font.png') + + def test_render_equal(self): + img_path = self._render(FONT_PATH) + with open(FONT_PATH, 'rb') as f: + font_filelike = BytesIO(f.read()) + img_filelike = self._render(font_filelike) + + self.assert_image_equal(img_path, img_filelike) + self._clean() + + def test_textsize_equal(self): + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + txt = "Hello World!" + size = draw.textsize(txt, ttf) + draw.text((10, 10), txt, font=ttf) + draw.rectangle((10, 10, 10 + size[0], 10 + size[1])) + del draw + + target = 'Tests/images/rectangle_surrounding_text.png' + target_img = Image.open(target) + + # Epsilon ~.5 fails with FreeType 2.7 + self.assert_image_similar(im, target_img, 2.5) + + def test_render_multiline(self): + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + line_spacing = draw.textsize('A', font=ttf)[1] + 4 + lines = TEST_TEXT.split("\n") + y = 0 + for line in lines: + draw.text((0, y), line, font=ttf) + y += line_spacing + + target = 'Tests/images/multiline_text.png' + target_img = Image.open(target) + + # some versions of freetype have different horizontal spacing. + # setting a tight epsilon, I'm showing the original test failure + # at epsilon = ~38. + self.assert_image_similar(im, target_img, 6.2) + + def test_render_multiline_text(self): + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + # Test that text() correctly connects to multiline_text() + # and that align defaults to left + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + draw.text((0, 0), TEST_TEXT, font=ttf) + + target = 'Tests/images/multiline_text.png' + target_img = Image.open(target) + + # Epsilon ~.5 fails with FreeType 2.7 + self.assert_image_similar(im, target_img, 6.2) + + # Test that text() can pass on additional arguments + # to multiline_text() + draw.text((0, 0), TEST_TEXT, fill=None, font=ttf, anchor=None, + spacing=4, align="left") + draw.text((0, 0), TEST_TEXT, None, ttf, None, 4, "left") + del draw + + # Test align center and right + for align, ext in {"center": "_center", + "right": "_right"}.items(): + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + draw.multiline_text((0, 0), TEST_TEXT, font=ttf, align=align) + del draw + + target = 'Tests/images/multiline_text'+ext+'.png' + target_img = Image.open(target) + + # Epsilon ~.5 fails with FreeType 2.7 + self.assert_image_similar(im, target_img, 6.2) - def __exit__(self, type, value, traceback): - # Restore the original value - if self._is_saved: - setattr(self._parent_obj, self._attr_name, self._saved) - else: - delattr(self._parent_obj, self._attr_name) - -@unittest.skipUnless(HAS_FREETYPE, "ImageFont not Available") -class TestImageFont(PillowTestCase): - LAYOUT_ENGINE = ImageFont.LAYOUT_BASIC - - # Freetype has different metrics depending on the version. - # (and, other things, but first things first) - METRICS = { ('2', '3'): {'multiline': 30, - 'textsize': 12, - 'getters': (13, 16)}, - ('2', '7'): {'multiline': 6.2, - 'textsize': 2.5, - 'getters': (12, 16)}, - ('2', '8'): {'multiline': 6.2, - 'textsize': 2.5, - 'getters': (12, 16)}, - 'Default': {'multiline': 0.5, - 'textsize': 0.5, - 'getters': (12, 16)}, - } - - def setUp(self): - freetype_version = tuple(ImageFont.core.freetype2_version.split('.'))[:2] - self.metrics = self.METRICS.get(freetype_version, self.METRICS['Default']) - - def get_font(self): - return ImageFont.truetype(FONT_PATH, FONT_SIZE, - layout_engine=self.LAYOUT_ENGINE) - - def test_sanity(self): - self.assertRegexpMatches( - ImageFont.core.freetype2_version, r"\d+\.\d+\.\d+$") - - def test_font_properties(self): - ttf = self.get_font() - self.assertEqual(ttf.path, FONT_PATH) - self.assertEqual(ttf.size, FONT_SIZE) - - ttf_copy = ttf.font_variant() - self.assertEqual(ttf_copy.path, FONT_PATH) - self.assertEqual(ttf_copy.size, FONT_SIZE) - - ttf_copy = ttf.font_variant(size=FONT_SIZE+1) - self.assertEqual(ttf_copy.size, FONT_SIZE+1) - - second_font_path = "Tests/fonts/DejaVuSans.ttf" - ttf_copy = ttf.font_variant(font=second_font_path) - self.assertEqual(ttf_copy.path, second_font_path) - - def test_font_with_name(self): - self.get_font() - self._render(FONT_PATH) - - def _font_as_bytes(self): - with open(FONT_PATH, 'rb') as f: - font_bytes = BytesIO(f.read()) - return font_bytes - - def test_font_with_filelike(self): - ImageFont.truetype(self._font_as_bytes(), FONT_SIZE, - layout_engine=self.LAYOUT_ENGINE) - self._render(self._font_as_bytes()) - # Usage note: making two fonts from the same buffer fails. - # shared_bytes = self._font_as_bytes() - # self._render(shared_bytes) - # self.assertRaises(Exception, lambda: _render(shared_bytes)) - - def test_font_with_open_file(self): - with open(FONT_PATH, 'rb') as f: - self._render(f) - - def _render(self, font): - txt = "Hello World!" - ttf = ImageFont.truetype(font, FONT_SIZE, - layout_engine=self.LAYOUT_ENGINE) - ttf.getsize(txt) - - img = Image.new("RGB", (256, 64), "white") - d = ImageDraw.Draw(img) - d.text((10, 10), txt, font=ttf, fill='black') - - return img - - def test_render_equal(self): - img_path = self._render(FONT_PATH) - with open(FONT_PATH, 'rb') as f: - font_filelike = BytesIO(f.read()) - img_filelike = self._render(font_filelike) - - self.assert_image_equal(img_path, img_filelike) - - def test_textsize_equal(self): - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - ttf = self.get_font() - - txt = "Hello World!" - size = draw.textsize(txt, ttf) - draw.text((10, 10), txt, font=ttf) - draw.rectangle((10, 10, 10 + size[0], 10 + size[1])) - del draw - - target = 'Tests/images/rectangle_surrounding_text.png' - target_img = Image.open(target) - - # Epsilon ~.5 fails with FreeType 2.7 - self.assert_image_similar(im, target_img, self.metrics['textsize']) - - def test_render_multiline(self): - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - ttf = self.get_font() - line_spacing = draw.textsize('A', font=ttf)[1] + 4 - lines = TEST_TEXT.split("\n") - y = 0 - for line in lines: - draw.text((0, y), line, font=ttf) - y += line_spacing - - target = 'Tests/images/multiline_text.png' - target_img = Image.open(target) - - # some versions of freetype have different horizontal spacing. - # setting a tight epsilon, I'm showing the original test failure - # at epsilon = ~38. - self.assert_image_similar(im, target_img, self.metrics['multiline']) - - def test_render_multiline_text(self): - ttf = self.get_font() - - # Test that text() correctly connects to multiline_text() - # and that align defaults to left - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.text((0, 0), TEST_TEXT, font=ttf) - - target = 'Tests/images/multiline_text.png' - target_img = Image.open(target) - - # Epsilon ~.5 fails with FreeType 2.7 - self.assert_image_similar(im, target_img, self.metrics['multiline']) - - # Test that text() can pass on additional arguments - # to multiline_text() - draw.text((0, 0), TEST_TEXT, fill=None, font=ttf, anchor=None, - spacing=4, align="left") - draw.text((0, 0), TEST_TEXT, None, ttf, None, 4, "left") - del draw - - # Test align center and right - for align, ext in {"center": "_center", - "right": "_right"}.items(): + def test_unknown_align(self): im = Image.new(mode='RGB', size=(300, 100)) draw = ImageDraw.Draw(im) - draw.multiline_text((0, 0), TEST_TEXT, font=ttf, align=align) + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + # Act/Assert + self.assertRaises(AssertionError, + lambda: draw.multiline_text((0, 0), TEST_TEXT, + font=ttf, + align="unknown")) + + def test_multiline_size(self): + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + + # Test that textsize() correctly connects to multiline_textsize() + self.assertEqual(draw.textsize(TEST_TEXT, font=ttf), + draw.multiline_textsize(TEST_TEXT, font=ttf)) + + # Test that textsize() can pass on additional arguments + # to multiline_textsize() + draw.textsize(TEST_TEXT, font=ttf, spacing=4) + draw.textsize(TEST_TEXT, ttf, 4) + del draw + + def test_multiline_width(self): + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + + self.assertEqual(draw.textsize("longest line", font=ttf)[0], + draw.multiline_textsize("longest line\nline", + font=ttf)[0]) + del draw + + def test_multiline_spacing(self): + ttf = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + draw.multiline_text((0, 0), TEST_TEXT, font=ttf, spacing=10) del draw - target = 'Tests/images/multiline_text'+ext+'.png' + target = 'Tests/images/multiline_text_spacing.png' target_img = Image.open(target) # Epsilon ~.5 fails with FreeType 2.7 - self.assert_image_similar(im, target_img, self.metrics['multiline']) + self.assert_image_similar(im, target_img, 6.2) - def test_unknown_align(self): - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - ttf = self.get_font() - - # Act/Assert - self.assertRaises(AssertionError, - lambda: draw.multiline_text((0, 0), TEST_TEXT, - font=ttf, - align="unknown")) - - def test_multiline_size(self): - ttf = self.get_font() - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - - # Test that textsize() correctly connects to multiline_textsize() - self.assertEqual(draw.textsize(TEST_TEXT, font=ttf), - draw.multiline_textsize(TEST_TEXT, font=ttf)) - - # Test that textsize() can pass on additional arguments - # to multiline_textsize() - draw.textsize(TEST_TEXT, font=ttf, spacing=4) - draw.textsize(TEST_TEXT, ttf, 4) - del draw - - def test_multiline_width(self): - ttf = self.get_font() - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - - self.assertEqual(draw.textsize("longest line", font=ttf)[0], - draw.multiline_textsize("longest line\nline", - font=ttf)[0]) - del draw - - def test_multiline_spacing(self): - ttf = self.get_font() - - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - draw.multiline_text((0, 0), TEST_TEXT, font=ttf, spacing=10) - del draw - - target = 'Tests/images/multiline_text_spacing.png' - target_img = Image.open(target) - from PIL import ImageChops - - ImageChops.difference(im, target_img).save('multiline.png') - # Epsilon ~.5 fails with FreeType 2.7 - self.assert_image_similar(im, target_img, self.metrics['multiline']) - - def test_rotated_transposed_font(self): - img_grey = Image.new("L", (100, 100)) - draw = ImageDraw.Draw(img_grey) - word = "testing" - font = self.get_font() - - orientation = Image.ROTATE_90 - transposed_font = ImageFont.TransposedFont( - font, orientation=orientation) - - # Original font - draw.font = font - box_size_a = draw.textsize(word) - - # Rotated font - draw.font = transposed_font - box_size_b = draw.textsize(word) - del draw - - # Check (w,h) of box a is (h,w) of box b - self.assertEqual(box_size_a[0], box_size_b[1]) - self.assertEqual(box_size_a[1], box_size_b[0]) - - def test_unrotated_transposed_font(self): - img_grey = Image.new("L", (100, 100)) - draw = ImageDraw.Draw(img_grey) - word = "testing" - font = self.get_font() - - orientation = None - transposed_font = ImageFont.TransposedFont( - font, orientation=orientation) - - # Original font - draw.font = font - box_size_a = draw.textsize(word) - - # Rotated font - draw.font = transposed_font - box_size_b = draw.textsize(word) - del draw - - # Check boxes a and b are same size - self.assertEqual(box_size_a, box_size_b) - - def test_rotated_transposed_font_get_mask(self): - # Arrange - text = "mask this" - font = self.get_font() - orientation = Image.ROTATE_90 - transposed_font = ImageFont.TransposedFont( - font, orientation=orientation) - - # Act - mask = transposed_font.getmask(text) - - # Assert - self.assertEqual(mask.size, (13, 108)) - - def test_unrotated_transposed_font_get_mask(self): - # Arrange - text = "mask this" - font = self.get_font() - orientation = None - transposed_font = ImageFont.TransposedFont( - font, orientation=orientation) - - # Act - mask = transposed_font.getmask(text) - - # Assert - self.assertEqual(mask.size, (108, 13)) - - def test_free_type_font_get_name(self): - # Arrange - font = self.get_font() - - # Act - name = font.getname() - - # Assert - self.assertEqual(('FreeMono', 'Regular'), name) - - def test_free_type_font_get_metrics(self): - # Arrange - font = self.get_font() - - # Act - ascent, descent = font.getmetrics() - - # Assert - self.assertIsInstance(ascent, int) - self.assertIsInstance(descent, int) - self.assertEqual((ascent, descent), (16, 4)) # too exact check? - - def test_free_type_font_get_offset(self): - # Arrange - font = self.get_font() - text = "offset this" - - # Act - offset = font.getoffset(text) - - # Assert - self.assertEqual(offset, (0, 3)) - - def test_free_type_font_get_mask(self): - # Arrange - font = self.get_font() - text = "mask this" - - # Act - mask = font.getmask(text) - - # Assert - self.assertEqual(mask.size, (108, 13)) - - def test_load_path_not_found(self): - # Arrange - filename = "somefilenamethatdoesntexist.ttf" - - # Act/Assert - self.assertRaises(IOError, lambda: ImageFont.load_path(filename)) - - def test_default_font(self): - # Arrange - txt = 'This is a "better than nothing" default font.' - im = Image.new(mode='RGB', size=(300, 100)) - draw = ImageDraw.Draw(im) - - target = 'Tests/images/default_font.png' - target_img = Image.open(target) - - # Act - default_font = ImageFont.load_default() - draw.text((10, 10), txt, font=default_font) - del draw - - # Assert - self.assert_image_equal(im, target_img) - - def _test_fake_loading_font(self, path_to_fake, fontname): - # Make a copy of FreeTypeFont so we can patch the original - free_type_font = copy.deepcopy(ImageFont.FreeTypeFont) - with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font): - def loadable_font(filepath, size, index, encoding, *args, **kwargs): - if filepath == path_to_fake: - return ImageFont._FreeTypeFont(FONT_PATH, size, index, - encoding, *args, **kwargs) - return ImageFont._FreeTypeFont(filepath, size, index, - encoding, *args, **kwargs) - with SimplePatcher(ImageFont, 'FreeTypeFont', loadable_font): - font = ImageFont.truetype(fontname) - # Make sure it's loaded - name = font.getname() - self.assertEqual(('FreeMono', 'Regular'), name) - - @unittest.skipIf(sys.platform.startswith('win32'), - "requires Unix or MacOS") - def test_find_linux_font(self): - # A lot of mocking here - this is more for hitting code and - # catching syntax like errors - font_directory = '/usr/local/share/fonts' - with SimplePatcher(sys, 'platform', 'linux'): - patched_env = copy.deepcopy(os.environ) - patched_env['XDG_DATA_DIRS'] = '/usr/share/:/usr/local/share/' - with SimplePatcher(os, 'environ', patched_env): + def test_rotated_transposed_font(self): + img_grey = Image.new("L", (100, 100)) + draw = ImageDraw.Draw(img_grey) + word = "testing" + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + orientation = Image.ROTATE_90 + transposed_font = ImageFont.TransposedFont( + font, orientation=orientation) + + # Original font + draw.font = font + box_size_a = draw.textsize(word) + + # Rotated font + draw.font = transposed_font + box_size_b = draw.textsize(word) + del draw + + # Check (w,h) of box a is (h,w) of box b + self.assertEqual(box_size_a[0], box_size_b[1]) + self.assertEqual(box_size_a[1], box_size_b[0]) + + def test_unrotated_transposed_font(self): + img_grey = Image.new("L", (100, 100)) + draw = ImageDraw.Draw(img_grey) + word = "testing" + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + orientation = None + transposed_font = ImageFont.TransposedFont( + font, orientation=orientation) + + # Original font + draw.font = font + box_size_a = draw.textsize(word) + + # Rotated font + draw.font = transposed_font + box_size_b = draw.textsize(word) + del draw + + # Check boxes a and b are same size + self.assertEqual(box_size_a, box_size_b) + + def test_rotated_transposed_font_get_mask(self): + # Arrange + text = "mask this" + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + orientation = Image.ROTATE_90 + transposed_font = ImageFont.TransposedFont( + font, orientation=orientation) + + # Act + mask = transposed_font.getmask(text) + + # Assert + self.assertEqual(mask.size, (13, 108)) + + def test_unrotated_transposed_font_get_mask(self): + # Arrange + text = "mask this" + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + orientation = None + transposed_font = ImageFont.TransposedFont( + font, orientation=orientation) + + # Act + mask = transposed_font.getmask(text) + + # Assert + self.assertEqual(mask.size, (108, 13)) + + def test_free_type_font_get_name(self): + # Arrange + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + # Act + name = font.getname() + + # Assert + self.assertEqual(('FreeMono', 'Regular'), name) + + def test_free_type_font_get_metrics(self): + # Arrange + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + # Act + ascent, descent = font.getmetrics() + + # Assert + self.assertIsInstance(ascent, int) + self.assertIsInstance(descent, int) + self.assertEqual((ascent, descent), (16, 4)) # too exact check? + + def test_free_type_font_get_offset(self): + # Arrange + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + text = "offset this" + + # Act + offset = font.getoffset(text) + + # Assert + self.assertEqual(offset, (0, 3)) + + def test_free_type_font_get_mask(self): + # Arrange + font = ImageFont.truetype(FONT_PATH, FONT_SIZE) + text = "mask this" + + # Act + mask = font.getmask(text) + + # Assert + self.assertEqual(mask.size, (108, 13)) + + def test_load_path_not_found(self): + # Arrange + filename = "somefilenamethatdoesntexist.ttf" + + # Act/Assert + self.assertRaises(IOError, lambda: ImageFont.load_path(filename)) + + def test_default_font(self): + # Arrange + txt = 'This is a "better than nothing" default font.' + im = Image.new(mode='RGB', size=(300, 100)) + draw = ImageDraw.Draw(im) + + target = 'Tests/images/default_font.png' + target_img = Image.open(target) + + # Act + default_font = ImageFont.load_default() + draw.text((10, 10), txt, font=default_font) + del draw + + # Assert + self.assert_image_equal(im, target_img) + + def _test_fake_loading_font(self, path_to_fake, fontname): + # Make a copy of FreeTypeFont so we can patch the original + free_type_font = copy.deepcopy(ImageFont.FreeTypeFont) + with SimplePatcher(ImageFont, '_FreeTypeFont', free_type_font): + def loadable_font(filepath, size, index, encoding): + if filepath == path_to_fake: + return ImageFont._FreeTypeFont(FONT_PATH, size, index, + encoding) + return ImageFont._FreeTypeFont(filepath, size, index, + encoding) + with SimplePatcher(ImageFont, 'FreeTypeFont', loadable_font): + font = ImageFont.truetype(fontname) + # Make sure it's loaded + name = font.getname() + self.assertEqual(('FreeMono', 'Regular'), name) + + @unittest.skipIf(sys.platform.startswith('win32'), + "requires Unix or MacOS") + def test_find_linux_font(self): + # A lot of mocking here - this is more for hitting code and + # catching syntax like errors + font_directory = '/usr/local/share/fonts' + with SimplePatcher(sys, 'platform', 'linux'): + patched_env = copy.deepcopy(os.environ) + patched_env['XDG_DATA_DIRS'] = '/usr/share/:/usr/local/share/' + with SimplePatcher(os, 'environ', patched_env): + def fake_walker(path): + if path == font_directory: + return [(path, [], [ + 'Arial.ttf', 'Single.otf', 'Duplicate.otf', + 'Duplicate.ttf'], )] + return [(path, [], ['some_random_font.ttf'], )] + with SimplePatcher(os, 'walk', fake_walker): + # Test that the font loads both with and without the + # extension + self._test_fake_loading_font( + font_directory+'/Arial.ttf', 'Arial.ttf') + self._test_fake_loading_font( + font_directory+'/Arial.ttf', 'Arial') + + # Test that non-ttf fonts can be found without the + # extension + self._test_fake_loading_font( + font_directory+'/Single.otf', 'Single') + + # Test that ttf fonts are preferred if the extension is + # not specified + self._test_fake_loading_font( + font_directory+'/Duplicate.ttf', 'Duplicate') + + @unittest.skipIf(sys.platform.startswith('win32'), + "requires Unix or MacOS") + def test_find_macos_font(self): + # Like the linux test, more cover hitting code rather than testing + # correctness. + font_directory = '/System/Library/Fonts' + with SimplePatcher(sys, 'platform', 'darwin'): def fake_walker(path): if path == font_directory: - return [(path, [], [ - 'Arial.ttf', 'Single.otf', 'Duplicate.otf', - 'Duplicate.ttf'], )] + return [(path, [], + ['Arial.ttf', 'Single.otf', + 'Duplicate.otf', 'Duplicate.ttf'], )] return [(path, [], ['some_random_font.ttf'], )] with SimplePatcher(os, 'walk', fake_walker): - # Test that the font loads both with and without the - # extension self._test_fake_loading_font( font_directory+'/Arial.ttf', 'Arial.ttf') self._test_fake_loading_font( font_directory+'/Arial.ttf', 'Arial') - - # Test that non-ttf fonts can be found without the - # extension self._test_fake_loading_font( font_directory+'/Single.otf', 'Single') - - # Test that ttf fonts are preferred if the extension is - # not specified self._test_fake_loading_font( font_directory+'/Duplicate.ttf', 'Duplicate') - @unittest.skipIf(sys.platform.startswith('win32'), - "requires Unix or MacOS") - def test_find_macos_font(self): - # Like the linux test, more cover hitting code rather than testing - # correctness. - font_directory = '/System/Library/Fonts' - with SimplePatcher(sys, 'platform', 'darwin'): - def fake_walker(path): - if path == font_directory: - return [(path, [], - ['Arial.ttf', 'Single.otf', - 'Duplicate.otf', 'Duplicate.ttf'], )] - return [(path, [], ['some_random_font.ttf'], )] - with SimplePatcher(os, 'walk', fake_walker): - self._test_fake_loading_font( - font_directory+'/Arial.ttf', 'Arial.ttf') - self._test_fake_loading_font( - font_directory+'/Arial.ttf', 'Arial') - self._test_fake_loading_font( - font_directory+'/Single.otf', 'Single') - self._test_fake_loading_font( - font_directory+'/Duplicate.ttf', 'Duplicate') - - def test_imagefont_getters(self): - # Arrange - t = self.get_font() - - # Act / Assert - self.assertEqual(t.getmetrics(), (16, 4)) - self.assertEqual(t.font.ascent, 16) - self.assertEqual(t.font.descent, 4) - self.assertEqual(t.font.height, 20) - self.assertEqual(t.font.x_ppem, 20) - self.assertEqual(t.font.y_ppem, 20) - self.assertEqual(t.font.glyphs, 4177) - self.assertEqual(t.getsize('A'), (12, 16)) - self.assertEqual(t.getsize('AB'), (24, 16)) - self.assertEqual(t.getsize('M'), self.metrics['getters']) - self.assertEqual(t.getsize('y'), (12, 20)) - self.assertEqual(t.getsize('a'), (12, 16)) - - -@unittest.skipUnless(HAS_RAQM, "Raqm not Available") -class TestImageFont_RaqmLayout(TestImageFont): - LAYOUT_ENGINE = ImageFont.LAYOUT_RAQM + def test_imagefont_getters(self): + # Arrange + t = ImageFont.truetype(FONT_PATH, FONT_SIZE) + + # Act / Assert + self.assertEqual(t.getmetrics(), (16, 4)) + self.assertEqual(t.font.ascent, 16) + self.assertEqual(t.font.descent, 4) + self.assertEqual(t.font.height, 20) + self.assertEqual(t.font.x_ppem, 20) + self.assertEqual(t.font.y_ppem, 20) + self.assertEqual(t.font.glyphs, 4177) + self.assertEqual(t.getsize('A'), (12, 16)) + self.assertEqual(t.getsize('AB'), (24, 16)) + self.assertEqual(t.getsize('M'), (12, 16)) + self.assertEqual(t.getsize('y'), (12, 20)) + self.assertEqual(t.getsize('a'), (12, 16)) + + +except ImportError: + class TestImageFont(PillowTestCase): + def test_skip(self): + self.skipTest("ImportError") + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_image_fromqpixmap.py pillow-4.1.1/Tests/test_image_fromqpixmap.py --- pillow-4.2.1/Tests/test_image_fromqpixmap.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_fromqpixmap.py 2017-04-04 18:14:25.000000000 +0000 @@ -1,9 +1,8 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase, hopper, distro from test_imageqt import PillowQtTestCase, PillowQPixmapTestCase from PIL import ImageQt - class TestFromQPixmap(PillowQPixmapTestCase, PillowTestCase): def roundtrip(self, expected): diff -Nru pillow-4.2.1/Tests/test_image_getbbox.py pillow-4.1.1/Tests/test_image_getbbox.py --- pillow-4.2.1/Tests/test_image_getbbox.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_getbbox.py 2016-10-18 19:11:47.000000000 +0000 @@ -14,7 +14,7 @@ # 8-bit mode im = Image.new("L", (100, 100), 0) - self.assertIsNone(im.getbbox()) + self.assertEqual(im.getbbox(), None) im.paste(255, (10, 25, 90, 75)) self.assertEqual(im.getbbox(), (10, 25, 90, 75)) @@ -27,7 +27,7 @@ # 32-bit mode im = Image.new("RGB", (100, 100), 0) - self.assertIsNone(im.getbbox()) + self.assertEqual(im.getbbox(), None) im.paste(255, (10, 25, 90, 75)) self.assertEqual(im.getbbox(), (10, 25, 90, 75)) diff -Nru pillow-4.2.1/Tests/test_image_getcolors.py pillow-4.1.1/Tests/test_image_getcolors.py --- pillow-4.2.1/Tests/test_image_getcolors.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_getcolors.py 2016-10-18 19:11:47.000000000 +0000 @@ -20,15 +20,15 @@ self.assertEqual(getcolors("I"), 255) self.assertEqual(getcolors("F"), 255) self.assertEqual(getcolors("P"), 90) # fixed palette - self.assertIsNone(getcolors("RGB")) - self.assertIsNone(getcolors("RGBA")) - self.assertIsNone(getcolors("CMYK")) - self.assertIsNone(getcolors("YCbCr")) + self.assertEqual(getcolors("RGB"), None) + self.assertEqual(getcolors("RGBA"), None) + self.assertEqual(getcolors("CMYK"), None) + self.assertEqual(getcolors("YCbCr"), None) - self.assertIsNone(getcolors("L", 128)) + self.assertEqual(getcolors("L", 128), None) self.assertEqual(getcolors("L", 1024), 255) - self.assertIsNone(getcolors("RGB", 8192)) + self.assertEqual(getcolors("RGB", 8192), None) self.assertEqual(getcolors("RGB", 16384), 10100) self.assertEqual(getcolors("RGB", 100000), 10100) @@ -48,7 +48,7 @@ (7960, (31, 20, 33))] A = im.getcolors(maxcolors=2) - self.assertIsNone(A) + self.assertEqual(A, None) A = im.getcolors(maxcolors=3) A.sort() diff -Nru pillow-4.2.1/Tests/test_image_getpalette.py pillow-4.1.1/Tests/test_image_getpalette.py --- pillow-4.2.1/Tests/test_image_getpalette.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_getpalette.py 2016-10-18 19:11:47.000000000 +0000 @@ -9,15 +9,15 @@ if p: return p[:10] return None - self.assertIsNone(palette("1")) - self.assertIsNone(palette("L")) - self.assertIsNone(palette("I")) - self.assertIsNone(palette("F")) + self.assertEqual(palette("1"), None) + self.assertEqual(palette("L"), None) + self.assertEqual(palette("I"), None) + self.assertEqual(palette("F"), None) self.assertEqual(palette("P"), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - self.assertIsNone(palette("RGB")) - self.assertIsNone(palette("RGBA")) - self.assertIsNone(palette("CMYK")) - self.assertIsNone(palette("YCbCr")) + self.assertEqual(palette("RGB"), None) + self.assertEqual(palette("RGBA"), None) + self.assertEqual(palette("CMYK"), None) + self.assertEqual(palette("YCbCr"), None) if __name__ == '__main__': diff -Nru pillow-4.2.1/Tests/test_imagegrab.py pillow-4.1.1/Tests/test_imagegrab.py --- pillow-4.2.1/Tests/test_imagegrab.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagegrab.py 2016-10-18 19:11:47.000000000 +0000 @@ -38,7 +38,7 @@ # Assert if sys.platform in ["win32", "darwin"]: - self.assertIsNone(exception) + self.assertIsNone(exception, None) else: self.assertIsInstance(exception, ImportError) self.assertEqual(str(exception), diff -Nru pillow-4.2.1/Tests/test_imagemorph.py pillow-4.1.1/Tests/test_imagemorph.py --- pillow-4.2.1/Tests/test_imagemorph.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagemorph.py 2017-04-04 18:14:25.000000000 +0000 @@ -176,40 +176,6 @@ self.assertEqual(len(coords), 4) self.assertEqual(tuple(coords), ((2, 2), (4, 2), (2, 4), (4, 4))) - def test_mirroring(self): - # Test 'M' for mirroring - mop = ImageMorph.MorphOp(patterns=['1:(... ... ...)->0', - 'M:(00. 01. ...)->1']) - count, Aout = mop.apply(self.A) - self.assertEqual(count, 7) - self.assert_img_equal_img_string(Aout, - """ - ....... - ....... - ..1.1.. - ....... - ....... - ....... - ....... - """) - - def test_negate(self): - # Test 'N' for negate - mop = ImageMorph.MorphOp(patterns=['1:(... ... ...)->0', - 'N:(00. 01. ...)->1']) - count, Aout = mop.apply(self.A) - self.assertEqual(count, 8) - self.assert_img_equal_img_string(Aout, - """ - ....... - ....... - ..1.... - ....... - ....... - ....... - ....... - """) - def test_non_binary_images(self): im = hopper('RGB') mop = ImageMorph.MorphOp(op_name="erosion8") @@ -218,74 +184,6 @@ self.assertRaises(Exception, lambda: mop.match(im)) self.assertRaises(Exception, lambda: mop.get_on_pixels(im)) - def test_add_patterns(self): - # Arrange - lb = ImageMorph.LutBuilder(op_name='corner') - self.assertEqual(lb.patterns, ['1:(... ... ...)->0', - '4:(00. 01. ...)->1']) - new_patterns = ['M:(00. 01. ...)->1', - 'N:(00. 01. ...)->1'] - - # Act - lb.add_patterns(new_patterns) - - # Assert - self.assertEqual( - lb.patterns, - ['1:(... ... ...)->0', - '4:(00. 01. ...)->1', - 'M:(00. 01. ...)->1', - 'N:(00. 01. ...)->1']) - - def test_unknown_pattern(self): - self.assertRaises( - Exception, - lambda: ImageMorph.LutBuilder(op_name='unknown')) - - def test_pattern_syntax_error(self): - # Arrange - lb = ImageMorph.LutBuilder(op_name='corner') - new_patterns = ['a pattern with a syntax error'] - lb.add_patterns(new_patterns) - - # Act / Assert - self.assertRaises( - Exception, - lambda: lb.build_lut()) - - def test_load_invalid_mrl(self): - # Arrange - invalid_mrl = 'Tests/images/hopper.png' - mop = ImageMorph.MorphOp() - - # Act / Assert - self.assertRaises(Exception, lambda: mop.load_lut(invalid_mrl)) - - def test_roundtrip_mrl(self): - # Arrange - tempfile = self.tempfile('temp.mrl') - mop = ImageMorph.MorphOp(op_name='corner') - initial_lut = mop.lut - - # Act - mop.save_lut(tempfile) - mop.load_lut(tempfile) - - # Act / Assert - self.assertEqual(mop.lut, initial_lut) - - def test_set_lut(self): - # Arrange - lb = ImageMorph.LutBuilder(op_name='corner') - lut = lb.build_lut() - mop = ImageMorph.MorphOp() - - # Act - mop.set_lut(lut) - - # Assert - self.assertEqual(mop.lut, lut) - if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_imagepalette.py pillow-4.1.1/Tests/test_imagepalette.py --- pillow-4.2.1/Tests/test_imagepalette.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagepalette.py 2017-01-02 11:47:11.000000000 +0000 @@ -128,16 +128,16 @@ def test_2bit_palette(self): # issue #2258, 2 bit palettes are corrupted. outfile = self.tempfile('temp.png') - + rgb = b'\x00' * 2 + b'\x01' * 2 + b'\x02' * 2 img = Image.frombytes('P', (6, 1), rgb) - img.putpalette(b'\xFF\x00\x00\x00\xFF\x00\x00\x00\xFF') # RGB + img.putpalette(b'\xFF\x00\x00\x00\xFF\x00\x00\x00\xFF') # RGB img.save(outfile, format='PNG') reloaded = Image.open(outfile) self.assert_image_equal(img, reloaded) - + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_image_paste.py pillow-4.1.1/Tests/test_image_paste.py --- pillow-4.2.1/Tests/test_image_paste.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_paste.py 2017-04-04 18:14:25.000000000 +0000 @@ -9,9 +9,9 @@ def assert_9points_image(self, im, expected): expected = [ - point[0] + point[0] if im.mode == 'L' else - point[:len(im.mode)] + point[:len(im.mode)] for point in expected ] px = im.load() @@ -249,7 +249,7 @@ im2 = Image.new('RGB', (50, 50)) im.copy().paste(im2) - im.copy().paste(im2, (0, 0)) + im.copy().paste(im2, (0,0)) if __name__ == '__main__': diff -Nru pillow-4.2.1/Tests/test_image.py pillow-4.1.1/Tests/test_image.py --- pillow-4.2.1/Tests/test_image.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image.py 2017-04-04 18:14:25.000000000 +0000 @@ -170,7 +170,7 @@ im2 = Image.new('RGB', (25, 25), 'white') # Act / Assert - self.assertNotEqual(im1, im2) + self.assertTrue(im1 != im2) def test_alpha_composite(self): # https://stackoverflow.com/questions/3374878 @@ -202,44 +202,6 @@ img_colors = sorted(img.getcolors()) self.assertEqual(img_colors, expected_colors) - def test_alpha_inplace(self): - src = Image.new('RGBA', (128,128), 'blue') - - over = Image.new('RGBA', (128,128), 'red') - mask = hopper('L') - over.putalpha(mask) - - target = Image.alpha_composite(src, over) - - # basic - full = src.copy() - full.alpha_composite(over) - self.assert_image_equal(full, target) - - # with offset down to right - offset = src.copy() - offset.alpha_composite(over, (64, 64)) - self.assert_image_equal(offset.crop((64, 64, 127, 127)), - target.crop((0, 0, 63, 63))) - self.assertEqual(offset.size, (128, 128)) - - # offset and crop - box = src.copy() - box.alpha_composite(over, (64, 64), (0, 0, 32, 32)) - self.assert_image_equal(box.crop((64, 64, 96, 96)), - target.crop((0, 0, 32, 32))) - self.assert_image_equal(box.crop((96, 96, 128, 128)), - src.crop((0, 0, 32, 32))) - self.assertEqual(box.size, (128, 128)) - - # source point - source = src.copy() - source.alpha_composite(over, (32, 32), (32, 32, 96, 96)) - - self.assert_image_equal(source.crop((32, 32, 96, 96)), - target.crop((32, 32, 96, 96))) - self.assertEqual(source.size, (128, 128)) - def test_registered_extensions_uninitialized(self): # Arrange Image._initialized = 0 @@ -413,22 +375,19 @@ self.assert_image_equal(im, target) -class MockEncoder(object): - pass - +class MockEncoder(object):pass def mock_encode(*args): encoder = MockEncoder() encoder.args = args return encoder - class TestRegistry(PillowTestCase): def test_encode_registry(self): Image.register_encoder('MOCK', mock_encode) - self.assertIn('MOCK', Image.ENCODERS) + self.assert_('MOCK' in Image.ENCODERS) enc = Image._getencoder('RGB', 'MOCK', ('args',), extra=('extra',)) diff -Nru pillow-4.2.1/Tests/test_image_resample.py pillow-4.1.1/Tests/test_image_resample.py --- pillow-4.2.1/Tests/test_image_resample.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_resample.py 2017-01-02 11:47:11.000000000 +0000 @@ -1,6 +1,6 @@ from __future__ import print_function from helper import unittest, PillowTestCase, hopper -from PIL import Image, ImageDraw +from PIL import Image, ImageDraw, ImageMode class TestImagingResampleVulnerability(PillowTestCase): @@ -16,8 +16,8 @@ def test_invalid_size(self): im = hopper() - # Should not crash im.resize((100, 100)) + self.assertTrue(True, "Should not Crash") with self.assertRaises(ValueError): im.resize((-100, 100)) @@ -158,12 +158,14 @@ def test_enlarge_hamming(self): for mode in ['RGBX', 'RGB', 'La', 'L']: - case = self.make_case(mode, (2, 2), 0xe1) - case = case.resize((4, 4), Image.HAMMING) - data = ('e1 d2' - 'd2 c5') + case = self.make_case(mode, (4, 4), 0xe1) + case = case.resize((8, 8), Image.HAMMING) + data = ('e1 e1 ea d1' + 'e1 e1 ea d1' + 'ea ea f4 d9' + 'd1 d1 d9 c4') for channel in case.split(): - self.check_case(channel, self.make_sample(data, (4, 4))) + self.check_case(channel, self.make_sample(data, (8, 8))) def test_enlarge_bicubic(self): for mode in ['RGBX', 'RGB', 'La', 'L']: @@ -242,8 +244,8 @@ for y in range(i.size[1]): used_colors = {px[x, y][0] for x in range(i.size[0])} self.assertEqual(256, len(used_colors), - 'All colors should present in resized image. ' - 'Only {} on {} line.'.format(len(used_colors), y)) + 'All colors should present in resized image. ' + 'Only {} on {} line.'.format(len(used_colors), y)) @unittest.skip("current implementation isn't precise enough") def test_levels_rgba(self): @@ -341,10 +343,10 @@ im = Image.new('RGBA', (1280, 1280), (0x20, 0x40, 0x60, 0xff)) histogram = im.resize((256, 256), Image.BICUBIC).histogram() - self.assertEqual(histogram[0x100 * 0 + 0x20], 0x10000) # first channel - self.assertEqual(histogram[0x100 * 1 + 0x40], 0x10000) # second channel - self.assertEqual(histogram[0x100 * 2 + 0x60], 0x10000) # third channel - self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) # fourth channel + self.assertEqual(histogram[0x100 * 0 + 0x20], 0x10000) # first channel + self.assertEqual(histogram[0x100 * 1 + 0x40], 0x10000) # second channel + self.assertEqual(histogram[0x100 * 2 + 0x60], 0x10000) # third channel + self.assertEqual(histogram[0x100 * 3 + 0xff], 0x10000) # fourth channel if __name__ == '__main__': diff -Nru pillow-4.2.1/Tests/test_image_resize.py pillow-4.1.1/Tests/test_image_resize.py --- pillow-4.2.1/Tests/test_image_resize.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_resize.py 2017-04-04 18:14:25.000000000 +0000 @@ -92,10 +92,10 @@ def test_enlarge_zero(self): for f in [Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, Image.BICUBIC, Image.LANCZOS]: - r = self.resize(Image.new('RGB', (0, 0), "white"), (212, 195), f) + r = self.resize(Image.new('RGB', (0,0), "white"), (212, 195), f) self.assertEqual(r.mode, "RGB") self.assertEqual(r.size, (212, 195)) - self.assertEqual(r.getdata()[0], (0, 0, 0)) + self.assertEqual(r.getdata()[0], (0,0,0)) def test_unknown_filter(self): self.assertRaises(ValueError, self.resize, hopper(), (10, 10), 9) diff -Nru pillow-4.2.1/Tests/test_image_rotate.py pillow-4.1.1/Tests/test_image_rotate.py --- pillow-4.2.1/Tests/test_image_rotate.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_rotate.py 2017-01-02 11:47:11.000000000 +0000 @@ -17,7 +17,7 @@ else: self.assertNotEqual(out.size, im.size) - def test_mode(self): + def test_mode(self): for mode in ("1", "P", "L", "RGB", "I", "F"): im = hopper(mode) self.rotate(im, mode, 45) @@ -29,13 +29,13 @@ def test_zero(self): for angle in (0, 45, 90, 180, 270): - im = Image.new('RGB', (0, 0)) + im = Image.new('RGB',(0,0)) self.rotate(im, im.mode, angle) def test_resample(self): - # Target image creation, inspected by eye. + # Target image creation, inspected by eye. # >>> im = Image.open('Tests/images/hopper.ppm') - # >>> im = im.rotate(45, resample=Image.BICUBIC, expand=True) + # >>> im = im.rotate(45, resample=Image.BICUBIC, expand=True) # >>> im.save('Tests/images/hopper_45.png') target = Image.open('Tests/images/hopper_45.png') @@ -52,7 +52,7 @@ target_origin = target.size[1]/2 target = target.crop((0, target_origin, 128, target_origin + 128)) - im = im.rotate(45, center=(0, 0), resample=Image.BICUBIC) + im = im.rotate(45, center=(0,0), resample=Image.BICUBIC) self.assert_image_similar(im, target, 15) @@ -62,7 +62,7 @@ target_origin = target.size[1] / 2 - 14 target = target.crop((6, target_origin, 128 + 6, target_origin + 128)) - im = im.rotate(45, center=(14, 14), resample=Image.BICUBIC) + im = im.rotate(45, center=(14,14), resample=Image.BICUBIC) self.assert_image_similar(im, target, 10) @@ -73,7 +73,7 @@ target = target.crop((target_origin, target_origin, target_origin + 128, target_origin + 128)) - im = im.rotate(45, translate=(5, 5), resample=Image.BICUBIC) + im = im.rotate(45, translate=(5,5), resample=Image.BICUBIC) self.assert_image_similar(im, target, 1) @@ -81,14 +81,14 @@ # if the center is -1,-1 and we rotate by 90<=x<=270 the # resulting image should be black for angle in (90, 180, 270): - im = hopper().rotate(angle, center=(-1, -1)) + im = hopper().rotate(angle, center=(-1,-1)) self.assert_image_equal(im, Image.new('RGB', im.size, 'black')) def test_fastpath_translate(self): # if we post-translate by -128 # resulting image should be black for angle in (0, 90, 180, 270): - im = hopper().rotate(angle, translate=(-128, -128)) + im = hopper().rotate(angle, translate=(-128,-128)) self.assert_image_equal(im, Image.new('RGB', im.size, 'black')) def test_center(self): @@ -97,6 +97,8 @@ self.rotate(im, im.mode, 45, translate=(im.size[0]/2, 0)) self.rotate(im, im.mode, 45, center=(0, 0), translate=(im.size[0]/2, 0)) + + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_imagesequence.py pillow-4.1.1/Tests/test_imagesequence.py --- pillow-4.2.1/Tests/test_imagesequence.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagesequence.py 2017-04-04 18:14:25.000000000 +0000 @@ -62,6 +62,7 @@ self.assert_image_equal(frame, firstFrame) break + def test_palette_mmap(self): # Using mmap in ImageFile can require to reload the palette. im = Image.open('Tests/images/multipage-mmap.tiff') diff -Nru pillow-4.2.1/Tests/test_imagetk.py pillow-4.1.1/Tests/test_imagetk.py --- pillow-4.2.1/Tests/test_imagetk.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagetk.py 2017-04-04 18:14:25.000000000 +0000 @@ -10,10 +10,9 @@ except (OSError, ImportError) as v: # Skipped via setUp() HAS_TK = False - + TK_MODES = ('1', 'L', 'P', 'RGB', 'RGBA') - class TestImageTk(PillowTestCase): def setUp(self): @@ -22,7 +21,7 @@ try: # setup tk app = tk.Frame() - # root = tk.Tk() + #root = tk.Tk() except (tk.TclError) as v: self.skipTest("TCL Error: %s" % v) @@ -45,13 +44,14 @@ # Test no relevant entry im = ImageTk._get_image_from_kw(kw) - self.assertIsNone(im) + self.assertEqual(im, None) + def test_photoimage(self): for mode in TK_MODES: # test as image: im = hopper(mode) - + # this should not crash im_tk = ImageTk.PhotoImage(im) @@ -59,32 +59,35 @@ self.assertEqual(im_tk.height(), im.height) # _tkinter.TclError: this function is not yet supported - # reloaded = ImageTk.getimage(im_tk) - # self.assert_image_equal(reloaded, im) + #reloaded = ImageTk.getimage(im_tk) + #self.assert_image_equal(reloaded, im) + + def test_photoimage_blank(self): # test a image using mode/size: for mode in TK_MODES: - im_tk = ImageTk.PhotoImage(mode, (100, 100)) - + im_tk = ImageTk.PhotoImage(mode, (100,100)) + self.assertEqual(im_tk.width(), 100) self.assertEqual(im_tk.height(), 100) - - # reloaded = ImageTk.getimage(im_tk) - # self.assert_image_equal(reloaded, im) + + #reloaded = ImageTk.getimage(im_tk) + #self.assert_image_equal(reloaded, im) def test_bitmapimage(self): im = hopper('1') # this should not crash im_tk = ImageTk.BitmapImage(im) - + self.assertEqual(im_tk.width(), im.width) self.assertEqual(im_tk.height(), im.height) + + #reloaded = ImageTk.getimage(im_tk) + #self.assert_image_equal(reloaded, im) + - # reloaded = ImageTk.getimage(im_tk) - # self.assert_image_equal(reloaded, im) - - + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_image_toqimage.py pillow-4.1.1/Tests/test_image_toqimage.py --- pillow-4.2.1/Tests/test_image_toqimage.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_toqimage.py 2017-04-04 18:14:25.000000000 +0000 @@ -20,8 +20,7 @@ from PySide import QtGui from PySide.QtGui import QWidget, QHBoxLayout, QLabel, QApplication QT_VERSION = 4 - - + class TestToQImage(PillowQtTestCase, PillowTestCase): def test_sanity(self): @@ -46,12 +45,12 @@ # libpng warning: Invalid color type/bit depth combination in IHDR # libpng error: Invalid IHDR data continue - + # Test saving the file tempfile = self.tempfile('temp_{}.png'.format(mode)) data.save(tempfile) - # Check that it actually worked. + # Check that it actually worked. reloaded = Image.open(tempfile) # Gray images appear to come back in palette mode. # They're roughly equivalent @@ -59,6 +58,7 @@ src = src.convert('P') self.assert_image_equal(reloaded, src) + def test_segfault(self): PillowQtTestCase.setUp(self) diff -Nru pillow-4.2.1/Tests/test_image_toqpixmap.py pillow-4.1.1/Tests/test_image_toqpixmap.py --- pillow-4.2.1/Tests/test_image_toqpixmap.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_image_toqpixmap.py 2017-04-04 18:14:25.000000000 +0000 @@ -1,4 +1,4 @@ -from helper import unittest, PillowTestCase, hopper +from helper import unittest, PillowTestCase, hopper, distro from test_imageqt import PillowQtTestCase, PillowQPixmapTestCase from PIL import ImageQt diff -Nru pillow-4.2.1/Tests/test_imagewin.py pillow-4.1.1/Tests/test_imagewin.py --- pillow-4.2.1/Tests/test_imagewin.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_imagewin.py 2016-10-18 19:11:47.000000000 +0000 @@ -107,6 +107,15 @@ # Confirm they're the same self.assertEqual(dib1.tobytes(), dib2.tobytes()) + def test_removed_methods(self): + # Arrange + im = hopper() + dib = ImageWin.Dib(im) + + # Act/Assert + self.assertRaises(Exception, dib.tostring) + self.assertRaises(Exception, dib.fromstring) + if __name__ == '__main__': unittest.main() diff -Nru pillow-4.2.1/Tests/test_tiff_ifdrational.py pillow-4.1.1/Tests/test_tiff_ifdrational.py --- pillow-4.2.1/Tests/test_tiff_ifdrational.py 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/Tests/test_tiff_ifdrational.py 2017-04-04 18:14:25.000000000 +0000 @@ -34,10 +34,10 @@ xres = IFDRational(72) yres = IFDRational(72) - self.assertIsNotNone(xres._val) - self.assertIsNotNone(xres.numerator) - self.assertIsNotNone(xres.denominator) - self.assertIsNotNone(yres._val) + self.assertTrue(xres._val is not None) + self.assertTrue(xres.numerator is not None) + self.assertTrue(xres.denominator is not None) + self.assertTrue(yres._val is not None) self.assertTrue(xres and 1) self.assertTrue(xres and yres) diff -Nru pillow-4.2.1/_webp.c pillow-4.1.1/_webp.c --- pillow-4.2.1/_webp.c 2017-07-01 15:55:53.000000000 +0000 +++ pillow-4.1.1/_webp.c 2017-04-28 16:48:58.000000000 +0000 @@ -29,7 +29,7 @@ if (!PyArg_ParseTuple(args, "s#iiifss#s#", (char**)&rgb, &size, &width, &height, &lossless, &quality_factor, &mode, &icc_bytes, &icc_size, &exif_bytes, &exif_size)) { - return NULL; + Py_RETURN_NONE; } if (strcmp(mode, "RGBA")==0){ if (size < width * height * 4){ @@ -145,7 +145,7 @@ char* mode = "RGB"; if (!PyArg_ParseTuple(args, "S", &webp_string)) { - return NULL; + Py_RETURN_NONE; } if (!WebPInitDecoderConfig(&config)) { @@ -247,12 +247,8 @@ * The version of webp that ships with (0.1.3) Ubuntu 12.04 doesn't handle alpha well. * Files that are valid with 0.3 are reported as being invalid. */ -int WebPDecoderBuggyAlpha() { - return WebPGetDecoderVersion()==0x0103; -} - PyObject* WebPDecoderBuggyAlpha_wrapper(PyObject* self, PyObject* args){ - return Py_BuildValue("i", WebPDecoderBuggyAlpha()); + return Py_BuildValue("i", WebPGetDecoderVersion()==0x0103); } static PyMethodDef webpMethods[] = @@ -272,11 +268,6 @@ #endif } -void addTransparencyFlagToModule(PyObject* m) { - PyModule_AddObject(m, "HAVE_TRANSPARENCY", - PyBool_FromLong(!WebPDecoderBuggyAlpha())); -} - #if PY_VERSION_HEX >= 0x03000000 PyMODINIT_FUNC @@ -293,7 +284,6 @@ m = PyModule_Create(&module_def); addMuxFlagToModule(m); - addTransparencyFlagToModule(m); return m; } #else @@ -302,6 +292,5 @@ { PyObject* m = Py_InitModule("_webp", webpMethods); addMuxFlagToModule(m); - addTransparencyFlagToModule(m); } #endif diff -Nru pillow-4.2.1/winbuild/appveyor_install_pypy.cmd pillow-4.1.1/winbuild/appveyor_install_pypy.cmd --- pillow-4.2.1/winbuild/appveyor_install_pypy.cmd 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/winbuild/appveyor_install_pypy.cmd 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -curl -fsSL -o pypy2.zip https://bitbucket.org/pypy/pypy/downloads/pypy2-v5.8.0-win32.zip -7z x pypy2.zip -oc:\ -c:\Python34\Scripts\virtualenv.exe -p c:\pypy2-v5.8.0-win32\pypy.exe c:\vp\pypy2 \ No newline at end of file diff -Nru pillow-4.2.1/winbuild/build.py pillow-4.1.1/winbuild/build.py --- pillow-4.2.1/winbuild/build.py 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/winbuild/build.py 2017-04-04 18:14:25.000000000 +0000 @@ -12,7 +12,7 @@ def setup_vms(): ret = [] - for py in pythons: + for py in pythons.keys(): for arch in ('', X64_EXT): ret.append("virtualenv -p c:/Python%s%s/python.exe --clear %s%s%s" % (py, arch, VIRT_BASE, py, arch)) @@ -72,11 +72,6 @@ args['python_path'] = "%PYTHON%" else: args['python_path'] = "%s%s\\Scripts" % (VIRT_BASE, py_ver) - - args['executable'] = "python.exe" - if 'EXECUTABLE' in os.environ: - args['executable'] = "%EXECUTABLE%" - args['py_ver'] = py_ver if '34' in py_ver: args['tcl_ver'] = '86' @@ -92,7 +87,7 @@ setlocal set LIB=%%LIB%%;C:\Python%(py_ver)s\tcl -call %(python_path)s\%(executable)s setup.py %%BLDOPT%% +call %(python_path)s\python.exe setup.py %%BLDOPT%% endlocal endlocal diff -Nru pillow-4.2.1/winbuild/config.py pillow-4.1.1/winbuild/config.py --- pillow-4.2.1/winbuild/config.py 2017-07-06 20:46:51.000000000 +0000 +++ pillow-4.1.1/winbuild/config.py 2017-04-04 18:14:25.000000000 +0000 @@ -5,7 +5,6 @@ pythons = { # '26': 7, '27': 7, - 'pypy2': 7, # '32': 7, '33': 7.1, '34': 7.1} @@ -29,14 +28,14 @@ 'dir': 'jpeg-9b', }, 'tiff': { - 'url': 'ftp://download.osgeo.org/libtiff/tiff-4.0.8.zip', - 'filename': PILLOW_DEPENDS_DIR + 'tiff-4.0.8.zip', - 'dir': 'tiff-4.0.8', + 'url': 'ftp://download.osgeo.org/libtiff/tiff-4.0.7.zip', + 'filename': PILLOW_DEPENDS_DIR + 'tiff-4.0.7.zip', + 'dir': 'tiff-4.0.7', }, 'freetype': { - 'url': 'https://download.savannah.gnu.org/releases/freetype/freetype-2.8.tar.gz', - 'filename': PILLOW_DEPENDS_DIR + 'freetype-2.8.tar.gz', - 'dir': 'freetype-2.8', + 'url': 'https://download.savannah.gnu.org/releases/freetype/freetype-2.7.1.tar.gz', + 'filename': PILLOW_DEPENDS_DIR + 'freetype-2.7.1.tar.gz', + 'dir': 'freetype-2.7.1', }, 'lcms': { 'url': SF_MIRROR+'/project/lcms/lcms/2.7/lcms2-2.7.zip', @@ -117,7 +116,7 @@ py = os.environ['PYTHON'] py_version = '27' - for k in pythons: + for k in pythons.keys(): if k in py: py_version = k break