From 4a9afc79bf3011792339134896ca0fc9dfd4a46a Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 12:00:23 +0200 Subject: [PATCH 001/126] improve ImageShow docs --- docs/PIL.rst | 8 -- docs/reference/ImageShow.rst | 27 +++++ docs/reference/index.rst | 1 + src/PIL/ImageShow.py | 194 ++++++++++++++++++++--------------- 4 files changed, 140 insertions(+), 90 deletions(-) create mode 100644 docs/reference/ImageShow.rst diff --git a/docs/PIL.rst b/docs/PIL.rst index fe69fed62..21adc5a16 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -62,14 +62,6 @@ can be found here. :undoc-members: :show-inheritance: -:mod:`ImageShow` Module ------------------------ - -.. automodule:: PIL.ImageShow - :members: - :undoc-members: - :show-inheritance: - :mod:`ImageTransform` Module ---------------------------- diff --git a/docs/reference/ImageShow.rst b/docs/reference/ImageShow.rst new file mode 100644 index 000000000..0b012d856 --- /dev/null +++ b/docs/reference/ImageShow.rst @@ -0,0 +1,27 @@ +.. py:module:: PIL.ImageShow +.. py:currentmodule:: PIL.ImageShow + +:py:mod:`ImageShow` Module +========================== + +The :py:mod:`ImageShow` Module is used to display images. +All default viewers convert the image to be shown to PNG format. + +.. autofunction:: PIL.ImageShow.show + +.. autoclass:: WindowsViewer +.. autoclass:: MacViewer + +.. class:: UnixViewer + + The following viewers may be registered on Unix-based systems, if the given command is found: + + .. autoclass:: PIL.ImageShow.DisplayViewer + .. autoclass:: PIL.ImageShow.EogViewer + .. autoclass:: PIL.ImageShow.XVViewer + +.. autofunction:: PIL.ImageShow.register +.. autoclass:: PIL.ImageShow.Viewer + :member-order: bysource + :members: + :undoc-members: diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 8c09e7b67..25c84126d 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -22,6 +22,7 @@ Reference ImagePath ImageQt ImageSequence + ImageShow ImageStat ImageTk ImageWin diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index fc5089423..4a597ce9a 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -24,6 +24,14 @@ _viewers = [] def register(viewer, order=1): + """ + The :py:func:`register` function is used to register additional viewers. + + :param viewer: The viewer to be registered. + :param order: + A negative integer to prepend this viewer to the list, + or a positive integer to append it. + """ try: if issubclass(viewer, Viewer): viewer = viewer() @@ -40,9 +48,9 @@ def show(image, title=None, **options): Display a given image. :param image: An image object. - :param title: Optional title. Not all viewers can display the title. + :param title: Optional title. Not all viewers can display the title. :param \**options: Additional viewer options. - :returns: True if a suitable viewer was found, false otherwise. + :returns: ``True`` if a suitable viewer was found, ``False`` otherwise. """ for viewer in _viewers: if viewer.show(image, title=title, **options): @@ -56,6 +64,10 @@ class Viewer: # main api def show(self, image, **options): + """ + The main function for displaying an image. + Converts the given image to the target format and displays it. + """ # save temporary image to disk if not ( @@ -70,25 +82,31 @@ class Viewer: # hook methods format = None + """The format to convert the image into.""" options = {} + """Additional options used to convert the image.""" def get_format(self, image): - """Return format name, or None to save as PGM/PPM""" + """Return format name, or ``None`` to save as PGM/PPM.""" return self.format def get_command(self, file, **options): + """ + Returns the command used to display the file. + Not implemented in the base class. + """ raise NotImplementedError def save_image(self, image): - """Save to temporary file, and return filename""" + """Save to temporary file and return filename.""" return image._dump(format=self.get_format(image), **self.options) def show_image(self, image, **options): - """Display given image""" + """Display the given image.""" return self.show_file(self.save_image(image), **options) def show_file(self, file, **options): - """Display given file""" + """Display the given file.""" os.system(self.get_command(file, **options)) return 1 @@ -96,104 +114,116 @@ class Viewer: # -------------------------------------------------------------------- +class WindowsViewer(Viewer): + """The default viewer on Windows is the default system application for PNG files.""" + + format = "PNG" + options = {"compress_level": 1} + + def get_command(self, file, **options): + return ( + 'start "Pillow" /WAIT "%s" ' + "&& ping -n 2 127.0.0.1 >NUL " + '&& del /f "%s"' % (file, file) + ) + + if sys.platform == "win32": - - class WindowsViewer(Viewer): - format = "PNG" - options = {"compress_level": 1} - - def get_command(self, file, **options): - return ( - 'start "Pillow" /WAIT "%s" ' - "&& ping -n 2 127.0.0.1 >NUL " - '&& del /f "%s"' % (file, file) - ) - register(WindowsViewer) -elif sys.platform == "darwin": - class MacViewer(Viewer): - format = "PNG" - options = {"compress_level": 1} +class MacViewer(Viewer): + """The default viewer on MacOS using ``Preview.app``.""" - def get_command(self, file, **options): - # on darwin open returns immediately resulting in the temp - # file removal while app is opening - command = "open -a Preview.app" - command = "({} {}; sleep 20; rm -f {})&".format( - command, quote(file), quote(file) + format = "PNG" + options = {"compress_level": 1} + + def get_command(self, file, **options): + # on darwin open returns immediately resulting in the temp + # file removal while app is opening + command = "open -a Preview.app" + command = "({} {}; sleep 20; rm -f {})&".format( + command, quote(file), quote(file) + ) + return command + + def show_file(self, file, **options): + """Display given file""" + fd, path = tempfile.mkstemp() + with os.fdopen(fd, "w") as f: + f.write(file) + with open(path, "r") as f: + subprocess.Popen( + ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"], + shell=True, + stdin=f, ) - return command + os.remove(path) + return 1 - def show_file(self, file, **options): - """Display given file""" - fd, path = tempfile.mkstemp() - with os.fdopen(fd, "w") as f: - f.write(file) - with open(path, "r") as f: - subprocess.Popen( - ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"], - shell=True, - stdin=f, - ) - os.remove(path) - return 1 +if sys.platform == "darwin": register(MacViewer) -else: - # unixoids +class UnixViewer(Viewer): + format = "PNG" + options = {"compress_level": 1} - class UnixViewer(Viewer): - format = "PNG" - options = {"compress_level": 1} + def get_command(self, file, **options): + command = self.get_command_ex(file, **options)[0] + return "({} {}; rm -f {})&".format(command, quote(file), quote(file)) - def get_command(self, file, **options): + def show_file(self, file, **options): + """Display given file""" + fd, path = tempfile.mkstemp() + with os.fdopen(fd, "w") as f: + f.write(file) + with open(path, "r") as f: command = self.get_command_ex(file, **options)[0] - return "({} {}; rm -f {})&".format(command, quote(file), quote(file)) + subprocess.Popen( + ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f + ) + os.remove(path) + return 1 - def show_file(self, file, **options): - """Display given file""" - fd, path = tempfile.mkstemp() - with os.fdopen(fd, "w") as f: - f.write(file) - with open(path, "r") as f: - command = self.get_command_ex(file, **options)[0] - subprocess.Popen( - ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f - ) - os.remove(path) - return 1 - # implementations +class DisplayViewer(UnixViewer): + """The ImageMagick ``display`` command.""" - class DisplayViewer(UnixViewer): - def get_command_ex(self, file, **options): - command = executable = "display" - return command, executable + def get_command_ex(self, file, **options): + command = executable = "display" + return command, executable + +class EogViewer(UnixViewer): + """The GNOME Image Viewer ``eog`` command.""" + + def get_command_ex(self, file, **options): + command = executable = "eog" + return command, executable + + +class XVViewer(UnixViewer): + """ + The X Viewer ``xv`` command. + This viewer supports the ``title`` parameter. + """ + + def get_command_ex(self, file, title=None, **options): + # note: xv is pretty outdated. most modern systems have + # imagemagick's display command instead. + command = executable = "xv" + if title: + command += " -name %s" % quote(title) + return command, executable + + +if sys.platform not in ("win32", "darwin"): # unixoids if shutil.which("display"): register(DisplayViewer) - - class EogViewer(UnixViewer): - def get_command_ex(self, file, **options): - command = executable = "eog" - return command, executable - if shutil.which("eog"): register(EogViewer) - - class XVViewer(UnixViewer): - def get_command_ex(self, file, title=None, **options): - # note: xv is pretty outdated. most modern systems have - # imagemagick's display command instead. - command = executable = "xv" - if title: - command += " -name %s" % quote(title) - return command, executable - if shutil.which("xv"): register(XVViewer) From f19e3ec1246d28bab3092d3c53cc4b17b55cdafd Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 13:46:52 +0200 Subject: [PATCH 002/126] promote JpegPresets from autodoc section --- docs/PIL.rst | 8 -------- docs/reference/JpegPresets.rst | 11 +++++++++++ docs/reference/index.rst | 1 + src/PIL/JpegPresets.py | 9 +++++---- 4 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 docs/reference/JpegPresets.rst diff --git a/docs/PIL.rst b/docs/PIL.rst index 21adc5a16..e7939554d 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -70,14 +70,6 @@ can be found here. :undoc-members: :show-inheritance: -:mod:`JpegPresets` Module -------------------------- - -.. automodule:: PIL.JpegPresets - :members: - :undoc-members: - :show-inheritance: - :mod:`PaletteFile` Module ------------------------- diff --git a/docs/reference/JpegPresets.rst b/docs/reference/JpegPresets.rst new file mode 100644 index 000000000..bf93f891f --- /dev/null +++ b/docs/reference/JpegPresets.rst @@ -0,0 +1,11 @@ +.. py:currentmodule:: PIL.JpegPresets + +:py:mod:`JpegPresets` Module +============================ + +.. automodule:: PIL.JpegPresets + + .. data:: presets + :annotation: + + A dict of all supported presets. diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 25c84126d..9f9e7142b 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -28,6 +28,7 @@ Reference ImageWin ExifTags TiffTags + JpegPresets PSDraw PixelAccess PyAccess diff --git a/src/PIL/JpegPresets.py b/src/PIL/JpegPresets.py index 118dab061..09691d79d 100644 --- a/src/PIL/JpegPresets.py +++ b/src/PIL/JpegPresets.py @@ -1,9 +1,11 @@ """ JPEG quality settings equivalent to the Photoshop settings. +Can be used when saving JPEG files. -More presets can be added to the presets dict if needed. - -Can be use when saving JPEG file. +The following presets are available by default: +``web_low``, ``web_medium``, ``web_high``, ``web_very_high``, ``web_maximum``, +``low``, ``medium``, ``high``, ``maximum``. +More presets can be added to the :py:data:`presets` dict if needed. To apply the preset, specify:: @@ -21,7 +23,6 @@ Example:: im.save("image_name.jpg", quality="web_high") - Subsampling ----------- From d2f7e46c5dfacfa732a4e2ef11f4585737fa93ca Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 13:47:59 +0200 Subject: [PATCH 003/126] convert comments into docstrings in autodoc files --- src/PIL/BdfFontFile.py | 14 ++++++-------- src/PIL/ContainerIO.py | 8 +++++--- src/PIL/FontFile.py | 7 ++----- src/PIL/GdImageFile.py | 28 ++++++++++++++++------------ src/PIL/GimpGradientFile.py | 21 +++++++++++---------- src/PIL/GimpPaletteFile.py | 4 +--- src/PIL/ImageDraw2.py | 4 ++++ src/PIL/PaletteFile.py | 4 +--- src/PIL/PcfFontFile.py | 5 +---- src/PIL/TarIO.py | 6 ++---- src/PIL/WalImageFile.py | 17 ++++++++++------- src/PIL/_binary.py | 4 ++++ 12 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/PIL/BdfFontFile.py b/src/PIL/BdfFontFile.py index 7a485cf80..102b72e1d 100644 --- a/src/PIL/BdfFontFile.py +++ b/src/PIL/BdfFontFile.py @@ -17,13 +17,13 @@ # See the README file for information on usage and redistribution. # +""" +Parse X Bitmap Distribution Format (BDF) +""" + from . import FontFile, Image -# -------------------------------------------------------------------- -# parse X Bitmap Distribution Format (BDF) -# -------------------------------------------------------------------- - bdf_slant = { "R": "Roman", "I": "Italic", @@ -78,11 +78,9 @@ def bdf_char(f): return id, int(props["ENCODING"]), bbox, im -## -# Font file plugin for the X11 BDF format. - - class BdfFontFile(FontFile.FontFile): + """Font file plugin for the X11 BDF format.""" + def __init__(self, fp): super().__init__() diff --git a/src/PIL/ContainerIO.py b/src/PIL/ContainerIO.py index 5bb0086f6..45e80b39a 100644 --- a/src/PIL/ContainerIO.py +++ b/src/PIL/ContainerIO.py @@ -14,14 +14,16 @@ # See the README file for information on usage and redistribution. # -## -# A file object that provides read access to a part of an existing -# file (for example a TAR file). import io class ContainerIO: + """ + A file object that provides read access to a part of an existing + file (for example a TAR file). + """ + def __init__(self, file, offset, length): """ Create file object. diff --git a/src/PIL/FontFile.py b/src/PIL/FontFile.py index 979a1e33c..4243b28b6 100644 --- a/src/PIL/FontFile.py +++ b/src/PIL/FontFile.py @@ -23,18 +23,15 @@ WIDTH = 800 def puti16(fp, values): - # write network order (big-endian) 16-bit sequence + """write network order (big-endian) 16-bit sequence""" for v in values: if v < 0: v += 65536 fp.write(_binary.o16be(v)) -## -# Base class for raster font file handlers. - - class FontFile: + """Base class for raster font file handlers.""" bitmap = None diff --git a/src/PIL/GdImageFile.py b/src/PIL/GdImageFile.py index b3ab01a4e..abdc05f90 100644 --- a/src/PIL/GdImageFile.py +++ b/src/PIL/GdImageFile.py @@ -14,26 +14,30 @@ # -# NOTE: This format cannot be automatically recognized, so the -# class is not registered for use with Image.open(). To open a -# gd file, use the GdImageFile.open() function instead. +""" +.. note:: + This format cannot be automatically recognized, so the + class is not registered for use with :py:func:`PIL.Image.open()`. To open a + gd file, use the :py:func:`PIL.GdImageFile.open()` function instead. -# THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This -# implementation is provided for convenience and demonstrational -# purposes only. +.. warning:: + THE GD FORMAT IS NOT DESIGNED FOR DATA INTERCHANGE. This + implementation is provided for convenience and demonstrational + purposes only. +""" from . import ImageFile, ImagePalette, UnidentifiedImageError from ._binary import i8, i16be as i16, i32be as i32 -## -# Image plugin for the GD uncompressed format. Note that this format -# is not supported by the standard Image.open function. To use -# this plugin, you have to import the GdImageFile module and -# use the GdImageFile.open function. - class GdImageFile(ImageFile.ImageFile): + """ + Image plugin for the GD uncompressed format. Note that this format + is not supported by the standard :py:func:`PIL.Image.open()` function. To use + this plugin, you have to import the :py:mod:`PIL.GdImageFile` module and + use the :py:func:`PIL.GdImageFile.open()` function. + """ format = "GD" format_description = "GD uncompressed images" diff --git a/src/PIL/GimpGradientFile.py b/src/PIL/GimpGradientFile.py index 1cacf5718..7ab7f9990 100644 --- a/src/PIL/GimpGradientFile.py +++ b/src/PIL/GimpGradientFile.py @@ -13,17 +13,19 @@ # See the README file for information on usage and redistribution. # +""" +Stuff to translate curve segments to palette values (derived from +the corresponding code in GIMP, written by Federico Mena Quintero. +See the GIMP distribution for more information.) +""" + + from math import log, pi, sin, sqrt from ._binary import o8 -# -------------------------------------------------------------------- -# Stuff to translate curve segments to palette values (derived from -# the corresponding code in GIMP, written by Federico Mena Quintero. -# See the GIMP distribution for more information.) -# - EPSILON = 1e-10 +"""""" # Enable auto-doc for data member def linear(middle, pos): @@ -58,6 +60,7 @@ def sphere_decreasing(middle, pos): SEGMENTS = [linear, curved, sine, sphere_increasing, sphere_decreasing] +"""""" # Enable auto-doc for data member class GradientFile: @@ -98,11 +101,9 @@ class GradientFile: return b"".join(palette), "RGBA" -## -# File handler for GIMP's gradient format. - - class GimpGradientFile(GradientFile): + """File handler for GIMP's gradient format.""" + def __init__(self, fp): if fp.readline()[:13] != b"GIMP Gradient": diff --git a/src/PIL/GimpPaletteFile.py b/src/PIL/GimpPaletteFile.py index e3060ab8a..10fd3ad81 100644 --- a/src/PIL/GimpPaletteFile.py +++ b/src/PIL/GimpPaletteFile.py @@ -18,11 +18,9 @@ import re from ._binary import o8 -## -# File handler for GIMP's palette format. - class GimpPaletteFile: + """File handler for GIMP's palette format.""" rawmode = "RGB" diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index 20b5fe4c4..f0b4698f3 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -16,6 +16,10 @@ # See the README file for information on usage and redistribution. # + +"""WCK-style drawing interface operations""" + + from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath diff --git a/src/PIL/PaletteFile.py b/src/PIL/PaletteFile.py index 73f1b4b27..6ccaa1f53 100644 --- a/src/PIL/PaletteFile.py +++ b/src/PIL/PaletteFile.py @@ -15,11 +15,9 @@ from ._binary import o8 -## -# File handler for Teragon-style palette files. - class PaletteFile: + """File handler for Teragon-style palette files.""" rawmode = "RGB" diff --git a/src/PIL/PcfFontFile.py b/src/PIL/PcfFontFile.py index c463533cd..f8836ad88 100644 --- a/src/PIL/PcfFontFile.py +++ b/src/PIL/PcfFontFile.py @@ -48,11 +48,8 @@ def sz(s, o): return s[o : s.index(b"\0", o)] -## -# Font file plugin for the X11 PCF format. - - class PcfFontFile(FontFile.FontFile): + """Font file plugin for the X11 PCF format.""" name = "name" diff --git a/src/PIL/TarIO.py b/src/PIL/TarIO.py index ede646453..d108362fc 100644 --- a/src/PIL/TarIO.py +++ b/src/PIL/TarIO.py @@ -18,12 +18,10 @@ import io from . import ContainerIO -## -# A file object that provides read access to a given member of a TAR -# file. - class TarIO(ContainerIO.ContainerIO): + """A file object that provides read access to a given member of a TAR file.""" + def __init__(self, tarfile, file): """ Create file object. diff --git a/src/PIL/WalImageFile.py b/src/PIL/WalImageFile.py index d5a5c8e67..b578d6981 100644 --- a/src/PIL/WalImageFile.py +++ b/src/PIL/WalImageFile.py @@ -12,13 +12,16 @@ # See the README file for information on usage and redistribution. # -# NOTE: This format cannot be automatically recognized, so the reader -# is not registered for use with Image.open(). To open a WAL file, use -# the WalImageFile.open() function instead. +""" +This reader is based on the specification available from: +https://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml +and has been tested with a few sample files found using google. -# This reader is based on the specification available from: -# https://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml -# and has been tested with a few sample files found using google. +.. note:: + This format cannot be automatically recognized, so the reader + is not registered for use with :py:func:`PIL.Image.open()`. + To open a WAL file, use the :py:func:`PIL.WalImageFile.open()` function instead. +""" import builtins @@ -31,7 +34,7 @@ def open(filename): Load texture from a Quake2 WAL texture file. By default, a Quake2 standard palette is attached to the texture. - To override the palette, use the putpalette method. + To override the palette, use the :py:func:`PIL.Image.Image.putpalette()` method. :param filename: WAL file name, or an opened file handle. :returns: An image instance. diff --git a/src/PIL/_binary.py b/src/PIL/_binary.py index 529b8c94b..5564f450d 100644 --- a/src/PIL/_binary.py +++ b/src/PIL/_binary.py @@ -11,6 +11,10 @@ # See the README file for information on usage and redistribution. # + +"""Binary input/output support routines.""" + + from struct import pack, unpack_from From eab2260313625787c2b645f83a7a9d99165ca7af Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 14:39:48 +0200 Subject: [PATCH 004/126] add docs for ImageDraw2 based on ImageDraw, fix ImageDraw links --- docs/PIL.rst | 3 +- docs/reference/ImageDraw.rst | 38 ++++++++++---------- src/PIL/ImageDraw2.py | 70 +++++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/docs/PIL.rst b/docs/PIL.rst index e7939554d..07cacf31f 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -52,13 +52,12 @@ can be found here. :undoc-members: :show-inheritance: -.. intentionally skipped documenting this because it's not documented anywhere - :mod:`ImageDraw2` Module ------------------------ .. automodule:: PIL.ImageDraw2 :members: + :member-order: bysource :undoc-members: :show-inheritance: diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 782b0434b..495a7d117 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -124,7 +124,7 @@ Example: Draw Multiline Text Functions --------- -.. py:class:: PIL.ImageDraw.Draw(im, mode=None) +.. py:method:: Draw(im, mode=None) Creates an object that can be used to draw in the given image. @@ -140,13 +140,13 @@ Functions Methods ------- -.. py:method:: PIL.ImageDraw.ImageDraw.getfont() +.. py:method:: ImageDraw.getfont() Get the current default font. :returns: An image font. -.. py:method:: PIL.ImageDraw.ImageDraw.arc(xy, start, end, fill=None, width=0) +.. py:method:: ImageDraw.arc(xy, start, end, fill=None, width=0) Draws an arc (a portion of a circle outline) between the start and end angles, inside the given bounding box. @@ -162,7 +162,7 @@ Methods .. versionadded:: 5.3.0 -.. py:method:: PIL.ImageDraw.ImageDraw.bitmap(xy, bitmap, fill=None) +.. py:method:: ImageDraw.bitmap(xy, bitmap, fill=None) Draws a bitmap (mask) at the given position, using the current fill color for the non-zero portions. The bitmap should be a valid transparency mask @@ -173,7 +173,7 @@ Methods To paste pixel data into an image, use the :py:meth:`~PIL.Image.Image.paste` method on the image itself. -.. py:method:: PIL.ImageDraw.ImageDraw.chord(xy, start, end, fill=None, outline=None, width=1) +.. py:method:: ImageDraw.chord(xy, start, end, fill=None, outline=None, width=1) Same as :py:meth:`~PIL.ImageDraw.ImageDraw.arc`, but connects the end points with a straight line. @@ -187,7 +187,7 @@ Methods .. versionadded:: 5.3.0 -.. py:method:: PIL.ImageDraw.ImageDraw.ellipse(xy, fill=None, outline=None, width=1) +.. py:method:: ImageDraw.ellipse(xy, fill=None, outline=None, width=1) Draws an ellipse inside the given bounding box. @@ -200,9 +200,9 @@ Methods .. versionadded:: 5.3.0 -.. py:method:: PIL.ImageDraw.ImageDraw.line(xy, fill=None, width=0, joint=None) +.. py:method:: ImageDraw.line(xy, fill=None, width=0, joint=None) - Draws a line between the coordinates in the **xy** list. + Draws a line between the coordinates in the ``xy`` list. :param xy: Sequence of either 2-tuples like ``[(x, y), (x, y), ...]`` or numeric values like ``[x, y, x, y, ...]``. @@ -216,7 +216,7 @@ Methods .. versionadded:: 5.3.0 -.. py:method:: PIL.ImageDraw.ImageDraw.pieslice(xy, start, end, fill=None, outline=None, width=1) +.. py:method:: ImageDraw.pieslice(xy, start, end, fill=None, outline=None, width=1) Same as arc, but also draws straight lines between the end points and the center of the bounding box. @@ -233,7 +233,7 @@ Methods .. versionadded:: 5.3.0 -.. py:method:: PIL.ImageDraw.ImageDraw.point(xy, fill=None) +.. py:method:: ImageDraw.point(xy, fill=None) Draws points (individual pixels) at the given coordinates. @@ -241,7 +241,7 @@ Methods numeric values like ``[x, y, x, y, ...]``. :param fill: Color to use for the point. -.. py:method:: PIL.ImageDraw.ImageDraw.polygon(xy, fill=None, outline=None) +.. py:method:: ImageDraw.polygon(xy, fill=None, outline=None) Draws a polygon. @@ -254,7 +254,7 @@ Methods :param outline: Color to use for the outline. :param fill: Color to use for the fill. -.. py:method:: PIL.ImageDraw.ImageDraw.rectangle(xy, fill=None, outline=None, width=1) +.. py:method:: ImageDraw.rectangle(xy, fill=None, outline=None, width=1) Draws a rectangle. @@ -267,13 +267,13 @@ Methods .. versionadded:: 5.3.0 -.. py:method:: PIL.ImageDraw.ImageDraw.shape(shape, fill=None, outline=None) +.. py:method:: ImageDraw.shape(shape, fill=None, outline=None) .. warning:: This method is experimental. Draw a shape. -.. py:method:: PIL.ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None) +.. py:method:: ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None, stroke_width=0, stroke_fill=None) Draws the string at the given position. @@ -325,7 +325,7 @@ Methods .. versionadded:: 6.2.0 -.. py:method:: PIL.ImageDraw.ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None) +.. py:method:: ImageDraw.multiline_text(xy, text, fill=None, font=None, anchor=None, spacing=4, align="left", direction=None, features=None, language=None) Draws the string at the given position. @@ -362,7 +362,7 @@ Methods .. versionadded:: 6.0.0 -.. py:method:: PIL.ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) +.. py:method:: ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) Return the size of the given string, in pixels. @@ -401,7 +401,7 @@ Methods .. versionadded:: 6.2.0 -.. py:method:: PIL.ImageDraw.ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) +.. py:method:: ImageDraw.multiline_textsize(text, font=None, spacing=4, direction=None, features=None, language=None, stroke_width=0) Return the size of the given string, in pixels. @@ -439,7 +439,7 @@ Methods .. versionadded:: 6.2.0 -.. py:method:: PIL.ImageDraw.getdraw(im=None, hints=None) +.. py:method:: getdraw(im=None, hints=None) .. warning:: This method is experimental. @@ -450,7 +450,7 @@ Methods :param hints: An optional list of hints. :returns: A (drawing context, drawing resource factory) tuple. -.. py:method:: PIL.ImageDraw.floodfill(image, xy, value, border=None, thresh=0) +.. py:method:: floodfill(image, xy, value, border=None, thresh=0) .. warning:: This method is experimental. diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index f0b4698f3..b14b68e3e 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -17,24 +17,34 @@ # -"""WCK-style drawing interface operations""" +""" +(Experimental) WCK-style drawing interface operations + +.. seealso:: :py:mod:`PIL.ImageDraw` +""" from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath class Pen: + """Stores an outline color and width.""" + def __init__(self, color, width=1, opacity=255): self.color = ImageColor.getrgb(color) self.width = width class Brush: + """Stores a fill color""" + def __init__(self, color, opacity=255): self.color = ImageColor.getrgb(color) class Font: + """Stores a TrueType font and color""" + def __init__(self, color, file, size=12): # FIXME: add support for bitmap fonts self.color = ImageColor.getrgb(color) @@ -42,6 +52,10 @@ class Font: class Draw: + """ + (Experimental) WCK-style drawing interface + """ + def __init__(self, image, size=None, color=None): if not hasattr(image, "im"): image = Image.new(image, size, color) @@ -77,35 +91,89 @@ class Draw: getattr(self.draw, op)(xy, fill=fill, outline=outline) def settransform(self, offset): + """Sets a transformation offset.""" (xoffset, yoffset) = offset self.transform = (1, 0, xoffset, 0, 1, yoffset) def arc(self, xy, start, end, *options): + """ + Draws an arc (a portion of a circle outline) between the start and end + angles, inside the given bounding box. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.arc` + """ self.render("arc", xy, start, end, *options) def chord(self, xy, start, end, *options): + """ + Same as :py:meth:`~PIL.ImageDraw2.ImageDraw.arc`, but connects the end points + with a straight line. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.chord` + """ self.render("chord", xy, start, end, *options) def ellipse(self, xy, *options): + """ + Draws an ellipse inside the given bounding box. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.ellipse` + """ self.render("ellipse", xy, *options) def line(self, xy, *options): + """ + Draws a line between the coordinates in the ``xy`` list. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.line` + """ self.render("line", xy, *options) def pieslice(self, xy, start, end, *options): + """ + Same as arc, but also draws straight lines between the end points and the + center of the bounding box. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.pieslice` + """ self.render("pieslice", xy, start, end, *options) def polygon(self, xy, *options): + """ + Draws a polygon. + + The polygon outline consists of straight lines between the given + coordinates, plus a straight line between the last and the first + coordinate. + + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.polygon` + """ self.render("polygon", xy, *options) def rectangle(self, xy, *options): + """ + Draws a rectangle. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.rectangle` + """ self.render("rectangle", xy, *options) def text(self, xy, text, font): + """ + Draws the string at the given position. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.text` + """ if self.transform: xy = ImagePath.Path(xy) xy.transform(self.transform) self.draw.text(xy, text, font=font.font, fill=font.color) def textsize(self, text, font): + """ + Return the size of the given string, in pixels. + + .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize` + """ return self.draw.textsize(text, font=font.font) From eb150c5518ac25fa2e423e6ef471a00ddb1ab44d Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 14:46:14 +0200 Subject: [PATCH 005/126] sort docs index --- docs/reference/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 9f9e7142b..df7a63b04 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -7,8 +7,8 @@ Reference Image ImageChops - ImageColor ImageCms + ImageColor ImageDraw ImageEnhance ImageFile From 255bd0caef8118b909edb2a976caa8385f77c7c3 Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 16:39:23 +0200 Subject: [PATCH 006/126] create docs section Internal Modules --- docs/PIL.rst | 9 ------- docs/reference/internal_design.rst | 2 +- docs/reference/internal_modules.rst | 38 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 docs/reference/internal_modules.rst diff --git a/docs/PIL.rst b/docs/PIL.rst index 07cacf31f..d098e1bb5 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -123,12 +123,3 @@ can be found here. :members: :undoc-members: :show-inheritance: - -:mod:`_binary` Module ---------------------- - -.. automodule:: PIL._binary - :members: - :undoc-members: - :show-inheritance: - diff --git a/docs/reference/internal_design.rst b/docs/reference/internal_design.rst index bbc9050cf..5f911db51 100644 --- a/docs/reference/internal_design.rst +++ b/docs/reference/internal_design.rst @@ -7,4 +7,4 @@ Internal Reference Docs open_files limits block_allocator - + internal_modules diff --git a/docs/reference/internal_modules.rst b/docs/reference/internal_modules.rst new file mode 100644 index 000000000..7a7967d23 --- /dev/null +++ b/docs/reference/internal_modules.rst @@ -0,0 +1,38 @@ +Internal Modules +================ + +:mod:`_binary` Module +--------------------- + +.. automodule:: PIL._binary + :members: + :undoc-members: + :show-inheritance: + +:mod:`_tkinter_finder` Module +----------------------------- + +.. automodule:: PIL._tkinter_finder + :members: + :undoc-members: + :show-inheritance: + +:mod:`_util` Module +------------------- + +.. automodule:: PIL._util + :members: + :undoc-members: + :show-inheritance: + +:mod:`_version` Module +---------------------- + +.. module:: PIL._version + +.. data:: __version__ + :annotation: + :type: str + + This is the master version number for Pillow, + all other uses reference this module. From d4c432dd2f87a6ae0f6f157ca14cf22b32db6b5c Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 16:40:28 +0200 Subject: [PATCH 007/126] add autodocs for UnidentifiedImageError --- docs/PIL.rst | 8 ++++++++ src/PIL/__init__.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/docs/PIL.rst b/docs/PIL.rst index d098e1bb5..222322b0d 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -4,6 +4,14 @@ PIL Package (autodoc of remaining modules) Reference for modules whose documentation has not yet been ported or written can be found here. +:mod:`PIL` Module +------------------------- + +.. py:module:: PIL + +.. autoexception:: UnidentifiedImageError + :show-inheritance: + :mod:`BdfFontFile` Module ------------------------- diff --git a/src/PIL/__init__.py b/src/PIL/__init__.py index 81b87e012..d225ed134 100644 --- a/src/PIL/__init__.py +++ b/src/PIL/__init__.py @@ -132,4 +132,8 @@ _plugins = [ class UnidentifiedImageError(OSError): + """ + Raised in :py:meth:`PIL.Image.open` if an image cannot be opened and identified. + """ + pass From c40b0e54267d148fd6d1bb8523ec0f8fe8e44cf3 Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 17:16:15 +0200 Subject: [PATCH 008/126] fix some docs links --- docs/reference/ExifTags.rst | 6 ++++-- docs/reference/ImageEnhance.rst | 11 ++++++----- docs/reference/ImageStat.rst | 8 ++++---- docs/reference/JpegPresets.rst | 4 ++-- docs/reference/TiffTags.rst | 19 +++++++++++-------- src/PIL/ExifTags.py | 14 ++++++-------- 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/docs/reference/ExifTags.rst b/docs/reference/ExifTags.rst index 9fc7cd13b..39fdab02c 100644 --- a/docs/reference/ExifTags.rst +++ b/docs/reference/ExifTags.rst @@ -7,7 +7,8 @@ The :py:mod:`ExifTags` module exposes two dictionaries which provide constants and clear-text names for various well-known EXIF tags. -.. py:class:: PIL.ExifTags.TAGS +.. py:data:: TAGS + :type: dict The TAG dictionary maps 16-bit integer EXIF tag enumerations to descriptive string names. For instance: @@ -16,7 +17,8 @@ provide constants and clear-text names for various well-known EXIF tags. >>> TAGS[0x010e] 'ImageDescription' -.. py:class:: PIL.ExifTags.GPSTAGS +.. py:data:: GPSTAGS + :type: dict The GPSTAGS dictionary maps 8-bit integer EXIF gps enumerations to descriptive string names. For instance: diff --git a/docs/reference/ImageEnhance.rst b/docs/reference/ImageEnhance.rst index b172054b2..f98d8f780 100644 --- a/docs/reference/ImageEnhance.rst +++ b/docs/reference/ImageEnhance.rst @@ -29,7 +29,8 @@ Classes All enhancement classes implement a common interface, containing a single method: -.. py:class:: PIL.ImageEnhance._Enhance +.. py:class:: _Enhance + .. py:method:: enhance(factor) Returns an enhanced image. @@ -40,7 +41,7 @@ method: etc), and higher values more. There are no restrictions on this value. -.. py:class:: PIL.ImageEnhance.Color(image) +.. py:class:: Color(image) Adjust image color balance. @@ -49,7 +50,7 @@ method: factor of 0.0 gives a black and white image. A factor of 1.0 gives the original image. -.. py:class:: PIL.ImageEnhance.Contrast(image) +.. py:class:: Contrast(image) Adjust image contrast. @@ -57,7 +58,7 @@ method: to the contrast control on a TV set. An enhancement factor of 0.0 gives a solid grey image. A factor of 1.0 gives the original image. -.. py:class:: PIL.ImageEnhance.Brightness(image) +.. py:class:: Brightness(image) Adjust image brightness. @@ -65,7 +66,7 @@ method: enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the original image. -.. py:class:: PIL.ImageEnhance.Sharpness(image) +.. py:class:: Sharpness(image) Adjust image sharpness. diff --git a/docs/reference/ImageStat.rst b/docs/reference/ImageStat.rst index 32f5917c1..e94c24aa4 100644 --- a/docs/reference/ImageStat.rst +++ b/docs/reference/ImageStat.rst @@ -7,7 +7,7 @@ The :py:mod:`ImageStat` module calculates global statistics for an image, or for a region of an image. -.. py:class:: PIL.ImageStat.Stat(image_or_list, mask=None) +.. py:class:: Stat(image_or_list, mask=None) Calculate statistics for the given image. If a mask is included, only the regions covered by that mask are included in the @@ -22,13 +22,13 @@ for a region of an image. .. note:: - This relies on the :py:meth:`~PIL.Image.histogram` method, and + This relies on the :py:meth:`~PIL.Image.Image.histogram` method, and simply returns the low and high bins used. This is correct for images with 8 bits per channel, but fails for other modes such as - ``I`` or ``F``. Instead, use :py:meth:`~PIL.Image.getextrema` to + ``I`` or ``F``. Instead, use :py:meth:`~PIL.Image.Image.getextrema` to return per-band extrema for the image. This is more correct and efficient because, for non-8-bit modes, the histogram method uses - :py:meth:`~PIL.Image.getextrema` to determine the bins used. + :py:meth:`~PIL.Image.Image.getextrema` to determine the bins used. .. py:attribute:: count diff --git a/docs/reference/JpegPresets.rst b/docs/reference/JpegPresets.rst index bf93f891f..0a0914601 100644 --- a/docs/reference/JpegPresets.rst +++ b/docs/reference/JpegPresets.rst @@ -6,6 +6,6 @@ .. automodule:: PIL.JpegPresets .. data:: presets - :annotation: + :type: dict - A dict of all supported presets. + A dictionary of all supported presets. diff --git a/docs/reference/TiffTags.rst b/docs/reference/TiffTags.rst index 3b261625a..4161110bd 100644 --- a/docs/reference/TiffTags.rst +++ b/docs/reference/TiffTags.rst @@ -10,8 +10,8 @@ metadata tag numbers, names, and type information. .. method:: lookup(tag) :param tag: Integer tag number - :returns: Taginfo namedtuple, From the ``TAGS_V2`` info if possible, - otherwise just populating the value and name from ``TAGS``. + :returns: Taginfo namedtuple, From the :py:data:`~PIL.TiffTags.TAGS_V2` info if possible, + otherwise just populating the value and name from :py:data:`~PIL.TiffTags.TAGS`. If the tag is not recognized, "unknown" is returned for the name .. versionadded:: 3.1.0 @@ -22,7 +22,7 @@ metadata tag numbers, names, and type information. :param value: Integer Tag Number :param name: Tag Name - :param type: Integer type from :py:attr:`PIL.TiffTags.TYPES` + :param type: Integer type from :py:data:`PIL.TiffTags.TYPES` :param length: Array length: 0 == variable, 1 == single value, n = fixed :param enum: Dict of name:integer value options for an enumeration @@ -33,15 +33,17 @@ metadata tag numbers, names, and type information. .. versionadded:: 3.0.0 -.. py:attribute:: PIL.TiffTags.TAGS_V2 +.. py:data:: PIL.TiffTags.TAGS_V2 + :type: dict The ``TAGS_V2`` dictionary maps 16-bit integer tag numbers to - :py:class:`PIL.TagTypes.TagInfo` tuples for metadata fields defined in the TIFF + :py:class:`PIL.TiffTags.TagInfo` tuples for metadata fields defined in the TIFF spec. .. versionadded:: 3.0.0 -.. py:attribute:: PIL.TiffTags.TAGS +.. py:data:: PIL.TiffTags.TAGS + :type: dict The ``TAGS`` dictionary maps 16-bit integer TIFF tag number to descriptive string names. For instance: @@ -50,10 +52,11 @@ metadata tag numbers, names, and type information. >>> TAGS[0x010e] 'ImageDescription' - This dictionary contains a superset of the tags in TAGS_V2, common + This dictionary contains a superset of the tags in :py:data:`~PIL.TiffTags.TAGS_V2`, common EXIF tags, and other well known metadata tags. -.. py:attribute:: PIL.TiffTags.TYPES +.. py:data:: PIL.TiffTags.TYPES + :type: dict The ``TYPES`` dictionary maps the TIFF type short integer to a human readable type name. diff --git a/src/PIL/ExifTags.py b/src/PIL/ExifTags.py index cecc3f246..f1c037e51 100644 --- a/src/PIL/ExifTags.py +++ b/src/PIL/ExifTags.py @@ -9,13 +9,11 @@ # See the README file for information on usage and redistribution. # -## -# This module provides constants and clear-text names for various -# well-known EXIF tags. -## +""" +This module provides constants and clear-text names for various +well-known EXIF tags. +""" -## -# Maps EXIF tags to tag names. TAGS = { # possibly incomplete @@ -280,9 +278,8 @@ TAGS = { 0xC74E: "OpcodeList3", 0xC761: "NoiseProfile", } +"""Maps EXIF tags to tag names.""" -## -# Maps EXIF GPS tags to tag names. GPSTAGS = { 0: "GPSVersionID", @@ -318,3 +315,4 @@ GPSTAGS = { 30: "GPSDifferential", 31: "GPSHPositioningError", } +"""Maps EXIF GPS tags to tag names.""" From 12cd02bd2de96bf1b1d6e91b9de5bfe70d5985ca Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 18:21:06 +0200 Subject: [PATCH 009/126] use xfail for failing tests --- .ci/test.sh | 2 +- .github/workflows/test-windows.yml | 2 +- Tests/test_image_resample.py | 14 +++++++------- Tests/test_imagefont.py | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.ci/test.sh b/.ci/test.sh index 516581ff0..b0e65abc4 100755 --- a/.ci/test.sh +++ b/.ci/test.sh @@ -2,7 +2,7 @@ set -e -python -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests +python -m pytest -v -x -ra -W always --cov PIL --cov Tests --cov-report term Tests # Docs if [ "$TRAVIS_PYTHON_VERSION" == "3.8" ] && [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 7ae26b883..1989bc00c 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -113,7 +113,7 @@ jobs: - name: Test Pillow run: | path %GITHUB_WORKSPACE%\\winbuild\\build\\bin;%PATH% - python.exe -m pytest -vx -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests + python.exe -m pytest -vxra -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests shell: cmd - name: Prepare to upload errors diff --git a/Tests/test_image_resample.py b/Tests/test_image_resample.py index 764a3ca49..35eae128b 100644 --- a/Tests/test_image_resample.py +++ b/Tests/test_image_resample.py @@ -218,7 +218,7 @@ class TestImagingCoreResampleAccuracy: assert_image_equal(im, ref) -class CoreResampleConsistencyTest: +class TestCoreResampleConsistency: def make_case(self, mode, fill): im = Image.new(mode, (512, 9), fill) return im.resize((9, 512), Image.LANCZOS), im.load()[0, 0] @@ -253,7 +253,7 @@ class CoreResampleConsistencyTest: self.run_case(self.make_case("F", 1.192093e-07)) -class CoreResampleAlphaCorrectTest: +class TestCoreResampleAlphaCorrect: def make_levels_case(self, mode): i = Image.new(mode, (256, 16)) px = i.load() @@ -274,7 +274,7 @@ class CoreResampleAlphaCorrectTest: len(used_colors), y ) - @pytest.mark.skip("Current implementation isn't precise enough") + @pytest.mark.xfail(reason="Current implementation isn't precise enough") def test_levels_rgba(self): case = self.make_levels_case("RGBA") self.run_levels_case(case.resize((512, 32), Image.BOX)) @@ -283,7 +283,7 @@ class CoreResampleAlphaCorrectTest: self.run_levels_case(case.resize((512, 32), Image.BICUBIC)) self.run_levels_case(case.resize((512, 32), Image.LANCZOS)) - @pytest.mark.skip("Current implementation isn't precise enough") + @pytest.mark.xfail(reason="Current implementation isn't precise enough") def test_levels_la(self): case = self.make_levels_case("LA") self.run_levels_case(case.resize((512, 32), Image.BOX)) @@ -329,7 +329,7 @@ class CoreResampleAlphaCorrectTest: self.run_dirty_case(case.resize((20, 20), Image.LANCZOS), (255,)) -class CoreResamplePassesTest: +class TestCoreResamplePasses: @contextmanager def count(self, diff): count = Image.core.get_stats()["new_count"] @@ -372,7 +372,7 @@ class CoreResamplePassesTest: assert_image_similar(with_box, cropped, 0.1) -class CoreResampleCoefficientsTest: +class TestCoreResampleCoefficients: def test_reduce(self): test_color = 254 @@ -401,7 +401,7 @@ class CoreResampleCoefficientsTest: assert histogram[0x100 * 3 + 0xFF] == 0x10000 -class CoreResampleBoxTest: +class TestCoreResampleBox: def test_wrong_arguments(self): im = hopper() for resample in ( diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index bd79f08e3..65d749b14 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -443,7 +443,7 @@ class TestImageFont: with pytest.raises(UnicodeEncodeError): font.getsize("’") - @pytest.mark.skipif(is_pypy(), reason="failing on PyPy") + @pytest.mark.xfail(is_pypy(), reason="failing on PyPy with Raqm") def test_unicode_extended(self): # issue #3777 text = "A\u278A\U0001F12B" From fc92f56382d9335b942881e84c5a2645e5304e5c Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 20:08:27 +0200 Subject: [PATCH 010/126] replace skip_known_bad_test with xfail --- Tests/helper.py | 6 ------ Tests/test_file_palm.py | 11 +++-------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Tests/helper.py b/Tests/helper.py index 7e8abc9c9..cdc5f4efe 100644 --- a/Tests/helper.py +++ b/Tests/helper.py @@ -165,12 +165,6 @@ def assert_tuple_approx_equal(actuals, targets, threshold, msg): assert value, msg + ": " + repr(actuals) + " != " + repr(targets) -def skip_known_bad_test(msg=None): - # Skip if PILLOW_RUN_KNOWN_BAD is not true in the environment. - if not os.environ.get("PILLOW_RUN_KNOWN_BAD", False): - pytest.skip(msg or "Known bad test") - - def skip_unless_feature(feature): reason = "%s not available" % feature return pytest.mark.skipif(not features.check(feature), reason=reason) diff --git a/Tests/test_file_palm.py b/Tests/test_file_palm.py index 38f6dccd9..25d194b62 100644 --- a/Tests/test_file_palm.py +++ b/Tests/test_file_palm.py @@ -2,15 +2,10 @@ import os.path import subprocess import pytest + from PIL import Image -from .helper import ( - IMCONVERT, - assert_image_equal, - hopper, - imagemagick_available, - skip_known_bad_test, -) +from .helper import IMCONVERT, assert_image_equal, hopper, imagemagick_available _roundtrip = imagemagick_available() @@ -62,13 +57,13 @@ def test_monochrome(tmp_path): roundtrip(tmp_path, mode) +@pytest.mark.xfail(reason="Palm P image is wrong") def test_p_mode(tmp_path): # Arrange mode = "P" # Act / Assert helper_save_as_palm(tmp_path, mode) - skip_known_bad_test("Palm P image is wrong") roundtrip(tmp_path, mode) From dc41a4ec21990ea45fc12e5b099a61c974ed8db3 Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 14 Jun 2020 20:16:00 +0200 Subject: [PATCH 011/126] use skip_unless_feature in more tests --- Tests/test_image_reduce.py | 6 ++---- Tests/test_imagegrab.py | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Tests/test_image_reduce.py b/Tests/test_image_reduce.py index 353d0def0..0f92b87f8 100644 --- a/Tests/test_image_reduce.py +++ b/Tests/test_image_reduce.py @@ -1,7 +1,7 @@ import pytest from PIL import Image, ImageMath, ImageMode -from .helper import convert_to_comparable +from .helper import convert_to_comparable, skip_unless_feature codecs = dir(Image.core) @@ -254,9 +254,7 @@ def test_mode_F(): compare_reduce_with_box(im, factor) -@pytest.mark.skipif( - "jpeg2k_decoder" not in codecs, reason="JPEG 2000 support not available" -) +@skip_unless_feature("jpg_2000") def test_jpeg2k(): with Image.open("Tests/images/test-card-lossless.jp2") as im: assert im.reduce(2).size == (320, 240) diff --git a/Tests/test_imagegrab.py b/Tests/test_imagegrab.py index 82e746fda..3e1cfa87f 100644 --- a/Tests/test_imagegrab.py +++ b/Tests/test_imagegrab.py @@ -4,7 +4,7 @@ import sys import pytest from PIL import Image, ImageGrab -from .helper import assert_image +from .helper import assert_image, skip_unless_feature class TestImageGrab: @@ -22,7 +22,7 @@ class TestImageGrab: im = ImageGrab.grab(bbox=(10, 20, 50, 80)) assert_image(im, im.mode, (40, 60)) - @pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB") + @skip_unless_feature("xcb") def test_grab_x11(self): try: if sys.platform not in ("win32", "darwin"): @@ -45,7 +45,7 @@ class TestImageGrab: ImageGrab.grab(xdisplay="") assert str(e.value).startswith("Pillow was built without XCB support") - @pytest.mark.skipif(not Image.core.HAVE_XCB, reason="requires XCB") + @skip_unless_feature("xcb") def test_grab_invalid_xdisplay(self): with pytest.raises(OSError) as e: ImageGrab.grab(xdisplay="error.test:0.0") From e2e8db4fe8b7a34f06bde86462dc6e2b9ef2a05f Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 15 Jun 2020 10:16:18 +0300 Subject: [PATCH 012/126] Fix isort --- Tests/test_file_palm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/test_file_palm.py b/Tests/test_file_palm.py index 25d194b62..e7afeef23 100644 --- a/Tests/test_file_palm.py +++ b/Tests/test_file_palm.py @@ -2,7 +2,6 @@ import os.path import subprocess import pytest - from PIL import Image from .helper import IMCONVERT, assert_image_equal, hopper, imagemagick_available From 703a9a0eb5a3bc4328d49e132b6ee1388e35dc16 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 15 Jun 2020 14:15:53 +0200 Subject: [PATCH 013/126] add pytest -ra into setup.cfg --- .ci/test.sh | 2 +- .github/workflows/test-windows.yml | 2 +- setup.cfg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.ci/test.sh b/.ci/test.sh index b0e65abc4..516581ff0 100755 --- a/.ci/test.sh +++ b/.ci/test.sh @@ -2,7 +2,7 @@ set -e -python -m pytest -v -x -ra -W always --cov PIL --cov Tests --cov-report term Tests +python -m pytest -v -x -W always --cov PIL --cov Tests --cov-report term Tests # Docs if [ "$TRAVIS_PYTHON_VERSION" == "3.8" ] && [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 1989bc00c..7ae26b883 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -113,7 +113,7 @@ jobs: - name: Test Pillow run: | path %GITHUB_WORKSPACE%\\winbuild\\build\\bin;%PATH% - python.exe -m pytest -vxra -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests + python.exe -m pytest -vx -W always --cov PIL --cov Tests --cov-report term --cov-report xml Tests shell: cmd - name: Prepare to upload errors diff --git a/setup.cfg b/setup.cfg index 30843b847..5593c29b4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,5 @@ line_length = 88 multi_line_output = 3 [tool:pytest] -addopts = -rs +addopts = -ra testpaths = Tests From 2f3deef8c56d7b9199dba3881f09445085328ab9 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 20 Jun 2020 13:10:10 +0200 Subject: [PATCH 014/126] update wording for #4706 --- src/PIL/ImageShow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index c833ce8e6..57b7dcac7 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -29,8 +29,8 @@ def register(viewer, order=1): :param viewer: The viewer to be registered. :param order: - A negative integer to prepend this viewer to the list, - or a positive integer to append it. + Zero or a negative integer to prepend this viewer to the list, + a positive integer to append it. """ try: if issubclass(viewer, Viewer): From d728cd58754f6701ffb3487609eabe39602238f5 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 26 May 2020 16:38:38 +1000 Subject: [PATCH 015/126] Allow libtiff to write COLORMAP tag --- Tests/test_file_libtiff.py | 13 +++++++++++++ src/PIL/TiffImagePlugin.py | 1 - src/PIL/TiffTags.py | 1 - src/encode.c | 23 +++++++++++++++++++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 855a9ab3a..9c18eca26 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -203,6 +203,7 @@ class TestFileLibTiff(LibTiffTestCase): del core_items[tag] except KeyError: pass + del core_items[320] # colormap is special, tested below # Type codes: # 2: "ascii", @@ -479,6 +480,18 @@ class TestFileLibTiff(LibTiffTestCase): with Image.open(out) as im2: assert_image_equal(im, im2) + def test_palette_save(self, tmp_path): + im = hopper("P") + out = str(tmp_path / "temp.tif") + + TiffImagePlugin.WRITE_LIBTIFF = True + im.save(out) + TiffImagePlugin.WRITE_LIBTIFF = False + + with Image.open(out) as reloaded: + # colormap/palette tag + assert len(reloaded.tag_v2[320]) == 768 + def xtest_bw_compression_w_rgb(self, tmp_path): """ This test passes, but when running all tests causes a failure due to output on stderr from the error thrown by libtiff. We need to diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index ee183ccba..6fc8cc8cf 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1524,7 +1524,6 @@ def _save(im, fp, filename): # BITSPERSAMPLE, etc), passing arrays with a different length will result in # segfaults. Block these tags until we add extra validation. blocklist = [ - COLORMAP, REFERENCEBLACKWHITE, SAMPLEFORMAT, STRIPBYTECOUNTS, diff --git a/src/PIL/TiffTags.py b/src/PIL/TiffTags.py index 6cc9ff7f3..e1c1b701b 100644 --- a/src/PIL/TiffTags.py +++ b/src/PIL/TiffTags.py @@ -483,7 +483,6 @@ LIBTIFF_CORE = { 65537, } -LIBTIFF_CORE.remove(320) # Array of short, crashes LIBTIFF_CORE.remove(301) # Array of short, crashes LIBTIFF_CORE.remove(532) # Array of long, crashes diff --git a/src/encode.c b/src/encode.c index 03a39448d..d64f47d2b 100644 --- a/src/encode.c +++ b/src/encode.c @@ -671,7 +671,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) // This list also exists in TiffTags.py const int core_tags[] = { 256, 257, 258, 259, 262, 263, 266, 269, 274, 277, 278, 280, 281, 340, - 341, 282, 283, 284, 286, 287, 296, 297, 321, 338, 32995, 32998, 32996, + 341, 282, 283, 284, 286, 287, 296, 297, 320, 321, 338, 32995, 32998, 32996, 339, 32997, 330, 531, 530, 65537 }; @@ -801,7 +801,26 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) TRACE(("Setting from Tuple: %d \n", key_int)); len = PyTuple_Size(value); - if (type == TIFF_SHORT) { + if (key_int == TIFFTAG_COLORMAP) { + int stride = 256; + if (len != 768) { + PyErr_SetString(PyExc_ValueError, "Requiring 768 items for for Colormap"); + return NULL; + } + UINT16 *av; + /* malloc check ok, calloc checks for overflow */ + av = calloc(len, sizeof(UINT16)); + if (av) { + for (i=0;istate, (ttag_t) key_int, + av, + av + stride, + av + stride * 2); + free(av); + } + } else if (type == TIFF_SHORT) { UINT16 *av; /* malloc check ok, calloc checks for overflow */ av = calloc(len, sizeof(UINT16)); From 2f0d4308076d9c59662c563d9024382b3972e1cf Mon Sep 17 00:00:00 2001 From: Ram Rachum Date: Sun, 21 Jun 2020 13:13:35 +0300 Subject: [PATCH 016/126] Fix exception causes all over the codebase --- docs/example/DdsImagePlugin.py | 8 +++---- src/PIL/BlpImagePlugin.py | 4 ++-- src/PIL/BmpImagePlugin.py | 4 ++-- src/PIL/EpsImagePlugin.py | 4 ++-- src/PIL/FpxImagePlugin.py | 4 ++-- src/PIL/GdImageFile.py | 4 ++-- src/PIL/GifImagePlugin.py | 4 ++-- src/PIL/ImImagePlugin.py | 8 +++---- src/PIL/Image.py | 40 +++++++++++++++++----------------- src/PIL/ImageCms.py | 32 +++++++++++++-------------- src/PIL/ImageFile.py | 10 ++++----- src/PIL/ImageFilter.py | 4 ++-- src/PIL/ImageFont.py | 12 +++++----- src/PIL/ImageMath.py | 8 +++---- src/PIL/ImagePalette.py | 4 ++-- src/PIL/ImageSequence.py | 8 +++---- src/PIL/IptcImagePlugin.py | 4 ++-- src/PIL/JpegImagePlugin.py | 24 ++++++++++---------- src/PIL/MicImagePlugin.py | 8 +++---- src/PIL/MspImagePlugin.py | 8 +++---- src/PIL/PcxImagePlugin.py | 4 ++-- src/PIL/PngImagePlugin.py | 18 ++++++++------- src/PIL/PsdImagePlugin.py | 4 ++-- src/PIL/SpiderImagePlugin.py | 4 ++-- src/PIL/TgaImagePlugin.py | 4 ++-- src/PIL/TiffImagePlugin.py | 12 +++++----- 26 files changed, 125 insertions(+), 123 deletions(-) diff --git a/docs/example/DdsImagePlugin.py b/docs/example/DdsImagePlugin.py index 45f63f164..1e36f093a 100644 --- a/docs/example/DdsImagePlugin.py +++ b/docs/example/DdsImagePlugin.py @@ -249,8 +249,8 @@ class DXT1Decoder(ImageFile.PyDecoder): def decode(self, buffer): try: self.set_as_raw(_dxt1(self.fd, self.state.xsize, self.state.ysize)) - except struct.error: - raise OSError("Truncated DDS file") + except struct.error as e: + raise OSError("Truncated DDS file") from e return 0, 0 @@ -260,8 +260,8 @@ class DXT5Decoder(ImageFile.PyDecoder): def decode(self, buffer): try: self.set_as_raw(_dxt5(self.fd, self.state.xsize, self.state.ysize)) - except struct.error: - raise OSError("Truncated DDS file") + except struct.error as e: + raise OSError("Truncated DDS file") from e return 0, 0 diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index 5ccba37db..cb8a08e20 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -282,8 +282,8 @@ class _BLPBaseDecoder(ImageFile.PyDecoder): self.magic = self.fd.read(4) self._read_blp_header() self._load() - except struct.error: - raise OSError("Truncated Blp file") + except struct.error as e: + raise OSError("Truncated Blp file") from e return 0, 0 def _read_palette(self): diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index 85e2350c5..e87f7b95e 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -304,8 +304,8 @@ def _dib_save(im, fp, filename): def _save(im, fp, filename, bitmap_header=True): try: rawmode, bits, colors = SAVE[im.mode] - except KeyError: - raise OSError("cannot write mode %s as BMP" % im.mode) + except KeyError as e: + raise OSError("cannot write mode %s as BMP" % im.mode) from e info = im.encoderinfo diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index e27a57671..652dc489a 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -231,8 +231,8 @@ class EpsImageFile(ImageFile.ImageFile): try: m = split.match(s) - except re.error: - raise SyntaxError("not an EPS file") + except re.error as e: + raise SyntaxError("not an EPS file") from e if m: k, v = m.group(1, 2) diff --git a/src/PIL/FpxImagePlugin.py b/src/PIL/FpxImagePlugin.py index 81501e244..bbee9e24d 100644 --- a/src/PIL/FpxImagePlugin.py +++ b/src/PIL/FpxImagePlugin.py @@ -59,8 +59,8 @@ class FpxImageFile(ImageFile.ImageFile): try: self.ole = olefile.OleFileIO(self.fp) - except OSError: - raise SyntaxError("not an FPX file; invalid OLE file") + except OSError as e: + raise SyntaxError("not an FPX file; invalid OLE file") from e if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B": raise SyntaxError("not an FPX file; bad root CLSID") diff --git a/src/PIL/GdImageFile.py b/src/PIL/GdImageFile.py index b3ab01a4e..9ee373868 100644 --- a/src/PIL/GdImageFile.py +++ b/src/PIL/GdImageFile.py @@ -81,5 +81,5 @@ def open(fp, mode="r"): try: return GdImageFile(fp) - except SyntaxError: - raise UnidentifiedImageError("cannot identify this image file") + except SyntaxError as e: + raise UnidentifiedImageError("cannot identify this image file") from e diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 9d360beae..ac214bb29 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -130,9 +130,9 @@ class GifImageFile(ImageFile.ImageFile): for f in range(self.__frame + 1, frame + 1): try: self._seek(f) - except EOFError: + except EOFError as e: self.seek(last_frame) - raise EOFError("no more images in GIF file") + raise EOFError("no more images in GIF file") from e def _seek(self, frame): diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index 8b03f35da..d940899b0 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -163,8 +163,8 @@ class ImImageFile(ImageFile.ImageFile): try: m = split.match(s) - except re.error: - raise SyntaxError("not an IM file") + except re.error as e: + raise SyntaxError("not an IM file") from e if m: @@ -341,8 +341,8 @@ def _save(im, fp, filename): try: image_type, rawmode = SAVE[im.mode] - except KeyError: - raise ValueError("Cannot save %s images as IM" % im.mode) + except KeyError as e: + raise ValueError("Cannot save %s images as IM" % im.mode) from e frames = im.encoderinfo.get("frames", 1) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 9d94bce0e..210a0ff5e 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -434,8 +434,8 @@ def _getdecoder(mode, decoder_name, args, extra=()): try: # get decoder decoder = getattr(core, decoder_name + "_decoder") - except AttributeError: - raise OSError("decoder %s not available" % decoder_name) + except AttributeError as e: + raise OSError("decoder %s not available" % decoder_name) from e return decoder(mode, *args + extra) @@ -457,8 +457,8 @@ def _getencoder(mode, encoder_name, args, extra=()): try: # get encoder encoder = getattr(core, encoder_name + "_encoder") - except AttributeError: - raise OSError("encoder %s not available" % encoder_name) + except AttributeError as e: + raise OSError("encoder %s not available" % encoder_name) from e return encoder(mode, *args + extra) @@ -971,10 +971,10 @@ class Image: if isinstance(t, tuple): try: t = trns_im.palette.getcolor(t) - except Exception: + except Exception as e: raise ValueError( "Couldn't allocate a palette color for transparency" - ) + ) from e trns_im.putpixel((0, 0), t) if mode in ("L", "RGB"): @@ -1027,8 +1027,8 @@ class Image: # normalize source image and try again im = self.im.convert(getmodebase(self.mode)) im = im.convert(mode, dither) - except KeyError: - raise ValueError("illegal conversion") + except KeyError as e: + raise ValueError("illegal conversion") from e new_im = self._new(im) if delete_trns: @@ -1625,16 +1625,16 @@ class Image: mode = getmodebase(self.mode) + "A" try: self.im.setmode(mode) - except (AttributeError, ValueError): + except (AttributeError, ValueError) as e: # do things the hard way im = self.im.convert(mode) if im.mode not in ("LA", "PA", "RGBA"): - raise ValueError # sanity check + raise ValueError from e # sanity check self.im = im self.pyaccess = None self.mode = self.im.mode - except (KeyError, ValueError): - raise ValueError("illegal image mode") + except (KeyError, ValueError) as e: + raise ValueError("illegal image mode") from e if self.mode in ("LA", "PA"): band = 1 @@ -2136,8 +2136,8 @@ class Image: init() try: format = EXTENSION[ext] - except KeyError: - raise ValueError("unknown file extension: {}".format(ext)) + except KeyError as e: + raise ValueError("unknown file extension: {}".format(ext)) from e if format.upper() not in SAVE: init() @@ -2238,8 +2238,8 @@ class Image: if isinstance(channel, str): try: channel = self.getbands().index(channel) - except ValueError: - raise ValueError('The image has no channel "{}"'.format(channel)) + except ValueError as e: + raise ValueError('The image has no channel "{}"'.format(channel)) from e return self._new(self.im.getband(channel)) @@ -2736,12 +2736,12 @@ def fromarray(obj, mode=None): if mode is None: try: typekey = (1, 1) + shape[2:], arr["typestr"] - except KeyError: - raise TypeError("Cannot handle this data type") + except KeyError as e: + raise TypeError("Cannot handle this data type") from e try: mode, rawmode = _fromarray_typemap[typekey] - except KeyError: - raise TypeError("Cannot handle this data type: %s, %s" % typekey) + except KeyError as e: + raise TypeError("Cannot handle this data type: %s, %s" % typekey) from e else: rawmode = mode if mode in ["1", "L", "I", "P", "F"]: diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index 723e7ceb7..8b97c19a1 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -369,7 +369,7 @@ def profileToProfile( else: imOut = transform.apply(im) except (OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v return imOut @@ -393,7 +393,7 @@ def getOpenProfile(profileFilename): try: return ImageCmsProfile(profileFilename) except (OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def buildTransform( @@ -474,7 +474,7 @@ def buildTransform( inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags ) except (OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def buildProofTransform( @@ -585,7 +585,7 @@ def buildProofTransform( flags, ) except (OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v buildTransformFromOpenProfiles = buildTransform @@ -640,7 +640,7 @@ def applyTransform(im, transform, inPlace=False): else: imOut = transform.apply(im) except (TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v return imOut @@ -682,15 +682,15 @@ def createProfile(colorSpace, colorTemp=-1): if colorSpace == "LAB": try: colorTemp = float(colorTemp) - except (TypeError, ValueError): + except (TypeError, ValueError) as e: raise PyCMSError( 'Color temperature must be numeric, "%s" not valid' % colorTemp - ) + ) from e try: return core.createProfile(colorSpace, colorTemp) except (TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getProfileName(profile): @@ -732,7 +732,7 @@ def getProfileName(profile): return "{} - {}\n".format(model, manufacturer) except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getProfileInfo(profile): @@ -772,7 +772,7 @@ def getProfileInfo(profile): return "\r\n\r\n".join(arr) + "\r\n\r\n" except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getProfileCopyright(profile): @@ -800,7 +800,7 @@ def getProfileCopyright(profile): profile = ImageCmsProfile(profile) return (profile.profile.copyright or "") + "\n" except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getProfileManufacturer(profile): @@ -828,7 +828,7 @@ def getProfileManufacturer(profile): profile = ImageCmsProfile(profile) return (profile.profile.manufacturer or "") + "\n" except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getProfileModel(profile): @@ -857,7 +857,7 @@ def getProfileModel(profile): profile = ImageCmsProfile(profile) return (profile.profile.model or "") + "\n" except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getProfileDescription(profile): @@ -886,7 +886,7 @@ def getProfileDescription(profile): profile = ImageCmsProfile(profile) return (profile.profile.profile_description or "") + "\n" except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def getDefaultIntent(profile): @@ -925,7 +925,7 @@ def getDefaultIntent(profile): profile = ImageCmsProfile(profile) return profile.profile.rendering_intent except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def isIntentSupported(profile, intent, direction): @@ -976,7 +976,7 @@ def isIntentSupported(profile, intent, direction): else: return -1 except (AttributeError, OSError, TypeError, ValueError) as v: - raise PyCMSError(v) + raise PyCMSError(v) from v def versions(): diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 9a780b4e0..9c9e89e3f 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -122,7 +122,7 @@ class ImageFile(Image.Image): EOFError, # got header but not the first frame struct.error, ) as v: - raise SyntaxError(v) + raise SyntaxError(v) from v if not self.mode or self.size[0] <= 0: raise SyntaxError("not identified by this driver") @@ -241,12 +241,12 @@ class ImageFile(Image.Image): while True: try: s = read(self.decodermaxblock) - except (IndexError, struct.error): + except (IndexError, struct.error) as e: # truncated png/gif if LOAD_TRUNCATED_IMAGES: break else: - raise OSError("image file is truncated") + raise OSError("image file is truncated") from e if not s: # truncated jpeg if LOAD_TRUNCATED_IMAGES: @@ -505,7 +505,7 @@ def _save(im, fp, tile, bufsize=0): try: fh = fp.fileno() fp.flush() - except (AttributeError, io.UnsupportedOperation): + except (AttributeError, io.UnsupportedOperation) as e: # compress to Python file-compatible object for e, b, o, a in tile: e = Image._getencoder(im.mode, e, a, im.encoderconfig) @@ -522,7 +522,7 @@ def _save(im, fp, tile, bufsize=0): if s: break if s < 0: - raise OSError("encoder error %d when writing image file" % s) + raise OSError("encoder error %d when writing image file" % s) from e e.cleanup() else: # slight speedup: compress to real file object diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 6b0f5eb37..3e61a6ca1 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -411,10 +411,10 @@ class Color3DLUT(MultibandFilter): def _check_size(size): try: _, _, _ = size - except ValueError: + except ValueError as e: raise ValueError( "Size should be either an integer or a tuple of three integers." - ) + ) from e except TypeError: size = (size, size, size) size = [int(x) for x in size] diff --git a/src/PIL/ImageFont.py b/src/PIL/ImageFont.py index 79c161713..6b7368c1b 100644 --- a/src/PIL/ImageFont.py +++ b/src/PIL/ImageFont.py @@ -503,8 +503,8 @@ class FreeTypeFont: """ try: names = self.font.getvarnames() - except AttributeError: - raise NotImplementedError("FreeType 2.9.1 or greater is required") + except AttributeError as e: + raise NotImplementedError("FreeType 2.9.1 or greater is required") from e return [name.replace(b"\x00", b"") for name in names] def set_variation_by_name(self, name): @@ -533,8 +533,8 @@ class FreeTypeFont: """ try: axes = self.font.getvaraxes() - except AttributeError: - raise NotImplementedError("FreeType 2.9.1 or greater is required") + except AttributeError as e: + raise NotImplementedError("FreeType 2.9.1 or greater is required") from e for axis in axes: axis["name"] = axis["name"].replace(b"\x00", b"") return axes @@ -546,8 +546,8 @@ class FreeTypeFont: """ try: self.font.setvaraxes(axes) - except AttributeError: - raise NotImplementedError("FreeType 2.9.1 or greater is required") + except AttributeError as e: + raise NotImplementedError("FreeType 2.9.1 or greater is required") from e class TransposedFont: diff --git a/src/PIL/ImageMath.py b/src/PIL/ImageMath.py index adbb94000..9a2d0b78e 100644 --- a/src/PIL/ImageMath.py +++ b/src/PIL/ImageMath.py @@ -57,8 +57,8 @@ class _Operand: im1.load() try: op = getattr(_imagingmath, op + "_" + im1.mode) - except AttributeError: - raise TypeError("bad operand type for '%s'" % op) + except AttributeError as e: + raise TypeError("bad operand type for '%s'" % op) from e _imagingmath.unop(op, out.im.id, im1.im.id) else: # binary operation @@ -85,8 +85,8 @@ class _Operand: im2.load() try: op = getattr(_imagingmath, op + "_" + im1.mode) - except AttributeError: - raise TypeError("bad operand type for '%s'" % op) + except AttributeError as e: + raise TypeError("bad operand type for '%s'" % op) from e _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id) return _Operand(out) diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py index e0d439c98..5dba6176f 100644 --- a/src/PIL/ImagePalette.py +++ b/src/PIL/ImagePalette.py @@ -97,13 +97,13 @@ class ImagePalette: if isinstance(color, tuple): try: return self.colors[color] - except KeyError: + except KeyError as e: # allocate new color slot if isinstance(self.palette, bytes): self.palette = bytearray(self.palette) index = len(self.colors) if index >= 256: - raise ValueError("cannot allocate more than 256 colors") + raise ValueError("cannot allocate more than 256 colors") from e self.colors[color] = index self.palette[index] = color[0] self.palette[index + 256] = color[1] diff --git a/src/PIL/ImageSequence.py b/src/PIL/ImageSequence.py index 4e9f5c210..9df910a43 100644 --- a/src/PIL/ImageSequence.py +++ b/src/PIL/ImageSequence.py @@ -38,8 +38,8 @@ class Iterator: try: self.im.seek(ix) return self.im - except EOFError: - raise IndexError # end of sequence + except EOFError as e: + raise IndexError from e # end of sequence def __iter__(self): return self @@ -49,8 +49,8 @@ class Iterator: self.im.seek(self.position) self.position += 1 return self.im - except EOFError: - raise StopIteration + except EOFError as e: + raise StopIteration from e def all_frames(im, func=None): diff --git a/src/PIL/IptcImagePlugin.py b/src/PIL/IptcImagePlugin.py index b2f976dda..75e7b5a2a 100644 --- a/src/PIL/IptcImagePlugin.py +++ b/src/PIL/IptcImagePlugin.py @@ -118,8 +118,8 @@ class IptcImageFile(ImageFile.ImageFile): # compression try: compression = COMPRESSION[self.getint((3, 120))] - except KeyError: - raise OSError("Unknown IPTC image compression") + except KeyError as e: + raise OSError("Unknown IPTC image compression") from e # tile if tag == (8, 10): diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index 89e70f0e9..449d9cde7 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -503,13 +503,13 @@ def _getmp(self): file_contents.seek(info.next) info.load(file_contents) mp = dict(info) - except Exception: - raise SyntaxError("malformed MP Index (unreadable directory)") + except Exception as e: + raise SyntaxError("malformed MP Index (unreadable directory)") from e # it's an error not to have a number of images try: quant = mp[0xB001] - except KeyError: - raise SyntaxError("malformed MP Index (no number of images)") + except KeyError as e: + raise SyntaxError("malformed MP Index (no number of images)") from e # get MP entries mpentries = [] try: @@ -545,8 +545,8 @@ def _getmp(self): mpentry["Attribute"] = mpentryattr mpentries.append(mpentry) mp[0xB002] = mpentries - except KeyError: - raise SyntaxError("malformed MP Index (bad MP Entry)") + except KeyError as e: + raise SyntaxError("malformed MP Index (bad MP Entry)") from e # Next we should try and parse the individual image unique ID list; # we don't because I've never seen this actually used in a real MPO # file and so can't test it. @@ -610,8 +610,8 @@ def _save(im, fp, filename): try: rawmode = RAWMODE[im.mode] - except KeyError: - raise OSError("cannot write mode %s as JPEG" % im.mode) + except KeyError as e: + raise OSError("cannot write mode %s as JPEG" % im.mode) from e info = im.encoderinfo @@ -663,8 +663,8 @@ def _save(im, fp, filename): for line in qtables.splitlines() for num in line.split("#", 1)[0].split() ] - except ValueError: - raise ValueError("Invalid quantization table") + except ValueError as e: + raise ValueError("Invalid quantization table") from e else: qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)] if isinstance(qtables, (tuple, list, dict)): @@ -679,8 +679,8 @@ def _save(im, fp, filename): if len(table) != 64: raise TypeError table = array.array("B", table) - except TypeError: - raise ValueError("Invalid quantization table") + except TypeError as e: + raise ValueError("Invalid quantization table") from e else: qtables[idx] = list(table) return qtables diff --git a/src/PIL/MicImagePlugin.py b/src/PIL/MicImagePlugin.py index 1d7af7c7a..2aed26030 100644 --- a/src/PIL/MicImagePlugin.py +++ b/src/PIL/MicImagePlugin.py @@ -46,8 +46,8 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): try: self.ole = olefile.OleFileIO(self.fp) - except OSError: - raise SyntaxError("not an MIC file; invalid OLE file") + except OSError as e: + raise SyntaxError("not an MIC file; invalid OLE file") from e # find ACI subfiles with Image members (maybe not the # best way to identify MIC files, but what the... ;-) @@ -77,8 +77,8 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): return try: filename = self.images[frame] - except IndexError: - raise EOFError("no such frame") + except IndexError as e: + raise EOFError("no such frame") from e self.fp = self.ole.openstream(filename) diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index 2b2937ecf..a729e7b49 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -116,8 +116,8 @@ class MspDecoder(ImageFile.PyDecoder): rowmap = struct.unpack_from( "<%dH" % (self.state.ysize), self.fd.read(self.state.ysize * 2) ) - except struct.error: - raise OSError("Truncated MSP file in row map") + except struct.error as e: + raise OSError("Truncated MSP file in row map") from e for x, rowlen in enumerate(rowmap): try: @@ -142,8 +142,8 @@ class MspDecoder(ImageFile.PyDecoder): img.write(row[idx : idx + runcount]) idx += runcount - except struct.error: - raise OSError("Corrupted MSP file in row %d" % x) + except struct.error as e: + raise OSError("Corrupted MSP file in row %d" % x) from e self.set_as_raw(img.getvalue(), ("1", 0, 1)) diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index 6cf10deb3..f7ae3bf70 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -131,8 +131,8 @@ def _save(im, fp, filename): try: version, bits, planes, rawmode = SAVE[im.mode] - except KeyError: - raise ValueError("Cannot save %s images as PCX" % im.mode) + except KeyError as e: + raise ValueError("Cannot save %s images as PCX" % im.mode) from e # bytes per plane stride = (im.size[0] * bits + 7) // 8 diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index f62bf8542..025e4ec26 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -168,8 +168,10 @@ class ChunkStream: crc2 = i32(self.fp.read(4)) if crc1 != crc2: raise SyntaxError("broken PNG file (bad header checksum in %r)" % cid) - except struct.error: - raise SyntaxError("broken PNG file (incomplete checksum in %r)" % cid) + except struct.error as e: + raise SyntaxError( + "broken PNG file (incomplete checksum in %r)" % cid + ) from e def crc_skip(self, cid, data): """Read checksum. Used if the C module is not present""" @@ -186,8 +188,8 @@ class ChunkStream: while True: try: cid, pos, length = self.read() - except struct.error: - raise OSError("truncated PNG file") + except struct.error as e: + raise OSError("truncated PNG file") from e if cid == endchunk: break @@ -737,9 +739,9 @@ class PngImageFile(ImageFile.ImageFile): for f in range(self.__frame + 1, frame + 1): try: self._seek(f) - except EOFError: + except EOFError as e: self.seek(last_frame) - raise EOFError("no more images in APNG file") + raise EOFError("no more images in APNG file") from e def _seek(self, frame, rewind=False): if frame == 0: @@ -1168,8 +1170,8 @@ def _save(im, fp, filename, chunk=putchunk, save_all=False): # get the corresponding PNG mode try: rawmode, mode = _OUTMODES[mode] - except KeyError: - raise OSError("cannot write mode %s as PNG" % mode) + except KeyError as e: + raise OSError("cannot write mode %s as PNG" % mode) from e # # write minimal PNG file diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 044df443d..1ff4c8624 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -144,8 +144,8 @@ class PsdImageFile(ImageFile.ImageFile): self.frame = layer self.fp = self.__fp return name, bbox - except IndexError: - raise EOFError("no such layer") + except IndexError as e: + raise EOFError("no such layer") from e def tell(self): # return layer number (0=image, 1..max=layers) diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index cbd31cf82..56aac2987 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -111,8 +111,8 @@ class SpiderImageFile(ImageFile.ImageFile): hdrlen = isSpiderHeader(t) if hdrlen == 0: raise SyntaxError("not a valid Spider file") - except struct.error: - raise SyntaxError("not a valid Spider file") + except struct.error as e: + raise SyntaxError("not a valid Spider file") from e h = (99,) + t # add 1 value : spider header index starts at 1 iform = int(h[5]) diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index fd71e545d..566f0ac18 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -167,8 +167,8 @@ def _save(im, fp, filename): try: rawmode, bits, colormaptype, imagetype = SAVE[im.mode] - except KeyError: - raise OSError("cannot write mode %s as TGA" % im.mode) + except KeyError as e: + raise OSError("cannot write mode %s as TGA" % im.mode) from e if "rle" in im.encoderinfo: rle = im.encoderinfo["rle"] diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index bee05e6ed..cb725d952 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1117,8 +1117,8 @@ class TiffImageFile(ImageFile.ImageFile): ) try: decoder.setimage(self.im, extents) - except ValueError: - raise OSError("Couldn't set the image") + except ValueError as e: + raise OSError("Couldn't set the image") from e close_self_fp = self._exclusive_fp and not self.is_animated if hasattr(self.fp, "getvalue"): @@ -1231,9 +1231,9 @@ class TiffImageFile(ImageFile.ImageFile): logger.debug("format key: {}".format(key)) try: self.mode, rawmode = OPEN_INFO[key] - except KeyError: + except KeyError as e: logger.debug("- unsupported format") - raise SyntaxError("unknown pixel mode") + raise SyntaxError("unknown pixel mode") from e logger.debug("- raw mode: {}".format(rawmode)) logger.debug("- pil mode: {}".format(self.mode)) @@ -1400,8 +1400,8 @@ def _save(im, fp, filename): try: rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode] - except KeyError: - raise OSError("cannot write mode %s as TIFF" % im.mode) + except KeyError as e: + raise OSError("cannot write mode %s as TIFF" % im.mode) from e ifd = ImageFileDirectory_v2(prefix=prefix) From 66eee05a37bb5674e7a9d24d2951e71ed773b8e2 Mon Sep 17 00:00:00 2001 From: nulano Date: Sun, 21 Jun 2020 18:47:30 +0100 Subject: [PATCH 017/126] Apply suggestions from code review Co-authored-by: Hugo van Kemenade --- docs/PIL.rst | 2 +- src/PIL/FontFile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/PIL.rst b/docs/PIL.rst index 222322b0d..8f8cda5fb 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -5,7 +5,7 @@ Reference for modules whose documentation has not yet been ported or written can be found here. :mod:`PIL` Module -------------------------- +----------------- .. py:module:: PIL diff --git a/src/PIL/FontFile.py b/src/PIL/FontFile.py index 4243b28b6..3ebd90730 100644 --- a/src/PIL/FontFile.py +++ b/src/PIL/FontFile.py @@ -23,7 +23,7 @@ WIDTH = 800 def puti16(fp, values): - """write network order (big-endian) 16-bit sequence""" + """Write network order (big-endian) 16-bit sequence""" for v in values: if v < 0: v += 65536 From 224ef2fadd1fffefa6b2ff0b98be2595c23b4188 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 05:11:02 +0200 Subject: [PATCH 018/126] require sphinx>=2.4 --- docs/conf.py | 2 +- requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index a0a3315c6..d95ec2a4a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ import sphinx_rtd_theme # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' +needs_sphinx = "2.4" # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom diff --git a/requirements.txt b/requirements.txt index 14f934c9c..0e0d38cdd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,4 +9,5 @@ pyflakes pyroma pytest pytest-cov +sphinx>=2.4 sphinx-rtd-theme From c4c1b51f459ba8804a7af13b142d7caea42725e0 Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 22 Jun 2020 12:10:45 +0300 Subject: [PATCH 019/126] pre-commit: when hooks fail, run 'git diff' directly afterwards --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 9f310ca3a..8005888d4 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,7 @@ deps = [testenv:lint] commands = - pre-commit run --all-files + pre-commit run --all-files --show-diff-on-failure check-manifest deps = pre-commit From 7e3556e5f640b63103d92b2f749f7aef6f3d5d44 Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 22 Jun 2020 12:22:43 +0300 Subject: [PATCH 020/126] GHA: Force colour output of pre-commit --- .github/workflows/lint.yml | 4 +++- tox.ini | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6c5d81ac4..64296b377 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v2 - name: pip cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cache/pip key: lint-pip-${{ hashFiles('**/setup.py') }} @@ -46,4 +46,6 @@ jobs: - name: Lint run: tox -e lint + env: + PRE_COMMIT_COLOR: always diff --git a/tox.ini b/tox.ini index 8005888d4..aa6875374 100644 --- a/tox.ini +++ b/tox.ini @@ -30,3 +30,4 @@ deps = pre-commit check-manifest skip_install = true +passenv = PRE_COMMIT_COLOR From 519ce4b8db49b533e7ac833ff4363d0d0990b542 Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 22 Jun 2020 12:42:02 +0300 Subject: [PATCH 021/126] GHA: Force colour output of pytest --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 30843b847..f9d47e243 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,5 +9,5 @@ line_length = 88 multi_line_output = 3 [tool:pytest] -addopts = -rs +addopts = -rs --color=yes testpaths = Tests From ee06255ff0ee64f8d3d1062c75e455973cc9d2fc Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 21 Jun 2020 22:17:18 +1000 Subject: [PATCH 022/126] Deprecated _showxv --- Tests/test_image.py | 18 +++++++++++++++++- docs/deprecations.rst | 9 +++++++++ docs/releasenotes/7.2.0.rst | 7 +++++++ src/PIL/Image.py | 9 +++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index f284f89a7..be67f5947 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -5,7 +5,7 @@ import tempfile import PIL import pytest -from PIL import Image, ImageDraw, ImagePalette, UnidentifiedImageError +from PIL import Image, ImageDraw, ImagePalette, ImageShow, UnidentifiedImageError from .helper import ( assert_image_equal, @@ -585,6 +585,22 @@ class TestImage: expected = Image.new(mode, (100, 100), color) assert_image_equal(im.convert(mode), expected) + def test_showxv_deprecation(self): + class TestViewer(ImageShow.Viewer): + def show_image(self, image, **options): + return True + + viewer = TestViewer() + ImageShow.register(viewer, -1) + + im = Image.new("RGB", (50, 50), "white") + + with pytest.warns(DeprecationWarning): + Image._showxv(im) + + # Restore original state + ImageShow._viewers.pop(0) + def test_no_resource_warning_on_save(self, tmp_path): # https://github.com/python-pillow/Pillow/issues/835 # Arrange diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 38d2143c4..f78842ac1 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -20,6 +20,15 @@ Image.show command parameter The ``command`` parameter was deprecated and will be removed in a future release. Use a subclass of ``ImageShow.Viewer`` instead. +Image._showxv +~~~~~~~~~~~~~ + +.. deprecated:: 7.2.0 + +``Image._showxv`` has been deprecated. Use :py:meth:`~PIL.Image.Image.show` +instead. If custom behaviour is required, use :py:meth:`~PIL.ImageShow.register` to add +a custom :py:class:`~PIL.ImageShow.Viewer` class. + ImageFile.raise_ioerror ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/releasenotes/7.2.0.rst b/docs/releasenotes/7.2.0.rst index 6b91a1b01..ff1b7c9e7 100644 --- a/docs/releasenotes/7.2.0.rst +++ b/docs/releasenotes/7.2.0.rst @@ -43,6 +43,13 @@ Image.show command parameter The ``command`` parameter was deprecated and will be removed in a future release. Use a subclass of :py:class:`PIL.ImageShow.Viewer` instead. +Image._showxv +~~~~~~~~~~~~~ + +``Image._showxv`` has been deprecated. Use :py:meth:`~PIL.Image.Image.show` +instead. If custom behaviour is required, use :py:meth:`~PIL.ImageShow.register` to add +a custom :py:class:`~PIL.ImageShow.Viewer` class. + ImageFile.raise_ioerror ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 02c73bc49..7a2ae02d6 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -3150,12 +3150,21 @@ def register_encoder(name, encoder): def _show(image, **options): + options["_internal_pillow"] = True _showxv(image, **options) def _showxv(image, title=None, **options): from . import ImageShow + if "_internal_pillow" in options: + del options["_internal_pillow"] + else: + warnings.warn( + "_showxv is deprecated and will be removed in a future release. " + "Use Image.show instead.", + DeprecationWarning, + ) ImageShow.show(image, title, **options) From bd466c41c141472f69318c46a7b3ed74d3f1b45d Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 24 Jun 2020 10:11:16 +0300 Subject: [PATCH 023/126] Fix setting disposal --- src/PIL/PngImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 51b78c7de..32ba68cd5 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -1036,7 +1036,7 @@ def _write_multiple_frames(im, fp, chunk, rawmode): prev_disposal = previous["encoderinfo"].get("disposal") prev_blend = previous["encoderinfo"].get("blend") if prev_disposal == APNG_DISPOSE_OP_PREVIOUS and len(im_frames) < 2: - prev_disposal == APNG_DISPOSE_OP_BACKGROUND + prev_disposal = APNG_DISPOSE_OP_BACKGROUND if prev_disposal == APNG_DISPOSE_OP_BACKGROUND: base_im = previous["im"] From 685c0439b8ef3c0f9f7be4837a751d22f07cbb87 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 26 Jun 2020 18:47:34 +1000 Subject: [PATCH 024/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index c79b9d1ef..c5b55a524 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 7.2.0 (unreleased) ------------------ +- Deprecated _showxv #4714 + [radarhere] + - Deprecate Image.show(command="...") #4646 [nulano, hugovk, radarhere] From d641bdc504a943b21eaa770e3a549dd6b33d15af Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 27 Jun 2020 14:05:34 +0300 Subject: [PATCH 025/126] Fix isort --- Tests/test_imagegrab.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/test_imagegrab.py b/Tests/test_imagegrab.py index a1453a07e..ae1277ced 100644 --- a/Tests/test_imagegrab.py +++ b/Tests/test_imagegrab.py @@ -4,6 +4,7 @@ import sys import pytest from PIL import Image, ImageGrab + from .helper import assert_image, assert_image_equal_tofile, skip_unless_feature From e4210eb8d776bdbe57a17bb4a256e64d4367dcc0 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 06:43:14 +0200 Subject: [PATCH 026/126] fix ImageFile references (cherry picked from commit 6ac071782f820fa59acc91ff0fe0a697fc5f8cbe) --- docs/reference/ImageFile.rst | 17 ++++++++++++----- src/PIL/ImageFile.py | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/reference/ImageFile.rst b/docs/reference/ImageFile.rst index d93dfb3a3..6da402283 100644 --- a/docs/reference/ImageFile.rst +++ b/docs/reference/ImageFile.rst @@ -34,14 +34,21 @@ Example: Parse an image im.save("copy.jpg") -:py:class:`~PIL.ImageFile.Parser` ---------------------------------- +Classes +------- .. autoclass:: PIL.ImageFile.Parser() :members: -:py:class:`~PIL.ImageFile.PyDecoder` ------------------------------------- - .. autoclass:: PIL.ImageFile.PyDecoder() :members: + +.. autoclass:: PIL.ImageFile.ImageFile() + :member-order: bysource + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: PIL.ImageFile.StubImageFile() + :members: + :show-inheritance: diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index 9a780b4e0..b431fbd1c 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -85,7 +85,7 @@ def _tilesort(t): class ImageFile(Image.Image): - "Base class for image file format handlers." + """Base class for image file format handlers.""" def __init__(self, fp=None, filename=None): super().__init__() From 471f24f660c7d98023f0458853fc5548431d48b9 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 06:43:29 +0200 Subject: [PATCH 027/126] fix PyCMSError references (cherry picked from commit 63d0fb4f7019a8423bb5c62ea7b225f437f823cf) --- docs/reference/ImageCms.rst | 27 ++++++++++-- src/PIL/ImageCms.py | 87 +++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 45 deletions(-) diff --git a/docs/reference/ImageCms.rst b/docs/reference/ImageCms.rst index 67c581765..30690da34 100644 --- a/docs/reference/ImageCms.rst +++ b/docs/reference/ImageCms.rst @@ -8,9 +8,30 @@ The :py:mod:`ImageCms` module provides color profile management support using the LittleCMS2 color management engine, based on Kevin Cazabon's PyCMS library. -.. automodule:: PIL.ImageCms - :members: - :noindex: +.. autoclass:: ImageCmsTransform +.. autoexception:: PyCMSError + +Functions +--------- + +.. autofunction:: applyTransform +.. autofunction:: buildProofTransform +.. autofunction:: buildProofTransformFromOpenProfiles +.. autofunction:: buildTransform +.. autofunction:: buildTransformFromOpenProfiles +.. autofunction:: createProfile +.. autofunction:: getDefaultIntent +.. autofunction:: getOpenProfile +.. autofunction:: getProfileCopyright +.. autofunction:: getProfileDescription +.. autofunction:: getProfileInfo +.. autofunction:: getProfileManufacturer +.. autofunction:: getProfileModel +.. autofunction:: getProfileName +.. autofunction:: get_display_profile +.. autofunction:: isIntentSupported +.. autofunction:: profileToProfile +.. autofunction:: versions CmsProfile ---------- diff --git a/src/PIL/ImageCms.py b/src/PIL/ImageCms.py index 723e7ceb7..93f345907 100644 --- a/src/PIL/ImageCms.py +++ b/src/PIL/ImageCms.py @@ -295,11 +295,12 @@ def profileToProfile( ``inputProfile`` to ``outputProfile``. If the input or output profiles specified are not valid filenames, a - ``PyCMSError`` will be raised. If ``inPlace`` is ``True`` and - ``outputMode != im.mode``, a ``PyCMSError`` will be raised. If an error - occurs during application of the profiles, a ``PyCMSError`` will be raised. + :exc:`PyCMSError` will be raised. If ``inPlace`` is ``True`` and + ``outputMode != im.mode``, a :exc:`PyCMSError` will be raised. + If an error occurs during application of the profiles, + a :exc:`PyCMSError` will be raised. If ``outputMode`` is not a mode supported by the ``outputProfile`` (or by pyCMS), - a ``PyCMSError`` will be raised. + a :exc:`PyCMSError` will be raised. This function applies an ICC transformation to im from ``inputProfile``'s color space to ``outputProfile``'s color space using the specified rendering @@ -381,8 +382,8 @@ def getOpenProfile(profileFilename): The PyCMSProfile object can be passed back into pyCMS for use in creating transforms and such (as in ImageCms.buildTransformFromOpenProfiles()). - If ``profileFilename`` is not a valid filename for an ICC profile, a ``PyCMSError`` - will be raised. + If ``profileFilename`` is not a valid filename for an ICC profile, + a :exc:`PyCMSError` will be raised. :param profileFilename: String, as a valid filename path to the ICC profile you wish to open, or a file-like object. @@ -410,11 +411,11 @@ def buildTransform( image. If the input or output profiles specified are not valid filenames, a - ``PyCMSError`` will be raised. If an error occurs during creation of the - transform, a ``PyCMSError`` will be raised. + :exc:`PyCMSError` will be raised. If an error occurs during creation + of the transform, a :exc:`PyCMSError` will be raised. If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile`` - (or by pyCMS), a ``PyCMSError`` will be raised. + (or by pyCMS), a :exc:`PyCMSError` will be raised. This function builds and returns an ICC transform from the ``inputProfile`` to the ``outputProfile`` using the ``renderingIntent`` to determine what to do @@ -493,13 +494,13 @@ def buildProofTransform( obtained on the ``proofProfile`` device. If the input, output, or proof profiles specified are not valid - filenames, a ``PyCMSError`` will be raised. + filenames, a :exc:`PyCMSError` will be raised. - If an error occurs during creation of the transform, a ``PyCMSError`` - will be raised. + If an error occurs during creation of the transform, + a :exc:`PyCMSError` will be raised. If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile`` - (or by pyCMS), a ``PyCMSError`` will be raised. + (or by pyCMS), a :exc:`PyCMSError` will be raised. This function builds and returns an ICC transform from the ``inputProfile`` to the ``outputProfile``, but tries to simulate the result that would be @@ -596,17 +597,17 @@ def applyTransform(im, transform, inPlace=False): """ (pyCMS) Applies a transform to a given image. - If ``im.mode != transform.inMode``, a ``PyCMSError`` is raised. + If ``im.mode != transform.inMode``, a :exc:`PyCMSError` is raised. If ``inPlace`` is ``True`` and ``transform.inMode != transform.outMode``, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. If ``im.mode``, ``transform.inMode`` or ``transform.outMode`` is not supported by pyCMSdll or the profiles you used for the transform, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. - If an error occurs while the transform is being applied, a ``PyCMSError`` - is raised. + If an error occurs while the transform is being applied, + a :exc:`PyCMSError` is raised. This function applies a pre-calculated transform (from ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles()) @@ -649,12 +650,14 @@ def createProfile(colorSpace, colorTemp=-1): """ (pyCMS) Creates a profile. - If colorSpace not in ``["LAB", "XYZ", "sRGB"]``, a ``PyCMSError`` is raised. + If colorSpace not in ``["LAB", "XYZ", "sRGB"]``, + a :exc:`PyCMSError` is raised. - If using LAB and ``colorTemp`` is not a positive integer, a ``PyCMSError`` is - raised. + If using LAB and ``colorTemp`` is not a positive integer, + a :exc:`PyCMSError` is raised. - If an error occurs while creating the profile, a ``PyCMSError`` is raised. + If an error occurs while creating the profile, + a :exc:`PyCMSError` is raised. Use this function to create common profiles on-the-fly instead of having to supply a profile on disk and knowing the path to it. It @@ -699,8 +702,8 @@ def getProfileName(profile): (pyCMS) Gets the internal product name for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, - a ``PyCMSError`` is raised If an error occurs while trying to obtain the - name tag, a ``PyCMSError`` is raised. + a :exc:`PyCMSError` is raised If an error occurs while trying + to obtain the name tag, a :exc:`PyCMSError` is raised. Use this function to obtain the INTERNAL name of the profile (stored in an ICC tag in the profile itself), usually the one used when the @@ -740,10 +743,10 @@ def getProfileInfo(profile): (pyCMS) Gets the internal product information for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, - a ``PyCMSError`` is raised. + a :exc:`PyCMSError` is raised. - If an error occurs while trying to obtain the info tag, a ``PyCMSError`` - is raised. + If an error occurs while trying to obtain the info tag, + a :exc:`PyCMSError` is raised. Use this function to obtain the information stored in the profile's info tag. This often contains details about the profile, and how it @@ -780,10 +783,10 @@ def getProfileCopyright(profile): (pyCMS) Gets the copyright for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. - If an error occurs while trying to obtain the copyright tag, a ``PyCMSError`` - is raised. + If an error occurs while trying to obtain the copyright tag, + a :exc:`PyCMSError` is raised. Use this function to obtain the information stored in the profile's copyright tag. @@ -808,10 +811,10 @@ def getProfileManufacturer(profile): (pyCMS) Gets the manufacturer for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. If an error occurs while trying to obtain the manufacturer tag, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. Use this function to obtain the information stored in the profile's manufacturer tag. @@ -836,10 +839,10 @@ def getProfileModel(profile): (pyCMS) Gets the model for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. - If an error occurs while trying to obtain the model tag, a ``PyCMSError`` - is raised. + If an error occurs while trying to obtain the model tag, + a :exc:`PyCMSError` is raised. Use this function to obtain the information stored in the profile's model tag. @@ -865,10 +868,10 @@ def getProfileDescription(profile): (pyCMS) Gets the description for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. - If an error occurs while trying to obtain the description tag, a ``PyCMSError`` - is raised. + If an error occurs while trying to obtain the description tag, + a :exc:`PyCMSError` is raised. Use this function to obtain the information stored in the profile's description tag. @@ -894,10 +897,10 @@ def getDefaultIntent(profile): (pyCMS) Gets the default intent name for the given profile. If ``profile`` isn't a valid CmsProfile object or filename to a profile, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. If an error occurs while trying to obtain the default intent, a - ``PyCMSError`` is raised. + :exc:`PyCMSError` is raised. Use this function to determine the default (and usually best optimized) rendering intent for this profile. Most profiles support multiple @@ -940,8 +943,8 @@ def isIntentSupported(profile, intent, direction): be used for others. Some profiles can only be used for certain rendering intents, so it's best to either verify this before trying to create a transform with them (using this function), or catch the - potential ``PyCMSError`` that will occur if they don't support the modes - you select. + potential :exc:`PyCMSError` that will occur if they don't + support the modes you select. :param profile: EITHER a valid CmsProfile object, OR a string of the filename of an ICC profile. From 2761a02d130c53a1731439e571016ae286ba093d Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 05:52:50 +0200 Subject: [PATCH 028/126] fix module references (cherry picked from commit b077850baa60e413534defeab997a9b574daaa6e) --- docs/PIL.rst | 48 ++++---- docs/porting.rst | 2 +- docs/reference/ExifTags.rst | 6 +- docs/reference/Image.rst | 4 +- docs/reference/ImageChops.rst | 8 +- docs/reference/ImageCms.rst | 6 +- docs/reference/ImageColor.rst | 6 +- docs/reference/ImageDraw.rst | 6 +- docs/reference/ImageEnhance.rst | 6 +- docs/reference/ImageFile.rst | 6 +- docs/reference/ImageFilter.rst | 6 +- docs/reference/ImageFont.rst | 6 +- docs/reference/ImageGrab.rst | 6 +- docs/reference/ImageMath.rst | 6 +- docs/reference/ImageMorph.rst | 6 +- docs/reference/ImageOps.rst | 6 +- docs/reference/ImagePalette.rst | 6 +- docs/reference/ImagePath.rst | 6 +- docs/reference/ImageQt.rst | 6 +- docs/reference/ImageSequence.rst | 6 +- docs/reference/ImageShow.rst | 6 +- docs/reference/ImageStat.rst | 6 +- docs/reference/ImageTk.rst | 6 +- docs/reference/ImageWin.rst | 6 +- docs/reference/JpegPresets.rst | 4 +- docs/reference/PSDraw.rst | 6 +- docs/reference/PyAccess.rst | 6 +- docs/reference/TiffTags.rst | 6 +- docs/reference/features.rst | 4 +- docs/reference/internal_modules.rst | 16 +-- docs/reference/plugins.rst | 164 ++++++++++++++-------------- 31 files changed, 194 insertions(+), 194 deletions(-) diff --git a/docs/PIL.rst b/docs/PIL.rst index 8f8cda5fb..4b10184fa 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -12,56 +12,56 @@ can be found here. .. autoexception:: UnidentifiedImageError :show-inheritance: -:mod:`BdfFontFile` Module -------------------------- +:mod:`~PIL.BdfFontFile` Module +------------------------------ .. automodule:: PIL.BdfFontFile :members: :undoc-members: :show-inheritance: -:mod:`ContainerIO` Module -------------------------- +:mod:`~PIL.ContainerIO` Module +------------------------------ .. automodule:: PIL.ContainerIO :members: :undoc-members: :show-inheritance: -:mod:`FontFile` Module ----------------------- +:mod:`~PIL.FontFile` Module +--------------------------- .. automodule:: PIL.FontFile :members: :undoc-members: :show-inheritance: -:mod:`GdImageFile` Module -------------------------- +:mod:`~PIL.GdImageFile` Module +------------------------------ .. automodule:: PIL.GdImageFile :members: :undoc-members: :show-inheritance: -:mod:`GimpGradientFile` Module ------------------------------- +:mod:`~PIL.GimpGradientFile` Module +----------------------------------- .. automodule:: PIL.GimpGradientFile :members: :undoc-members: :show-inheritance: -:mod:`GimpPaletteFile` Module ------------------------------ +:mod:`~PIL.GimpPaletteFile` Module +---------------------------------- .. automodule:: PIL.GimpPaletteFile :members: :undoc-members: :show-inheritance: -:mod:`ImageDraw2` Module ------------------------- +:mod:`~PIL.ImageDraw2` Module +----------------------------- .. automodule:: PIL.ImageDraw2 :members: @@ -69,24 +69,24 @@ can be found here. :undoc-members: :show-inheritance: -:mod:`ImageTransform` Module ----------------------------- +:mod:`~PIL.ImageTransform` Module +--------------------------------- .. automodule:: PIL.ImageTransform :members: :undoc-members: :show-inheritance: -:mod:`PaletteFile` Module -------------------------- +:mod:`~PIL.PaletteFile` Module +------------------------------ .. automodule:: PIL.PaletteFile :members: :undoc-members: :show-inheritance: -:mod:`PcfFontFile` Module -------------------------- +:mod:`~PIL.PcfFontFile` Module +------------------------------ .. automodule:: PIL.PcfFontFile :members: @@ -116,16 +116,16 @@ can be found here. :show-inheritance: -:mod:`TarIO` Module -------------------- +:mod:`~PIL.TarIO` Module +------------------------ .. automodule:: PIL.TarIO :members: :undoc-members: :show-inheritance: -:mod:`WalImageFile` Module --------------------------- +:mod:`~PIL.WalImageFile` Module +------------------------------- .. automodule:: PIL.WalImageFile :members: diff --git a/docs/porting.rst b/docs/porting.rst index 3b14cde9d..d962e9330 100644 --- a/docs/porting.rst +++ b/docs/porting.rst @@ -19,7 +19,7 @@ to this:: from PIL import Image -The :py:mod:`_imaging` module has been moved. You can now import it like this:: +The :py:mod:`~PIL._imaging` module has been moved. You can now import it like this:: from PIL.Image import core as _imaging diff --git a/docs/reference/ExifTags.rst b/docs/reference/ExifTags.rst index 39fdab02c..4567d4d3e 100644 --- a/docs/reference/ExifTags.rst +++ b/docs/reference/ExifTags.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ExifTags .. py:currentmodule:: PIL.ExifTags -:py:mod:`ExifTags` Module -========================== +:py:mod:`~PIL.ExifTags` Module +============================== -The :py:mod:`ExifTags` module exposes two dictionaries which +The :py:mod:`~PIL.ExifTags` module exposes two dictionaries which provide constants and clear-text names for various well-known EXIF tags. .. py:data:: TAGS diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 216fa1196..469774a8d 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -1,8 +1,8 @@ .. py:module:: PIL.Image .. py:currentmodule:: PIL.Image -:py:mod:`Image` Module -====================== +:py:mod:`~PIL.Image` Module +=========================== The :py:mod:`~PIL.Image` module provides a class with the same name which is used to represent a PIL image. The module also provides a number of factory diff --git a/docs/reference/ImageChops.rst b/docs/reference/ImageChops.rst index fb7422549..772d9c983 100644 --- a/docs/reference/ImageChops.rst +++ b/docs/reference/ImageChops.rst @@ -1,15 +1,15 @@ .. py:module:: PIL.ImageChops .. py:currentmodule:: PIL.ImageChops -:py:mod:`ImageChops` ("Channel Operations") Module -================================================== +:py:mod:`~PIL.ImageChops` ("Channel Operations") Module +======================================================= -The :py:mod:`ImageChops` module contains a number of arithmetical image +The :py:mod:`~PIL.ImageChops` module contains a number of arithmetical image operations, called channel operations (“chops”). These can be used for various purposes, including special effects, image compositions, algorithmic painting, and more. -For more pre-made operations, see :py:mod:`ImageOps`. +For more pre-made operations, see :py:mod:`~PIL.ImageOps`. At this time, most channel operations are only implemented for 8-bit images (e.g. “L” and “RGB”). diff --git a/docs/reference/ImageCms.rst b/docs/reference/ImageCms.rst index 67c581765..8c11e1476 100644 --- a/docs/reference/ImageCms.rst +++ b/docs/reference/ImageCms.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageCms .. py:currentmodule:: PIL.ImageCms -:py:mod:`ImageCms` Module -========================= +:py:mod:`~PIL.ImageCms` Module +============================== -The :py:mod:`ImageCms` module provides color profile management +The :py:mod:`~PIL.ImageCms` module provides color profile management support using the LittleCMS2 color management engine, based on Kevin Cazabon's PyCMS library. diff --git a/docs/reference/ImageColor.rst b/docs/reference/ImageColor.rst index 187306f1b..e32a77b54 100644 --- a/docs/reference/ImageColor.rst +++ b/docs/reference/ImageColor.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageColor .. py:currentmodule:: PIL.ImageColor -:py:mod:`ImageColor` Module -=========================== +:py:mod:`~PIL.ImageColor` Module +================================ -The :py:mod:`ImageColor` module contains color tables and converters from +The :py:mod:`~PIL.ImageColor` module contains color tables and converters from CSS3-style color specifiers to RGB tuples. This module is used by :py:meth:`PIL.Image.new` and the :py:mod:`~PIL.ImageDraw` module, among others. diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index 495a7d117..fd74b69c1 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageDraw .. py:currentmodule:: PIL.ImageDraw -:py:mod:`ImageDraw` Module -========================== +:py:mod:`~PIL.ImageDraw` Module +=============================== -The :py:mod:`ImageDraw` module provides simple 2D graphics for +The :py:mod:`~PIL.ImageDraw` module provides 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. diff --git a/docs/reference/ImageEnhance.rst b/docs/reference/ImageEnhance.rst index f98d8f780..742cf0068 100644 --- a/docs/reference/ImageEnhance.rst +++ b/docs/reference/ImageEnhance.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageEnhance .. py:currentmodule:: PIL.ImageEnhance -:py:mod:`ImageEnhance` Module -============================= +:py:mod:`~PIL.ImageEnhance` Module +================================== -The :py:mod:`ImageEnhance` module contains a number of classes that can be used +The :py:mod:`~PIL.ImageEnhance` module contains a number of classes that can be used for image enhancement. Example: Vary the sharpness of an image diff --git a/docs/reference/ImageFile.rst b/docs/reference/ImageFile.rst index d93dfb3a3..82a84dbde 100644 --- a/docs/reference/ImageFile.rst +++ b/docs/reference/ImageFile.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageFile .. py:currentmodule:: PIL.ImageFile -:py:mod:`ImageFile` Module -========================== +:py:mod:`~PIL.ImageFile` Module +=============================== -The :py:mod:`ImageFile` module provides support functions for the image open +The :py:mod:`~PIL.ImageFile` module provides support functions for the image open and save functions. In addition, it provides a :py:class:`Parser` class which can be used to decode diff --git a/docs/reference/ImageFilter.rst b/docs/reference/ImageFilter.rst index 52a7d7500..1b93c53e7 100644 --- a/docs/reference/ImageFilter.rst +++ b/docs/reference/ImageFilter.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageFilter .. py:currentmodule:: PIL.ImageFilter -:py:mod:`ImageFilter` Module -============================ +:py:mod:`~PIL.ImageFilter` Module +================================= -The :py:mod:`ImageFilter` module contains definitions for a pre-defined set of +The :py:mod:`~PIL.ImageFilter` module contains definitions for a pre-defined set of filters, which can be be used with the :py:meth:`Image.filter() ` method. diff --git a/docs/reference/ImageFont.rst b/docs/reference/ImageFont.rst index 1aa22aa51..b3c3cce57 100644 --- a/docs/reference/ImageFont.rst +++ b/docs/reference/ImageFont.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageFont .. py:currentmodule:: PIL.ImageFont -:py:mod:`ImageFont` Module -========================== +:py:mod:`~PIL.ImageFont` Module +=============================== -The :py:mod:`ImageFont` module defines a class with the same name. Instances of +The :py:mod:`~PIL.ImageFont` module defines a class with the same name. Instances of this class store bitmap fonts, and are used with the :py:meth:`PIL.ImageDraw.Draw.text` method. diff --git a/docs/reference/ImageGrab.rst b/docs/reference/ImageGrab.rst index 943fdf69b..a9427be9c 100644 --- a/docs/reference/ImageGrab.rst +++ b/docs/reference/ImageGrab.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageGrab .. py:currentmodule:: PIL.ImageGrab -:py:mod:`ImageGrab` Module -========================== +:py:mod:`~PIL.ImageGrab` Module +=============================== -The :py:mod:`ImageGrab` module can be used to copy the contents of the screen +The :py:mod:`~PIL.ImageGrab` module can be used to copy the contents of the screen or the clipboard to a PIL image memory. .. versionadded:: 1.1.3 diff --git a/docs/reference/ImageMath.rst b/docs/reference/ImageMath.rst index ca30244d1..45b9200d1 100644 --- a/docs/reference/ImageMath.rst +++ b/docs/reference/ImageMath.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageMath .. py:currentmodule:: PIL.ImageMath -:py:mod:`ImageMath` Module -========================== +:py:mod:`~PIL.ImageMath` Module +=============================== -The :py:mod:`ImageMath` module can be used to evaluate “image expressions”. The +The :py:mod:`~PIL.ImageMath` module can be used to evaluate “image expressions”. The module provides a single :py:meth:`~PIL.ImageMath.eval` function, which takes an expression string and one or more images. diff --git a/docs/reference/ImageMorph.rst b/docs/reference/ImageMorph.rst index be9d59348..d4522a06a 100644 --- a/docs/reference/ImageMorph.rst +++ b/docs/reference/ImageMorph.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageMorph .. py:currentmodule:: PIL.ImageMorph -:py:mod:`ImageMorph` Module -=========================== +:py:mod:`~PIL.ImageMorph` Module +================================ -The :py:mod:`ImageMorph` module provides morphology operations on images. +The :py:mod:`~PIL.ImageMorph` module provides morphology operations on images. .. automodule:: PIL.ImageMorph :members: diff --git a/docs/reference/ImageOps.rst b/docs/reference/ImageOps.rst index 1c86d168f..9a16d6625 100644 --- a/docs/reference/ImageOps.rst +++ b/docs/reference/ImageOps.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageOps .. py:currentmodule:: PIL.ImageOps -:py:mod:`ImageOps` Module -========================== +:py:mod:`~PIL.ImageOps` Module +============================== -The :py:mod:`ImageOps` module contains a number of ‘ready-made’ image +The :py:mod:`~PIL.ImageOps` module contains a number of ‘ready-made’ image processing operations. This module is somewhat experimental, and most operators only work on L and RGB images. diff --git a/docs/reference/ImagePalette.rst b/docs/reference/ImagePalette.rst index 15b8aed8f..f14c1c3a4 100644 --- a/docs/reference/ImagePalette.rst +++ b/docs/reference/ImagePalette.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImagePalette .. py:currentmodule:: PIL.ImagePalette -:py:mod:`ImagePalette` Module -============================= +:py:mod:`~PIL.ImagePalette` Module +================================== -The :py:mod:`ImagePalette` module contains a class of the same name to +The :py:mod:`~PIL.ImagePalette` module contains a class of the same name to represent the color palette of palette mapped images. .. note:: diff --git a/docs/reference/ImagePath.rst b/docs/reference/ImagePath.rst index 5ab350ef3..21a202b5e 100644 --- a/docs/reference/ImagePath.rst +++ b/docs/reference/ImagePath.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImagePath .. py:currentmodule:: PIL.ImagePath -:py:mod:`ImagePath` Module -========================== +:py:mod:`~PIL.ImagePath` Module +=============================== -The :py:mod:`ImagePath` module is used to store and manipulate 2-dimensional +The :py:mod:`~PIL.ImagePath` module is used to store and manipulate 2-dimensional vector data. Path objects can be passed to the methods on the :py:mod:`~PIL.ImageDraw` module. diff --git a/docs/reference/ImageQt.rst b/docs/reference/ImageQt.rst index 7dd7084db..887eab9ba 100644 --- a/docs/reference/ImageQt.rst +++ b/docs/reference/ImageQt.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageQt .. py:currentmodule:: PIL.ImageQt -:py:mod:`ImageQt` Module -======================== +:py:mod:`~PIL.ImageQt` Module +============================= -The :py:mod:`ImageQt` module contains support for creating PyQt5 or PySide2 QImage +The :py:mod:`~PIL.ImageQt` module contains support for creating PyQt5 or PySide2 QImage objects from PIL images. .. versionadded:: 1.1.6 diff --git a/docs/reference/ImageSequence.rst b/docs/reference/ImageSequence.rst index 353e8099e..ae93fa47d 100644 --- a/docs/reference/ImageSequence.rst +++ b/docs/reference/ImageSequence.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageSequence .. py:currentmodule:: PIL.ImageSequence -:py:mod:`ImageSequence` Module -============================== +:py:mod:`~PIL.ImageSequence` Module +=================================== -The :py:mod:`ImageSequence` module contains a wrapper class that lets you +The :py:mod:`~PIL.ImageSequence` module contains a wrapper class that lets you iterate over the frames of an image sequence. Extracting frames from an animation diff --git a/docs/reference/ImageShow.rst b/docs/reference/ImageShow.rst index 0b012d856..a30a6caed 100644 --- a/docs/reference/ImageShow.rst +++ b/docs/reference/ImageShow.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageShow .. py:currentmodule:: PIL.ImageShow -:py:mod:`ImageShow` Module -========================== +:py:mod:`~PIL.ImageShow` Module +=============================== -The :py:mod:`ImageShow` Module is used to display images. +The :py:mod:`~PIL.ImageShow` Module is used to display images. All default viewers convert the image to be shown to PNG format. .. autofunction:: PIL.ImageShow.show diff --git a/docs/reference/ImageStat.rst b/docs/reference/ImageStat.rst index e94c24aa4..5bb735296 100644 --- a/docs/reference/ImageStat.rst +++ b/docs/reference/ImageStat.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageStat .. py:currentmodule:: PIL.ImageStat -:py:mod:`ImageStat` Module -========================== +:py:mod:`~PIL.ImageStat` Module +=============================== -The :py:mod:`ImageStat` module calculates global statistics for an image, or +The :py:mod:`~PIL.ImageStat` module calculates global statistics for an image, or for a region of an image. .. py:class:: Stat(image_or_list, mask=None) diff --git a/docs/reference/ImageTk.rst b/docs/reference/ImageTk.rst index 7ee4af029..134ef5651 100644 --- a/docs/reference/ImageTk.rst +++ b/docs/reference/ImageTk.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageTk .. py:currentmodule:: PIL.ImageTk -:py:mod:`ImageTk` Module -======================== +:py:mod:`~PIL.ImageTk` Module +============================= -The :py:mod:`ImageTk` module contains support to create and modify Tkinter +The :py:mod:`~PIL.ImageTk` module contains support to create and modify Tkinter BitmapImage and PhotoImage objects from PIL images. For examples, see the demo programs in the Scripts directory. diff --git a/docs/reference/ImageWin.rst b/docs/reference/ImageWin.rst index ff3d6a7fc..2ee3cadb7 100644 --- a/docs/reference/ImageWin.rst +++ b/docs/reference/ImageWin.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.ImageWin .. py:currentmodule:: PIL.ImageWin -:py:mod:`ImageWin` Module (Windows-only) -======================================== +:py:mod:`~PIL.ImageWin` Module (Windows-only) +============================================= -The :py:mod:`ImageWin` module contains support to create and display images on +The :py:mod:`~PIL.ImageWin` module contains support to create and display images on Windows. ImageWin can be used with PythonWin and other user interface toolkits that diff --git a/docs/reference/JpegPresets.rst b/docs/reference/JpegPresets.rst index 0a0914601..aafae44cf 100644 --- a/docs/reference/JpegPresets.rst +++ b/docs/reference/JpegPresets.rst @@ -1,7 +1,7 @@ .. py:currentmodule:: PIL.JpegPresets -:py:mod:`JpegPresets` Module -============================ +:py:mod:`~PIL.JpegPresets` Module +================================= .. automodule:: PIL.JpegPresets diff --git a/docs/reference/PSDraw.rst b/docs/reference/PSDraw.rst index 2b5b9b340..958385818 100644 --- a/docs/reference/PSDraw.rst +++ b/docs/reference/PSDraw.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.PSDraw .. py:currentmodule:: PIL.PSDraw -:py:mod:`PSDraw` Module -======================= +:py:mod:`~PIL.PSDraw` Module +============================ -The :py:mod:`PSDraw` module provides simple print support for Postscript +The :py:mod:`~PIL.PSDraw` module provides simple print support for Postscript printers. You can print text, graphics and images through this module. .. autoclass:: PIL.PSDraw.PSDraw diff --git a/docs/reference/PyAccess.rst b/docs/reference/PyAccess.rst index e00741c43..486c9fc21 100644 --- a/docs/reference/PyAccess.rst +++ b/docs/reference/PyAccess.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.PyAccess .. py:currentmodule:: PIL.PyAccess -:py:mod:`PyAccess` Module -========================= +:py:mod:`~PIL.PyAccess` Module +============================== -The :py:mod:`PyAccess` module provides a CFFI/Python implementation of the :ref:`PixelAccess`. This implementation is far faster on PyPy than the PixelAccess version. +The :py:mod:`~PIL.PyAccess` module provides a CFFI/Python implementation of the :ref:`PixelAccess`. This implementation is far faster on PyPy than the PixelAccess version. .. note:: Accessing individual pixels is fairly slow. If you are looping over all of the pixels in an image, there is likely diff --git a/docs/reference/TiffTags.rst b/docs/reference/TiffTags.rst index 4161110bd..a53788a9f 100644 --- a/docs/reference/TiffTags.rst +++ b/docs/reference/TiffTags.rst @@ -1,10 +1,10 @@ .. py:module:: PIL.TiffTags .. py:currentmodule:: PIL.TiffTags -:py:mod:`TiffTags` Module -========================= +:py:mod:`~PIL.TiffTags` Module +============================== -The :py:mod:`TiffTags` module exposes many of the standard TIFF +The :py:mod:`~PIL.TiffTags` module exposes many of the standard TIFF metadata tag numbers, names, and type information. .. method:: lookup(tag) diff --git a/docs/reference/features.rst b/docs/reference/features.rst index 47e9a6d63..dd218fa0e 100644 --- a/docs/reference/features.rst +++ b/docs/reference/features.rst @@ -1,8 +1,8 @@ .. py:module:: PIL.features .. py:currentmodule:: PIL.features -:py:mod:`features` Module -========================== +:py:mod:`~PIL.features` Module +============================== The :py:mod:`PIL.features` module can be used to detect which Pillow features are available on your system. diff --git a/docs/reference/internal_modules.rst b/docs/reference/internal_modules.rst index 7a7967d23..288a049ee 100644 --- a/docs/reference/internal_modules.rst +++ b/docs/reference/internal_modules.rst @@ -1,32 +1,32 @@ Internal Modules ================ -:mod:`_binary` Module ---------------------- +:mod:`~PIL._binary` Module +-------------------------- .. automodule:: PIL._binary :members: :undoc-members: :show-inheritance: -:mod:`_tkinter_finder` Module ------------------------------ +:mod:`~PIL._tkinter_finder` Module +---------------------------------- .. automodule:: PIL._tkinter_finder :members: :undoc-members: :show-inheritance: -:mod:`_util` Module -------------------- +:mod:`~PIL._util` Module +------------------------ .. automodule:: PIL._util :members: :undoc-members: :show-inheritance: -:mod:`_version` Module ----------------------- +:mod:`~PIL._version` Module +--------------------------- .. module:: PIL._version diff --git a/docs/reference/plugins.rst b/docs/reference/plugins.rst index cc0742fde..ef080b6db 100644 --- a/docs/reference/plugins.rst +++ b/docs/reference/plugins.rst @@ -1,232 +1,232 @@ Plugin reference ================ -:mod:`BmpImagePlugin` Module ----------------------------- +:mod:`~PIL.BmpImagePlugin` Module +--------------------------------- .. automodule:: PIL.BmpImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`BufrStubImagePlugin` Module ---------------------------------- +:mod:`~PIL.BufrStubImagePlugin` Module +-------------------------------------- .. automodule:: PIL.BufrStubImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`CurImagePlugin` Module ----------------------------- +:mod:`~PIL.CurImagePlugin` Module +--------------------------------- .. automodule:: PIL.CurImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`DcxImagePlugin` Module ----------------------------- +:mod:`~PIL.DcxImagePlugin` Module +--------------------------------- .. automodule:: PIL.DcxImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`EpsImagePlugin` Module ----------------------------- +:mod:`~PIL.EpsImagePlugin` Module +--------------------------------- .. automodule:: PIL.EpsImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`FitsStubImagePlugin` Module ---------------------------------- +:mod:`~PIL.FitsStubImagePlugin` Module +-------------------------------------- .. automodule:: PIL.FitsStubImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`FliImagePlugin` Module ----------------------------- +:mod:`~PIL.FliImagePlugin` Module +--------------------------------- .. automodule:: PIL.FliImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`FpxImagePlugin` Module ----------------------------- +:mod:`~PIL.FpxImagePlugin` Module +--------------------------------- .. automodule:: PIL.FpxImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`GbrImagePlugin` Module ----------------------------- +:mod:`~PIL.GbrImagePlugin` Module +--------------------------------- .. automodule:: PIL.GbrImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`GifImagePlugin` Module ----------------------------- +:mod:`~PIL.GifImagePlugin` Module +--------------------------------- .. automodule:: PIL.GifImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`GribStubImagePlugin` Module ---------------------------------- +:mod:`~PIL.GribStubImagePlugin` Module +-------------------------------------- .. automodule:: PIL.GribStubImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`Hdf5StubImagePlugin` Module ---------------------------------- +:mod:`~PIL.Hdf5StubImagePlugin` Module +-------------------------------------- .. automodule:: PIL.Hdf5StubImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`IcnsImagePlugin` Module ------------------------------ +:mod:`~PIL.IcnsImagePlugin` Module +---------------------------------- .. automodule:: PIL.IcnsImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`IcoImagePlugin` Module ----------------------------- +:mod:`~PIL.IcoImagePlugin` Module +--------------------------------- .. automodule:: PIL.IcoImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`ImImagePlugin` Module ---------------------------- +:mod:`~PIL.ImImagePlugin` Module +-------------------------------- .. automodule:: PIL.ImImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`ImtImagePlugin` Module ----------------------------- +:mod:`~PIL.ImtImagePlugin` Module +--------------------------------- .. automodule:: PIL.ImtImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`IptcImagePlugin` Module ------------------------------ +:mod:`~PIL.IptcImagePlugin` Module +---------------------------------- .. automodule:: PIL.IptcImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`JpegImagePlugin` Module ------------------------------ +:mod:`~PIL.JpegImagePlugin` Module +---------------------------------- .. automodule:: PIL.JpegImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`Jpeg2KImagePlugin` Module -------------------------------- +:mod:`~PIL.Jpeg2KImagePlugin` Module +------------------------------------ .. automodule:: PIL.Jpeg2KImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`McIdasImagePlugin` Module -------------------------------- +:mod:`~PIL.McIdasImagePlugin` Module +------------------------------------ .. automodule:: PIL.McIdasImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`MicImagePlugin` Module ----------------------------- +:mod:`~PIL.MicImagePlugin` Module +--------------------------------- .. automodule:: PIL.MicImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`MpegImagePlugin` Module ------------------------------ +:mod:`~PIL.MpegImagePlugin` Module +---------------------------------- .. automodule:: PIL.MpegImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`MspImagePlugin` Module ----------------------------- +:mod:`~PIL.MspImagePlugin` Module +--------------------------------- .. automodule:: PIL.MspImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PalmImagePlugin` Module ------------------------------ +:mod:`~PIL.PalmImagePlugin` Module +---------------------------------- .. automodule:: PIL.PalmImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PcdImagePlugin` Module ----------------------------- +:mod:`~PIL.PcdImagePlugin` Module +--------------------------------- .. automodule:: PIL.PcdImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PcxImagePlugin` Module ----------------------------- +:mod:`~PIL.PcxImagePlugin` Module +--------------------------------- .. automodule:: PIL.PcxImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PdfImagePlugin` Module ----------------------------- +:mod:`~PIL.PdfImagePlugin` Module +--------------------------------- .. automodule:: PIL.PdfImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PixarImagePlugin` Module ------------------------------- +:mod:`~PIL.PixarImagePlugin` Module +----------------------------------- .. automodule:: PIL.PixarImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PngImagePlugin` Module ----------------------------- +:mod:`~PIL.PngImagePlugin` Module +--------------------------------- .. automodule:: PIL.PngImagePlugin :members: ChunkStream, PngStream, getchunks, is_cid, putchunk @@ -245,96 +245,96 @@ Plugin reference :show-inheritance: -:mod:`PpmImagePlugin` Module ----------------------------- +:mod:`~PIL.PpmImagePlugin` Module +--------------------------------- .. automodule:: PIL.PpmImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`PsdImagePlugin` Module ----------------------------- +:mod:`~PIL.PsdImagePlugin` Module +--------------------------------- .. automodule:: PIL.PsdImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`SgiImagePlugin` Module ----------------------------- +:mod:`~PIL.SgiImagePlugin` Module +--------------------------------- .. automodule:: PIL.SgiImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`SpiderImagePlugin` Module -------------------------------- +:mod:`~PIL.SpiderImagePlugin` Module +------------------------------------ .. automodule:: PIL.SpiderImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`SunImagePlugin` Module ----------------------------- +:mod:`~PIL.SunImagePlugin` Module +--------------------------------- .. automodule:: PIL.SunImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`TgaImagePlugin` Module ----------------------------- +:mod:`~PIL.TgaImagePlugin` Module +--------------------------------- .. automodule:: PIL.TgaImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`TiffImagePlugin` Module ------------------------------ +:mod:`~PIL.TiffImagePlugin` Module +---------------------------------- .. automodule:: PIL.TiffImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`WebPImagePlugin` Module ------------------------------ +:mod:`~PIL.WebPImagePlugin` Module +---------------------------------- .. automodule:: PIL.WebPImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`WmfImagePlugin` Module ----------------------------- +:mod:`~PIL.WmfImagePlugin` Module +--------------------------------- .. automodule:: PIL.WmfImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`XVThumbImagePlugin` Module --------------------------------- +:mod:`~PIL.XVThumbImagePlugin` Module +------------------------------------- .. automodule:: PIL.XVThumbImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`XbmImagePlugin` Module ----------------------------- +:mod:`~PIL.XbmImagePlugin` Module +--------------------------------- .. automodule:: PIL.XbmImagePlugin :members: :undoc-members: :show-inheritance: -:mod:`XpmImagePlugin` Module ----------------------------- +:mod:`~PIL.XpmImagePlugin` Module +--------------------------------- .. automodule:: PIL.XpmImagePlugin :members: From bd2c705606069cb29d466768f306a3a621c949e8 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 07:14:07 +0200 Subject: [PATCH 029/126] fix CmsProfile type references (cherry picked from commit 61966951562ac9c7f1dd7764d913c9166f642e45) --- docs/reference/ImageCms.rst | 139 +++++++++++++++--------------------- 1 file changed, 57 insertions(+), 82 deletions(-) diff --git a/docs/reference/ImageCms.rst b/docs/reference/ImageCms.rst index 67c581765..01682137b 100644 --- a/docs/reference/ImageCms.rst +++ b/docs/reference/ImageCms.rst @@ -25,31 +25,30 @@ can be easily displayed in a chromaticity diagram, for example). .. py:class:: CmsProfile .. py:attribute:: creation_date + :type: Optional[datetime.datetime] Date and time this profile was first created (see 7.2.1 of ICC.1:2010). - :type: :py:class:`datetime.datetime` or ``None`` - .. py:attribute:: version + :type: float The version number of the ICC standard that this profile follows (e.g. ``2.0``). - :type: :py:class:`float` - .. py:attribute:: icc_version + :type: int Same as ``version``, but in encoded format (see 7.2.4 of ICC.1:2010). .. py:attribute:: device_class + :type: str 4-character string identifying the profile class. One of ``scnr``, ``mntr``, ``prtr``, ``link``, ``spac``, ``abst``, ``nmcl`` (see 7.2.5 of ICC.1:2010 for details). - :type: :py:class:`string` - .. py:attribute:: xcolor_space + :type: str 4-character string (padded with whitespace) identifying the color space, e.g. ``XYZ␣``, ``RGB␣`` or ``CMYK`` (see 7.2.6 of @@ -59,9 +58,8 @@ can be easily displayed in a chromaticity diagram, for example). interpreted (non-padded) variant of this (but can be empty on unknown input). - :type: :py:class:`string` - .. py:attribute:: connection_space + :type: str 4-character string (padded with whitespace) identifying the color space on the B-side of the transform (see 7.2.7 of ICC.1:2010 for @@ -70,42 +68,37 @@ can be easily displayed in a chromaticity diagram, for example). Note that the deprecated attribute ``pcs`` contains an interpreted (non-padded) variant of this (but can be empty on unknown input). - :type: :py:class:`string` - .. py:attribute:: header_flags + :type: int The encoded header flags of the profile (see 7.2.11 of ICC.1:2010 for details). - :type: :py:class:`int` - .. py:attribute:: header_manufacturer + :type: str 4-character string (padded with whitespace) identifying the device manufacturer, which shall match the signature contained in the appropriate section of the ICC signature registry found at www.color.org (see 7.2.12 of ICC.1:2010). - :type: :py:class:`string` - .. py:attribute:: header_model + :type: str 4-character string (padded with whitespace) identifying the device model, which shall match the signature contained in the appropriate section of the ICC signature registry found at www.color.org (see 7.2.13 of ICC.1:2010). - :type: :py:class:`string` - .. py:attribute:: attributes + :type: int Flags used to identify attributes unique to the particular device setup for which the profile is applicable (see 7.2.14 of ICC.1:2010 for details). - :type: :py:class:`int` - .. py:attribute:: rendering_intent + :type: int The rendering intent to use when combining this profile with another profile (usually overridden at run-time, but provided here @@ -114,84 +107,82 @@ can be easily displayed in a chromaticity diagram, for example). One of ``ImageCms.INTENT_ABSOLUTE_COLORIMETRIC``, ``ImageCms.INTENT_PERCEPTUAL``, ``ImageCms.INTENT_RELATIVE_COLORIMETRIC`` and ``ImageCms.INTENT_SATURATION``. - :type: :py:class:`int` - .. py:attribute:: profile_id + :type: bytes A sequence of 16 bytes identifying the profile (via a specially constructed MD5 sum), or 16 binary zeroes if the profile ID has not been calculated (see 7.2.18 of ICC.1:2010). - :type: :py:class:`bytes` - .. py:attribute:: copyright + :type: Optional[str] The text copyright information for the profile (see 9.2.21 of ICC.1:2010). - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: manufacturer + :type: Optional[str] The (English) display string for the device manufacturer (see 9.2.22 of ICC.1:2010). - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: model + :type: Optional[str] The (English) display string for the device model of the device for which this profile is created (see 9.2.23 of ICC.1:2010). - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: profile_description + :type: Optional[str] The (English) display string for the profile description (see 9.2.41 of ICC.1:2010). - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: target + :type: Optional[str] The name of the registered characterization data set, or the measurement data for a characterization target (see 9.2.14 of ICC.1:2010). - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: red_colorant + :type: Optional[tuple[tuple[float]]] The first column in the matrix used in matrix/TRC transforms (see 9.2.44 of ICC.1:2010). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: green_colorant + :type: Optional[tuple[tuple[float]]] The second column in the matrix used in matrix/TRC transforms (see 9.2.30 of ICC.1:2010). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: blue_colorant + :type: Optional[tuple[tuple[float]]] The third column in the matrix used in matrix/TRC transforms (see 9.2.4 of ICC.1:2010). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: luminance + :type: Optional[tuple[tuple[float]]] The absolute luminance of emissive devices in candelas per square metre as described by the Y channel (see 9.2.32 of ICC.1:2010). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: chromaticity + :type: Optional[tuple[tuple[float]]] The data of the phosphor/colorant chromaticity set used (red, green and blue channels, see 9.2.16 of ICC.1:2010). - :type: ``((x, y, Y), (x, y, Y), (x, y, Y))`` or ``None`` + The value is in the format ``((x, y, Y), (x, y, Y), (x, y, Y))``, if available. .. py:attribute:: chromatic_adaption + :type: tuple[tuple[float]] The chromatic adaption matrix converts a color measured using the actual illumination conditions and relative to the actual adopted @@ -199,58 +190,52 @@ can be easily displayed in a chromaticity diagram, for example). complete adaptation from the actual adopted white chromaticity to the PCS adopted white chromaticity (see 9.2.15 of ICC.1:2010). - Two matrices are returned, one in (X, Y, Z) space and one in (x, y, Y) space. - - :type: 2-tuple of 3-tuple, the first with (X, Y, Z) and the second with (x, y, Y) values + Two 3-tuples of floats are returned in a 2-tuple, + one in (X, Y, Z) space and one in (x, y, Y) space. .. py:attribute:: colorant_table + :type: list[str] This tag identifies the colorants used in the profile by a unique name and set of PCSXYZ or PCSLAB values (see 9.2.19 of ICC.1:2010). - :type: list of strings - .. py:attribute:: colorant_table_out + :type: list[str] This tag identifies the colorants used in the profile by a unique name and set of PCSLAB values (for DeviceLink profiles only, see 9.2.19 of ICC.1:2010). - :type: list of strings - .. py:attribute:: colorimetric_intent + :type: Optional[str] 4-character string (padded with whitespace) identifying the image state of PCS colorimetry produced using the colorimetric intent transforms (see 9.2.20 of ICC.1:2010 for details). - :type: :py:class:`string` or ``None`` - .. py:attribute:: perceptual_rendering_intent_gamut + :type: Optional[str] 4-character string (padded with whitespace) identifying the (one) standard reference medium gamut (see 9.2.37 of ICC.1:2010 for details). - :type: :py:class:`string` or ``None`` - .. py:attribute:: saturation_rendering_intent_gamut + :type: Optional[str] 4-character string (padded with whitespace) identifying the (one) standard reference medium gamut (see 9.2.37 of ICC.1:2010 for details). - :type: :py:class:`string` or ``None`` - .. py:attribute:: technology + :type: Optional[str] 4-character string (padded with whitespace) identifying the device technology (see 9.2.47 of ICC.1:2010 for details). - :type: :py:class:`string` or ``None`` - .. py:attribute:: media_black_point + :type: Optional[tuple[tuple[float]]] This tag specifies the media black point and is used for generating absolute colorimetry. @@ -258,57 +243,57 @@ can be easily displayed in a chromaticity diagram, for example). This tag was available in ICC 3.2, but it is removed from version 4. - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: media_white_point_temperature + :type: Optional[float] Calculates the white point temperature (see the LCMS documentation for more information). - :type: :py:class:`float` or ``None`` - .. py:attribute:: viewing_condition + :type: Optional[str] The (English) display string for the viewing conditions (see 9.2.48 of ICC.1:2010). - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: screening_description + :type: Optional[str] The (English) display string for the screening conditions. This tag was available in ICC 3.2, but it is removed from version 4. - :type: :py:class:`unicode` or ``None`` - .. py:attribute:: red_primary + :type: Optional[tuple[tuple[float]]] The XYZ-transformed of the RGB primary color red (1, 0, 0). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: green_primary + :type: Optional[tuple[tuple[float]]] The XYZ-transformed of the RGB primary color green (0, 1, 0). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: blue_primary + :type: Optional[tuple[tuple[float]]] The XYZ-transformed of the RGB primary color blue (0, 0, 1). - :type: ``((X, Y, Z), (x, y, Y))`` or ``None`` + The value is in the format ``((X, Y, Z), (x, y, Y))``, if available. .. py:attribute:: is_matrix_shaper + :type: bool True if this profile is implemented as a matrix shaper (see documentation on LCMS). - :type: :py:class:`bool` - .. py:attribute:: clut + :type: dict[tuple[bool]] Returns a dictionary of all supported intents and directions for the CLUT model. @@ -326,9 +311,8 @@ can be easily displayed in a chromaticity diagram, for example). The elements of the tuple are booleans. If the value is ``True``, that intent is supported for that direction. - :type: :py:class:`dict` of boolean 3-tuples - .. py:attribute:: intent_supported + :type: dict[tuple[bool]] Returns a dictionary of all supported intents and directions. @@ -345,53 +329,46 @@ can be easily displayed in a chromaticity diagram, for example). The elements of the tuple are booleans. If the value is ``True``, that intent is supported for that direction. - :type: :py:class:`dict` of boolean 3-tuples - .. py:attribute:: color_space + :type: str Deprecated but retained for backwards compatibility. Interpreted value of :py:attr:`.xcolor_space`. May be the empty string if value could not be decoded. - :type: :py:class:`string` - .. py:attribute:: pcs + :type: str Deprecated but retained for backwards compatibility. Interpreted value of :py:attr:`.connection_space`. May be the empty string if value could not be decoded. - :type: :py:class:`string` - .. py:attribute:: product_model + :type: str Deprecated but retained for backwards compatibility. ASCII-encoded value of :py:attr:`.model`. - :type: :py:class:`string` - .. py:attribute:: product_manufacturer + :type: str Deprecated but retained for backwards compatibility. ASCII-encoded value of :py:attr:`.manufacturer`. - :type: :py:class:`string` - .. py:attribute:: product_copyright + :type: str Deprecated but retained for backwards compatibility. ASCII-encoded value of :py:attr:`.copyright`. - :type: :py:class:`string` - .. py:attribute:: product_description + :type: str Deprecated but retained for backwards compatibility. ASCII-encoded value of :py:attr:`.profile_description`. - :type: :py:class:`string` - .. py:attribute:: product_desc + :type: str Deprecated but retained for backwards compatibility. ASCII-encoded value of :py:attr:`.profile_description`. @@ -401,8 +378,6 @@ can be easily displayed in a chromaticity diagram, for example). depending on the value of the description, copyright, manufacturer and model fields). - :type: :py:class:`string` - There is one function defined on the class: .. py:method:: is_intent_supported(intent, direction) From 5e4c3ae5542437fd13ae5f022672c379ad75c1bd Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 07:22:13 +0200 Subject: [PATCH 030/126] fix ImageMath creating false index entries (cherry picked from commit eebecba3c20cde0aca126eaa081ebe8a49f7c659) --- docs/reference/ImageMath.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/reference/ImageMath.rst b/docs/reference/ImageMath.rst index ca30244d1..4425d03ad 100644 --- a/docs/reference/ImageMath.rst +++ b/docs/reference/ImageMath.rst @@ -98,20 +98,24 @@ These functions are applied to each individual pixel. .. py:currentmodule:: None .. py:function:: abs(image) + :noindex: Absolute value. .. py:function:: convert(image, mode) + :noindex: Convert image to the given mode. The mode must be given as a string constant. .. py:function:: float(image) + :noindex: Convert image to 32-bit floating point. This is equivalent to convert(image, “F”). .. py:function:: int(image) + :noindex: Convert image to 32-bit integer. This is equivalent to convert(image, “I”). @@ -119,9 +123,11 @@ These functions are applied to each individual pixel. integers if necessary to get a correct result. .. py:function:: max(image1, image2) + :noindex: Maximum value. .. py:function:: min(image1, image2) + :noindex: Minimum value. From 8b005dfe333e0fb7c71119e734dd3362b2fef014 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 08:59:57 +0200 Subject: [PATCH 031/126] fix base Image attribute references (cherry picked from commit 07cc74d38bb1a1309e872d47a4a2d08bd97e9423) --- docs/reference/Image.rst | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 216fa1196..641b14c57 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -260,57 +260,51 @@ Attributes Instances of the :py:class:`Image` class have the following attributes: -.. py:attribute:: filename +.. py:attribute:: Image.filename + :type: str The filename or path of the source file. Only images created with the factory function ``open`` have a filename attribute. If the input is a file like object, the filename attribute is set to an empty string. - :type: :py:class:`string` - -.. py:attribute:: format +.. py:attribute:: Image.format + :type: Optional[str] The file format of the source file. For images created by the library itself (via a factory function, or by running a method on an existing image), this attribute is set to ``None``. - :type: :py:class:`string` or ``None`` - -.. py:attribute:: mode +.. py:attribute:: Image.mode + :type: str Image mode. This is a string specifying the pixel format used by the image. Typical values are “1”, “L”, “RGB”, or “CMYK.” See :ref:`concept-modes` for a full list. - :type: :py:class:`string` - -.. py:attribute:: size +.. py:attribute:: Image.size + :type: tuple[int] Image size, in pixels. The size is given as a 2-tuple (width, height). - :type: ``(width, height)`` - -.. py:attribute:: width +.. py:attribute:: Image.width + :type: int Image width, in pixels. - :type: :py:class:`int` - -.. py:attribute:: height +.. py:attribute:: Image.height + :type: int Image height, in pixels. - :type: :py:class:`int` - -.. py:attribute:: palette +.. py:attribute:: Image.palette + :type: Optional[PIL.ImagePalette.ImagePalette] Colour palette table, if any. If mode is "P" or "PA", this should be an instance of the :py:class:`~PIL.ImagePalette.ImagePalette` class. Otherwise, it should be set to ``None``. - :type: :py:class:`~PIL.ImagePalette.ImagePalette` or ``None`` - -.. py:attribute:: info +.. py:attribute:: Image.info + :type: dict A dictionary holding data associated with the image. This dictionary is used by file handlers to pass on various non-image information read from @@ -322,5 +316,3 @@ Instances of the :py:class:`Image` class have the following attributes: keep a reference to the info dictionary returned from the open method. Unless noted elsewhere, this dictionary does not affect saving files. - - :type: :py:class:`dict` From 3342270947b6dd8442eaf9e14e7c34f9c017f507 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 08:45:18 +0200 Subject: [PATCH 032/126] fix Image constants references (cherry picked from commit 5511111f3b36890a64ec7b44368996f72ab4d876) --- docs/handbook/concepts.rst | 58 +++++++++------- docs/reference/Image.rst | 133 +++++++++++++++++++++++++++++++++++- docs/releasenotes/2.7.0.rst | 68 +++++++++--------- docs/releasenotes/4.2.0.rst | 2 +- src/PIL/Image.py | 70 +++++++++---------- 5 files changed, 235 insertions(+), 96 deletions(-) diff --git a/docs/handbook/concepts.rst b/docs/handbook/concepts.rst index e4a720a08..f62e4b176 100644 --- a/docs/handbook/concepts.rst +++ b/docs/handbook/concepts.rst @@ -121,39 +121,47 @@ Filters For geometry operations that may map multiple input pixels to a single output pixel, the Python Imaging Library provides different resampling *filters*. -``NEAREST`` +.. py:currentmodule:: PIL.Image + +.. data:: NEAREST + Pick one nearest pixel from the input image. Ignore all other input pixels. -``BOX`` +.. data:: BOX + Each pixel of source image contributes to one pixel of the destination image with identical weights. - For upscaling is equivalent of ``NEAREST``. + For upscaling is equivalent of :data:`NEAREST`. This filter can only be used with the :py:meth:`~PIL.Image.Image.resize` and :py:meth:`~PIL.Image.Image.thumbnail` methods. .. versionadded:: 3.4.0 -``BILINEAR`` +.. data:: BILINEAR + For resize calculate the output pixel value using linear interpolation on all pixels that may contribute to the output value. For other transformations linear interpolation over a 2x2 environment in the input image is used. -``HAMMING`` - Produces a sharper image than ``BILINEAR``, doesn't have dislocations - on local level like with ``BOX``. +.. data:: HAMMING + + Produces a sharper image than :data:`BILINEAR`, doesn't have dislocations + on local level like with :data:`BOX`. This filter can only be used with the :py:meth:`~PIL.Image.Image.resize` and :py:meth:`~PIL.Image.Image.thumbnail` methods. .. versionadded:: 3.4.0 -``BICUBIC`` +.. data:: BICUBIC + For resize calculate the output pixel value using cubic interpolation on all pixels that may contribute to the output value. For other transformations cubic interpolation over a 4x4 environment in the input image is used. -``LANCZOS`` +.. data:: LANCZOS + Calculate the output pixel value using a high-quality Lanczos filter (a truncated sinc) on all pixels that may contribute to the output value. This filter can only be used with the :py:meth:`~PIL.Image.Image.resize` @@ -165,19 +173,19 @@ pixel, the Python Imaging Library provides different resampling *filters*. Filters comparison table ~~~~~~~~~~~~~~~~~~~~~~~~ -+------------+-------------+-----------+-------------+ -| Filter | Downscaling | Upscaling | Performance | -| | quality | quality | | -+============+=============+===========+=============+ -|``NEAREST`` | | | ⭐⭐⭐⭐⭐ | -+------------+-------------+-----------+-------------+ -|``BOX`` | ⭐ | | ⭐⭐⭐⭐ | -+------------+-------------+-----------+-------------+ -|``BILINEAR``| ⭐ | ⭐ | ⭐⭐⭐ | -+------------+-------------+-----------+-------------+ -|``HAMMING`` | ⭐⭐ | | ⭐⭐⭐ | -+------------+-------------+-----------+-------------+ -|``BICUBIC`` | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | -+------------+-------------+-----------+-------------+ -|``LANCZOS`` | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ | -+------------+-------------+-----------+-------------+ ++----------------+-------------+-----------+-------------+ +| Filter | Downscaling | Upscaling | Performance | +| | quality | quality | | ++================+=============+===========+=============+ +|:data:`NEAREST` | | | ⭐⭐⭐⭐⭐ | ++----------------+-------------+-----------+-------------+ +|:data:`BOX` | ⭐ | | ⭐⭐⭐⭐ | ++----------------+-------------+-----------+-------------+ +|:data:`BILINEAR`| ⭐ | ⭐ | ⭐⭐⭐ | ++----------------+-------------+-----------+-------------+ +|:data:`HAMMING` | ⭐⭐ | | ⭐⭐⭐ | ++----------------+-------------+-----------+-------------+ +|:data:`BICUBIC` | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ++----------------+-------------+-----------+-------------+ +|:data:`LANCZOS` | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ | ++----------------+-------------+-----------+-------------+ diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 216fa1196..7a3a58442 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -234,7 +234,7 @@ This rotates the input image by ``theta`` degrees counter clockwise: .. automethod:: PIL.Image.Image.transform .. automethod:: PIL.Image.Image.transpose -This flips the input image by using the ``Image.FLIP_LEFT_RIGHT`` method. +This flips the input image by using the :data:`FLIP_LEFT_RIGHT` method. .. code-block:: python @@ -324,3 +324,134 @@ Instances of the :py:class:`Image` class have the following attributes: Unless noted elsewhere, this dictionary does not affect saving files. :type: :py:class:`dict` + +Constants +--------- + +.. data:: NONE + +Transpose methods +^^^^^^^^^^^^^^^^^ + +Used to specify the :meth:`Image.transpose` method to use. + +.. data:: FLIP_LEFT_RIGHT +.. data:: FLIP_TOP_BOTTOM +.. data:: ROTATE_90 +.. data:: ROTATE_180 +.. data:: ROTATE_270 +.. data:: TRANSPOSE +.. data:: TRANSVERSE + +Transform methods +^^^^^^^^^^^^^^^^^ + +Used to specify the :meth:`Image.transform` method to use. + +.. data:: AFFINE + + Affine transform + +.. data:: EXTENT + + Cut out a rectangular subregion + +.. data:: PERSPECTIVE + + Perspective transform + +.. data:: QUAD + + Map a quadrilateral to a rectangle + +.. data:: MESH + + Map a number of source quadrilaterals in one operation + +Resampling filters +^^^^^^^^^^^^^^^^^^ + +See :ref:`concept-filters` for details. + +.. data:: NEAREST + :noindex: +.. data:: BOX + :noindex: +.. data:: BILINEAR + :noindex: +.. data:: HAMMING + :noindex: +.. data:: BICUBIC + :noindex: +.. data:: LANCZOS + :noindex: + +Some filters are also available under the following names for backwards compatibility: + +.. data:: NONE + :noindex: + :value: NEAREST +.. data:: LINEAR + :value: BILINEAR +.. data:: CUBIC + :value: BICUBIC +.. data:: ANTIALIAS + :value: LANCZOS + +Dither modes +^^^^^^^^^^^^ + +Used to specify the dithering method to use for the +:meth:`~Image.convert` and :meth:`~Image.quantize` methods. + +.. data:: NONE + :noindex: + + No dither + +.. comment: (not implemented) + .. data:: ORDERED + .. data:: RASTERIZE + +.. data:: FLOYDSTEINBERG + + Floyd-Steinberg dither + +Palettes +^^^^^^^^ + +Used to specify the pallete to use for the :meth:`~Image.convert` method. + +.. data:: WEB +.. data:: ADAPTIVE + +Quantization methods +^^^^^^^^^^^^^^^^^^^^ + +Used to specify the quantization method to use for the :meth:`~Image.quantize` method. + +.. data:: MEDIANCUT + + Median cut + +.. data:: MAXCOVERAGE + + Maximum coverage + +.. data:: FASTOCTREE + + Fast octree + +.. data:: LIBIMAGEQUANT + + libimagequant + + Check support using :py:func:`PIL.features.check_feature` + with ``feature="libimagequant"``. + +.. comment: These are not referenced anywhere? + Categories + ^^^^^^^^^^ + .. data:: NORMAL + .. data:: SEQUENCE + .. data:: CONTAINER diff --git a/docs/releasenotes/2.7.0.rst b/docs/releasenotes/2.7.0.rst index 931f9fd1e..03000528f 100644 --- a/docs/releasenotes/2.7.0.rst +++ b/docs/releasenotes/2.7.0.rst @@ -29,53 +29,53 @@ Image resizing filters Image resizing methods :py:meth:`~PIL.Image.Image.resize` and :py:meth:`~PIL.Image.Image.thumbnail` take a ``resample`` argument, which tells which filter should be used for resampling. Possible values are: -:py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`, -:py:attr:`PIL.Image.BICUBIC` and :py:attr:`PIL.Image.ANTIALIAS`. +:py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BILINEAR`, +:py:data:`PIL.Image.BICUBIC` and :py:data:`PIL.Image.ANTIALIAS`. Almost all of them were changed in this version. Bicubic and bilinear downscaling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -From the beginning :py:attr:`~PIL.Image.BILINEAR` and -:py:attr:`~PIL.Image.BICUBIC` filters were based on affine transformations +From the beginning :py:data:`~PIL.Image.BILINEAR` and +:py:data:`~PIL.Image.BICUBIC` filters were based on affine transformations and used a fixed number of pixels from the source image for every destination -pixel (2x2 pixels for :py:attr:`~PIL.Image.BILINEAR` and 4x4 for -:py:attr:`~PIL.Image.BICUBIC`). This gave an unsatisfactory result for +pixel (2x2 pixels for :py:data:`~PIL.Image.BILINEAR` and 4x4 for +:py:data:`~PIL.Image.BICUBIC`). This gave an unsatisfactory result for downscaling. At the same time, a high quality convolutions-based algorithm with -flexible kernel was used for :py:attr:`~PIL.Image.ANTIALIAS` filter. +flexible kernel was used for :py:data:`~PIL.Image.ANTIALIAS` filter. Starting from Pillow 2.7.0, a high quality convolutions-based algorithm is used for all of these three filters. If you have previously used any tricks to maintain quality when downscaling with -:py:attr:`~PIL.Image.BILINEAR` and :py:attr:`~PIL.Image.BICUBIC` filters +:py:data:`~PIL.Image.BILINEAR` and :py:data:`~PIL.Image.BICUBIC` filters (for example, reducing within several steps), they are unnecessary now. Antialias renamed to Lanczos ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -A new :py:attr:`PIL.Image.LANCZOS` constant was added instead of -:py:attr:`~PIL.Image.ANTIALIAS`. +A new :py:data:`PIL.Image.LANCZOS` constant was added instead of +:py:data:`~PIL.Image.ANTIALIAS`. -When :py:attr:`~PIL.Image.ANTIALIAS` was initially added, it was the only +When :py:data:`~PIL.Image.ANTIALIAS` was initially added, it was the only high-quality filter based on convolutions. It's name was supposed to reflect this. Starting from Pillow 2.7.0 all resize method are based on convolutions. All of them are antialias from now on. And the real name of the -:py:attr:`~PIL.Image.ANTIALIAS` filter is Lanczos filter. +:py:data:`~PIL.Image.ANTIALIAS` filter is Lanczos filter. -The :py:attr:`~PIL.Image.ANTIALIAS` constant is left for backward compatibility -and is an alias for :py:attr:`~PIL.Image.LANCZOS`. +The :py:data:`~PIL.Image.ANTIALIAS` constant is left for backward compatibility +and is an alias for :py:data:`~PIL.Image.LANCZOS`. Lanczos upscaling quality ^^^^^^^^^^^^^^^^^^^^^^^^^ -The image upscaling quality with :py:attr:`~PIL.Image.LANCZOS` filter was -almost the same as :py:attr:`~PIL.Image.BILINEAR` due to bug. This has been fixed. +The image upscaling quality with :py:data:`~PIL.Image.LANCZOS` filter was +almost the same as :py:data:`~PIL.Image.BILINEAR` due to bug. This has been fixed. Bicubic upscaling quality ^^^^^^^^^^^^^^^^^^^^^^^^^ -The :py:attr:`~PIL.Image.BICUBIC` filter for affine transformations produced +The :py:data:`~PIL.Image.BICUBIC` filter for affine transformations produced sharp, slightly pixelated image for upscaling. Bicubic for convolutions is more soft. @@ -84,42 +84,42 @@ Resize performance In most cases, convolution is more a expensive algorithm for downscaling because it takes into account all the pixels of source image. Therefore -:py:attr:`~PIL.Image.BILINEAR` and :py:attr:`~PIL.Image.BICUBIC` filters' +:py:data:`~PIL.Image.BILINEAR` and :py:data:`~PIL.Image.BICUBIC` filters' performance can be lower than before. On the other hand the quality of -:py:attr:`~PIL.Image.BILINEAR` and :py:attr:`~PIL.Image.BICUBIC` was close to -:py:attr:`~PIL.Image.NEAREST`. So if such quality is suitable for your tasks -you can switch to :py:attr:`~PIL.Image.NEAREST` filter for downscaling, +:py:data:`~PIL.Image.BILINEAR` and :py:data:`~PIL.Image.BICUBIC` was close to +:py:data:`~PIL.Image.NEAREST`. So if such quality is suitable for your tasks +you can switch to :py:data:`~PIL.Image.NEAREST` filter for downscaling, which will give a huge improvement in performance. At the same time performance of convolution resampling for downscaling has been improved by around a factor of two compared to the previous version. -The upscaling performance of the :py:attr:`~PIL.Image.LANCZOS` filter has -remained the same. For :py:attr:`~PIL.Image.BILINEAR` filter it has improved by -1.5 times and for :py:attr:`~PIL.Image.BICUBIC` by four times. +The upscaling performance of the :py:data:`~PIL.Image.LANCZOS` filter has +remained the same. For :py:data:`~PIL.Image.BILINEAR` filter it has improved by +1.5 times and for :py:data:`~PIL.Image.BICUBIC` by four times. Default filter for thumbnails ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In Pillow 2.5 the default filter for :py:meth:`~PIL.Image.Image.thumbnail` was -changed from :py:attr:`~PIL.Image.NEAREST` to :py:attr:`~PIL.Image.ANTIALIAS`. +changed from :py:data:`~PIL.Image.NEAREST` to :py:data:`~PIL.Image.ANTIALIAS`. Antialias was chosen because all the other filters gave poor quality for -reduction. Starting from Pillow 2.7.0, :py:attr:`~PIL.Image.ANTIALIAS` has been -replaced with :py:attr:`~PIL.Image.BICUBIC`, because it's faster and -:py:attr:`~PIL.Image.ANTIALIAS` doesn't give any advantages after +reduction. Starting from Pillow 2.7.0, :py:data:`~PIL.Image.ANTIALIAS` has been +replaced with :py:data:`~PIL.Image.BICUBIC`, because it's faster and +:py:data:`~PIL.Image.ANTIALIAS` doesn't give any advantages after downscaling with libjpeg, which uses supersampling internally, not convolutions. Image transposition ------------------- -A new method :py:attr:`PIL.Image.TRANSPOSE` has been added for the +A new method :py:data:`PIL.Image.TRANSPOSE` has been added for the :py:meth:`~PIL.Image.Image.transpose` operation in addition to -:py:attr:`~PIL.Image.FLIP_LEFT_RIGHT`, :py:attr:`~PIL.Image.FLIP_TOP_BOTTOM`, -:py:attr:`~PIL.Image.ROTATE_90`, :py:attr:`~PIL.Image.ROTATE_180`, -:py:attr:`~PIL.Image.ROTATE_270`. :py:attr:`~PIL.Image.TRANSPOSE` is an algebra +:py:data:`~PIL.Image.FLIP_LEFT_RIGHT`, :py:data:`~PIL.Image.FLIP_TOP_BOTTOM`, +:py:data:`~PIL.Image.ROTATE_90`, :py:data:`~PIL.Image.ROTATE_180`, +:py:data:`~PIL.Image.ROTATE_270`. :py:data:`~PIL.Image.TRANSPOSE` is an algebra transpose, with an image reflected across its main diagonal. -The speed of :py:attr:`~PIL.Image.ROTATE_90`, :py:attr:`~PIL.Image.ROTATE_270` -and :py:attr:`~PIL.Image.TRANSPOSE` has been significantly improved for large +The speed of :py:data:`~PIL.Image.ROTATE_90`, :py:data:`~PIL.Image.ROTATE_270` +and :py:data:`~PIL.Image.TRANSPOSE` has been significantly improved for large images which don't fit in the processor cache. Gaussian blur and unsharp mask diff --git a/docs/releasenotes/4.2.0.rst b/docs/releasenotes/4.2.0.rst index e07fd9071..906eeab8d 100644 --- a/docs/releasenotes/4.2.0.rst +++ b/docs/releasenotes/4.2.0.rst @@ -27,7 +27,7 @@ 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`. +specified by :py:data:`PIL.Image.MAX_PIXELS`. Removed Deprecated Items ======================== diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 7a2ae02d6..632818e73 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -876,7 +876,7 @@ class Image: The default method of converting a greyscale ("L") or "RGB" image into a bilevel (mode "1") image uses Floyd-Steinberg dither to approximate the original image luminosity levels. If - dither is NONE, all values larger than 128 are set to 255 (white), + dither is :data:`NONE`, all values larger than 128 are set to 255 (white), all other values to 0 (black). To use other thresholds, use the :py:meth:`~PIL.Image.Image.point` method. @@ -889,11 +889,11 @@ class Image: should be 4- or 12-tuple containing floating point values. :param dither: Dithering method, used when converting from mode "RGB" to "P" or from "RGB" or "L" to "1". - Available methods are NONE or FLOYDSTEINBERG (default). + Available methods are :data:`NONE` or :data:`FLOYDSTEINBERG` (default). Note that this is not used when **matrix** is supplied. :param palette: Palette to use when converting from mode "RGB" - to "P". Available palettes are WEB or ADAPTIVE. - :param colors: Number of colors to use for the ADAPTIVE palette. + to "P". Available palettes are :data:`WEB` or :data:`ADAPTIVE`. + :param colors: Number of colors to use for the :data:`ADAPTIVE` palette. Defaults to 256. :rtype: :py:class:`~PIL.Image.Image` :returns: An :py:class:`~PIL.Image.Image` object. @@ -1051,10 +1051,10 @@ class Image: of colors. :param colors: The desired number of colors, <= 256 - :param method: ``Image.MEDIANCUT=0`` (median cut), - ``Image.MAXCOVERAGE=1`` (maximum coverage), - ``Image.FASTOCTREE=2`` (fast octree), - ``Image.LIBIMAGEQUANT=3`` (libimagequant; check support using + :param method: :data:`MEDIANCUT` (median cut), + :data:`MAXCOVERAGE` (maximum coverage), + :data:`FASTOCTREE` (fast octree), + :data:`LIBIMAGEQUANT` (libimagequant; check support using :py:func:`PIL.features.check_feature` with ``feature="libimagequant"``). :param kmeans: Integer @@ -1062,7 +1062,7 @@ class Image: :py:class:`PIL.Image.Image`. :param dither: Dithering method, used when converting from mode "RGB" to "P" or from "RGB" or "L" to "1". - Available methods are NONE or FLOYDSTEINBERG (default). + Available methods are :data:`NONE` or :data:`FLOYDSTEINBERG` (default). Default: 1 (legacy setting) :returns: A new image @@ -1842,12 +1842,12 @@ class Image: :param size: The requested size in pixels, as a 2-tuple: (width, height). :param resample: An optional resampling filter. This can be - one of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BOX`, - :py:attr:`PIL.Image.BILINEAR`, :py:attr:`PIL.Image.HAMMING`, - :py:attr:`PIL.Image.BICUBIC` or :py:attr:`PIL.Image.LANCZOS`. - Default filter is :py:attr:`PIL.Image.BICUBIC`. + one of :py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BOX`, + :py:data:`PIL.Image.BILINEAR`, :py:data:`PIL.Image.HAMMING`, + :py:data:`PIL.Image.BICUBIC` or :py:data:`PIL.Image.LANCZOS`. + Default filter is :py:data:`PIL.Image.BICUBIC`. If the image has mode "1" or "P", it is - always set to :py:attr:`PIL.Image.NEAREST`. + always set to :py:data:`PIL.Image.NEAREST`. See: :ref:`concept-filters`. :param box: An optional 4-tuple of floats providing the source image region to be scaled. @@ -1977,12 +1977,12 @@ class Image: :param angle: In degrees counter clockwise. :param resample: An optional resampling filter. This can be - one of :py:attr:`PIL.Image.NEAREST` (use nearest neighbour), - :py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2 - environment), or :py:attr:`PIL.Image.BICUBIC` + one of :py:data:`PIL.Image.NEAREST` (use nearest neighbour), + :py:data:`PIL.Image.BILINEAR` (linear interpolation in a 2x2 + environment), or :py:data:`PIL.Image.BICUBIC` (cubic spline interpolation in a 4x4 environment). If omitted, or if the image has mode "1" or "P", it is - set to :py:attr:`PIL.Image.NEAREST`. See :ref:`concept-filters`. + set to :py:data:`PIL.Image.NEAREST`. See :ref:`concept-filters`. :param expand: Optional expansion flag. If true, expands the output image to make it large enough to hold the entire rotated image. If false or omitted, make the output image the same size as the @@ -2274,10 +2274,10 @@ class Image: :param size: Requested size. :param resample: Optional resampling filter. This can be one - of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`, - :py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.LANCZOS`. - If omitted, it defaults to :py:attr:`PIL.Image.BICUBIC`. - (was :py:attr:`PIL.Image.NEAREST` prior to version 2.5.0). + of :py:data:`PIL.Image.NEAREST`, :py:data:`PIL.Image.BILINEAR`, + :py:data:`PIL.Image.BICUBIC`, or :py:data:`PIL.Image.LANCZOS`. + If omitted, it defaults to :py:data:`PIL.Image.BICUBIC`. + (was :py:data:`PIL.Image.NEAREST` prior to version 2.5.0). See: :ref:`concept-filters`. :param reducing_gap: Apply optimization by resizing the image in two steps. First, reducing the image by integer times @@ -2341,11 +2341,11 @@ class Image: :param size: The output size. :param method: The transformation method. This is one of - :py:attr:`PIL.Image.EXTENT` (cut out a rectangular subregion), - :py:attr:`PIL.Image.AFFINE` (affine transform), - :py:attr:`PIL.Image.PERSPECTIVE` (perspective transform), - :py:attr:`PIL.Image.QUAD` (map a quadrilateral to a rectangle), or - :py:attr:`PIL.Image.MESH` (map a number of source quadrilaterals + :py:data:`PIL.Image.EXTENT` (cut out a rectangular subregion), + :py:data:`PIL.Image.AFFINE` (affine transform), + :py:data:`PIL.Image.PERSPECTIVE` (perspective transform), + :py:data:`PIL.Image.QUAD` (map a quadrilateral to a rectangle), or + :py:data:`PIL.Image.MESH` (map a number of source quadrilaterals in one operation). It may also be an :py:class:`~PIL.Image.ImageTransformHandler` @@ -2365,11 +2365,11 @@ class Image: return method, data :param data: Extra data to the transformation method. :param resample: Optional resampling filter. It can be one of - :py:attr:`PIL.Image.NEAREST` (use nearest neighbour), - :py:attr:`PIL.Image.BILINEAR` (linear interpolation in a 2x2 - environment), or :py:attr:`PIL.Image.BICUBIC` (cubic spline + :py:data:`PIL.Image.NEAREST` (use nearest neighbour), + :py:data:`PIL.Image.BILINEAR` (linear interpolation in a 2x2 + environment), or :py:data:`PIL.Image.BICUBIC` (cubic spline interpolation in a 4x4 environment). If omitted, or if the image - has mode "1" or "P", it is set to :py:attr:`PIL.Image.NEAREST`. + has mode "1" or "P", it is set to :py:data:`PIL.Image.NEAREST`. See: :ref:`concept-filters`. :param fill: If **method** is an :py:class:`~PIL.Image.ImageTransformHandler` object, this is one of @@ -2493,10 +2493,10 @@ class Image: """ Transpose image (flip or rotate in 90 degree steps) - :param method: One of :py:attr:`PIL.Image.FLIP_LEFT_RIGHT`, - :py:attr:`PIL.Image.FLIP_TOP_BOTTOM`, :py:attr:`PIL.Image.ROTATE_90`, - :py:attr:`PIL.Image.ROTATE_180`, :py:attr:`PIL.Image.ROTATE_270`, - :py:attr:`PIL.Image.TRANSPOSE` or :py:attr:`PIL.Image.TRANSVERSE`. + :param method: One of :py:data:`PIL.Image.FLIP_LEFT_RIGHT`, + :py:data:`PIL.Image.FLIP_TOP_BOTTOM`, :py:data:`PIL.Image.ROTATE_90`, + :py:data:`PIL.Image.ROTATE_180`, :py:data:`PIL.Image.ROTATE_270`, + :py:data:`PIL.Image.TRANSPOSE` or :py:data:`PIL.Image.TRANSVERSE`. :returns: Returns a flipped or rotated copy of this image. """ From 19dd5cbfab75f6d9e74349a611140a5aa2fcd85e Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 09:00:17 +0200 Subject: [PATCH 033/126] fix some function references (cherry picked from commit 9fb582940d577857d9034e0bf0c5cf5630c2d42e) --- docs/handbook/image-file-formats.rst | 22 +++++++++++----------- src/PIL/ImageDraw2.py | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 40db9fe2b..6bcff7135 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -8,7 +8,7 @@ Over 30 different file formats can be identified and read by the library. Write support is less extensive, but most common interchange and presentation formats are supported. -The :py:meth:`~PIL.Image.Image.open` function identifies files from their +The :py:meth:`~PIL.Image.open` function identifies files from their contents, not their names, but the :py:meth:`~PIL.Image.Image.save` method looks at the name to determine which format to use, unless the format is given explicitly. @@ -25,7 +25,7 @@ Pillow reads and writes Windows and OS/2 BMP files containing ``1``, ``L``, ``P` or ``RGB`` data. 16-colour images are read as ``P`` images. Run-length encoding is not supported. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **compression** @@ -74,7 +74,7 @@ are used or GIF89a is already in use. Note that GIF files are always read as grayscale (``L``) or palette mode (``P``) images. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **background** @@ -203,7 +203,7 @@ ICNS Pillow reads and (macOS only) writes macOS ``.icns`` files. By default, the largest available icon is read, though you can override this by setting the :py:attr:`~PIL.Image.Image.size` property before calling -:py:meth:`~PIL.Image.Image.load`. The :py:meth:`~PIL.Image.Image.open` method +:py:meth:`~PIL.Image.Image.load`. The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` property: **sizes** @@ -257,7 +257,7 @@ Using the :py:meth:`~PIL.Image.Image.draft` method, you can speed things up by converting ``RGB`` images to ``L``, and resize images to 1/2, 1/4 or 1/8 of their original size while loading them. -The :py:meth:`~PIL.Image.Image.open` method may set the following +The :py:meth:`~PIL.Image.open` method may set the following :py:attr:`~PIL.Image.Image.info` properties if available: **jfif** @@ -697,7 +697,7 @@ Pillow also reads SPIDER stack files containing sequences of SPIDER images. The :py:meth:`~PIL.Image.Image.seek` and :py:meth:`~PIL.Image.Image.tell` methods are supported, and random access is allowed. -The :py:meth:`~PIL.Image.Image.open` method sets the following attributes: +The :py:meth:`~PIL.Image.open` method sets the following attributes: **format** Set to ``SPIDER`` @@ -750,7 +750,7 @@ uncompressed files. support for reading Packbits, LZW and JPEG compressed TIFFs without using libtiff. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **compression** @@ -1021,7 +1021,7 @@ FLI, FLC Pillow reads Autodesk FLI and FLC animations. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **duration** @@ -1054,7 +1054,7 @@ GBR The GBR decoder reads GIMP brush files, version 1 and 2. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **comment** @@ -1069,7 +1069,7 @@ GD Pillow reads uncompressed GD2 files. Note that you must use :py:func:`PIL.GdImageFile.open` to read such a file. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **transparency** @@ -1185,7 +1185,7 @@ XPM Pillow reads X pixmap files (mode ``P``) with 256 colors or less. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:meth:`~PIL.Image.open` method sets the following :py:attr:`~PIL.Image.Image.info` properties: **transparency** diff --git a/src/PIL/ImageDraw2.py b/src/PIL/ImageDraw2.py index b14b68e3e..1f63110fd 100644 --- a/src/PIL/ImageDraw2.py +++ b/src/PIL/ImageDraw2.py @@ -106,7 +106,7 @@ class Draw: def chord(self, xy, start, end, *options): """ - Same as :py:meth:`~PIL.ImageDraw2.ImageDraw.arc`, but connects the end points + Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points with a straight line. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.chord` From 4f1ee7a881f2ce08ae8f37a0d49241050f2d55b7 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 10:55:54 +0200 Subject: [PATCH 034/126] add missing and sort Image functions (cherry picked from commit f31c786aa6dadfcd93596887bb67b1d9a776f8c6) --- docs/reference/Image.rst | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 216fa1196..649c9a185 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -76,9 +76,16 @@ Constructing images .. autofunction:: new .. autofunction:: fromarray .. autofunction:: frombytes -.. autofunction:: fromstring .. autofunction:: frombuffer +Generating images +^^^^^^^^^^^^^^^^^ + +.. autofunction:: effect_mandelbrot +.. autofunction:: effect_noise +.. autofunction:: linear_gradient +.. autofunction:: radial_gradient + Registering plugins ^^^^^^^^^^^^^^^^^^^ @@ -88,12 +95,14 @@ Registering plugins ignore them. .. autofunction:: register_open -.. autofunction:: register_decoder .. autofunction:: register_mime .. autofunction:: register_save -.. autofunction:: register_encoder +.. autofunction:: register_save_all .. autofunction:: register_extension - +.. autofunction:: register_extensions +.. autofunction:: registered_extensions +.. autofunction:: register_decoder +.. autofunction:: register_encoder The Image Class --------------- @@ -140,6 +149,8 @@ This crops the input image with the provided coordinates: .. automethod:: PIL.Image.Image.draft +.. automethod:: PIL.Image.Image.effect_spread +.. automethod:: PIL.Image.Image.entropy .. automethod:: PIL.Image.Image.filter This blurs the input image using a filter from the ``ImageFilter`` module: @@ -176,12 +187,14 @@ This helps to get the bounding box coordinates of the input image: print(im.getbbox()) # Returns four coordinates in the format (left, upper, right, lower) +.. automethod:: PIL.Image.Image.getchannel .. automethod:: PIL.Image.Image.getcolors .. automethod:: PIL.Image.Image.getdata -.. automethod:: PIL.Image.Image.getextrema .. automethod:: PIL.Image.Image.getexif +.. automethod:: PIL.Image.Image.getextrema .. automethod:: PIL.Image.Image.getpalette .. automethod:: PIL.Image.Image.getpixel +.. automethod:: PIL.Image.Image.getprojection .. automethod:: PIL.Image.Image.histogram .. automethod:: PIL.Image.Image.offset .. automethod:: PIL.Image.Image.paste @@ -191,6 +204,8 @@ This helps to get the bounding box coordinates of the input image: .. automethod:: PIL.Image.Image.putpalette .. automethod:: PIL.Image.Image.putpixel .. automethod:: PIL.Image.Image.quantize +.. automethod:: PIL.Image.Image.reduce +.. automethod:: PIL.Image.Image.remap_palette .. automethod:: PIL.Image.Image.resize This resizes the given image from ``(width, height)`` to ``(width/2, height/2)``: @@ -205,7 +220,6 @@ This resizes the given image from ``(width, height)`` to ``(width/2, height/2)`` (width, height) = (im.width // 2, im.height // 2) im_resized = im.resize((width, height)) -.. automethod:: PIL.Image.Image.remap_palette .. automethod:: PIL.Image.Image.rotate This rotates the input image by ``theta`` degrees counter clockwise: @@ -225,7 +239,6 @@ This rotates the input image by ``theta`` degrees counter clockwise: .. automethod:: PIL.Image.Image.seek .. automethod:: PIL.Image.Image.show .. automethod:: PIL.Image.Image.split -.. automethod:: PIL.Image.Image.getchannel .. automethod:: PIL.Image.Image.tell .. automethod:: PIL.Image.Image.thumbnail .. automethod:: PIL.Image.Image.tobitmap From f5b4565d8c163cc1c55ed9f5525ec5848915aaa0 Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 27 Jun 2020 17:24:13 +0200 Subject: [PATCH 035/126] document is_animated and n_frames --- docs/reference/Image.rst | 31 +++++++++++++++++++++++++++++++ src/PIL/Image.py | 6 ++++++ 2 files changed, 37 insertions(+) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 216fa1196..bccaf01f4 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -324,3 +324,34 @@ Instances of the :py:class:`Image` class have the following attributes: Unless noted elsewhere, this dictionary does not affect saving files. :type: :py:class:`dict` + +.. py:attribute:: Image.is_animated + :type: bool + + This attribute is ``True`` if the Image is animated, ``False`` otherwise. + Typically defined as ``Image.n_frames > 1``. + + This attribute is only defined by Image plugins that support animated Images. + Plugins may leave this attribute undefined if they don't support loading + animated images, even if the given format supports animated images. Use + ``hasattr(image, "is_animated")`` to check whether the implementation + supports animated images, or ``getattr(image, "is_animated", False)`` + to check whether an image has been loaded with animation support. + + .. seealso:: :attr:`~Image.n_frames`, :func:`~Image.seek` and :func:`~Image.tell` + +.. py:attribute:: Image.n_frames + :type: int + + The number of frames in this image. + Defined if and only if :attr:`~Image.is_animated` is also defined. + Equal to 1 for non-animated images loaded by a plugin supporting animations. + + This attribute is only defined by Image plugins that support animated Images. + Plugins may leave this attribute undefined if they don't support loading + animated images, even if the given format supports animated images. Use + ``hasattr(image, "is_animated")`` to check whether the implementation + supports animated images, or ``getattr(image, "n_frames", 1)`` + to check whether an image has been loaded with more than one frame. + + .. seealso:: :attr:`~Image.is_animated`, :func:`~Image.seek` and :func:`~Image.tell` diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 7a2ae02d6..e272414d7 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2170,6 +2170,9 @@ class Image: See :py:meth:`~PIL.Image.Image.tell`. + If defined, :attr:`~PIL.Image.Image.n_frames` refers to the + number of available frames. + :param frame: Frame number, starting at 0. :exception EOFError: If the call attempts to seek beyond the end of the sequence. @@ -2254,6 +2257,9 @@ class Image: """ Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. + If defined, :attr:`~PIL.Image.Image.n_frames` refers to the + number of available frames. + :returns: Frame number, starting with 0. """ return 0 From 1e8d418f4266ddd1a14e024f0997c76b8dc1ca9c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 28 Jun 2020 17:24:27 +1000 Subject: [PATCH 036/126] Fixed ICNS file pointer saving --- Tests/test_file_icns.py | 13 +++++++++++++ src/PIL/IcnsImagePlugin.py | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 7bf7b72ec..05feedb1a 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -55,6 +55,19 @@ def test_save_append_images(tmp_path): assert_image_equal(reread, provided_im) +@pytest.mark.skipif(sys.platform != "darwin", reason="Requires macOS") +def test_save_fp(): + fp = io.BytesIO() + + with Image.open(TEST_FILE) as im: + im.save(fp, format="ICNS") + + with Image.open(fp) as reread: + assert reread.mode == "RGBA" + assert reread.size == (1024, 1024) + assert reread.format == "ICNS" + + def test_sizes(): # Check that we can load all of the sizes, and that the final pixel # dimensions are as expected diff --git a/src/PIL/IcnsImagePlugin.py b/src/PIL/IcnsImagePlugin.py index 9de7d8dfe..7023855ba 100644 --- a/src/PIL/IcnsImagePlugin.py +++ b/src/PIL/IcnsImagePlugin.py @@ -337,6 +337,10 @@ def _save(im, fp, filename): # iconutil -c icns -o {} {} + fp_only = not filename + if fp_only: + f, filename = tempfile.mkstemp(".icns") + os.close(f) convert_cmd = ["iconutil", "-c", "icns", "-o", filename, iconset] convert_proc = subprocess.Popen( convert_cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL @@ -349,6 +353,10 @@ def _save(im, fp, filename): if retcode: raise subprocess.CalledProcessError(retcode, convert_cmd) + if fp_only: + with open(filename, "rb") as f: + fp.write(f.read()) + Image.register_open(IcnsImageFile.format, IcnsImageFile, lambda x: x[:4] == b"icns") Image.register_extension(IcnsImageFile.format, ".icns") From cdf4936c07a48372f9120afb5a83ed426db0f14a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 29 Jun 2020 21:20:57 +1000 Subject: [PATCH 037/126] Fixed loading non-RGBA mode images with dispose background --- .../images/apng/dispose_op_background_p_mode.png | Bin 0 -> 1239 bytes Tests/test_file_apng.py | 7 +++++++ src/PIL/PngImagePlugin.py | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 Tests/images/apng/dispose_op_background_p_mode.png diff --git a/Tests/images/apng/dispose_op_background_p_mode.png b/Tests/images/apng/dispose_op_background_p_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..e5fb4784d260cd9fb1556011c97eb070e2d0a351 GIT binary patch literal 1239 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`!3-pya`gK$FfcO&_=LFr2l7Y3Xb6nd5D@R2 z8Op%G$WRjG7d+DQ!q1gAU4iL_smkWTDoTrOpNX4AD2N^-4O$z_l z=Xp4Q6#%*K*%TZY80#+vYzA_q(jdBlOh}OfVn6`%3r2 Date: Mon, 29 Jun 2020 22:02:01 +1000 Subject: [PATCH 038/126] Added disposal test --- Tests/test_file_apng.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index deb043fdd..1fd7d8c3d 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -494,6 +494,26 @@ def test_apng_save_disposal(tmp_path): assert im.getpixel((64, 32)) == (0, 255, 0, 255) +def test_apng_save_disposal_previous(tmp_path): + test_file = str(tmp_path / "temp.png") + size = (128, 64) + transparent = Image.new("RGBA", size, (0, 0, 0, 0)) + red = Image.new("RGBA", size, (255, 0, 0, 255)) + green = Image.new("RGBA", size, (0, 255, 0, 255)) + + # test APNG_DISPOSE_OP_NONE + transparent.save( + test_file, + save_all=True, + append_images=[red, green], + disposal=PngImagePlugin.APNG_DISPOSE_OP_PREVIOUS, + ) + with Image.open(test_file) as im: + im.seek(2) + assert im.getpixel((0, 0)) == (0, 255, 0, 255) + assert im.getpixel((64, 32)) == (0, 255, 0, 255) + + def test_apng_save_blend(tmp_path): test_file = str(tmp_path / "temp.png") size = (128, 64) From e1ae9a50cb002f5d5613c359d5e008ba5485d9d4 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 29 Jun 2020 22:14:40 +1000 Subject: [PATCH 039/126] Do not convert I;16 image when format is PNG --- src/PIL/ImageShow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PIL/ImageShow.py b/src/PIL/ImageShow.py index 57b7dcac7..3ffb4d632 100644 --- a/src/PIL/ImageShow.py +++ b/src/PIL/ImageShow.py @@ -71,7 +71,8 @@ class Viewer: # save temporary image to disk if not ( - image.mode in ("1", "RGBA") or (self.format == "PNG" and image.mode == "LA") + image.mode in ("1", "RGBA") + or (self.format == "PNG" and image.mode in ("I;16", "LA")) ): base = Image.getmodebase(image.mode) if image.mode != base: From 15f1e183d613cdf3c2a57f6fc2073fbf1ce8ecb7 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Jun 2020 00:33:51 +1000 Subject: [PATCH 040/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index c5b55a524..151ca8a3d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 7.2.0 (unreleased) ------------------ +- Fixed loading non-RGBA mode APNGs with dispose background #4742 + [radarhere] + - Deprecated _showxv #4714 [radarhere] From 3648332edca5a7c152c81e3f8ee81dd08fd39bcf Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Jun 2020 08:53:08 +1000 Subject: [PATCH 041/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 151ca8a3d..23c115a11 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,12 @@ Changelog (Pillow) 7.2.0 (unreleased) ------------------ +- Do not convert I;16 images when showing PNGs #4744 + [radarhere] + +- Fixed ICNS file pointer saving #4741 + [radarhere] + - Fixed loading non-RGBA mode APNGs with dispose background #4742 [radarhere] From 17b14f81fc103c822232101b143c85af12404e58 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Jun 2020 17:46:57 +1000 Subject: [PATCH 042/126] 7.2.0 version bump --- src/PIL/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/_version.py b/src/PIL/_version.py index eeee6a1f5..035deeba7 100644 --- a/src/PIL/_version.py +++ b/src/PIL/_version.py @@ -1,2 +1,2 @@ # Master version for Pillow -__version__ = "7.2.0.dev0" +__version__ = "7.2.0" From 2bd74943fb9f320def6c066e732b701d1c15f677 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Jun 2020 17:50:35 +1000 Subject: [PATCH 043/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 23c115a11..c63f05e6a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,7 +2,7 @@ Changelog (Pillow) ================== -7.2.0 (unreleased) +7.2.0 (2020-07-01) ------------------ - Do not convert I;16 images when showing PNGs #4744 From ed942911a812fa1b7d06c459e31c8a7b191131c3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 30 Jun 2020 20:50:02 +1000 Subject: [PATCH 044/126] 7.3.0.dev0 version bump --- src/PIL/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/_version.py b/src/PIL/_version.py index 035deeba7..a67ccbff4 100644 --- a/src/PIL/_version.py +++ b/src/PIL/_version.py @@ -1,2 +1,2 @@ # Master version for Pillow -__version__ = "7.2.0" +__version__ = "7.3.0.dev0" From 6cdeb5511892384046db0fb0ffd5bedd308269e4 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sat, 27 Jun 2020 14:39:44 +0300 Subject: [PATCH 045/126] Drop support for soon-EOL Python 3.5 --- .appveyor.yml | 2 +- .github/workflows/test-windows.yml | 2 +- .github/workflows/test.yml | 5 ++--- .travis.yml | 7 ++----- docs/installation.rst | 4 +++- setup.py | 3 +-- tox.ini | 2 +- winbuild/README.md | 4 ++-- winbuild/build.rst | 2 +- winbuild/build_prepare.py | 2 +- 10 files changed, 15 insertions(+), 18 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ad783f85e..965edb67f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -14,7 +14,7 @@ environment: matrix: - PYTHON: C:/Python38 ARCHITECTURE: x86 - - PYTHON: C:/Python35-x64 + - PYTHON: C:/Python36-x64 ARCHITECTURE: x64 diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 83dc5748b..ddee39a19 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.5", "3.6", "3.7", "3.8", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "pypy3"] architecture: ["x86", "x64"] include: - architecture: "x86" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8d2c6374..5a369956c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,13 +17,12 @@ jobs: "3.8", "3.7", "3.6", - "3.5", ] include: - - python-version: "3.5" - env: PYTHONOPTIMIZE=2 - python-version: "3.6" env: PYTHONOPTIMIZE=1 + - python-version: "3.7" + env: PYTHONOPTIMIZE=2 # Include new variables for Codecov - os: ubuntu-latest codecov-flag: GHA_Ubuntu diff --git a/.travis.yml b/.travis.yml index 980506368..d4c8bb18a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ matrix: arch: arm64 - python: "3.7" arch: ppc64le - - python: "3.5" + - python: "3.8" arch: s390x - python: "pypy3" @@ -36,15 +36,12 @@ matrix: services: xvfb - python: '3.7' name: "3.7 Xenial" + env: PYTHONOPTIMIZE=2 services: xvfb - python: '3.6' name: "3.6 Xenial PYTHONOPTIMIZE=1" env: PYTHONOPTIMIZE=1 services: xvfb - - python: '3.5' - name: "3.5 Xenial PYTHONOPTIMIZE=2" - env: PYTHONOPTIMIZE=2 - services: xvfb install: - | diff --git a/docs/installation.rst b/docs/installation.rst index e46bdf56c..24f895b85 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -19,7 +19,9 @@ Notes +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ |**Python** |**3.8**|**3.7**|**3.6**|**3.5**|**3.4**|**3.3**|**3.2**|**2.7**|**2.6**|**2.5**|**2.4**| +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow >= 7 | Yes | Yes | Yes | Yes | | | | | | | | +|Pillow >= 7.3 | Yes | Yes | Yes | | | | | | | | | ++--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +|Pillow 7.0 - 7.2 | Yes | Yes | Yes | Yes | | | | | | | | +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ |Pillow 6.2.1 - 6.2.2| Yes | Yes | Yes | Yes | | | | Yes | | | | +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ diff --git a/setup.py b/setup.py index b7982a5ba..59f6d2970 100755 --- a/setup.py +++ b/setup.py @@ -880,7 +880,6 @@ try: "Development Status :: 6 - Mature", "License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)", # noqa: E501 "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", @@ -893,7 +892,7 @@ try: "Topic :: Multimedia :: Graphics :: Graphics Conversion", "Topic :: Multimedia :: Graphics :: Viewers", ], - python_requires=">=3.5", + python_requires=">=3.6", cmdclass={"build_ext": pil_build_ext}, ext_modules=[Extension("PIL._imaging", ["_imaging.c"])], include_package_data=True, diff --git a/tox.ini b/tox.ini index aa6875374..22ca36daf 100644 --- a/tox.ini +++ b/tox.ini @@ -6,7 +6,7 @@ [tox] envlist = lint - py{35,36,37,38,py3} + py{36,37,38,py3} minversion = 1.9 [testenv] diff --git a/winbuild/README.md b/winbuild/README.md index d46361c9e..b7d1c548f 100644 --- a/winbuild/README.md +++ b/winbuild/README.md @@ -6,7 +6,7 @@ For more extensive info, see the [Windows build instructions](build.rst). * See [Current Windows Build/Testing process (Pillow#553)](https://github.com/python-pillow/Pillow/issues/553#issuecomment-37877416), [Definitive docs for how to compile on Windows (matplotlib#1717)](https://github.com/matplotlib/matplotlib/issues/1717#issuecomment-13343859), [Test Windows with GitHub Actions (Pillow#4084)](https://github.com/python-pillow/Pillow/pull/4084). - + * Requires Microsoft Visual Studio 2017 or newer with C++ component. * Requires NASM for libjpeg-turbo, a required dependency when using this script. @@ -17,7 +17,7 @@ For more extensive info, see the [Windows build instructions](build.rst). The following is a simplified version of the script used on AppVeyor: ``` -set PYTHON=C:\Python35\bin +set PYTHON=C:\Python38\bin cd /D C:\Pillow\winbuild C:\Python37\bin\python.exe build_prepare.py -v --depends=C:\pillow-depends build\build_dep_all.cmd diff --git a/winbuild/build.rst b/winbuild/build.rst index 517843a66..3122b79e6 100644 --- a/winbuild/build.rst +++ b/winbuild/build.rst @@ -104,7 +104,7 @@ The following is a simplified version of the script used on AppVeyor: .. code-block:: - set PYTHON=C:\Python35\bin + set PYTHON=C:\Python38\bin cd /D C:\Pillow\winbuild C:\Python37\bin\python.exe build_prepare.py -v --depends=C:\pillow-depends build\build_dep_all.cmd diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index 553ed6365..c17c3e43e 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -456,7 +456,7 @@ def build_pillow(): cmd_cd("{pillow_dir}"), *prefs["header"], cmd_set("DISTUTILS_USE_SDK", "1"), # use same compiler to build Pillow - cmd_set("MSSdk", "1"), # for Python 3.5 and PyPy3.6 + cmd_set("MSSdk", "1"), # for PyPy3.6 cmd_set("py_vcruntime_redist", "true"), # use /MD, not /MT r'"{python_dir}\{python_exe}" setup.py build_ext %*', ] From 04e93769af531147d3575fc0ee299525aa133897 Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Tue, 30 Jun 2020 16:34:10 +0100 Subject: [PATCH 046/126] Use correct function type for raqm_version_string. This causes compilation to (correctly) fail on Clang because this isn't the correct assignment type. --- src/_imagingft.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_imagingft.c b/src/_imagingft.c index f2ca26e2d..e00be58f7 100644 --- a/src/_imagingft.c +++ b/src/_imagingft.c @@ -175,7 +175,7 @@ setraqm(void) } #ifndef _WIN32 - p_raqm.version_string = (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_string"); + p_raqm.version_string = (t_raqm_version_string)dlsym(p_raqm.raqm, "raqm_version_string"); p_raqm.version_atleast = (t_raqm_version_atleast)dlsym(p_raqm.raqm, "raqm_version_atleast"); p_raqm.create = (t_raqm_create)dlsym(p_raqm.raqm, "raqm_create"); p_raqm.set_text = (t_raqm_set_text)dlsym(p_raqm.raqm, "raqm_set_text"); @@ -209,7 +209,7 @@ setraqm(void) return 2; } #else - p_raqm.version_string = (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_string"); + p_raqm.version_string = (t_raqm_version_string)GetProcAddress(p_raqm.raqm, "raqm_version_string"); p_raqm.version_atleast = (t_raqm_version_atleast)GetProcAddress(p_raqm.raqm, "raqm_version_atleast"); p_raqm.create = (t_raqm_create)GetProcAddress(p_raqm.raqm, "raqm_create"); p_raqm.set_text = (t_raqm_set_text)GetProcAddress(p_raqm.raqm, "raqm_set_text"); From d533b4fdb79bd81162d555eb3fdb30e7489e43e2 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 30 Jun 2020 20:49:40 +0300 Subject: [PATCH 047/126] Remove redundant requirements --- winbuild/README.md | 1 - winbuild/build.rst | 6 ------ 2 files changed, 7 deletions(-) diff --git a/winbuild/README.md b/winbuild/README.md index b7d1c548f..611d1ed1a 100644 --- a/winbuild/README.md +++ b/winbuild/README.md @@ -11,7 +11,6 @@ For more extensive info, see the [Windows build instructions](build.rst). * Requires Microsoft Visual Studio 2017 or newer with C++ component. * Requires NASM for libjpeg-turbo, a required dependency when using this script. * Requires CMake 3.12 or newer (available as Visual Studio component). -* Python 3.6+ is required to generate valid scripts, but builds targeting Python 3.5+ are supported. * Tested on Windows Server 2016 with Visual Studio 2017 Community (AppVeyor). * Tested on Windows Server 2019 with Visual Studio 2019 Enterprise (GitHub Actions). diff --git a/winbuild/build.rst b/winbuild/build.rst index 3122b79e6..aaed2c43f 100644 --- a/winbuild/build.rst +++ b/winbuild/build.rst @@ -12,12 +12,6 @@ Prerequisites ------------- -Python -^^^^^^ - -While the scripts can target any version of Python supported by Pillow, -Python 3.6+ is required to generate valid build scripts. - Compilers ^^^^^^^^^ From adec4f5a43cf8ca180366748405ebaf2648b2a52 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 30 Jun 2020 21:39:07 +0300 Subject: [PATCH 048/126] Remove compatibility for unsupported PyPy versions --- src/PIL/_tkinter_finder.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/PIL/_tkinter_finder.py b/src/PIL/_tkinter_finder.py index 30493066a..7018a1b79 100644 --- a/src/PIL/_tkinter_finder.py +++ b/src/PIL/_tkinter_finder.py @@ -4,13 +4,6 @@ import sys from tkinter import _tkinter as tk if hasattr(sys, "pypy_find_executable"): - # Tested with packages at https://bitbucket.org/pypy/pypy/downloads. - # PyPies 1.6, 2.0 do not have tkinter built in. PyPy3-2.3.1 gives an - # OSError trying to import tkinter. Otherwise: - try: # PyPy 5.1, 4.0.0, 2.6.1, 2.6.0 - TKINTER_LIB = tk.tklib_cffi.__file__ - except AttributeError: - # PyPy3 2.4, 2.1-beta1; PyPy 2.5.1, 2.5.0, 2.4.0, 2.3, 2.2, 2.1 - TKINTER_LIB = tk.tkffi.verifier.modulefilename + TKINTER_LIB = tk.tklib_cffi.__file__ else: TKINTER_LIB = tk.__file__ From a08588250b964f99496d84e758b0eb8366e8275b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 30 Jun 2020 22:01:19 +0300 Subject: [PATCH 049/126] Use v2 actions --- .github/workflows/lint.yml | 4 ++-- .github/workflows/test-windows.yml | 6 +++--- .github/workflows/test.yml | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 64296b377..387c4a632 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -24,7 +24,7 @@ jobs: lint-pip- - name: pre-commit cache - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.cache/pre-commit key: lint-pre-commit-${{ hashFiles('**/.pre-commit-config.yaml') }} @@ -32,7 +32,7 @@ jobs: lint-pre-commit- - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 83dc5748b..cab6e811e 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -36,7 +36,7 @@ jobs: path: winbuild\depends - name: Cache pip - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~\AppData\Local\pip\Cache key: @@ -47,7 +47,7 @@ jobs: # sets env: pythonLocation - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.architecture }} @@ -128,7 +128,7 @@ jobs: shell: pwsh - name: Upload errors - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 if: failure() with: name: errors diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8d2c6374..eb31ff997 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: - uses: actions/checkout@v2 - name: Ubuntu cache - uses: actions/cache@v1 + uses: actions/cache@v2 if: startsWith(matrix.os, 'ubuntu') with: path: ~/.cache/pip @@ -47,7 +47,7 @@ jobs: ${{ matrix.os }}-${{ matrix.python-version }}- - name: macOS cache - uses: actions/cache@v1 + uses: actions/cache@v2 if: startsWith(matrix.os, 'macOS') with: path: ~/Library/Caches/pip @@ -57,7 +57,7 @@ jobs: ${{ matrix.os }}-${{ matrix.python-version }}- - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} @@ -89,7 +89,7 @@ jobs: shell: pwsh - name: Upload errors - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 if: failure() with: name: errors From 829e1f189b88c3667a429de1b318fbd66de4dc26 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 30 Jun 2020 22:04:43 +0300 Subject: [PATCH 050/126] Simplify CI config --- .github/workflows/lint.yml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 387c4a632..b30901c18 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -6,9 +6,6 @@ jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.8"] name: Python ${{ matrix.python-version }} @@ -31,18 +28,18 @@ jobs: restore-keys: | lint-pre-commit- - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python uses: actions/setup-python@v2 with: - python-version: ${{ matrix.python-version }} + python-version: 3.8 - name: Build system information run: python .github/workflows/system-info.py - name: Install dependencies run: | - python -m pip install --upgrade pip - python -m pip install --upgrade tox + python -m pip install -U pip + python -m pip install -U tox - name: Lint run: tox -e lint From 410095e129924fb221db138865383cb8c5c92fc6 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 30 Jun 2020 22:26:41 +0300 Subject: [PATCH 051/126] Use new 'pip cache dir' to combine macOS/Ubuntu cache config --- .github/workflows/test.yml | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb31ff997..d65f14c11 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,31 +36,25 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Ubuntu cache - uses: actions/cache@v2 - if: startsWith(matrix.os, 'ubuntu') - with: - path: ~/.cache/pip - key: - ${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.ci/*.sh') }} - restore-keys: | - ${{ matrix.os }}-${{ matrix.python-version }}- - - - name: macOS cache - uses: actions/cache@v2 - if: startsWith(matrix.os, 'macOS') - with: - path: ~/Library/Caches/pip - key: - ${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.ci/*.sh') }} - restore-keys: | - ${{ matrix.os }}-${{ matrix.python-version }}- - - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} + - name: Get pip cache dir + id: pip-cache + run: | + echo "::set-output name=dir::$(pip cache dir)" + + - name: pip cache + uses: actions/cache@v2 + with: + path: ${{ steps.pip-cache.outputs.dir }} + key: + ${{ matrix.os }}-${{ matrix.python-version }}-${{ hashFiles('**/.ci/*.sh') }} + restore-keys: | + ${{ matrix.os }}-${{ matrix.python-version }}- + - name: Build system information run: python .github/workflows/system-info.py From fb2a184eedf8a4caa0fa3f1369661a0f9aab5486 Mon Sep 17 00:00:00 2001 From: Hamza Date: Wed, 1 Jul 2020 00:48:38 +0500 Subject: [PATCH 052/126] ImageOps autocontrast cutoff updated --- src/PIL/ImageOps.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index e4e0840b8..24f6a3b6b 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -88,12 +88,18 @@ def autocontrast(image, cutoff=0, ignore=None): h[ix] = 0 if cutoff: # cut off pixels from both ends of the histogram + if isinstance(cutoff, int): + cutoff = (cutoff, cutoff) + elif isinstance(cutoff, tuple): + pass + else: + raise ValueError("the cutoff can only be a integer or tuple") # get number of pixels n = 0 for ix in range(256): n = n + h[ix] # remove cutoff% pixels from the low end - cut = n * cutoff // 100 + cut = n * cutoff[0] // 100 for lo in range(256): if cut > h[lo]: cut = cut - h[lo] @@ -104,7 +110,7 @@ def autocontrast(image, cutoff=0, ignore=None): if cut <= 0: break # remove cutoff% samples from the hi end - cut = n * cutoff // 100 + cut = n * cutoff[1] // 100 for hi in range(255, -1, -1): if cut > h[hi]: cut = cut - h[hi] From b768cc09d74294cf20600910560483b185d0512d Mon Sep 17 00:00:00 2001 From: Hamza Date: Wed, 1 Jul 2020 04:01:06 +0500 Subject: [PATCH 053/126] added test --- Tests/test_imageops.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 3d0afba9c..170ad6b3d 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -300,3 +300,9 @@ def test_exif_transpose(): "Tests/images/hopper_orientation_" + str(i) + ext ) as orientation_im: check(orientation_im) + +def test_autocontrast_cutoff(): + # Test the cutoff argument of autocontrast + with Image.open("Tests/images/bw_gradient.png") as img: + assert ImageOps.autocontrast(img, cutoff=10).getdata() == ImageOps.autocontrast(img, cutoff=(10,10)).getdata() + assert ImageOps.autocontrast(img, cutoff=10).getdata() != ImageOps.autocontrast(img, cutoff=(1,10)).getdata() \ No newline at end of file From cbf4f328c7664e3690bbe2eb9136721730b14f46 Mon Sep 17 00:00:00 2001 From: Hamza Date: Wed, 1 Jul 2020 04:20:19 +0500 Subject: [PATCH 054/126] fixed tests --- Tests/test_imageops.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 170ad6b3d..ec6a55e0e 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -304,5 +304,5 @@ def test_exif_transpose(): def test_autocontrast_cutoff(): # Test the cutoff argument of autocontrast with Image.open("Tests/images/bw_gradient.png") as img: - assert ImageOps.autocontrast(img, cutoff=10).getdata() == ImageOps.autocontrast(img, cutoff=(10,10)).getdata() - assert ImageOps.autocontrast(img, cutoff=10).getdata() != ImageOps.autocontrast(img, cutoff=(1,10)).getdata() \ No newline at end of file + assert ImageOps.autocontrast(img, cutoff=10).histogram() == ImageOps.autocontrast(img, cutoff=(10,10)).histogram() + assert ImageOps.autocontrast(img, cutoff=10).histogram() != ImageOps.autocontrast(img, cutoff=(1,10)).histogram() \ No newline at end of file From 16e804b8924c516bf18287f250685220e01aea9c Mon Sep 17 00:00:00 2001 From: Hamza Date: Wed, 1 Jul 2020 04:37:17 +0500 Subject: [PATCH 055/126] linting fixed --- Tests/test_imageops.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index ec6a55e0e..9938aff28 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -301,8 +301,15 @@ def test_exif_transpose(): ) as orientation_im: check(orientation_im) + def test_autocontrast_cutoff(): # Test the cutoff argument of autocontrast with Image.open("Tests/images/bw_gradient.png") as img: - assert ImageOps.autocontrast(img, cutoff=10).histogram() == ImageOps.autocontrast(img, cutoff=(10,10)).histogram() - assert ImageOps.autocontrast(img, cutoff=10).histogram() != ImageOps.autocontrast(img, cutoff=(1,10)).histogram() \ No newline at end of file + assert ( + ImageOps.autocontrast(img, cutoff=10).histogram() + == ImageOps.autocontrast(img, cutoff=(10, 10)).histogram() + ) + assert ( + ImageOps.autocontrast(img, cutoff=10).histogram() + != ImageOps.autocontrast(img, cutoff=(1, 10)).histogram() + ) From e5e92d73461b828f6fb2b8ab7f5d8e762d7e5bbf Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 1 Jul 2020 18:47:54 +1000 Subject: [PATCH 056/126] Python 3.5 is no longer supported --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0e0d38cdd..93f713856 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # Development, documentation & testing requirements. -black; python_version >= '3.6' +black check-manifest coverage jarn.viewdoc From 630fb0c72e1cd70c360767121c6c3f17b8615dd1 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Wed, 1 Jul 2020 11:58:22 +0300 Subject: [PATCH 057/126] Update job name Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d4c8bb18a..be2682dd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ matrix: name: "3.8 Xenial" services: xvfb - python: '3.7' - name: "3.7 Xenial" + name: "3.7 Xenial PYTHONOPTIMIZE=2" env: PYTHONOPTIMIZE=2 services: xvfb - python: '3.6' From e7e02ae77dfc0dec02a6cdefe6af6618267e06e0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 1 Jul 2020 21:11:36 +1000 Subject: [PATCH 058/126] Added step to update Docker Images repository [ci skip] --- RELEASING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RELEASING.md b/RELEASING.md index a33a1684a..3f62a70c4 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -114,3 +114,12 @@ Released as needed privately to individual vendors for critical security-related ## Documentation * [ ] Make sure the [default version for Read the Docs](https://pillow.readthedocs.io/en/stable/) is up-to-date with the release changes + +## Docker Images + +* [ ] Update Pillow in the Docker Images repository + ```bash + git clone https://github.com/python-pillow/docker-images + cd docker-images + ./update-pillow-tag.sh [[release tag]] + ``` From 27c40910d83a028fde18b9da84e6031443a96c12 Mon Sep 17 00:00:00 2001 From: Hamza <52637755+millionhz@users.noreply.github.com> Date: Wed, 1 Jul 2020 19:01:53 +0500 Subject: [PATCH 059/126] Update src/PIL/ImageOps.py Yup you are absolutely correct; it does the job in fewer lines of code too. Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- src/PIL/ImageOps.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 24f6a3b6b..008ec0238 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -88,12 +88,8 @@ def autocontrast(image, cutoff=0, ignore=None): h[ix] = 0 if cutoff: # cut off pixels from both ends of the histogram - if isinstance(cutoff, int): + if not isinstance(cutoff, tuple): cutoff = (cutoff, cutoff) - elif isinstance(cutoff, tuple): - pass - else: - raise ValueError("the cutoff can only be a integer or tuple") # get number of pixels n = 0 for ix in range(256): From eb6faf6f02e9e4f471327abd0939f66a54fb4ad4 Mon Sep 17 00:00:00 2001 From: Conchylicultor Date: Wed, 1 Jul 2020 12:20:17 -0700 Subject: [PATCH 060/126] Minor str(bytes) call Some environments have strict mode to catch potential str<>bytes error. This is triggered by this line: ``` TiffImagePlugin.py3", line 996, in _open logger.debug("- ifh: {}".format(ifh)) BytesWarning: str() on a bytes instance ``` --- src/PIL/TiffImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 73e9a2763..7d4d8c2a9 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -993,7 +993,7 @@ class TiffImageFile(ImageFile.ImageFile): logger.debug("*** TiffImageFile._open ***") logger.debug("- __first: {}".format(self.__first)) - logger.debug("- ifh: {}".format(ifh)) + logger.debug("- ifh: {!r}".format(ifh)) # Use !r to avoid str(bytes) # and load the first frame self._seek(0) From 89fb0ee5aaccc5ed936cb0f7d25d773a60557cf7 Mon Sep 17 00:00:00 2001 From: Conchylicultor Date: Wed, 1 Jul 2020 14:05:47 -0700 Subject: [PATCH 061/126] Update TiffImagePlugin.py --- src/PIL/TiffImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 7d4d8c2a9..b56072737 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -776,7 +776,7 @@ class ImageFileDirectory_v2(MutableMapping): self.tagtype[tag] = typ msg += " - value: " + ( - "" % size if size > 32 else str(data) + "" % size if size > 32 else repr(data) ) logger.debug(msg) From 7d49c8f38cc5325bd87701b54086a3f9c499b7ac Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 2 Jul 2020 19:14:24 +1000 Subject: [PATCH 062/126] Updated documentation --- src/PIL/ImageOps.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 008ec0238..157da0b52 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -70,7 +70,9 @@ def autocontrast(image, cutoff=0, ignore=None): becomes white (255). :param image: The image to process. - :param cutoff: How many percent to cut off from the histogram. + :param cutoff: The percent to cut off from the histogram on the low and + high ends. Either a tuple of (low, high), or a single + number for both. :param ignore: The background pixel value (use None for no background). :return: An image. """ @@ -105,7 +107,7 @@ def autocontrast(image, cutoff=0, ignore=None): cut = 0 if cut <= 0: break - # remove cutoff% samples from the hi end + # remove cutoff% samples from the high end cut = n * cutoff[1] // 100 for hi in range(255, -1, -1): if cut > h[hi]: From 4b5eab4c1762910c3d80b10ec8b7dc1eb6a7939f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 2 Jul 2020 19:01:56 +1000 Subject: [PATCH 063/126] Simplified code --- Tests/test_imageops.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index 9938aff28..864df447e 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -305,11 +305,9 @@ def test_exif_transpose(): def test_autocontrast_cutoff(): # Test the cutoff argument of autocontrast with Image.open("Tests/images/bw_gradient.png") as img: - assert ( - ImageOps.autocontrast(img, cutoff=10).histogram() - == ImageOps.autocontrast(img, cutoff=(10, 10)).histogram() - ) - assert ( - ImageOps.autocontrast(img, cutoff=10).histogram() - != ImageOps.autocontrast(img, cutoff=(1, 10)).histogram() - ) + + def autocontrast(cutoff): + return ImageOps.autocontrast(img, cutoff).histogram() + + assert autocontrast(10) == autocontrast((10, 10)) + assert autocontrast(10) != autocontrast((1, 10)) From fc5f4b4976f2b58f7e5bbafe2f23f8eea3755117 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 2 Jul 2020 13:08:42 +0300 Subject: [PATCH 064/126] Name it "Lint" --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b30901c18..3c658293e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest - name: Python ${{ matrix.python-version }} + name: Lint steps: - uses: actions/checkout@v2 From 9432bba6d155920a7ec40ca20aedafc5eb31adf3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 2 Jul 2020 20:28:00 +1000 Subject: [PATCH 065/126] Moved tests --- Tests/test_image.py | 92 +++++++++++++++++++++++++++++++++++++++++ Tests/test_imagefile.py | 91 ---------------------------------------- 2 files changed, 92 insertions(+), 91 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index be67f5947..6d29ac80e 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -13,6 +13,7 @@ from .helper import ( assert_not_all_same, hopper, is_win32, + skip_unless_feature, ) @@ -625,6 +626,97 @@ class TestImage: assert not fp.closed + def test_exif_jpeg(self, tmp_path): + with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian + exif = im.getexif() + assert 258 not in exif + assert 40960 in exif + assert exif[40963] == 450 + assert exif[11] == "gThumb 3.0.1" + + out = str(tmp_path / "temp.jpg") + exif[258] = 8 + del exif[40960] + exif[40963] = 455 + exif[11] = "Pillow test" + im.save(out, exif=exif) + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + assert reloaded_exif[258] == 8 + assert 40960 not in reloaded_exif + assert reloaded_exif[40963] == 455 + assert reloaded_exif[11] == "Pillow test" + + with Image.open("Tests/images/no-dpi-in-exif.jpg") as im: # Big endian + exif = im.getexif() + assert 258 not in exif + assert 40962 in exif + assert exif[40963] == 200 + assert exif[305] == "Adobe Photoshop CC 2017 (Macintosh)" + + out = str(tmp_path / "temp.jpg") + exif[258] = 8 + del exif[34665] + exif[40963] = 455 + exif[305] = "Pillow test" + im.save(out, exif=exif) + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + assert reloaded_exif[258] == 8 + assert 34665 not in reloaded_exif + assert reloaded_exif[40963] == 455 + assert reloaded_exif[305] == "Pillow test" + + @skip_unless_feature("webp") + @skip_unless_feature("webp_anim") + def test_exif_webp(self, tmp_path): + with Image.open("Tests/images/hopper.webp") as im: + exif = im.getexif() + assert exif == {} + + out = str(tmp_path / "temp.webp") + exif[258] = 8 + exif[40963] = 455 + exif[305] = "Pillow test" + + def check_exif(): + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + assert reloaded_exif[258] == 8 + assert reloaded_exif[40963] == 455 + assert reloaded_exif[305] == "Pillow test" + + im.save(out, exif=exif) + check_exif() + im.save(out, exif=exif, save_all=True) + check_exif() + + def test_exif_png(self, tmp_path): + with Image.open("Tests/images/exif.png") as im: + exif = im.getexif() + assert exif == {274: 1} + + out = str(tmp_path / "temp.png") + exif[258] = 8 + del exif[274] + exif[40963] = 455 + exif[305] = "Pillow test" + im.save(out, exif=exif) + + with Image.open(out) as reloaded: + reloaded_exif = reloaded.getexif() + assert reloaded_exif == {258: 8, 40963: 455, 305: "Pillow test"} + + def test_exif_interop(self): + with Image.open("Tests/images/flower.jpg") as im: + exif = im.getexif() + assert exif.get_ifd(0xA005) == { + 1: "R98", + 2: b"0100", + 4097: 2272, + 4098: 1704, + } + @pytest.mark.parametrize( "test_module", [PIL, Image], ) diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 805625a24..48fecc26e 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -243,94 +243,3 @@ class TestPyDecoder: im = MockImageFile(buf) assert im.format is None assert im.get_format_mimetype() is None - - def test_exif_jpeg(self, tmp_path): - with Image.open("Tests/images/exif-72dpi-int.jpg") as im: # Little endian - exif = im.getexif() - assert 258 not in exif - assert 40960 in exif - assert exif[40963] == 450 - assert exif[11] == "gThumb 3.0.1" - - out = str(tmp_path / "temp.jpg") - exif[258] = 8 - del exif[40960] - exif[40963] = 455 - exif[11] = "Pillow test" - im.save(out, exif=exif) - with Image.open(out) as reloaded: - reloaded_exif = reloaded.getexif() - assert reloaded_exif[258] == 8 - assert 40960 not in reloaded_exif - assert reloaded_exif[40963] == 455 - assert reloaded_exif[11] == "Pillow test" - - with Image.open("Tests/images/no-dpi-in-exif.jpg") as im: # Big endian - exif = im.getexif() - assert 258 not in exif - assert 40962 in exif - assert exif[40963] == 200 - assert exif[305] == "Adobe Photoshop CC 2017 (Macintosh)" - - out = str(tmp_path / "temp.jpg") - exif[258] = 8 - del exif[34665] - exif[40963] = 455 - exif[305] = "Pillow test" - im.save(out, exif=exif) - with Image.open(out) as reloaded: - reloaded_exif = reloaded.getexif() - assert reloaded_exif[258] == 8 - assert 34665 not in reloaded_exif - assert reloaded_exif[40963] == 455 - assert reloaded_exif[305] == "Pillow test" - - @skip_unless_feature("webp") - @skip_unless_feature("webp_anim") - def test_exif_webp(self, tmp_path): - with Image.open("Tests/images/hopper.webp") as im: - exif = im.getexif() - assert exif == {} - - out = str(tmp_path / "temp.webp") - exif[258] = 8 - exif[40963] = 455 - exif[305] = "Pillow test" - - def check_exif(): - with Image.open(out) as reloaded: - reloaded_exif = reloaded.getexif() - assert reloaded_exif[258] == 8 - assert reloaded_exif[40963] == 455 - assert reloaded_exif[305] == "Pillow test" - - im.save(out, exif=exif) - check_exif() - im.save(out, exif=exif, save_all=True) - check_exif() - - def test_exif_png(self, tmp_path): - with Image.open("Tests/images/exif.png") as im: - exif = im.getexif() - assert exif == {274: 1} - - out = str(tmp_path / "temp.png") - exif[258] = 8 - del exif[274] - exif[40963] = 455 - exif[305] = "Pillow test" - im.save(out, exif=exif) - - with Image.open(out) as reloaded: - reloaded_exif = reloaded.getexif() - assert reloaded_exif == {258: 8, 40963: 455, 305: "Pillow test"} - - def test_exif_interop(self): - with Image.open("Tests/images/flower.jpg") as im: - exif = im.getexif() - assert exif.get_ifd(0xA005) == { - 1: "R98", - 2: b"0100", - 4097: 2272, - 4098: 1704, - } From 109c637ddbbaeb93ec11ee045b6dce2bf8f484f7 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 3 Jul 2020 09:38:30 +0300 Subject: [PATCH 066/126] 'plugin', formatting and typos --- .../writing-your-own-file-decoder.rst | 22 +++++++++---------- src/PIL/JpegImagePlugin.py | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/handbook/writing-your-own-file-decoder.rst b/docs/handbook/writing-your-own-file-decoder.rst index 42a6c4822..89d0e3e9f 100644 --- a/docs/handbook/writing-your-own-file-decoder.rst +++ b/docs/handbook/writing-your-own-file-decoder.rst @@ -3,9 +3,9 @@ Writing Your Own Image Plugin ============================= -The Pillow uses a plug-in model which allows you to add your own +Pillow uses a plugin model which allows you to add your own decoders to the library, without any changes to the library -itself. Such plug-ins usually have names like +itself. Such plugins usually have names like :file:`XxxImagePlugin.py`, where ``Xxx`` is a unique format name (usually an abbreviation). @@ -14,7 +14,7 @@ itself. Such plug-ins usually have names like :file:`ImagePlugin.py`. You will need to import your image plugin manually. -Pillow decodes files in 2 stages: +Pillow decodes files in two stages: 1. It loops over the available image plugins in the loaded order, and calls the plugin's ``_accept`` function with the first 16 bytes of @@ -26,7 +26,7 @@ Pillow decodes files in 2 stages: called, which sets up a decoder for each tile and feeds the data to it. -An image plug-in should contain a format handler derived from the +An image plugin should contain a format handler derived from the :py:class:`PIL.ImageFile.ImageFile` base class. This class should provide an :py:meth:`_open` method, which reads the file header and sets up at least the :py:attr:`~PIL.Image.Image.mode` and @@ -43,7 +43,7 @@ registered, via a call to the :py:mod:`~PIL.Image` module. Example ------- -The following plug-in supports a simple format, which has a 128-byte header +The following plugin supports a simple format, which has a 128-byte header consisting of the words “SPAM” followed by the width, height, and pixel size in bits. The header fields are separated by spaces. The image data follows directly after the header, and can be either bi-level, greyscale, or 24-bit @@ -82,14 +82,14 @@ true color. raise SyntaxError("unknown number of bits") # data descriptor - self.tile = [ - ("raw", (0, 0) + self.size, 128, (self.mode, 0, 1)) - ] + self.tile = [("raw", (0, 0) + self.size, 128, (self.mode, 0, 1))] + Image.register_open(SpamImageFile.format, SpamImageFile, _accept) Image.register_extension(SpamImageFile.format, ".spam") - Image.register_extension(SpamImageFile.format, ".spa") # dos version + Image.register_extension(SpamImageFile.format, ".spa") # DOS version + The format handler must always set the :py:attr:`~PIL.Image.Image.size` and :py:attr:`~PIL.Image.Image.mode` @@ -132,7 +132,7 @@ The fields are used as follows: **parameters** Parameters to the decoder. The contents of this field depends on the decoder specified by the first field in the tile descriptor tuple. If the - decoder doesn’t need any parameters, use None for this field. + decoder doesn’t need any parameters, use ``None`` for this field. Note that the :py:attr:`tile` attribute contains a list of tile descriptors, not just a single descriptor. @@ -211,7 +211,7 @@ Note that for the most common cases, the raw mode is simply the same as the mode The Python Imaging Library supports many other decoders, including JPEG, PNG, and PackBits. For details, see the :file:`decode.c` source file, and the -standard plug-in implementations provided with the library. +standard plugin implementations provided with the library. Decoding floating point data ---------------------------- diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index b4795c302..f18eedb20 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -488,7 +488,7 @@ def _getexif(self): def _getmp(self): # Extract MP information. This method was inspired by the "highly # experimental" _getexif version that's been in use for years now, - # itself based on the ImageFileDirectory class in the TIFF plug-in. + # itself based on the ImageFileDirectory class in the TIFF plugin. # The MP record essentially consists of a TIFF file embedded in a JPEG # application marker. From b9f1add34b0731a6f0e8ae23676109d428aeecda Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 5 Jul 2020 20:51:11 +1000 Subject: [PATCH 067/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index c63f05e6a..5cb400c24 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,6 +2,12 @@ Changelog (Pillow) ================== +7.3.0 (unreleased) +------------------ + +- Allow ImageOps.autocontrast to specify low and high cutoffs separately #4749 + [millionhz, radarhere] + 7.2.0 (2020-07-01) ------------------ From 91bd2d37529ecf15691fb790b8abba7ba7281215 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 5 Jul 2020 21:47:23 +1000 Subject: [PATCH 068/126] Altered descriptions [ci skip] --- docs/reference/Image.rst | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index dd56b20ff..1eced066f 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -333,15 +333,14 @@ Instances of the :py:class:`Image` class have the following attributes: .. py:attribute:: Image.is_animated :type: bool - This attribute is ``True`` if the Image is animated, ``False`` otherwise. - Typically defined as ``Image.n_frames > 1``. + ``True`` if this image has more than one frame, or ``False`` otherwise. - This attribute is only defined by Image plugins that support animated Images. + This attribute is only defined by image plugins that support animated images. Plugins may leave this attribute undefined if they don't support loading - animated images, even if the given format supports animated images. Use - ``hasattr(image, "is_animated")`` to check whether the implementation - supports animated images, or ``getattr(image, "is_animated", False)`` - to check whether an image has been loaded with animation support. + animated images, even if the given format supports animated images. + + To check whether an image is animated regardless of its format, use + ``getattr(image, "is_animated", False)``. .. seealso:: :attr:`~Image.n_frames`, :func:`~Image.seek` and :func:`~Image.tell` @@ -349,15 +348,13 @@ Instances of the :py:class:`Image` class have the following attributes: :type: int The number of frames in this image. - Defined if and only if :attr:`~Image.is_animated` is also defined. - Equal to 1 for non-animated images loaded by a plugin supporting animations. - This attribute is only defined by Image plugins that support animated Images. + This attribute is only defined by image plugins that support animated images. Plugins may leave this attribute undefined if they don't support loading - animated images, even if the given format supports animated images. Use - ``hasattr(image, "is_animated")`` to check whether the implementation - supports animated images, or ``getattr(image, "n_frames", 1)`` - to check whether an image has been loaded with more than one frame. + animated images, even if the given format supports animated images. + + To check the number of frames in an image regardless of its format, use + ``getattr(image, "n_frames", 1)``. .. seealso:: :attr:`~Image.is_animated`, :func:`~Image.seek` and :func:`~Image.tell` From 88b7b9c1f5196999b1cba13f23c1e224f60bc11c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 7 Jul 2020 20:46:10 +0300 Subject: [PATCH 069/126] Remove unused externs from Imaging.h --- src/libImaging/Imaging.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 47f577139..d7dbe0325 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -185,8 +185,6 @@ extern Imaging ImagingNew2Dirty(const char* mode, Imaging imOut, Imaging imIn); extern void ImagingDelete(Imaging im); extern Imaging ImagingNewBlock(const char* mode, int xsize, int ysize); -extern Imaging ImagingNewMap(const char* filename, int readonly, - const char* mode, int xsize, int ysize); extern Imaging ImagingNewPrologue(const char *mode, int xsize, int ysize); @@ -348,9 +346,6 @@ extern Imaging ImagingChopAnd(Imaging imIn1, Imaging imIn2); extern Imaging ImagingChopOr(Imaging imIn1, Imaging imIn2); extern Imaging ImagingChopXor(Imaging imIn1, Imaging imIn2); -/* Image measurement */ -extern void ImagingCrack(Imaging im, int x0, int y0); - /* Graphics */ extern int ImagingDrawArc(Imaging im, int x0, int y0, int x1, int y1, float start, float end, const void* ink, int width, @@ -396,10 +391,6 @@ extern Imaging ImagingEffectNoise(int xsize, int ysize, float sigma); extern Imaging ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality); -/* Obsolete */ -extern int ImagingToString(Imaging im, int orientation, char *buffer); -extern int ImagingFromString(Imaging im, int orientation, char *buffer); - /* File I/O */ /* -------- */ @@ -408,9 +399,6 @@ extern int ImagingFromString(Imaging im, int orientation, char *buffer); extern Imaging ImagingOpenPPM(const char* filename); extern int ImagingSavePPM(Imaging im, const char* filename); -/* Utility functions */ -extern UINT32 ImagingCRC32(UINT32 crc, UINT8* buffer, int bytes); - /* Codecs */ typedef struct ImagingCodecStateInstance *ImagingCodecState; typedef int (*ImagingCodec)(Imaging im, ImagingCodecState state, @@ -473,7 +461,6 @@ extern int ImagingRawEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes); extern int ImagingSgiRleDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes); -extern int ImagingSgiRleDecodeCleanup(ImagingCodecState state); extern int ImagingSunRleDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes); extern int ImagingTgaRleDecode(Imaging im, ImagingCodecState state, From b8326a08d5a131fff038d1eae899c7b617c3396c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 8 Jul 2020 08:50:55 +1000 Subject: [PATCH 070/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index 5cb400c24..62a134717 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -2,7 +2,7 @@ Changelog (Pillow) ================== -7.3.0 (unreleased) +8.0.0 (unreleased) ------------------ - Allow ImageOps.autocontrast to specify low and high cutoffs separately #4749 From 4323d975be951574ab229d7ad997d6ea2c6c3d0f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 9 Jul 2020 12:24:23 +0300 Subject: [PATCH 071/126] Use sphinx_removed_in extension for the '.. versionremoved::' directive --- .github/workflows/test.yml | 2 +- docs/conf.py | 7 ++++++- docs/deprecations.rst | 16 ++++++++-------- requirements.txt | 1 + 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b8d2c6374..eb8cada0d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,7 +98,7 @@ jobs: - name: Docs if: startsWith(matrix.os, 'ubuntu') && matrix.python-version == 3.8 run: | - pip install sphinx-rtd-theme + pip install sphinx-removed-in sphinx-rtd-theme make doccheck - name: After success diff --git a/docs/conf.py b/docs/conf.py index d95ec2a4a..c700fff79 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,7 +27,12 @@ needs_sphinx = "2.4" # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx.ext.intersphinx"] +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", + "sphinx_removed_in", +] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: diff --git a/docs/deprecations.rst b/docs/deprecations.rst index f78842ac1..4d982fa0e 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -78,7 +78,7 @@ period of deprecation has passed. Python 2.7 ~~~~~~~~~~ -*Removed in version 7.0.0.* +.. versionremoved:: 7.0.0 Python 2.7 reached end-of-life on 2020-01-01. Pillow 6.x was the last series to support Python 2. @@ -86,7 +86,7 @@ support Python 2. Image.__del__ ~~~~~~~~~~~~~ -*Removed in version 7.0.0.* +.. versionremoved:: 7.0.0 Implicitly closing the image's underlying file in ``Image.__del__`` has been removed. Use a context manager or call ``Image.close()`` instead to close the file in a @@ -109,7 +109,7 @@ Use instead: PIL.*ImagePlugin.__version__ attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*Removed in version 7.0.0.* +.. versionremoved:: 7.0.0 The version constants of individual plugins have been removed. Use ``PIL.__version__`` instead. @@ -134,7 +134,7 @@ Removed Removed Removed PyQt4 and PySide ~~~~~~~~~~~~~~~~ -*Removed in version 7.0.0.* +.. versionremoved:: 7.0.0 Qt 4 reached end-of-life on 2015-12-19. Its Python bindings are also EOL: PyQt4 since 2018-08-31 and PySide since 2015-10-14. @@ -145,7 +145,7 @@ or PySide2. Setting the size of TIFF images ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*Removed in version 7.0.0.* +.. versionremoved:: 7.0.0 Setting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws an error. Use ``Image.resize`` instead. @@ -153,7 +153,7 @@ an error. Use ``Image.resize`` instead. VERSION constant ~~~~~~~~~~~~~~~~ -*Removed in version 6.0.0.* +.. versionremoved:: 6.0.0 ``VERSION`` (the old PIL version, always 1.1.7) has been removed. Use ``__version__`` instead. @@ -161,7 +161,7 @@ VERSION constant Undocumented ImageOps functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -*Removed in version 6.0.0.* +.. versionremoved:: 6.0.0 Several undocumented functions in ``ImageOps`` have been removed. Use the equivalents in ``ImageFilter`` instead: @@ -179,7 +179,7 @@ Removed Use instead PIL.OleFileIO ~~~~~~~~~~~~~ -*Removed in version 6.0.0.* +.. versionremoved:: 6.0.0 PIL.OleFileIO was removed as a vendored file and in Pillow 4.0.0 (2017-01) in favour of the upstream olefile Python package, and replaced with an ``ImportError`` in 5.0.0 diff --git a/requirements.txt b/requirements.txt index 0e0d38cdd..25eb0ea11 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,5 @@ pyroma pytest pytest-cov sphinx>=2.4 +sphinx-removed-in sphinx-rtd-theme From 7c03590bcb53b2d15c6ed80ce102e9664069cd24 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 9 Jul 2020 12:46:44 +0300 Subject: [PATCH 072/126] Re-document deprecation versions of removals --- docs/deprecations.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 4d982fa0e..af8fc7527 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -78,6 +78,7 @@ period of deprecation has passed. Python 2.7 ~~~~~~~~~~ +.. deprecated:: 6.0.0 .. versionremoved:: 7.0.0 Python 2.7 reached end-of-life on 2020-01-01. Pillow 6.x was the last series to @@ -86,6 +87,7 @@ support Python 2. Image.__del__ ~~~~~~~~~~~~~ +.. deprecated:: 6.1.0 .. versionremoved:: 7.0.0 Implicitly closing the image's underlying file in ``Image.__del__`` has been removed. @@ -109,6 +111,7 @@ Use instead: PIL.*ImagePlugin.__version__ attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. deprecated:: 6.0.0 .. versionremoved:: 7.0.0 The version constants of individual plugins have been removed. Use ``PIL.__version__`` @@ -134,6 +137,7 @@ Removed Removed Removed PyQt4 and PySide ~~~~~~~~~~~~~~~~ +.. deprecated:: 6.0.0 .. versionremoved:: 7.0.0 Qt 4 reached end-of-life on 2015-12-19. Its Python bindings are also EOL: PyQt4 since @@ -145,6 +149,7 @@ or PySide2. Setting the size of TIFF images ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. deprecated:: 5.3.0 .. versionremoved:: 7.0.0 Setting the size of a TIFF image directly (eg. ``im.size = (256, 256)``) throws @@ -153,6 +158,7 @@ an error. Use ``Image.resize`` instead. VERSION constant ~~~~~~~~~~~~~~~~ +.. deprecated:: 5.2.0 .. versionremoved:: 6.0.0 ``VERSION`` (the old PIL version, always 1.1.7) has been removed. Use @@ -161,6 +167,7 @@ VERSION constant Undocumented ImageOps functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. deprecated:: 4.3.0 .. versionremoved:: 6.0.0 Several undocumented functions in ``ImageOps`` have been removed. Use the equivalents @@ -179,6 +186,7 @@ Removed Use instead PIL.OleFileIO ~~~~~~~~~~~~~ +.. deprecated:: 4.0.0 .. versionremoved:: 6.0.0 PIL.OleFileIO was removed as a vendored file and in Pillow 4.0.0 (2017-01) in favour of From 559510b378bc1761636dca866c1866ba0e4f1f84 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 9 Jul 2020 13:19:19 +0300 Subject: [PATCH 073/126] Remove attributes deprecated since 3.2.0 --- Tests/test_imagecms.py | 33 ------------ docs/deprecations.rst | 17 ++++--- src/_imagingcms.c | 111 ----------------------------------------- 3 files changed, 9 insertions(+), 152 deletions(-) diff --git a/Tests/test_imagecms.py b/Tests/test_imagecms.py index 953731215..e549f0922 100644 --- a/Tests/test_imagecms.py +++ b/Tests/test_imagecms.py @@ -435,39 +435,6 @@ def test_extended_information(): assert p.xcolor_space == "RGB " -def test_deprecations(): - skip_missing() - o = ImageCms.getOpenProfile(SRGB) - p = o.profile - - def helper_deprecated(attr, expected): - result = pytest.warns(DeprecationWarning, getattr, p, attr) - assert result == expected - - # p.color_space - helper_deprecated("color_space", "RGB") - - # p.pcs - helper_deprecated("pcs", "XYZ") - - # p.product_copyright - helper_deprecated( - "product_copyright", "Copyright International Color Consortium, 2009" - ) - - # p.product_desc - helper_deprecated("product_desc", "sRGB IEC61966-2-1 black scaled") - - # p.product_description - helper_deprecated("product_description", "sRGB IEC61966-2-1 black scaled") - - # p.product_manufacturer - helper_deprecated("product_manufacturer", "") - - # p.product_model - helper_deprecated("product_model", "IEC 61966-2-1 Default RGB Colour Space - sRGB") - - def test_profile_typesafety(): """ Profile init type safety diff --git a/docs/deprecations.rst b/docs/deprecations.rst index af8fc7527..b5ba00e40 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -49,16 +49,23 @@ PILLOW_VERSION constant It was initially removed in Pillow 7.0.0, but brought back in 7.1.0 to give projects more time to upgrade. +Removed features +---------------- + +Deprecated features are only removed in major releases after an appropriate +period of deprecation has passed. + ImageCms.CmsProfile attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. deprecated:: 3.2.0 +.. versionremoved:: 8.0.0 -Some attributes in ``ImageCms.CmsProfile`` are deprecated. From 6.0.0, they issue a +Some attributes in ``ImageCms.CmsProfile`` have been removed. From 6.0.0, they issued a ``DeprecationWarning``: ======================== =============================== -Deprecated Use instead +Removed Use instead ======================== =============================== ``color_space`` Padded ``xcolor_space`` ``pcs`` Padded ``connection_space`` @@ -69,12 +76,6 @@ Deprecated Use instead ``product_model`` Unicode ``model`` ======================== =============================== -Removed features ----------------- - -Deprecated features are only removed in major releases after an appropriate -period of deprecation has passed. - Python 2.7 ~~~~~~~~~~ diff --git a/src/_imagingcms.c b/src/_imagingcms.c index 7f23d5964..cba41ec90 100644 --- a/src/_imagingcms.c +++ b/src/_imagingcms.c @@ -223,25 +223,6 @@ cms_transform_dealloc(CmsTransformObject* self) /* -------------------------------------------------------------------- */ /* internal functions */ -static const char* -findICmode(cmsColorSpaceSignature cs) -{ - switch (cs) { - case cmsSigXYZData: return "XYZ"; - case cmsSigLabData: return "LAB"; - case cmsSigLuvData: return "LUV"; - case cmsSigYCbCrData: return "YCbCr"; - case cmsSigYxyData: return "YXY"; - case cmsSigRgbData: return "RGB"; - case cmsSigGrayData: return "L"; - case cmsSigHsvData: return "HSV"; - case cmsSigHlsData: return "HLS"; - case cmsSigCmykData: return "CMYK"; - case cmsSigCmyData: return "CMY"; - default: return ""; /* other TBA */ - } -} - static cmsUInt32Number findLCMStype(char* PILmode) { @@ -956,92 +937,12 @@ static struct PyMethodDef cms_profile_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyObject* -_profile_getattr(CmsProfileObject* self, cmsInfoType field) -{ - // UNDONE -- check that I'm getting the right fields on these. - // return PyUnicode_DecodeFSDefault(cmsTakeProductName(self->profile)); - //wchar_t buf[256]; -- UNDONE need wchar_t for unicode version. - char buf[256]; - cmsUInt32Number written; - written = cmsGetProfileInfoASCII(self->profile, - field, - "en", - "us", - buf, - 256); - if (written) { - return PyUnicode_FromString(buf); - } - // UNDONE suppressing error here by sending back blank string. - return PyUnicode_FromString(""); -} - -static PyObject* -cms_profile_getattr_product_desc(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "product_desc is deprecated. Use Unicode profile_description instead.", 1); - // description was Description != 'Copyright' || or "%s - %s" (manufacturer, model) in 1.x - return _profile_getattr(self, cmsInfoDescription); -} - -/* use these four for the individual fields. - */ -static PyObject* -cms_profile_getattr_product_description(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "product_description is deprecated. Use Unicode profile_description instead.", 1); - return _profile_getattr(self, cmsInfoDescription); -} - -static PyObject* -cms_profile_getattr_product_model(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "product_model is deprecated. Use Unicode model instead.", 1); - return _profile_getattr(self, cmsInfoModel); -} - -static PyObject* -cms_profile_getattr_product_manufacturer(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "product_manufacturer is deprecated. Use Unicode manufacturer instead.", 1); - return _profile_getattr(self, cmsInfoManufacturer); -} - -static PyObject* -cms_profile_getattr_product_copyright(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "product_copyright is deprecated. Use Unicode copyright instead.", 1); - return _profile_getattr(self, cmsInfoCopyright); -} - static PyObject* cms_profile_getattr_rendering_intent(CmsProfileObject* self, void* closure) { return PyLong_FromLong(cmsGetHeaderRenderingIntent(self->profile)); } -static PyObject* -cms_profile_getattr_pcs(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "pcs is deprecated. Use padded connection_space instead.", 1); - return PyUnicode_DecodeFSDefault(findICmode(cmsGetPCS(self->profile))); -} - -static PyObject* -cms_profile_getattr_color_space(CmsProfileObject* self, void* closure) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, - "color_space is deprecated. Use padded xcolor_space instead.", 1); - return PyUnicode_DecodeFSDefault(findICmode(cmsGetColorSpace(self->profile))); -} - /* New-style unicode interfaces. */ static PyObject* cms_profile_getattr_copyright(CmsProfileObject* self, void* closure) @@ -1149,14 +1050,12 @@ cms_profile_getattr_device_class(CmsProfileObject* self, void* closure) return _profile_read_int_as_string(cmsGetDeviceClass(self->profile)); } -/* Duplicate of pcs, but uninterpreted. */ static PyObject* cms_profile_getattr_connection_space(CmsProfileObject* self, void* closure) { return _profile_read_int_as_string(cmsGetPCS(self->profile)); } -/* Duplicate of color_space, but uninterpreted. */ static PyObject* cms_profile_getattr_xcolor_space(CmsProfileObject* self, void* closure) { @@ -1458,15 +1357,6 @@ cms_profile_getattr_icc_viewing_condition (CmsProfileObject* self, void* closure static struct PyGetSetDef cms_profile_getsetters[] = { - /* Compatibility interfaces. */ - { "product_desc", (getter) cms_profile_getattr_product_desc }, - { "product_description", (getter) cms_profile_getattr_product_description }, - { "product_manufacturer", (getter) cms_profile_getattr_product_manufacturer }, - { "product_model", (getter) cms_profile_getattr_product_model }, - { "product_copyright", (getter) cms_profile_getattr_product_copyright }, - { "pcs", (getter) cms_profile_getattr_pcs }, - { "color_space", (getter) cms_profile_getattr_color_space }, - /* New style interfaces. */ { "rendering_intent", (getter) cms_profile_getattr_rendering_intent }, { "creation_date", (getter) cms_profile_getattr_creation_date }, @@ -1485,7 +1375,6 @@ static struct PyGetSetDef cms_profile_getsetters[] = { { "header_model", (getter) cms_profile_getattr_header_model }, { "device_class", (getter) cms_profile_getattr_device_class }, { "connection_space", (getter) cms_profile_getattr_connection_space }, - /* Similar to color_space, but with full 4-letter signature (including trailing whitespace). */ { "xcolor_space", (getter) cms_profile_getattr_xcolor_space }, { "profile_id", (getter) cms_profile_getattr_profile_id }, { "is_matrix_shaper", (getter) cms_profile_getattr_is_matrix_shaper }, From c244ecf2452a87873f0dfba4a573e758b850f485 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 17:16:41 +0200 Subject: [PATCH 074/126] avoid suggesting that Pillow understands animation in all formats Co-authored-by: Andrew Murray <3112309+radarhere@users.noreply.github.com> --- docs/reference/Image.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 1eced066f..23f3eb03c 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -339,8 +339,9 @@ Instances of the :py:class:`Image` class have the following attributes: Plugins may leave this attribute undefined if they don't support loading animated images, even if the given format supports animated images. - To check whether an image is animated regardless of its format, use - ``getattr(image, "is_animated", False)``. + Given that this attribute is not present for all images use + ``getattr(image, "is_animated", False)`` to check if Pillow is aware of multiple + frames in an image regardless of its format. .. seealso:: :attr:`~Image.n_frames`, :func:`~Image.seek` and :func:`~Image.tell` @@ -353,8 +354,9 @@ Instances of the :py:class:`Image` class have the following attributes: Plugins may leave this attribute undefined if they don't support loading animated images, even if the given format supports animated images. - To check the number of frames in an image regardless of its format, use - ``getattr(image, "n_frames", 1)``. + Given that this attribute is not present for all images use + ``getattr(image, "n_frames", 1)`` to check the number of frames that Pillow is + aware of in an image regardless of its format. .. seealso:: :attr:`~Image.is_animated`, :func:`~Image.seek` and :func:`~Image.tell` From af5e0fa2aac6504846fad96f212243f70edfe8ff Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 23:20:45 +0200 Subject: [PATCH 075/126] add Python stdlib intersphinx mapping --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index c700fff79..ddfb24fe3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,6 +34,8 @@ extensions = [ "sphinx_removed_in", ] +intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} + # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] From 09a87161a240d84cf20e02b6ef6faea0172d8c01 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 23:46:28 +0200 Subject: [PATCH 076/126] fix sys.stdout reference --- src/PIL/PSDraw.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/PSDraw.py b/src/PIL/PSDraw.py index 762d31e88..a080ce44d 100644 --- a/src/PIL/PSDraw.py +++ b/src/PIL/PSDraw.py @@ -26,7 +26,7 @@ from . import EpsImagePlugin class PSDraw: """ Sets up printing to the given file. If **fp** is omitted, - :py:attr:`sys.stdout` is assumed. + :py:data:`sys.stdout` is assumed. """ def __init__(self, fp=None): From 9589159585e996e75dd47c7155635043a31cffca Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 23:50:57 +0200 Subject: [PATCH 077/126] use cross-reference for None value --- docs/handbook/image-file-formats.rst | 2 +- docs/handbook/writing-your-own-file-decoder.rst | 2 +- docs/reference/Image.rst | 4 ++-- docs/reference/ImageDraw.rst | 2 +- docs/reference/ImageGrab.rst | 2 +- docs/releasenotes/5.3.0.rst | 2 +- docs/releasenotes/7.0.0.rst | 4 ++-- docs/releasenotes/7.1.0.rst | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 6bcff7135..3daa75c96 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -857,7 +857,7 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum **compression** A string containing the desired compression method for the file. (valid only with libtiff installed) Valid compression - methods are: ``None``, ``"tiff_ccitt"``, ``"group3"``, + methods are: :data:`None`, ``"tiff_ccitt"``, ``"group3"``, ``"group4"``, ``"tiff_jpeg"``, ``"tiff_adobe_deflate"``, ``"tiff_thunderscan"``, ``"tiff_deflate"``, ``"tiff_sgilog"``, ``"tiff_sgilog24"``, ``"tiff_raw_16"`` diff --git a/docs/handbook/writing-your-own-file-decoder.rst b/docs/handbook/writing-your-own-file-decoder.rst index 89d0e3e9f..2a546b0c6 100644 --- a/docs/handbook/writing-your-own-file-decoder.rst +++ b/docs/handbook/writing-your-own-file-decoder.rst @@ -132,7 +132,7 @@ The fields are used as follows: **parameters** Parameters to the decoder. The contents of this field depends on the decoder specified by the first field in the tile descriptor tuple. If the - decoder doesn’t need any parameters, use ``None`` for this field. + decoder doesn’t need any parameters, use :data:`None` for this field. Note that the :py:attr:`tile` attribute contains a list of tile descriptors, not just a single descriptor. diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 6fe499036..347c57688 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -285,7 +285,7 @@ Instances of the :py:class:`Image` class have the following attributes: The file format of the source file. For images created by the library itself (via a factory function, or by running a method on an existing - image), this attribute is set to ``None``. + image), this attribute is set to :data:`None`. .. py:attribute:: Image.mode :type: str @@ -314,7 +314,7 @@ Instances of the :py:class:`Image` class have the following attributes: Colour palette table, if any. If mode is "P" or "PA", this should be an instance of the :py:class:`~PIL.ImagePalette.ImagePalette` class. - Otherwise, it should be set to ``None``. + Otherwise, it should be set to :data:`None`. .. py:attribute:: Image.info :type: dict diff --git a/docs/reference/ImageDraw.rst b/docs/reference/ImageDraw.rst index fd74b69c1..3faa0d3e0 100644 --- a/docs/reference/ImageDraw.rst +++ b/docs/reference/ImageDraw.rst @@ -212,7 +212,7 @@ Methods .. versionadded:: 1.1.5 .. note:: This option was broken until version 1.1.6. - :param joint: Joint type between a sequence of lines. It can be ``"curve"``, for rounded edges, or ``None``. + :param joint: Joint type between a sequence of lines. It can be ``"curve"``, for rounded edges, or :data:`None`. .. versionadded:: 5.3.0 diff --git a/docs/reference/ImageGrab.rst b/docs/reference/ImageGrab.rst index a9427be9c..ac83b2255 100644 --- a/docs/reference/ImageGrab.rst +++ b/docs/reference/ImageGrab.rst @@ -27,7 +27,7 @@ or the clipboard to a PIL image memory. .. versionadded:: 6.2.0 :param xdisplay: - X11 Display address. Pass ``None`` to grab the default system screen. Pass ``""`` to grab the default X11 screen on Windows or macOS. + X11 Display address. Pass :data:`None` to grab the default system screen. Pass ``""`` to grab the default X11 screen on Windows or macOS. You can check X11 support using :py:func:`PIL.features.check_feature` with ``feature="xcb"``. diff --git a/docs/releasenotes/5.3.0.rst b/docs/releasenotes/5.3.0.rst index cce671c32..bff56566b 100644 --- a/docs/releasenotes/5.3.0.rst +++ b/docs/releasenotes/5.3.0.rst @@ -34,7 +34,7 @@ Curved joints for line sequences ``ImageDraw.Draw.line`` draws a line, or lines, between points. Previously, when multiple points are given, for a larger ``width``, the joints between these lines looked unsightly. There is now an additional optional argument, -``joint``, defaulting to ``None``. When it is set to ``curved``, the joints +``joint``, defaulting to :data:`None`. When it is set to ``curved``, the joints between the lines will become rounded. ImageOps.colorize diff --git a/docs/releasenotes/7.0.0.rst b/docs/releasenotes/7.0.0.rst index 73c44275c..80002b0ce 100644 --- a/docs/releasenotes/7.0.0.rst +++ b/docs/releasenotes/7.0.0.rst @@ -66,7 +66,7 @@ See :ref:`concept-filters` to learn the difference. In short, Image.draft() return value ^^^^^^^^^^^^^^^^^^^^^^^^^^ -If the :py:meth:`~PIL.Image.Image.draft` method has no effect, it returns ``None``. +If the :py:meth:`~PIL.Image.Image.draft` method has no effect, it returns :data:`None`. If it does have an effect, then it previously returned the image itself. However, unlike other `chain methods`_, :py:meth:`~PIL.Image.Image.draft` does not return a modified version of the image, but modifies it in-place. So instead, if @@ -95,7 +95,7 @@ the closer the result to the fair resampling. The smaller ``reducing_gap``, the faster resizing. With ``reducing_gap`` greater or equal to 3.0, the result is indistinguishable from fair resampling. -The default value for :py:meth:`~PIL.Image.Image.resize` is ``None``, +The default value for :py:meth:`~PIL.Image.Image.resize` is :data:`None`, which means that the optimization is turned off by default. The default value for :py:meth:`~PIL.Image.Image.thumbnail` is 2.0, diff --git a/docs/releasenotes/7.1.0.rst b/docs/releasenotes/7.1.0.rst index 55a970c1e..35e5c4464 100644 --- a/docs/releasenotes/7.1.0.rst +++ b/docs/releasenotes/7.1.0.rst @@ -63,7 +63,7 @@ Support has been added for ``ImageGrab.grab()`` on Linux using the X server with the XCB library. An optional ``xdisplay`` parameter has been added to select the X server, -with the default value of ``None`` using the default X server. +with the default value of :data:`None` using the default X server. Passing a different value on Windows or macOS will force taking a snapshot using the selected X server; pass an empty string to use the default X server. From 6db12b29d9b38532fe88dec14cced18ad3d1c694 Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 10 Jul 2020 01:48:42 +0200 Subject: [PATCH 078/126] enable nitpicky warnings for docs builds --- docs/conf.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index c700fff79..6141fac18 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -103,6 +103,17 @@ pygments_style = "sphinx" # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False +# If true, Sphinx will warn about all references where the target cannot be found. +# Default is False. You can activate this mode temporarily using the -n command-line +# switch. +nitpicky = True + +# A list of (type, target) tuples (by default empty) that should be ignored when +# generating warnings in “nitpicky mode”. Note that type should include the domain name +# if present. Example entries would be ('py:func', 'int') or +# ('envvar', 'LD_LIBRARY_PATH'). +# nitpick_ignore = [] + # -- Options for HTML output ---------------------------------------------- From a04a10e7e35f3341543273ab3cc1ec1b1a58980f Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 10 Jul 2020 01:49:09 +0200 Subject: [PATCH 079/126] ignore some nitpicky warnings --- docs/conf.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 6141fac18..98e52b59b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -112,7 +112,20 @@ nitpicky = True # generating warnings in “nitpicky mode”. Note that type should include the domain name # if present. Example entries would be ('py:func', 'int') or # ('envvar', 'LD_LIBRARY_PATH'). -# nitpick_ignore = [] +nitpick_ignore = [ + ("py:meth", "_open"), + ("py:attr", "tile"), + ("py:meth", "CDC.GetHandleAttrib"), + ("py:meth", "PIL.Image.Image.convert2byte"), + ("py:attr", "PIL.Image.Image.tag"), + ("py:attr", "PIL.Image.Image.tag_v2"), + ("py:attr", "PIL.Image.Image.tile"), + ("py:data", "PIL.Image.MAX_PIXELS"), + ("py:func", "PIL.ImageMath.convert"), + ("py:func", "PIL.ImageMath.float"), + ("py:func", "PIL.ImageMath.int"), + ("py:attr", "PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype"), +] # -- Options for HTML output ---------------------------------------------- From f8ddb3aa486d828fd4d125c313b9a59a4f359a0f Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 10 Jul 2020 10:43:13 +0300 Subject: [PATCH 080/126] Update version Co-authored-by: nulano --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 24f895b85..c2a4ce2ae 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -19,7 +19,7 @@ Notes +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ |**Python** |**3.8**|**3.7**|**3.6**|**3.5**|**3.4**|**3.3**|**3.2**|**2.7**|**2.6**|**2.5**|**2.4**| +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow >= 7.3 | Yes | Yes | Yes | | | | | | | | | +|Pillow >= 8.0 | Yes | Yes | Yes | | | | | | | | | +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ |Pillow 7.0 - 7.2 | Yes | Yes | Yes | Yes | | | | | | | | +--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ From 3fa495ca25de2ca51ba053cc37430c890097393e Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 10 Jul 2020 11:12:21 +0300 Subject: [PATCH 081/126] Allow 3.9-dev to fail --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 980506368..bfe366000 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,6 +46,9 @@ matrix: env: PYTHONOPTIMIZE=2 services: xvfb + allow_failures: + - python: "3.9-dev" + install: - | if [ "$LINT" == "true" ]; then From 384523fab28c536eeedd3ea1e294fb4438a1ea6e Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 10 Jul 2020 11:48:02 +0300 Subject: [PATCH 082/126] Fix PostScript typos --- CHANGES.rst | 6 +++--- docs/handbook/tutorial.rst | 6 +++--- docs/reference/PSDraw.rst | 2 +- src/PIL/EpsImagePlugin.py | 6 +++--- src/PIL/PSDraw.py | 18 +++++++++--------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 62a134717..e06508f38 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5587,7 +5587,7 @@ Pre-fork any other pixel value means opaque. This is faster than using an "L" transparency mask. - + Properly writes EPS files (and properly prints images to postscript + + Properly writes EPS files (and properly prints images to PostScript printers as well). + Reads 4-bit BMP files, as well as 4 and 8-bit Windows ICO and CUR @@ -5670,7 +5670,7 @@ Pre-fork + Added the "pilfile" utility, which quickly identifies image files (without loading them, in most cases). - + Added the "pilprint" utility, which prints image files to Postscript + + Added the "pilprint" utility, which prints image files to PostScript printers. + Added a rudimentary version of the "pilview" utility, which is @@ -5684,5 +5684,5 @@ Pre-fork Jack). This allows you to read images through the Img extensions file format handlers. See the file "Lib/ImgExtImagePlugin.py" for details. - + Postscript printing is provided through the PSDraw module. See the + + PostScript printing is provided through the PSDraw module. See the handbook for details. diff --git a/docs/handbook/tutorial.rst b/docs/handbook/tutorial.rst index 94a8e3aa1..76c0fa83f 100644 --- a/docs/handbook/tutorial.rst +++ b/docs/handbook/tutorial.rst @@ -406,13 +406,13 @@ Using the ImageSequence Iterator class # ...do something to frame... -Postscript printing +PostScript printing ------------------- The Python Imaging Library includes functions to print images, text and -graphics on Postscript printers. Here’s a simple example: +graphics on PostScript printers. Here’s a simple example: -Drawing Postscript +Drawing PostScript ^^^^^^^^^^^^^^^^^^ :: diff --git a/docs/reference/PSDraw.rst b/docs/reference/PSDraw.rst index 958385818..3e8512e7a 100644 --- a/docs/reference/PSDraw.rst +++ b/docs/reference/PSDraw.rst @@ -4,7 +4,7 @@ :py:mod:`~PIL.PSDraw` Module ============================ -The :py:mod:`~PIL.PSDraw` module provides simple print support for Postscript +The :py:mod:`~PIL.PSDraw` module provides simple print support for PostScript printers. You can print text, graphics and images through this module. .. autoclass:: PIL.PSDraw.PSDraw diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 652dc489a..16d7ae039 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -191,7 +191,7 @@ def _accept(prefix): ## -# Image plugin for Encapsulated Postscript. This plugin supports only +# Image plugin for Encapsulated PostScript. This plugin supports only # a few variants of this format. @@ -262,7 +262,7 @@ class EpsImageFile(ImageFile.ImageFile): else: self.info[k] = "" elif s[0] == "%": - # handle non-DSC Postscript comments that some + # handle non-DSC PostScript comments that some # tools mistakenly put in the Comments section pass else: @@ -352,7 +352,7 @@ def _save(im, fp, filename, eps=1): im.load() # - # determine postscript image mode + # determine PostScript image mode if im.mode == "L": operator = (8, 1, "image") elif im.mode == "RGB": diff --git a/src/PIL/PSDraw.py b/src/PIL/PSDraw.py index 762d31e88..4b71d5790 100644 --- a/src/PIL/PSDraw.py +++ b/src/PIL/PSDraw.py @@ -2,7 +2,7 @@ # The Python Imaging Library # $Id$ # -# simple postscript graphics interface +# Simple PostScript graphics interface # # History: # 1996-04-20 fl Created @@ -20,7 +20,7 @@ import sys from . import EpsImagePlugin ## -# Simple Postscript graphics interface. +# Simple PostScript graphics interface. class PSDraw: @@ -41,7 +41,7 @@ class PSDraw: self.fp.write(bytes(to_write, "UTF-8")) def begin_document(self, id=None): - """Set up printing of a document. (Write Postscript DSC header.)""" + """Set up printing of a document. (Write PostScript DSC header.)""" # FIXME: incomplete self._fp_write( "%!PS-Adobe-3.0\n" @@ -57,7 +57,7 @@ class PSDraw: self.isofont = {} def end_document(self): - """Ends printing. (Write Postscript DSC footer.)""" + """Ends printing. (Write PostScript DSC footer.)""" self._fp_write("%%EndDocument\nrestore showpage\n%%End\n") if hasattr(self.fp, "flush"): self.fp.flush() @@ -66,7 +66,7 @@ class PSDraw: """ Selects which font to use. - :param font: A Postscript font name + :param font: A PostScript font name :param size: Size in points. """ if font not in self.isofont: @@ -79,7 +79,7 @@ class PSDraw: def line(self, xy0, xy1): """ Draws a line between the two points. Coordinates are given in - Postscript point coordinates (72 points per inch, (0, 0) is the lower + PostScript point coordinates (72 points per inch, (0, 0) is the lower left corner of the page). """ xy = xy0 + xy1 @@ -143,10 +143,10 @@ class PSDraw: # -------------------------------------------------------------------- -# Postscript driver +# PostScript driver # -# EDROFF.PS -- Postscript driver for Edroff 2 +# EDROFF.PS -- PostScript driver for Edroff 2 # # History: # 94-01-25 fl: created (edroff 2.04) @@ -176,7 +176,7 @@ EDROFF_PS = """\ """ # -# VDI.PS -- Postscript driver for VDI meta commands +# VDI.PS -- PostScript driver for VDI meta commands # # History: # 94-01-25 fl: created (edroff 2.04) From 20135f7cbd8309d20b9ebd8c005376efea8625f2 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 10 Jul 2020 21:26:49 +1000 Subject: [PATCH 083/126] Install setuptools 47.3.1 on Python 3.9 --- .ci/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/install.sh b/.ci/install.sh index 8a3b8fee4..36bce295c 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -30,6 +30,7 @@ pip install -U pytest-cov pip install pyroma pip install test-image-results pip install numpy +if [ "$TRAVIS_PYTHON_VERSION" == "3.9-dev" ]; then pip install setuptools==47.3.1 ; fi if [[ $TRAVIS_PYTHON_VERSION == 3.* ]]; then # arm64, ppc64le, s390x CPUs: # "ERROR: Could not find a version that satisfies the requirement pyqt5" From d7309b25d49ee0d4e2ceb57701a1e194962ea0fe Mon Sep 17 00:00:00 2001 From: joseville1001 <66519798+joseville1001@users.noreply.github.com> Date: Fri, 10 Jul 2020 21:17:08 -0400 Subject: [PATCH 084/126] Update ImageFilter.py `the` -> `The` --- src/PIL/ImageFilter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/ImageFilter.py b/src/PIL/ImageFilter.py index 3e61a6ca1..18c550c84 100644 --- a/src/PIL/ImageFilter.py +++ b/src/PIL/ImageFilter.py @@ -49,7 +49,7 @@ class Kernel(BuiltinFilter): version, this must be (3,3) or (5,5). :param kernel: A sequence containing kernel weights. :param scale: Scale factor. If given, the result for each pixel is - divided by this value. the default is the sum of the + divided by this value. The default is the sum of the kernel weights. :param offset: Offset. If given, this value is added to the result, after it has been divided by the scale factor. From 5e9e50159117b2970de98cfb2a4658dd14849d28 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 11 Jul 2020 13:13:49 +1000 Subject: [PATCH 085/126] Updated documentation [ci skip] --- docs/reference/ImageCms.rst | 56 ------------------------------------- 1 file changed, 56 deletions(-) diff --git a/docs/reference/ImageCms.rst b/docs/reference/ImageCms.rst index c8476f978..8fed4d092 100644 --- a/docs/reference/ImageCms.rst +++ b/docs/reference/ImageCms.rst @@ -75,10 +75,6 @@ can be easily displayed in a chromaticity diagram, for example). space, e.g. ``XYZ␣``, ``RGB␣`` or ``CMYK`` (see 7.2.6 of ICC.1:2010 for details). - Note that the deprecated attribute ``color_space`` contains an - interpreted (non-padded) variant of this (but can be empty on - unknown input). - .. py:attribute:: connection_space :type: str @@ -86,9 +82,6 @@ can be easily displayed in a chromaticity diagram, for example). space on the B-side of the transform (see 7.2.7 of ICC.1:2010 for details). - Note that the deprecated attribute ``pcs`` contains an interpreted - (non-padded) variant of this (but can be empty on unknown input). - .. py:attribute:: header_flags :type: int @@ -350,55 +343,6 @@ can be easily displayed in a chromaticity diagram, for example). The elements of the tuple are booleans. If the value is ``True``, that intent is supported for that direction. - .. py:attribute:: color_space - :type: str - - Deprecated but retained for backwards compatibility. - Interpreted value of :py:attr:`.xcolor_space`. May be the - empty string if value could not be decoded. - - .. py:attribute:: pcs - :type: str - - Deprecated but retained for backwards compatibility. - Interpreted value of :py:attr:`.connection_space`. May be - the empty string if value could not be decoded. - - .. py:attribute:: product_model - :type: str - - Deprecated but retained for backwards compatibility. - ASCII-encoded value of :py:attr:`.model`. - - .. py:attribute:: product_manufacturer - :type: str - - Deprecated but retained for backwards compatibility. - ASCII-encoded value of :py:attr:`.manufacturer`. - - .. py:attribute:: product_copyright - :type: str - - Deprecated but retained for backwards compatibility. - ASCII-encoded value of :py:attr:`.copyright`. - - .. py:attribute:: product_description - :type: str - - Deprecated but retained for backwards compatibility. - ASCII-encoded value of :py:attr:`.profile_description`. - - .. py:attribute:: product_desc - :type: str - - Deprecated but retained for backwards compatibility. - ASCII-encoded value of :py:attr:`.profile_description`. - - This alias of :py:attr:`.product_description` used to - contain a derived informative string about the profile, - depending on the value of the description, copyright, - manufacturer and model fields). - There is one function defined on the class: .. py:method:: is_intent_supported(intent, direction) From 9c277f5c498ddd451cdced6bc50d74e3020dd0e2 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 22:16:25 +0200 Subject: [PATCH 086/126] document PngImagePlugin constants --- docs/handbook/image-file-formats.rst | 8 +++++-- docs/reference/plugins.rst | 16 ++++--------- src/PIL/PngImagePlugin.py | 35 +++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 3daa75c96..771f4f557 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -501,12 +501,14 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following This key is omitted if the image is not a transparent palette image. +.. _png-text: + ``open`` also sets ``Image.text`` to a dictionary of the values of the ``tEXt``, ``zTXt``, and ``iTXt`` chunks of the PNG image. Individual compressed chunks are limited to a decompressed size of -``PngImagePlugin.MAX_TEXT_CHUNK``, by default 1MB, to prevent +:data:`.PngImagePlugin.MAX_TEXT_CHUNK`, by default 1MB, to prevent decompression bombs. Additionally, the total size of all of the text -chunks is limited to ``PngImagePlugin.MAX_TEXT_MEMORY``, defaulting to +chunks is limited to :data:`.PngImagePlugin.MAX_TEXT_MEMORY`, defaulting to 64MB. The :py:meth:`~PIL.Image.Image.save` method supports the following options: @@ -611,6 +613,8 @@ where applicable: Any APNG file containing sequence errors is treated as an invalid image. The APNG loader will not attempt to repair and reorder files containing sequence errors. +.. _apng-saving: + Saving ~~~~~~ diff --git a/docs/reference/plugins.rst b/docs/reference/plugins.rst index ef080b6db..7094f8784 100644 --- a/docs/reference/plugins.rst +++ b/docs/reference/plugins.rst @@ -229,20 +229,12 @@ Plugin reference --------------------------------- .. automodule:: PIL.PngImagePlugin - :members: ChunkStream, PngStream, getchunks, is_cid, putchunk - :show-inheritance: -.. autoclass:: PIL.PngImagePlugin.ChunkStream - :members: - :undoc-members: - :show-inheritance: -.. autoclass:: PIL.PngImagePlugin.PngImageFile - :members: - :undoc-members: - :show-inheritance: -.. autoclass:: PIL.PngImagePlugin.PngStream - :members: + :members: ChunkStream, PngImageFile, PngStream, getchunks, is_cid, putchunk, + MAX_TEXT_CHUNK, MAX_TEXT_MEMORY, APNG_BLEND_OP_SOURCE, APNG_BLEND_OP_OVER, + APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_PREVIOUS :undoc-members: :show-inheritance: + :member-order: groupwise :mod:`~PIL.PpmImagePlugin` Module diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index e027953dd..dd70edfe8 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -76,21 +76,50 @@ _MODES = { _simple_palette = re.compile(b"^\xff*\x00\xff*$") -# Maximum decompressed size for a iTXt or zTXt chunk. -# Eliminates decompression bombs where compressed chunks can expand 1000x MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK -# Set the maximum total text chunk size. +""" +Maximum decompressed size for a iTXt or zTXt chunk. +Eliminates decompression bombs where compressed chunks can expand 1000x +See :ref:`Text in PNG File Format`. +""" MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK +""" +Set the maximum total text chunk size. +See :ref:`Text in PNG File Format`. +""" # APNG frame disposal modes APNG_DISPOSE_OP_NONE = 0 +""" +No disposal is done on this frame before rendering the next frame. +See :ref:`Saving APNG sequences`. +""" APNG_DISPOSE_OP_BACKGROUND = 1 +""" +This frame’s modified region is cleared to fully transparent black before rendering +the next frame. +See :ref:`Saving APNG sequences`. +""" APNG_DISPOSE_OP_PREVIOUS = 2 +""" +This frame’s modified region is reverted to the previous frame’s contents before +rendering the next frame. +See :ref:`Saving APNG sequences`. +""" # APNG frame blend modes APNG_BLEND_OP_SOURCE = 0 +""" +All color components of this frame, including alpha, overwrite the previous output +image contents. +See :ref:`Saving APNG sequences`. +""" APNG_BLEND_OP_OVER = 1 +""" +This frame should be alpha composited with the previous output image contents. +See :ref:`Saving APNG sequences`. +""" def _safe_zlib_decompress(s): From 1fa01b013589c154a0d8ab33235cd9de2a1716c4 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 22:16:44 +0200 Subject: [PATCH 087/126] fix iTXt and PngInfo heading references --- docs/PIL.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/PIL.rst b/docs/PIL.rst index 4b10184fa..fa036b9cc 100644 --- a/docs/PIL.rst +++ b/docs/PIL.rst @@ -93,8 +93,8 @@ can be found here. :undoc-members: :show-inheritance: -:class:`PngImagePlugin.iTXt` Class ----------------------------------- +:class:`.PngImagePlugin.iTXt` Class +----------------------------------- .. autoclass:: PIL.PngImagePlugin.iTXt :members: @@ -107,8 +107,8 @@ can be found here. :param lang: language code :param tkey: UTF-8 version of the key name -:class:`PngImagePlugin.PngInfo` Class -------------------------------------- +:class:`.PngImagePlugin.PngInfo` Class +-------------------------------------- .. autoclass:: PIL.PngImagePlugin.PngInfo :members: From 2ce2fa2dfc61463823736fa0a8c724ae0665f751 Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 10 Jul 2020 14:17:10 +0100 Subject: [PATCH 088/126] Add a period Co-authored-by: Hugo van Kemenade --- src/PIL/PngImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index dd70edfe8..9d048b211 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -79,7 +79,7 @@ _simple_palette = re.compile(b"^\xff*\x00\xff*$") MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK """ Maximum decompressed size for a iTXt or zTXt chunk. -Eliminates decompression bombs where compressed chunks can expand 1000x +Eliminates decompression bombs where compressed chunks can expand 1000x. See :ref:`Text in PNG File Format`. """ MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK From 0083ebb3d49c580cb606ebec8a9e37062ef147d2 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 19:48:04 +0200 Subject: [PATCH 089/126] fix various reference typos --- docs/handbook/image-file-formats.rst | 2 +- docs/handbook/tutorial.rst | 4 ++-- docs/handbook/writing-your-own-file-decoder.rst | 2 +- docs/reference/ImageFont.rst | 2 +- src/PIL/Image.py | 10 +++++----- src/PIL/ImageChops.py | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 3daa75c96..d7fa89b2d 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -473,7 +473,7 @@ image formats, EXIF data is not guaranteed to be present in :py:attr:`~PIL.Image.Image.info` until :py:meth:`~PIL.Image.Image.load` has been called. -The :py:meth:`~PIL.Image.Image.open` method sets the following +The :py:func:`~PIL.Image.open` function sets the following :py:attr:`~PIL.Image.Image.info` properties, when appropriate: **chromaticity** diff --git a/docs/handbook/tutorial.rst b/docs/handbook/tutorial.rst index 76c0fa83f..b24a6eb4b 100644 --- a/docs/handbook/tutorial.rst +++ b/docs/handbook/tutorial.rst @@ -453,8 +453,8 @@ If everything goes well, the result is an :py:class:`PIL.Image.Image` object. Otherwise, an :exc:`OSError` exception is raised. You can use a file-like object instead of the filename. The object must -implement :py:meth:`~file.read`, :py:meth:`~file.seek` and -:py:meth:`~file.tell` methods, and be opened in binary mode. +implement ``file.read``, ``file.seek`` and ``file.tell`` methods, +and be opened in binary mode. Reading from an open file ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/handbook/writing-your-own-file-decoder.rst b/docs/handbook/writing-your-own-file-decoder.rst index 2a546b0c6..c73ad9cab 100644 --- a/docs/handbook/writing-your-own-file-decoder.rst +++ b/docs/handbook/writing-your-own-file-decoder.rst @@ -175,7 +175,7 @@ The fields are used as follows: The **raw mode** field is used to determine how the data should be unpacked to match PIL’s internal pixel layout. PIL supports a large set of raw modes; for a -complete list, see the table in the :py:mod:`Unpack.c` module. The following +complete list, see the table in the :file:`Unpack.c` module. The following table describes some commonly used **raw modes**: +-----------+-----------------------------------------------------------------+ diff --git a/docs/reference/ImageFont.rst b/docs/reference/ImageFont.rst index b3c3cce57..fc61cac13 100644 --- a/docs/reference/ImageFont.rst +++ b/docs/reference/ImageFont.rst @@ -6,7 +6,7 @@ The :py:mod:`~PIL.ImageFont` module defines a class with the same name. Instances of this class store bitmap fonts, and are used with the -:py:meth:`PIL.ImageDraw.Draw.text` method. +:py:meth:`PIL.ImageDraw.ImageDraw.text` method. PIL uses its own font file format to store bitmap fonts. You can use the :command:`pilfont` utility from diff --git a/src/PIL/Image.py b/src/PIL/Image.py index c1419744a..7c1fb0cb8 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -717,7 +717,7 @@ class Image: :param encoder_name: What encoder to use. The default is to use the standard "raw" encoder. :param args: Extra arguments to the encoder. - :rtype: A bytes object. + :returns: A :py:class:`bytes` object. """ # may pass tuple instead of argument list @@ -2352,10 +2352,10 @@ class Image: object:: class Example(Image.ImageTransformHandler): - def transform(size, method, data, resample, fill=1): + def transform(self, size, data, resample, fill=1): # Return result - It may also be an object with a :py:meth:`~method.getdata` method + It may also be an object with a ``method.getdata`` method that returns a tuple supplying new **method** and **data** values:: class Example: @@ -2847,8 +2847,8 @@ def open(fp, mode="r"): :py:func:`~PIL.Image.new`. See :ref:`file-handling`. :param fp: A filename (string), pathlib.Path object or a file object. - The file object must implement :py:meth:`~file.read`, - :py:meth:`~file.seek`, and :py:meth:`~file.tell` methods, + The file object must implement ``file.read``, + ``file.seek`, and ``file.tell`` methods, and be opened in binary mode. :param mode: The mode. If given, this argument must be "r". :returns: An :py:class:`~PIL.Image.Image` object. diff --git a/src/PIL/ImageChops.py b/src/PIL/ImageChops.py index c1a2574e4..9fccedcb2 100644 --- a/src/PIL/ImageChops.py +++ b/src/PIL/ImageChops.py @@ -293,7 +293,7 @@ def logical_xor(image1, image2): def blend(image1, image2, alpha): """Blend images using constant transparency weight. Alias for - :py:meth:`PIL.Image.Image.blend`. + :py:func:`PIL.Image.blend`. :rtype: :py:class:`~PIL.Image.Image` """ @@ -303,7 +303,7 @@ def blend(image1, image2, alpha): def composite(image1, image2, mask): """Create composite using transparency mask. Alias for - :py:meth:`PIL.Image.Image.composite`. + :py:func:`PIL.Image.composite`. :rtype: :py:class:`~PIL.Image.Image` """ From 73c5dffb5aad8fc4ffbacecf9902920ba31ca031 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 19:48:42 +0200 Subject: [PATCH 090/126] fix ImageTransformHandler and ImagePointHandler references --- docs/reference/Image.rst | 10 ++++++++-- src/PIL/Image.py | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 347c57688..b3f4b2b8e 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -268,8 +268,8 @@ This flips the input image by using the :data:`FLIP_LEFT_RIGHT` method. .. automethod:: PIL.Image.Image.load .. automethod:: PIL.Image.Image.close -Attributes ----------- +Image Attributes +---------------- Instances of the :py:class:`Image` class have the following attributes: @@ -330,6 +330,12 @@ Instances of the :py:class:`Image` class have the following attributes: Unless noted elsewhere, this dictionary does not affect saving files. +Classes +------- + +.. autoclass:: PIL.Image.ImagePointHandler +.. autoclass:: PIL.Image.ImageTransformHandler + Constants --------- diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 7c1fb0cb8..0d35d861d 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -1577,6 +1577,13 @@ class Image: single argument. The function is called once for each possible pixel value, and the resulting table is applied to all bands of the image. + + It may also be an :py:class:`~PIL.Image.ImagePointHandler` + object:: + + class Example(Image.ImagePointHandler): + def point(self, data): + # Return result :param mode: Output mode (default is same as input). In the current version, this can only be used if the source image has mode "L" or "P", and the output has mode "1" or the @@ -2534,12 +2541,20 @@ class Image: class ImagePointHandler: - # used as a mixin by point transforms (for use with im.point) + """ + Used as a mixin by point transforms + (for use with :py:meth:`~PIL.Image.Image.point`) + """ + pass class ImageTransformHandler: - # used as a mixin by geometry transforms (for use with im.transform) + """ + Used as a mixin by geometry transforms + (for use with :py:meth:`~PIL.Image.Image.transform`) + """ + pass From ec2b549a4da70d4af511108d3699d4e00606bcf9 Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 19:48:58 +0200 Subject: [PATCH 091/126] fix _imaging and Image.core references --- docs/porting.rst | 3 ++- docs/reference/internal_modules.rst | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/porting.rst b/docs/porting.rst index d962e9330..2943d72fd 100644 --- a/docs/porting.rst +++ b/docs/porting.rst @@ -19,7 +19,8 @@ to this:: from PIL import Image -The :py:mod:`~PIL._imaging` module has been moved. You can now import it like this:: +The :py:mod:`PIL._imaging` module has been moved to :py:mod:`PIL.Image.core`. +You can now import it like this:: from PIL.Image import core as _imaging diff --git a/docs/reference/internal_modules.rst b/docs/reference/internal_modules.rst index 288a049ee..1105ff76e 100644 --- a/docs/reference/internal_modules.rst +++ b/docs/reference/internal_modules.rst @@ -36,3 +36,12 @@ Internal Modules This is the master version number for Pillow, all other uses reference this module. + +:mod:`PIL.Image.core` Module +---------------------------- + +.. module:: PIL._imaging +.. module:: PIL.Image.core + +An internal interface module previously known as :mod:`~PIL._imaging`, +implemented in :file:`_imaging.c`. From f6b4c3f7410fe740e708a5a627aed400a465389a Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 20:19:34 +0200 Subject: [PATCH 092/126] don't link to removed methods --- docs/releasenotes/4.1.0.rst | 6 +++--- docs/releasenotes/4.2.0.rst | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/releasenotes/4.1.0.rst b/docs/releasenotes/4.1.0.rst index dc5d73479..4d6598d8e 100644 --- a/docs/releasenotes/4.1.0.rst +++ b/docs/releasenotes/4.1.0.rst @@ -10,9 +10,9 @@ Several deprecated items have been removed. resolution', 'resolution unit', and 'date time' has been removed. Underscores should be used instead. -* The methods :py:meth:`PIL.ImageDraw.ImageDraw.setink`, - :py:meth:`PIL.ImageDraw.ImageDraw.setfill`, and - :py:meth:`PIL.ImageDraw.ImageDraw.setfont` have been removed. +* The methods ``PIL.ImageDraw.ImageDraw.setink``, + ``PIL.ImageDraw.ImageDraw.setfill``, and + ``PIL.ImageDraw.ImageDraw.setfont`` have been removed. Closing Files When Opening Images diff --git a/docs/releasenotes/4.2.0.rst b/docs/releasenotes/4.2.0.rst index 906eeab8d..aee93bef6 100644 --- a/docs/releasenotes/4.2.0.rst +++ b/docs/releasenotes/4.2.0.rst @@ -34,9 +34,9 @@ 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 +* The methods ``PIL.ImageWin.Dib.fromstring``, + ``PIL.ImageWin.Dib.tostring`` and + ``PIL.TiffImagePlugin.ImageFileDirectory_v2.as_dict`` have been removed. * Before Pillow 4.2.0, attempting to save an RGBA image as JPEG would From 885ca9bb03f23b3bb11ed880148d758dd557c36c Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 20:23:19 +0200 Subject: [PATCH 093/126] add omitted ImageFilter types --- docs/reference/ImageFilter.rst | 26 ++++++++++++++++++++++++++ docs/releasenotes/4.3.0.rst | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/reference/ImageFilter.rst b/docs/reference/ImageFilter.rst index 1b93c53e7..fc879883a 100644 --- a/docs/reference/ImageFilter.rst +++ b/docs/reference/ImageFilter.rst @@ -66,3 +66,29 @@ image enhancement filters: .. autoclass:: PIL.ImageFilter.ModeFilter :members: + +.. class:: Filter + + An abstract mixin used for filtering images + (for use with :py:meth:`~PIL.Image.Image.filter`) + + Implementors must provide the following method: + + .. method:: filter(self, image) + + Applies a filter to a single-band image, or a single band of an image. + + :returns: A filtered copy of the image. + +.. class:: MultibandFilter + + An abstract mixin used for filtering multi-band images + (for use with :py:meth:`~PIL.Image.Image.filter`) + + Implementors must provide the following method: + + .. method:: filter(self, image) + + Applies a filter to a multi-band image. + + :returns: A filtered copy of the image. diff --git a/docs/releasenotes/4.3.0.rst b/docs/releasenotes/4.3.0.rst index 6fa554e23..ea81fc45e 100644 --- a/docs/releasenotes/4.3.0.rst +++ b/docs/releasenotes/4.3.0.rst @@ -124,7 +124,7 @@ This release contains several performance improvements: * ``Image.transpose`` has been accelerated 15% or more by using a cache friendly algorithm. * ImageFilters based on Kernel convolution are significantly faster - due to the new MultibandFilter feature. + due to the new :py:class:`~PIL.ImageFilter.MultibandFilter` feature. * All memory allocation for images is now done in blocks, rather than falling back to an allocation for each scan line for images larger than the block size. From 39b5d7b4acfa5c64fe597787bd2507f06c96089a Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 10 Jul 2020 00:47:30 +0200 Subject: [PATCH 094/126] fix TiffTags and Exif related references --- docs/handbook/image-file-formats.rst | 6 +++--- docs/reference/Image.rst | 4 ++++ docs/reference/TiffTags.rst | 5 +++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index d7fa89b2d..8955b3ede 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -774,7 +774,7 @@ The :py:meth:`~PIL.Image.open` method sets the following The :py:attr:`~PIL.Image.Image.tag_v2` attribute contains a dictionary of TIFF metadata. The keys are numerical indexes from -:py:attr:`~PIL.TiffTags.TAGS_V2`. Values are strings or numbers for single +:py:data:`.TiffTags.TAGS_V2`. Values are strings or numbers for single items, multiple values are returned in a tuple of values. Rational numbers are returned as a :py:class:`~PIL.TiffImagePlugin.IFDRational` object. @@ -827,7 +827,7 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum object and setting the type in :py:attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype` with the appropriate numerical value from - ``TiffTags.TYPES``. + :py:data:`.TiffTags.TYPES`. .. versionadded:: 2.3.0 @@ -844,7 +844,7 @@ The :py:meth:`~PIL.Image.Image.save` method can take the following keyword argum Previous versions only supported some tags when writing using libtiff. The supported list is found in - :py:attr:`~PIL:TiffTags.LIBTIFF_CORE`. + :py:data:`.TiffTags.LIBTIFF_CORE`. .. versionadded:: 6.1.0 diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index b3f4b2b8e..2a23cc76d 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -333,6 +333,10 @@ Instances of the :py:class:`Image` class have the following attributes: Classes ------- +.. autoclass:: PIL.Image.Exif + :members: + :undoc-members: + :show-inheritance: .. autoclass:: PIL.Image.ImagePointHandler .. autoclass:: PIL.Image.ImageTransformHandler diff --git a/docs/reference/TiffTags.rst b/docs/reference/TiffTags.rst index a53788a9f..231051632 100644 --- a/docs/reference/TiffTags.rst +++ b/docs/reference/TiffTags.rst @@ -60,3 +60,8 @@ metadata tag numbers, names, and type information. The ``TYPES`` dictionary maps the TIFF type short integer to a human readable type name. + +.. py:data:: PIL.TiffTags.LIBTIFF_CORE + :type: list + + A list of supported tag ids when writing using libtiff. From 7a660d548d5cc1b3cca154c7ebaee23ba59d7762 Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 10 Jul 2020 01:08:13 +0200 Subject: [PATCH 095/126] fix ImageQt reference --- docs/reference/ImageQt.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/ImageQt.rst b/docs/reference/ImageQt.rst index 887eab9ba..34d4cef51 100644 --- a/docs/reference/ImageQt.rst +++ b/docs/reference/ImageQt.rst @@ -9,7 +9,7 @@ objects from PIL images. .. versionadded:: 1.1.6 -.. py:class:: ImageQt.ImageQt(image) +.. py:class:: ImageQt(image) Creates an :py:class:`~PIL.ImageQt.ImageQt` object from a PIL :py:class:`~PIL.Image.Image` object. This class is a subclass of From 1ac943991ae7dd75996dbe25ab37c1a11a82bea9 Mon Sep 17 00:00:00 2001 From: nulano Date: Fri, 10 Jul 2020 14:16:04 +0100 Subject: [PATCH 096/126] Apply suggestions from code review Co-authored-by: Hugo van Kemenade --- docs/reference/ImageFilter.rst | 4 ++-- docs/reference/TiffTags.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference/ImageFilter.rst b/docs/reference/ImageFilter.rst index fc879883a..c85da4fb5 100644 --- a/docs/reference/ImageFilter.rst +++ b/docs/reference/ImageFilter.rst @@ -70,7 +70,7 @@ image enhancement filters: .. class:: Filter An abstract mixin used for filtering images - (for use with :py:meth:`~PIL.Image.Image.filter`) + (for use with :py:meth:`~PIL.Image.Image.filter`). Implementors must provide the following method: @@ -83,7 +83,7 @@ image enhancement filters: .. class:: MultibandFilter An abstract mixin used for filtering multi-band images - (for use with :py:meth:`~PIL.Image.Image.filter`) + (for use with :py:meth:`~PIL.Image.Image.filter`). Implementors must provide the following method: diff --git a/docs/reference/TiffTags.rst b/docs/reference/TiffTags.rst index 231051632..1441185dd 100644 --- a/docs/reference/TiffTags.rst +++ b/docs/reference/TiffTags.rst @@ -64,4 +64,4 @@ metadata tag numbers, names, and type information. .. py:data:: PIL.TiffTags.LIBTIFF_CORE :type: list - A list of supported tag ids when writing using libtiff. + A list of supported tag IDs when writing using LibTIFF. From c22328e3aa0722689a8e823f9738e63d5064b358 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 11 Jul 2020 13:57:35 +1000 Subject: [PATCH 097/126] Added description of release cycle [ci skip] --- docs/releasenotes/index.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/releasenotes/index.rst b/docs/releasenotes/index.rst index 4dd7d5e63..2d7747c3e 100644 --- a/docs/releasenotes/index.rst +++ b/docs/releasenotes/index.rst @@ -1,6 +1,13 @@ Release Notes ============= +Pillow is released quarterly on January 2nd, April 1st, July 1st and October 15th. +Patch releases are created if the latest release contains severe bugs, or if security +fixes are put together before a scheduled release. + +Please use the latest version of Pillow. Functionality and security fixes should not be +expected to be backported to earlier versions. + .. note:: Contributors please include release notes as needed or appropriate with your bug fixes, feature additions and tests. .. toctree:: From a2fa484c0625f17ce0520005c0f1da115517e227 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 11 Jul 2020 13:18:52 +0300 Subject: [PATCH 098/126] Add Python 3.9 column --- docs/installation.rst | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index c2a4ce2ae..02c4e6e34 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -16,27 +16,27 @@ Notes .. note:: Pillow is supported on the following Python versions -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|**Python** |**3.8**|**3.7**|**3.6**|**3.5**|**3.4**|**3.3**|**3.2**|**2.7**|**2.6**|**2.5**|**2.4**| -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow >= 8.0 | Yes | Yes | Yes | | | | | | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 7.0 - 7.2 | Yes | Yes | Yes | Yes | | | | | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 6.2.1 - 6.2.2| Yes | Yes | Yes | Yes | | | | Yes | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 6.0 - 6.2.0 | | Yes | Yes | Yes | | | | Yes | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 5.2 - 5.4 | | Yes | Yes | Yes | Yes | | | Yes | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 5.0 - 5.1 | | | Yes | Yes | Yes | | | Yes | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 4 | | | Yes | Yes | Yes | Yes | | Yes | | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow 2 - 3 | | | | Yes | Yes | Yes | Yes | Yes | Yes | | | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ -|Pillow < 2 | | | | | | | | Yes | Yes | Yes | Yes | -+--------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| **Python** |**3.9**|**3.8**|**3.7**|**3.6**|**3.5**|**3.4**|**3.3**|**3.2**|**2.7**|**2.6**|**2.5**|**2.4**| ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow >= 8.0 | Yes | Yes | Yes | Yes | | | | | | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 7.0 - 7.2 | | Yes | Yes | Yes | Yes | | | | | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 6.2.1 - 6.2.2 | | Yes | Yes | Yes | Yes | | | | Yes | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 6.0 - 6.2.0 | | | Yes | Yes | Yes | | | | Yes | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 5.2 - 5.4 | | | Yes | Yes | Yes | Yes | | | Yes | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 5.0 - 5.1 | | | | Yes | Yes | Yes | | | Yes | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 4 | | | | Yes | Yes | Yes | Yes | | Yes | | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow 2 - 3 | | | | | Yes | Yes | Yes | Yes | Yes | Yes | | | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ +| Pillow < 2 | | | | | | | | | Yes | Yes | Yes | Yes | ++----------------------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+-------+ Basic Installation ------------------ From 8d105aae18c3961cfcc9b1c219d6f878c0f2395f Mon Sep 17 00:00:00 2001 From: nulano Date: Sat, 11 Jul 2020 12:38:00 +0200 Subject: [PATCH 099/126] fix MAX_PIXELS typo --- docs/conf.py | 2 +- docs/releasenotes/4.2.0.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f650280ee..615afe715 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -122,7 +122,7 @@ nitpick_ignore = [ ("py:attr", "PIL.Image.Image.tag"), ("py:attr", "PIL.Image.Image.tag_v2"), ("py:attr", "PIL.Image.Image.tile"), - ("py:data", "PIL.Image.MAX_PIXELS"), + ("py:data", "PIL.Image.MAX_IMAGE_PIXELS"), ("py:func", "PIL.ImageMath.convert"), ("py:func", "PIL.ImageMath.float"), ("py:func", "PIL.ImageMath.int"), diff --git a/docs/releasenotes/4.2.0.rst b/docs/releasenotes/4.2.0.rst index aee93bef6..a3e29f271 100644 --- a/docs/releasenotes/4.2.0.rst +++ b/docs/releasenotes/4.2.0.rst @@ -27,7 +27,7 @@ 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:data:`PIL.Image.MAX_PIXELS`. +specified by :py:data:`PIL.Image.MAX_IMAGE_PIXELS`. Removed Deprecated Items ======================== From 71f8ec6a0cfc1008076a023c0756542539d057ab Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 12 Jul 2020 15:01:19 +1000 Subject: [PATCH 100/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index e06508f38..7eb694087 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 8.0.0 (unreleased) ------------------ +- Remove ImageCms.CmsProfile attributes deprecated since 3.2.0 #4768 + [hugovk, radarhere] + - Allow ImageOps.autocontrast to specify low and high cutoffs separately #4749 [millionhz, radarhere] From 2cec9f98a4afce2352a74b9061ccef299745ec3d Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 12 Jul 2020 15:03:10 +1000 Subject: [PATCH 101/126] Updated CI targets [ci skip] --- docs/installation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 02c4e6e34..c35b98f48 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -403,7 +403,7 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | Fedora 32 | 3.8 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| macOS 10.15 Catalina | 3.5, 3.6, 3.7, 3.8, PyPy3|x86-64 | +| macOS 10.15 Catalina | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 16.04 LTS | 3.5, 3.6, 3.7, 3.8, PyPy3|x86-64 | +----------------------------------+--------------------------+-----------------------+ @@ -413,11 +413,11 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | Windows Server 2016 | 3.8 |x86 | | +--------------------------+-----------------------+ -| | 3.5 |x86-64 | +| | 3.6 |x86-64 | | +--------------------------+-----------------------+ | | 3.7/MinGW |x86 | +----------------------------------+--------------------------+-----------------------+ -| Windows Server 2019 | 3.5, 3.6, 3.7, 3.8 |x86, x86-64 | +| Windows Server 2019 | 3.6, 3.7, 3.8 |x86, x86-64 | | +--------------------------+-----------------------+ | | PyPy3 |x86 | +----------------------------------+--------------------------+-----------------------+ From b913ae2685b5e516d49345c8af84129009ef4b7d Mon Sep 17 00:00:00 2001 From: nulano Date: Thu, 9 Jul 2020 21:08:15 +0200 Subject: [PATCH 102/126] use f-strings in winbuild --- winbuild/build_prepare.py | 61 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/winbuild/build_prepare.py b/winbuild/build_prepare.py index c17c3e43e..6f9cf4038 100644 --- a/winbuild/build_prepare.py +++ b/winbuild/build_prepare.py @@ -6,32 +6,32 @@ import sys def cmd_cd(path): - return "cd /D {path}".format(**locals()) + return f"cd /D {path}" def cmd_set(name, value): - return "set {name}={value}".format(**locals()) + return f"set {name}={value}" def cmd_append(name, value): - op = "path " if name == "PATH" else "set {name}=" - return (op + "%{name}%;{value}").format(**locals()) + op = "path " if name == "PATH" else f"set {name}=" + return op + f"%{name}%;{value}" def cmd_copy(src, tgt): - return 'copy /Y /B "{src}" "{tgt}"'.format(**locals()) + return f'copy /Y /B "{src}" "{tgt}"' def cmd_xcopy(src, tgt): - return 'xcopy /Y /E "{src}" "{tgt}"'.format(**locals()) + return f'xcopy /Y /E "{src}" "{tgt}"' def cmd_mkdir(path): - return 'mkdir "{path}"'.format(**locals()) + return f'mkdir "{path}"' def cmd_rmdir(path): - return 'rmdir /S /Q "{path}"'.format(**locals()) + return f'rmdir /S /Q "{path}"' def cmd_nmake(makefile=None, target="", params=None): @@ -44,13 +44,13 @@ def cmd_nmake(makefile=None, target="", params=None): return " ".join( [ - "{{nmake}}", + "{nmake}", "-nologo", - '-f "{makefile}"' if makefile is not None else "", - "{params}", - '"{target}"', + f'-f "{makefile}"' if makefile is not None else "", + f"{params}", + f'"{target}"', ] - ).format(**locals()) + ) def cmd_cmake(params=None, file="."): @@ -62,15 +62,15 @@ def cmd_cmake(params=None, file="."): params = str(params) return " ".join( [ - "{{cmake}}", + "{cmake}", "-DCMAKE_VERBOSE_MAKEFILE=ON", "-DCMAKE_RULE_MESSAGES:BOOL=OFF", "-DCMAKE_BUILD_TYPE=Release", - "{params}", + f"{params}", '-G "NMake Makefiles"', - '"{file}"', + f'"{file}"', ] - ).format(**locals()) + ) def cmd_msbuild( @@ -78,14 +78,14 @@ def cmd_msbuild( ): return " ".join( [ - "{{msbuild}}", - "{file}", - '/t:"{target}"', - '/p:Configuration="{configuration}"', - "/p:Platform={platform}", + "{msbuild}", + f"{file}", + f'/t:"{target}"', + f'/p:Configuration="{configuration}"', + f"/p:Platform={platform}", "/m", ] - ).format(**locals()) + ) SF_MIRROR = "http://iweb.dl.sourceforge.net" @@ -336,12 +336,12 @@ def find_msvs(): # vs2017 msbuild = os.path.join(vspath, "MSBuild", "15.0", "Bin", "MSBuild.exe") if os.path.isfile(msbuild): - vs["msbuild"] = '"{}"'.format(msbuild) + vs["msbuild"] = f'"{msbuild}"' else: # vs2019 msbuild = os.path.join(vspath, "MSBuild", "Current", "Bin", "MSBuild.exe") if os.path.isfile(msbuild): - vs["msbuild"] = '"{}"'.format(msbuild) + vs["msbuild"] = f'"{msbuild}"' else: print("Visual Studio MSBuild not found") return None @@ -350,7 +350,7 @@ def find_msvs(): if not os.path.isfile(vcvarsall): print("Visual Studio vcvarsall not found") return None - vs["header"].append('call "{}" {{vcvars_arch}}'.format(vcvarsall)) + vs["header"].append(f'call "{vcvarsall}" {{vcvars_arch}}') return vs @@ -411,7 +411,7 @@ def get_footer(dep): def build_dep(name): dep = deps[name] dir = dep["dir"] - file = "build_dep_{name}.cmd".format(**locals()) + file = f"build_dep_{name}.cmd" extract_dep(dep["url"], dep["filename"]) @@ -424,10 +424,10 @@ def build_dep(name): with open(patch_file, "w") as f: f.write(text) - banner = "Building {name} ({dir})".format(**locals()) + banner = f"Building {name} ({dir})" lines = [ "@echo " + ("=" * 70), - "@echo ==== {:<60} ====".format(banner), + f"@echo ==== {banner:<60} ====", "@echo " + ("=" * 70), "cd /D %s" % os.path.join(build_dir, dir), *prefs["header"], @@ -444,7 +444,8 @@ def build_dep_all(): for dep_name in deps: if dep_name in disabled: continue - lines.append(r'cmd.exe /c "{{build_dir}}\{}"'.format(build_dep(dep_name))) + script = build_dep(dep_name) + lines.append(fr'cmd.exe /c "{{build_dir}}\{script}"') lines.append("if errorlevel 1 echo Build failed! && exit /B 1") lines.append("@echo All Pillow dependencies built successfully!") write_script("build_dep_all.cmd", lines) From 701e05d2f79ac7c88614b68d176c28c910e73458 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 14 Jul 2020 20:43:34 +1000 Subject: [PATCH 103/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 7eb694087..07f16835c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 8.0.0 (unreleased) ------------------ +- Drop support for EOL Python 3.5 #4746 + [hugovk, radarhere, nulano] + - Remove ImageCms.CmsProfile attributes deprecated since 3.2.0 #4768 [hugovk, radarhere] From cd10404abb725c2b84a5265ada1e499e8d4d95ae Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 14 Jul 2020 22:18:25 +1000 Subject: [PATCH 104/126] Corrected reference --- docs/handbook/image-file-formats.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index 0355e1d18..bd565f79c 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -712,8 +712,8 @@ The :py:meth:`~PIL.Image.open` method sets the following attributes: **n_frames** Set to the number of images in the stack. -A convenience method, :py:meth:`~PIL.Image.Image.convert2byte`, is provided for -converting floating point data to byte data (mode ``L``):: +A convenience method, :py:meth:`~PIL.SpiderImagePlugin.SpiderImageFile.convert2byte`, +is provided for converting floating point data to byte data (mode ``L``):: im = Image.open('image001.spi').convert2byte() From 470bf71e7af7f9bde20fbf1f4acd78cb63988471 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 14 Jul 2020 22:23:57 +1000 Subject: [PATCH 105/126] Removed domain references from image expressions --- docs/reference/ImageMath.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/reference/ImageMath.rst b/docs/reference/ImageMath.rst index 21308b339..821f60cf5 100644 --- a/docs/reference/ImageMath.rst +++ b/docs/reference/ImageMath.rst @@ -60,9 +60,8 @@ point values, as necessary. For example, if you add two 8-bit images, the result will be a 32-bit integer image. If you add a floating point constant to an 8-bit image, the result will be a 32-bit floating point image. -You can force conversion using the :py:func:`~PIL.ImageMath.convert`, -:py:func:`~PIL.ImageMath.float`, and :py:func:`~PIL.ImageMath.int` functions -described below. +You can force conversion using the ``convert()``, ``float()``, and ``int()`` +functions described below. Bitwise Operators ^^^^^^^^^^^^^^^^^ From 45564fe89d7db4b819ecb8a93457a6a5129cbe51 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 14 Jul 2020 22:20:44 +1000 Subject: [PATCH 106/126] Removed domain references when referring to hypothetical code --- docs/conf.py | 7 ------- docs/handbook/writing-your-own-file-decoder.rst | 16 ++++++++-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 615afe715..2d80e3170 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -115,17 +115,10 @@ nitpicky = True # if present. Example entries would be ('py:func', 'int') or # ('envvar', 'LD_LIBRARY_PATH'). nitpick_ignore = [ - ("py:meth", "_open"), - ("py:attr", "tile"), - ("py:meth", "CDC.GetHandleAttrib"), - ("py:meth", "PIL.Image.Image.convert2byte"), ("py:attr", "PIL.Image.Image.tag"), ("py:attr", "PIL.Image.Image.tag_v2"), ("py:attr", "PIL.Image.Image.tile"), ("py:data", "PIL.Image.MAX_IMAGE_PIXELS"), - ("py:func", "PIL.ImageMath.convert"), - ("py:func", "PIL.ImageMath.float"), - ("py:func", "PIL.ImageMath.int"), ("py:attr", "PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype"), ] diff --git a/docs/handbook/writing-your-own-file-decoder.rst b/docs/handbook/writing-your-own-file-decoder.rst index c73ad9cab..471ae3377 100644 --- a/docs/handbook/writing-your-own-file-decoder.rst +++ b/docs/handbook/writing-your-own-file-decoder.rst @@ -28,16 +28,16 @@ Pillow decodes files in two stages: An image plugin should contain a format handler derived from the :py:class:`PIL.ImageFile.ImageFile` base class. This class should -provide an :py:meth:`_open` method, which reads the file header and +provide an ``_open`` method, which reads the file header and sets up at least the :py:attr:`~PIL.Image.Image.mode` and :py:attr:`~PIL.Image.Image.size` attributes. To be able to load the -file, the method must also create a list of :py:attr:`tile` -descriptors, which contain a decoder name, extents of the tile, and +file, the method must also create a list of ``tile`` descriptors, +which contain a decoder name, extents of the tile, and any decoder-specific data. The format handler class must be explicitly registered, via a call to the :py:mod:`~PIL.Image` module. .. note:: For performance reasons, it is important that the - :py:meth:`_open` method quickly rejects files that do not have the + ``_open`` method quickly rejects files that do not have the appropriate contents. Example @@ -103,10 +103,10 @@ Note that the image plugin must be explicitly registered using :py:func:`PIL.Image.register_open`. Although not required, it is also a good idea to register any extensions used by this format. -The :py:attr:`tile` attribute ------------------------------ +The ``tile`` attribute +---------------------- -To be able to read the file as well as just identifying it, the :py:attr:`tile` +To be able to read the file as well as just identifying it, the ``tile`` attribute must also be set. This attribute consists of a list of tile descriptors, where each descriptor specifies how data should be loaded to a given region in the image. In most cases, only a single descriptor is used, @@ -134,7 +134,7 @@ The fields are used as follows: decoder specified by the first field in the tile descriptor tuple. If the decoder doesn’t need any parameters, use :data:`None` for this field. -Note that the :py:attr:`tile` attribute contains a list of tile descriptors, +Note that the ``tile`` attribute contains a list of tile descriptors, not just a single descriptor. Decoders From f454b242889d62982c898f6a5519269818005611 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 14 Jul 2020 22:37:03 +1000 Subject: [PATCH 107/126] Removed domain reference for external method --- src/PIL/ImageWin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/ImageWin.py b/src/PIL/ImageWin.py index afba61c32..2ca4acdf8 100644 --- a/src/PIL/ImageWin.py +++ b/src/PIL/ImageWin.py @@ -88,8 +88,8 @@ class Dib: Copy the bitmap contents to a device context. :param handle: Device context (HDC), cast to a Python integer, or an - HDC or HWND instance. In PythonWin, you can use the - :py:meth:`CDC.GetHandleAttrib` to get a suitable handle. + HDC or HWND instance. In PythonWin, you can use + ``CDC.GetHandleAttrib()`` to get a suitable handle. """ if isinstance(handle, HWND): dc = self.image.getdc(handle) From e30836be5c2f17b1e017f5230181783da8eb0dd9 Mon Sep 17 00:00:00 2001 From: Sam Morgan Date: Wed, 15 Jul 2020 15:31:43 -0700 Subject: [PATCH 108/126] Add MIME type to PsdImagePlugin Resolves #4787 --- src/PIL/PsdImagePlugin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index f019bb64e..80bc116fc 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -307,3 +307,5 @@ def _maketile(file, mode, bbox, channels): Image.register_open(PsdImageFile.format, PsdImageFile, _accept) Image.register_extension(PsdImageFile.format, ".psd") + +Image.register_mime(PsdImageFile.format, "image/vnd.adobe.photoshop") From ee856bdc251d3fb61ed5ee5ead32a4fdbcd1a415 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Kul=C3=ADk?= Date: Thu, 16 Jul 2020 11:04:16 +0200 Subject: [PATCH 109/126] Fix expected failures on big endian systems without CI --- Tests/test_file_jpeg2k.py | 5 ++--- Tests/test_file_png.py | 3 +-- Tests/test_file_webp_animated.py | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index 07f8e8e05..d558843b8 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -8,7 +8,6 @@ from .helper import ( assert_image_equal, assert_image_similar, is_big_endian, - on_ci, skip_unless_feature, ) @@ -190,14 +189,14 @@ def test_16bit_monochrome_has_correct_mode(): assert jp2.mode == "I;16" -@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian") +@pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_16bit_monochrome_jp2_like_tiff(): with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: with Image.open("Tests/images/16bit.cropped.jp2") as jp2: assert_image_similar(jp2, tiff_16bit, 1e-3) -@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian") +@pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_16bit_monochrome_j2k_like_tiff(): with Image.open("Tests/images/16bit.cropped.tif") as tiff_16bit: with Image.open("Tests/images/16bit.cropped.j2k") as j2k: diff --git a/Tests/test_file_png.py b/Tests/test_file_png.py index 9bd8507d9..9891b6399 100644 --- a/Tests/test_file_png.py +++ b/Tests/test_file_png.py @@ -12,7 +12,6 @@ from .helper import ( hopper, is_big_endian, is_win32, - on_ci, skip_unless_feature, ) @@ -69,7 +68,7 @@ class TestFilePng: png.crc(cid, s) return chunks - @pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian") + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_sanity(self, tmp_path): # internal version number diff --git a/Tests/test_file_webp_animated.py b/Tests/test_file_webp_animated.py index a846a6db4..cd272f154 100644 --- a/Tests/test_file_webp_animated.py +++ b/Tests/test_file_webp_animated.py @@ -5,7 +5,6 @@ from .helper import ( assert_image_equal, assert_image_similar, is_big_endian, - on_ci, skip_unless_feature, ) @@ -27,7 +26,7 @@ def test_n_frames(): assert im.is_animated -@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian") +@pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_write_animation_L(tmp_path): """ Convert an animated GIF to animated WebP, then compare the frame count, and first @@ -53,7 +52,7 @@ def test_write_animation_L(tmp_path): assert_image_similar(im, orig.convert("RGBA"), 25.0) -@pytest.mark.xfail(is_big_endian() and on_ci(), reason="Fails on big-endian") +@pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_write_animation_RGB(tmp_path): """ Write an animated WebP from RGB frames, and ensure the frames From e06c7e766735cb719a9ec4fa6daba603bdd9ce74 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 16 Jul 2020 12:09:19 +0300 Subject: [PATCH 110/126] 8.0.0.dev0 version bump --- src/PIL/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/_version.py b/src/PIL/_version.py index a67ccbff4..717ab07fc 100644 --- a/src/PIL/_version.py +++ b/src/PIL/_version.py @@ -1,2 +1,2 @@ # Master version for Pillow -__version__ = "7.3.0.dev0" +__version__ = "8.0.0.dev0" From e866143eff4a2b6f34348cd9b0ed57a5ce49d939 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 16 Jul 2020 20:17:25 +1000 Subject: [PATCH 111/126] Removed Docker images running Python 3.5 --- .github/workflows/test-docker.yml | 2 -- docs/installation.rst | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/test-docker.yml b/.github/workflows/test-docker.yml index f168304bc..9025dec1c 100644 --- a/.github/workflows/test-docker.yml +++ b/.github/workflows/test-docker.yml @@ -12,10 +12,8 @@ jobs: docker: [ alpine, arch, - ubuntu-16.04-xenial-amd64, ubuntu-18.04-bionic-amd64, ubuntu-20.04-focal-amd64, - debian-9-stretch-x86, debian-10-buster-x86, centos-6-amd64, centos-7-amd64, diff --git a/docs/installation.rst b/docs/installation.rst index c35b98f48..ab5e1ee62 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -395,8 +395,6 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | CentOS 8 | 3.6 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| Debian 9 Stretch | 3.5 |x86 | -+----------------------------------+--------------------------+-----------------------+ | Debian 10 Buster | 3.7 |x86 | +----------------------------------+--------------------------+-----------------------+ | Fedora 31 | 3.7 |x86-64 | @@ -405,7 +403,7 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | macOS 10.15 Catalina | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| Ubuntu Linux 16.04 LTS | 3.5, 3.6, 3.7, 3.8, PyPy3|x86-64 | +| Ubuntu Linux 16.04 LTS | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 18.04 LTS | 3.6 |x86-64 | +----------------------------------+--------------------------+-----------------------+ From d0cad3331abd8fb7eed66a45b706e4a2e18ea810 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Thu, 16 Jul 2020 20:31:07 +1000 Subject: [PATCH 112/126] Added Ubuntu 16.04 code name [ci skip] Co-authored-by: Hugo van Kemenade --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index ab5e1ee62..f22a41795 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -403,7 +403,7 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | macOS 10.15 Catalina | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| Ubuntu Linux 16.04 LTS | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +| Ubuntu Linux 16.04 LTS (Xenial) | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 18.04 LTS | 3.6 |x86-64 | +----------------------------------+--------------------------+-----------------------+ From b2370b60556b6c4cb43762073cf79951023c2494 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 16 Jul 2020 20:33:17 +1000 Subject: [PATCH 113/126] Added further Ubuntu code names [ci skip] --- docs/installation.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index f22a41795..9a50951ca 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -405,9 +405,9 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 16.04 LTS (Xenial) | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| Ubuntu Linux 18.04 LTS | 3.6 |x86-64 | +| Ubuntu Linux 18.04 LTS (Bionic) | 3.6 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| Ubuntu Linux 20.04 LTS | 3.8 |x86-64 | +| Ubuntu Linux 20.04 LTS (Focal) | 3.8 |x86-64 | +----------------------------------+--------------------------+-----------------------+ | Windows Server 2016 | 3.8 |x86 | | +--------------------------+-----------------------+ @@ -458,14 +458,14 @@ These platforms have been reported to work at the versions mentioned. +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Fedora 23 | 2.7, 3.4 | 3.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| Ubuntu Linux 12.04 LTS | 2.6, 3.2, 3.3, 3.4, 3.5 | 3.4.1 |x86,x86-64 | +| Ubuntu Linux 12.04 LTS (Precise) | 2.6, 3.2, 3.3, 3.4, 3.5 | 3.4.1 |x86,x86-64 | | | PyPy5.3.1, PyPy3 v2.4.0 | | | | +------------------------------+--------------------------------+-----------------------+ | | 2.7 | 4.3.0 |x86-64 | | +------------------------------+--------------------------------+-----------------------+ | | 2.7, 3.2 | 3.4.1 |ppc | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| Ubuntu Linux 10.04 LTS | 2.6 | 2.3.0 |x86,x86-64 | +| Ubuntu Linux 10.04 LTS (Lucid) | 2.6 | 2.3.0 |x86,x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | Debian 8.2 Jessie | 2.7, 3.4 | 3.1.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ From 80402e419a38999852e818c82a447873025e58c3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 16 Jul 2020 21:50:43 +1000 Subject: [PATCH 114/126] Updated CI targets [ci skip] --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 9a50951ca..84377b1c2 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -405,7 +405,7 @@ These platforms are built and tested for every change. +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 16.04 LTS (Xenial) | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ -| Ubuntu Linux 18.04 LTS (Bionic) | 3.6 |x86-64 | +| Ubuntu Linux 18.04 LTS (Bionic) | 3.6, 3.7, 3.8, PyPy3 |x86-64 | +----------------------------------+--------------------------+-----------------------+ | Ubuntu Linux 20.04 LTS (Focal) | 3.8 |x86-64 | +----------------------------------+--------------------------+-----------------------+ From 304d3c108033169fd8555cfc4d5be767e64cd007 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Thu, 16 Jul 2020 14:57:39 +0300 Subject: [PATCH 115/126] Replace distutils.version with packaging.version.parse, distutils will eventually be removed from stdlib --- Tests/test_imagefont.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Tests/test_imagefont.py b/Tests/test_imagefont.py index 9ae2bdfc7..6668a100b 100644 --- a/Tests/test_imagefont.py +++ b/Tests/test_imagefont.py @@ -1,5 +1,4 @@ import copy -import distutils.version import os import re import shutil @@ -7,6 +6,7 @@ import sys from io import BytesIO import pytest +from packaging.version import parse as parse_version from PIL import Image, ImageDraw, ImageFont, features from .helper import ( @@ -41,7 +41,7 @@ class TestImageFont: @classmethod def setup_class(self): - freetype = distutils.version.StrictVersion(features.version_module("freetype2")) + freetype = parse_version(features.version_module("freetype2")) self.metrics = self.METRICS["Default"] for conditions, metrics in self.METRICS.items(): @@ -49,7 +49,7 @@ class TestImageFont: continue for condition in conditions: - version = re.sub("[<=>]", "", condition) + version = parse_version(re.sub("[<=>]", "", condition)) if (condition.startswith(">=") and freetype >= version) or ( condition.startswith("<") and freetype < version ): @@ -620,8 +620,8 @@ class TestImageFont: def test_variation_get(self): font = self.get_font() - freetype = distutils.version.StrictVersion(features.version_module("freetype2")) - if freetype < "2.9.1": + freetype = parse_version(features.version_module("freetype2")) + if freetype < parse_version("2.9.1"): with pytest.raises(NotImplementedError): font.get_variation_names() with pytest.raises(NotImplementedError): @@ -692,8 +692,8 @@ class TestImageFont: def test_variation_set_by_name(self): font = self.get_font() - freetype = distutils.version.StrictVersion(features.version_module("freetype2")) - if freetype < "2.9.1": + freetype = parse_version(features.version_module("freetype2")) + if freetype < parse_version("2.9.1"): with pytest.raises(NotImplementedError): font.set_variation_by_name("Bold") return @@ -716,8 +716,8 @@ class TestImageFont: def test_variation_set_by_axes(self): font = self.get_font() - freetype = distutils.version.StrictVersion(features.version_module("freetype2")) - if freetype < "2.9.1": + freetype = parse_version(features.version_module("freetype2")) + if freetype < parse_version("2.9.1"): with pytest.raises(NotImplementedError): font.set_variation_by_axes([100]) return @@ -742,7 +742,7 @@ class TestImageFont_RaqmLayout(TestImageFont): def test_render_mono_size(): # issue 4177 - if distutils.version.StrictVersion(ImageFont.core.freetype2_version) < "2.4": + if parse_version(ImageFont.core.freetype2_version) < parse_version("2.4"): pytest.skip("Different metrics") im = Image.new("P", (100, 30), "white") From 74e02e6c4ec7c48f2d899490277c063778c6ee15 Mon Sep 17 00:00:00 2001 From: Sam Morgan Date: Thu, 16 Jul 2020 08:26:42 -0700 Subject: [PATCH 116/126] Add test for PSD mimetype --- Tests/test_file_psd.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/test_file_psd.py b/Tests/test_file_psd.py index 011efc977..6b26fe442 100644 --- a/Tests/test_file_psd.py +++ b/Tests/test_file_psd.py @@ -12,6 +12,7 @@ def test_sanity(): assert im.mode == "RGB" assert im.size == (128, 128) assert im.format == "PSD" + assert im.get_format_mimetype() == "image/vnd.adobe.photoshop" im2 = hopper() assert_image_similar(im, im2, 4.8) From be04bc9926f1a7b80542649be7e81f1819e32f2e Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 17 Jul 2020 21:09:49 +1000 Subject: [PATCH 117/126] Updated CHANGES.rst [ci skip] --- CHANGES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index 07f16835c..d5d1330c2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,9 @@ Changelog (Pillow) 8.0.0 (unreleased) ------------------ +- Add MIME type to PsdImagePlugin #4788 + [samamorgan] + - Drop support for EOL Python 3.5 #4746 [hugovk, radarhere, nulano] From 46244cb4ed3c31106e5de44cd47ffc2713f86d0e Mon Sep 17 00:00:00 2001 From: nulano Date: Wed, 15 Jul 2020 13:50:22 +0200 Subject: [PATCH 118/126] enable Python 3.9 GHA tests --- .github/workflows/test-windows.yml | 2 +- .github/workflows/test.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 65657f266..9b04b2bd7 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.6", "3.7", "3.8", "pypy3"] + python-version: ["3.6", "3.7", "3.8", "3.9-dev", "pypy3"] architecture: ["x86", "x64"] include: - architecture: "x86" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a99d09f2..65673b0a2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,6 +14,7 @@ jobs: ] python-version: [ "pypy3", + "3.9-dev", "3.8", "3.7", "3.6", From bd65c1071ef1273f10028d0815315124c30f7734 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 18 Jul 2020 20:11:00 +1000 Subject: [PATCH 119/126] Updated macOS tested Pillow versions [ci skip] --- docs/installation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 84377b1c2..958a076f1 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -434,7 +434,7 @@ These platforms have been reported to work at the versions mentioned. +----------------------------------+------------------------------+--------------------------------+-----------------------+ |**Operating system** |**Tested Python versions** |**Latest tested Pillow version**|**Tested processors** | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| macOS 10.15 Catalina | 3.5, 3.6, 3.7, 3.8 | 7.1.2 |x86-64 | +| macOS 10.15 Catalina | 3.5, 3.6, 3.7, 3.8 | 7.2.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ | macOS 10.14 Mojave | 2.7, 3.5, 3.6, 3.7 | 6.0.0 |x86-64 | | +------------------------------+--------------------------------+ + From 45f09b413978e5ae0ab5c86d27d67b40bb3d3272 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Sat, 18 Jul 2020 17:08:25 +0300 Subject: [PATCH 120/126] Tested 7.2.0 with 3.5-3.8 on macOS Mojave --- docs/installation.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 958a076f1..706cfb1d7 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -436,7 +436,9 @@ These platforms have been reported to work at the versions mentioned. +----------------------------------+------------------------------+--------------------------------+-----------------------+ | macOS 10.15 Catalina | 3.5, 3.6, 3.7, 3.8 | 7.2.0 |x86-64 | +----------------------------------+------------------------------+--------------------------------+-----------------------+ -| macOS 10.14 Mojave | 2.7, 3.5, 3.6, 3.7 | 6.0.0 |x86-64 | +| macOS 10.14 Mojave | 3.5, 3.6, 3.7, 3.8 | 7.2.0 |x86-64 | +| +------------------------------+--------------------------------+ + +| | 2.7 | 6.0.0 | | | +------------------------------+--------------------------------+ + | | 3.4 | 5.4.1 | | +----------------------------------+------------------------------+--------------------------------+-----------------------+ From 9db4a849832cea2846f7850db1a699b54f755e1f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 20 Jul 2020 21:16:33 +1000 Subject: [PATCH 121/126] Documented MAX_IMAGE_PIXELS --- docs/conf.py | 1 - docs/reference/Image.rst | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 2d80e3170..5b42bba11 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -118,7 +118,6 @@ nitpick_ignore = [ ("py:attr", "PIL.Image.Image.tag"), ("py:attr", "PIL.Image.Image.tag_v2"), ("py:attr", "PIL.Image.Image.tile"), - ("py:data", "PIL.Image.MAX_IMAGE_PIXELS"), ("py:attr", "PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype"), ] diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index f24d382b8..da14fb343 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -374,6 +374,10 @@ Constants --------- .. data:: NONE +.. data:: MAX_IMAGE_PIXELS + + Set to 89,478,485, approximately 0.25gb for a 24 bit (3 bpp) image. + See :py:meth:`~PIL.Image.open` for more information about how this is used. Transpose methods ^^^^^^^^^^^^^^^^^ From d98b85d38673196236f0dfe83098e2c81d6d4162 Mon Sep 17 00:00:00 2001 From: Andrew Murray <3112309+radarhere@users.noreply.github.com> Date: Mon, 20 Jul 2020 23:08:25 +1000 Subject: [PATCH 122/126] Capitalise and hyphenate [ci skip] Co-authored-by: Hugo van Kemenade --- docs/reference/Image.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index da14fb343..738fd8c0e 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -376,7 +376,7 @@ Constants .. data:: NONE .. data:: MAX_IMAGE_PIXELS - Set to 89,478,485, approximately 0.25gb for a 24 bit (3 bpp) image. + Set to 89,478,485, approximately 0.25GB for a 24-bit (3 bpp) image. See :py:meth:`~PIL.Image.open` for more information about how this is used. Transpose methods From 56a43a5fa77d5c508587ee7d06c59565ebbba5e1 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 21 Jul 2020 20:42:11 +1000 Subject: [PATCH 123/126] Fixed typo --- src/PIL/Image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 03829d9a9..cc1cd56a5 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2869,7 +2869,7 @@ def open(fp, mode="r"): :param fp: A filename (string), pathlib.Path object or a file object. The file object must implement ``file.read``, - ``file.seek`, and ``file.tell`` methods, + ``file.seek``, and ``file.tell`` methods, and be opened in binary mode. :param mode: The mode. If given, this argument must be "r". :returns: An :py:class:`~PIL.Image.Image` object. From 265bfef36e3081016f5efc7a9f5b037747571a14 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 21 Jul 2020 20:46:50 +1000 Subject: [PATCH 124/126] Improved documentation --- docs/reference/Image.rst | 10 +++++----- src/PIL/Image.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 738fd8c0e..57709ce8c 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -52,11 +52,11 @@ Functions .. warning:: To protect against potential DOS attacks caused by "`decompression bombs`_" (i.e. malicious files which decompress into a huge amount of data and are designed to crash or cause disruption by using up - a lot of memory), Pillow will issue a ``DecompressionBombWarning`` if the image is over a certain - limit. If desired, the warning can be turned into an error with - ``warnings.simplefilter('error', Image.DecompressionBombWarning)`` or suppressed entirely with - ``warnings.simplefilter('ignore', Image.DecompressionBombWarning)``. See also `the logging - documentation`_ to have warnings output to the logging facility instead of stderr. + a lot of memory), Pillow will issue a ``DecompressionBombWarning`` if the number of pixels in an + image is over a certain limit, :py:data:`PIL.Image.MAX_IMAGE_PIXELS`. If desired, the warning can be + turned into an error with ``warnings.simplefilter('error', Image.DecompressionBombWarning)`` or + suppressed entirely with ``warnings.simplefilter('ignore', Image.DecompressionBombWarning)``. See + also `the logging documentation`_ to have warnings output to the logging facility instead of stderr. .. _decompression bombs: https://en.wikipedia.org/wiki/Zip_bomb .. _the logging documentation: https://docs.python.org/3/library/logging.html#integration-with-the-warnings-module diff --git a/src/PIL/Image.py b/src/PIL/Image.py index cc1cd56a5..927147956 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -81,7 +81,7 @@ class DecompressionBombError(Exception): pass -# Limit to around a quarter gigabyte for a 24 bit (3 bpp) image +# Limit to around a quarter gigabyte for a 24-bit (3 bpp) image MAX_IMAGE_PIXELS = int(1024 * 1024 * 1024 // 4 // 3) From 5abf0eb4f3e40b00036e3e8759a456cd3686a02f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 21 Jul 2020 21:46:31 +1000 Subject: [PATCH 125/126] Include reference to DecompressionBombError --- docs/reference/Image.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index 57709ce8c..fbf61073d 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -57,6 +57,8 @@ Functions turned into an error with ``warnings.simplefilter('error', Image.DecompressionBombWarning)`` or suppressed entirely with ``warnings.simplefilter('ignore', Image.DecompressionBombWarning)``. See also `the logging documentation`_ to have warnings output to the logging facility instead of stderr. + If the number of pixels is greater than twice :py:data:`PIL.Image.MAX_IMAGE_PIXELS`, then a + ``DecompressionBombError`` will be raised instead. .. _decompression bombs: https://en.wikipedia.org/wiki/Zip_bomb .. _the logging documentation: https://docs.python.org/3/library/logging.html#integration-with-the-warnings-module From 7f829b60c9e30505c86bc5849ff1d39b1163a0f4 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Tue, 21 Jul 2020 23:01:51 +1000 Subject: [PATCH 126/126] MAX_IMAGE_PIXELS can be changed --- docs/reference/Image.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/reference/Image.rst b/docs/reference/Image.rst index fbf61073d..c656507d9 100644 --- a/docs/reference/Image.rst +++ b/docs/reference/Image.rst @@ -53,10 +53,16 @@ Functions To protect against potential DOS attacks caused by "`decompression bombs`_" (i.e. malicious files which decompress into a huge amount of data and are designed to crash or cause disruption by using up a lot of memory), Pillow will issue a ``DecompressionBombWarning`` if the number of pixels in an - image is over a certain limit, :py:data:`PIL.Image.MAX_IMAGE_PIXELS`. If desired, the warning can be - turned into an error with ``warnings.simplefilter('error', Image.DecompressionBombWarning)`` or - suppressed entirely with ``warnings.simplefilter('ignore', Image.DecompressionBombWarning)``. See - also `the logging documentation`_ to have warnings output to the logging facility instead of stderr. + image is over a certain limit, :py:data:`PIL.Image.MAX_IMAGE_PIXELS`. + + This threshold can be changed by setting :py:data:`PIL.Image.MAX_IMAGE_PIXELS`. It can be disabled + by setting ``Image.MAX_IMAGE_PIXELS = None``. + + If desired, the warning can be turned into an error with + ``warnings.simplefilter('error', Image.DecompressionBombWarning)`` or suppressed entirely with + ``warnings.simplefilter('ignore', Image.DecompressionBombWarning)``. See also + `the logging documentation`_ to have warnings output to the logging facility instead of stderr. + If the number of pixels is greater than twice :py:data:`PIL.Image.MAX_IMAGE_PIXELS`, then a ``DecompressionBombError`` will be raised instead.