From 2f0d4308076d9c59662c563d9024382b3972e1cf Mon Sep 17 00:00:00 2001 From: Ram Rachum Date: Sun, 21 Jun 2020 13:13:35 +0300 Subject: [PATCH 01/26] 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 c4c1b51f459ba8804a7af13b142d7caea42725e0 Mon Sep 17 00:00:00 2001 From: Hugo Date: Mon, 22 Jun 2020 12:10:45 +0300 Subject: [PATCH 02/26] 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 03/26] 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 04/26] 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 bd466c41c141472f69318c46a7b3ed74d3f1b45d Mon Sep 17 00:00:00 2001 From: Hugo Date: Wed, 24 Jun 2020 10:11:16 +0300 Subject: [PATCH 05/26] 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 e4210eb8d776bdbe57a17bb4a256e64d4367dcc0 Mon Sep 17 00:00:00 2001 From: nulano Date: Mon, 22 Jun 2020 06:43:14 +0200 Subject: [PATCH 06/26] 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 07/26] 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 08/26] 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 09/26] 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 10/26] 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 11/26] 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 12/26] 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 13/26] 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 14/26] 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 1e8d418f4266ddd1a14e024f0997c76b8dc1ca9c Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 28 Jun 2020 17:24:27 +1000 Subject: [PATCH 15/26] 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 16/26] 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 17/26] 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 18/26] 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 19/26] 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 20/26] 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 21/26] 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 22/26] 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 23/26] 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 04e93769af531147d3575fc0ee299525aa133897 Mon Sep 17 00:00:00 2001 From: Luke Granger-Brown Date: Tue, 30 Jun 2020 16:34:10 +0100 Subject: [PATCH 24/26] 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 e7e02ae77dfc0dec02a6cdefe6af6618267e06e0 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 1 Jul 2020 21:11:36 +1000 Subject: [PATCH 25/26] 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 9432bba6d155920a7ec40ca20aedafc5eb31adf3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 2 Jul 2020 20:28:00 +1000 Subject: [PATCH 26/26] 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, - }