Type annotations: Image.py.

This commit is contained in:
neiljp (Neil Pilgrim) 2017-08-16 23:01:27 -07:00 committed by Eric Soroos
parent bad730ecff
commit 97c2312c07

View File

@ -24,6 +24,25 @@
# See the README file for information on usage and redistribution. # See the README file for information on usage and redistribution.
# #
if False:
from typing import Any, Text, Optional, Tuple, List, Sequence, Union, Callable, Dict
# Type aliases; names subject to change
LURD = Tuple[int, int, int, int] # left, up(per), right, down = x0, y0, x1, y1
XY = Tuple[int, int]
Coord = XY
Size = XY # NOTE: All XY aliases will be interchangeable
Matrix4 = Tuple[float, float, float, float]
Matrix12 = Tuple[float, float, float, float, float, float, float, float, float, float, float, float]
# Just required for typing, or gradual module inclusion while adding annotation?
from io import BytesIO
import pathlib
import ImagingPalette
from ImageFilter import Filter
from ImageFile import PyDecoder
from ImageFile import PyEncoder
from . import VERSION, PILLOW_VERSION, _plugins from . import VERSION, PILLOW_VERSION, _plugins
import logging import logging
@ -138,6 +157,7 @@ except ImportError:
def isImageType(t): def isImageType(t):
# type: (object) -> bool
""" """
Checks if an object is an image object. Checks if an object is an image object.
@ -211,14 +231,14 @@ if hasattr(core, 'DEFAULT_STRATEGY'):
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Registries # Registries
ID = [] ID = [] # type: List[Text]
OPEN = {} OPEN = {} # type: Dict[Text, Tuple[Callable, Optional[Callable[..., bool]]]]
MIME = {} MIME = {}
SAVE = {} SAVE = {} # type: Dict[Text, Callable]
SAVE_ALL = {} SAVE_ALL = {} # type: Dict[Text, Callable]
EXTENSION = {} EXTENSION = {} # type: Dict[Text, Text]
DECODERS = {} DECODERS = {} # type: Dict[Text, Callable[..., PyDecoder]]
ENCODERS = {} ENCODERS = {} # type: Dict[Text, Callable[..., PyEncoder]]
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Modes supported by this version # Modes supported by this version
@ -284,6 +304,7 @@ _MODE_CONV = {
def _conv_type_shape(im): def _conv_type_shape(im):
# type: (Image) -> Tuple
typ, extra = _MODE_CONV[im.mode] typ, extra = _MODE_CONV[im.mode]
if extra is None: if extra is None:
return (im.size[1], im.size[0]), typ return (im.size[1], im.size[0]), typ
@ -299,6 +320,7 @@ _MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B")
def getmodebase(mode): def getmodebase(mode):
# type: (Text) -> Text
""" """
Gets the "base" mode for given mode. This function returns "L" for Gets the "base" mode for given mode. This function returns "L" for
images that contain grayscale data, and "RGB" for images that images that contain grayscale data, and "RGB" for images that
@ -312,6 +334,7 @@ def getmodebase(mode):
def getmodetype(mode): def getmodetype(mode):
# type: (Text) -> Text
""" """
Gets the storage type mode. Given a mode, this function returns a Gets the storage type mode. Given a mode, this function returns a
single-layer mode suitable for storing individual bands. single-layer mode suitable for storing individual bands.
@ -324,6 +347,7 @@ def getmodetype(mode):
def getmodebandnames(mode): def getmodebandnames(mode):
# type: (Text) -> Tuple
""" """
Gets a list of individual band names. Given a mode, this function returns Gets a list of individual band names. Given a mode, this function returns
a tuple containing the names of individual bands (use a tuple containing the names of individual bands (use
@ -339,6 +363,7 @@ def getmodebandnames(mode):
def getmodebands(mode): def getmodebands(mode):
# type: (Text) -> int
""" """
Gets the number of individual bands for this mode. Gets the number of individual bands for this mode.
@ -356,6 +381,7 @@ _initialized = 0
def preinit(): def preinit():
# type: () -> None
"Explicitly load standard file format drivers." "Explicitly load standard file format drivers."
global _initialized global _initialized
@ -391,6 +417,7 @@ def preinit():
def init(): def init():
# type: () -> int
""" """
Explicitly initializes the Python Imaging Library. This function Explicitly initializes the Python Imaging Library. This function
loads all available file format drivers. loads all available file format drivers.
@ -411,11 +438,14 @@ def init():
_initialized = 2 _initialized = 2
return 1 return 1
# FIXME: mypy suggests a default return may be necessary here?
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# Codec factories (used by tobytes/frombytes and ImageFile.load) # Codec factories (used by tobytes/frombytes and ImageFile.load)
def _getdecoder(mode, decoder_name, args, extra=()): def _getdecoder(mode, decoder_name, args, extra=()):
# type: (Text, Text, Optional[Tuple], Tuple) -> PyDecoder
# tweak arguments # tweak arguments
if args is None: if args is None:
@ -438,6 +468,7 @@ def _getdecoder(mode, decoder_name, args, extra=()):
def _getencoder(mode, encoder_name, args, extra=()): def _getencoder(mode, encoder_name, args, extra=()):
# type: (Text, Text, Optional[Tuple], Tuple) -> PyEncoder
# tweak arguments # tweak arguments
if args is None: if args is None:
@ -517,26 +548,30 @@ class Image(object):
_close_exclusive_fp_after_loading = True _close_exclusive_fp_after_loading = True
def __init__(self): def __init__(self):
# type: () -> None
# FIXME: take "new" parameters / other image? # FIXME: take "new" parameters / other image?
# FIXME: turn mode and size into delegating properties? # FIXME: turn mode and size into delegating properties?
self.im = None self.im = None
self.mode = "" self.mode = ""
self.size = (0, 0) self.size = (0, 0)
self.palette = None self.palette = None # type: Optional[ImagePalette.ImagePalette]
self.info = {} self.info = {} # type: Dict[Text, Any]
self.category = NORMAL self.category = NORMAL
self.readonly = 0 self.readonly = 0
self.pyaccess = None self.pyaccess = None
@property @property
def width(self): def width(self):
# type: () -> int
return self.size[0] return self.size[0]
@property @property
def height(self): def height(self):
# type: () -> int
return self.size[1] return self.size[1]
def _new(self, im): def _new(self, im):
# type: (Image) -> Image
new = Image() new = Image()
new.im = im new.im = im
new.mode = im.mode new.mode = im.mode
@ -552,12 +587,15 @@ class Image(object):
# Context Manager Support # Context Manager Support
def __enter__(self): def __enter__(self):
# type: () -> Image
return self return self
def __exit__(self, *args): def __exit__(self, *args):
# type: (*Any) -> None
self.close() self.close()
def close(self): def close(self):
# type: () -> None
""" """
Closes the file pointer, if possible. Closes the file pointer, if possible.
@ -584,12 +622,14 @@ class Image(object):
if sys.version_info >= (3, 4, 0): if sys.version_info >= (3, 4, 0):
def __del__(self): def __del__(self):
# type: () -> None
if (hasattr(self, 'fp') and hasattr(self, '_exclusive_fp') if (hasattr(self, 'fp') and hasattr(self, '_exclusive_fp')
and self.fp and self._exclusive_fp): and self.fp and self._exclusive_fp):
self.fp.close() self.fp.close()
self.fp = None self.fp = None
def _copy(self): def _copy(self):
# type: () -> None
self.load() self.load()
self.im = self.im.copy() self.im = self.im.copy()
self.pyaccess = None self.pyaccess = None
@ -602,6 +642,7 @@ class Image(object):
self.load() self.load()
def _dump(self, file=None, format=None, **options): def _dump(self, file=None, format=None, **options):
# type: (Optional[Text], Optional[Text], **Any) -> Text
import tempfile import tempfile
suffix = '' suffix = ''
@ -626,6 +667,7 @@ class Image(object):
return filename return filename
def __eq__(self, other): def __eq__(self, other):
# type: (Image) -> bool
return (isinstance(other, Image) and return (isinstance(other, Image) and
self.__class__.__name__ == other.__class__.__name__ and self.__class__.__name__ == other.__class__.__name__ and
self.mode == other.mode and self.mode == other.mode and
@ -637,10 +679,12 @@ class Image(object):
self.tobytes() == other.tobytes()) self.tobytes() == other.tobytes())
def __ne__(self, other): def __ne__(self, other):
# type: (Image) -> bool
eq = (self == other) eq = (self == other)
return not eq return not eq
def __repr__(self): def __repr__(self):
# type: () -> Text
return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % (
self.__class__.__module__, self.__class__.__name__, self.__class__.__module__, self.__class__.__name__,
self.mode, self.size[0], self.size[1], self.mode, self.size[0], self.size[1],
@ -648,6 +692,7 @@ class Image(object):
) )
def _repr_png_(self): def _repr_png_(self):
# type: () -> bytes
""" iPython display hook support """ iPython display hook support
:returns: png version of the image as bytes :returns: png version of the image as bytes
@ -659,6 +704,7 @@ class Image(object):
@property @property
def __array_interface__(self): def __array_interface__(self):
# type: () -> Dict[Text, Any]
# numpy array interface support # numpy array interface support
new = {} new = {}
shape, typestr = _conv_type_shape(self) shape, typestr = _conv_type_shape(self)
@ -674,6 +720,7 @@ class Image(object):
return new return new
def __getstate__(self): def __getstate__(self):
# type: () -> List
return [ return [
self.info, self.info,
self.mode, self.mode,
@ -682,6 +729,7 @@ class Image(object):
self.tobytes()] self.tobytes()]
def __setstate__(self, state): def __setstate__(self, state):
# type: (List) -> None
Image.__init__(self) Image.__init__(self)
self.tile = [] self.tile = []
info, mode, size, palette, data = state info, mode, size, palette, data = state
@ -694,6 +742,7 @@ class Image(object):
self.frombytes(data) self.frombytes(data)
def tobytes(self, encoder_name="raw", *args): def tobytes(self, encoder_name="raw", *args):
# type: (Text, *Text) -> bytes
""" """
Return image as a bytes object. Return image as a bytes object.
@ -737,10 +786,12 @@ class Image(object):
return b"".join(data) return b"".join(data)
def tostring(self, *args, **kw): def tostring(self, *args, **kw):
# type: (*Any, **Any) -> None
raise NotImplementedError("tostring() has been removed. " raise NotImplementedError("tostring() has been removed. "
"Please call tobytes() instead.") "Please call tobytes() instead.")
def tobitmap(self, name="image"): def tobitmap(self, name="image"):
# type: (Text) -> bytes
""" """
Returns the image converted to an X11 bitmap. Returns the image converted to an X11 bitmap.
@ -762,6 +813,7 @@ class Image(object):
]) ])
def frombytes(self, data, decoder_name="raw", *args): def frombytes(self, data, decoder_name="raw", *args):
# type: (Any, Text, *Any) -> None
""" """
Loads this image with pixel data from a bytes object. Loads this image with pixel data from a bytes object.
@ -788,10 +840,12 @@ class Image(object):
raise ValueError("cannot decode image data") raise ValueError("cannot decode image data")
def fromstring(self, *args, **kw): def fromstring(self, *args, **kw):
# type: (*Any, **Any) -> None
raise NotImplementedError("fromstring() has been removed. " raise NotImplementedError("fromstring() has been removed. "
"Please call frombytes() instead.") "Please call frombytes() instead.")
def load(self): def load(self):
# type: () -> Any
""" """
Allocates storage for the image and loads the pixel data. In Allocates storage for the image and loads the pixel data. In
normal cases, you don't need to call this method, since the normal cases, you don't need to call this method, since the
@ -826,6 +880,7 @@ class Image(object):
return self.im.pixel_access(self.readonly) return self.im.pixel_access(self.readonly)
def verify(self): def verify(self):
# type: () -> None
""" """
Verifies the contents of a file. For data read from a file, this Verifies the contents of a file. For data read from a file, this
method attempts to determine if the file is broken, without method attempts to determine if the file is broken, without
@ -838,6 +893,7 @@ class Image(object):
def convert(self, mode=None, matrix=None, dither=None, def convert(self, mode=None, matrix=None, dither=None,
palette=WEB, colors=256): palette=WEB, colors=256):
# type: (Optional[Text], Optional[Union[Matrix4, Matrix12]], Optional[int], Optional[int], int) -> Image
""" """
Returns a converted copy of this image. For the "P" mode, this Returns a converted copy of this image. For the "P" mode, this
method translates pixels through the palette. If mode is method translates pixels through the palette. If mode is
@ -1000,6 +1056,7 @@ class Image(object):
return new_im return new_im
def quantize(self, colors=256, method=None, kmeans=0, palette=None): def quantize(self, colors=256, method=None, kmeans=0, palette=None):
# type: (int, Optional[int], int, Optional[ImagingPalette]) -> Image
""" """
Convert the image to 'P' mode with the specified number Convert the image to 'P' mode with the specified number
of colors. of colors.
@ -1044,6 +1101,7 @@ class Image(object):
return self._new(self.im.quantize(colors, method, kmeans)) return self._new(self.im.quantize(colors, method, kmeans))
def copy(self): def copy(self):
# type: () -> Image
""" """
Copies this image. Use this method if you wish to paste things Copies this image. Use this method if you wish to paste things
into an image, but still retain the original. into an image, but still retain the original.
@ -1057,6 +1115,7 @@ class Image(object):
__copy__ = copy __copy__ = copy
def crop(self, box=None): def crop(self, box=None):
# type: (Optional[LURD]) -> Image
""" """
Returns a rectangular region from this image. The box is a Returns a rectangular region from this image. The box is a
4-tuple defining the left, upper, right, and lower pixel 4-tuple defining the left, upper, right, and lower pixel
@ -1076,6 +1135,7 @@ class Image(object):
return self._new(self._crop(self.im, box)) return self._new(self._crop(self.im, box))
def _crop(self, im, box): def _crop(self, im, box):
# type: (Image, LURD) -> Image
""" """
Returns a rectangular region from the core image object im. Returns a rectangular region from the core image object im.
@ -1099,6 +1159,8 @@ class Image(object):
return im.crop((x0, y0, x1, y1)) return im.crop((x0, y0, x1, y1))
def draft(self, mode, size): def draft(self, mode, size):
# type: (Any, Any) -> Any
# TODO unclear types
""" """
Configures the image file loader so it returns a version of the Configures the image file loader so it returns a version of the
image that as closely as possible matches the given mode and image that as closely as possible matches the given mode and
@ -1119,12 +1181,14 @@ class Image(object):
pass pass
def _expand(self, xmargin, ymargin=None): def _expand(self, xmargin, ymargin=None):
# type: (int, Optional[int]) -> Image
if ymargin is None: if ymargin is None:
ymargin = xmargin ymargin = xmargin
self.load() self.load()
return self._new(self.im.expand(xmargin, ymargin, 0)) return self._new(self.im.expand(xmargin, ymargin, 0))
def filter(self, filter): def filter(self, filter):
# type: (Filter) -> Image
""" """
Filters this image using the given filter. For a list of Filters this image using the given filter. For a list of
available filters, see the :py:mod:`~PIL.ImageFilter` module. available filters, see the :py:mod:`~PIL.ImageFilter` module.
@ -1152,6 +1216,7 @@ class Image(object):
return merge(self.mode, ims) return merge(self.mode, ims)
def getbands(self): def getbands(self):
# type: () -> Tuple[Any]
""" """
Returns a tuple containing the name of each band in this image. Returns a tuple containing the name of each band in this image.
For example, **getbands** on an RGB image returns ("R", "G", "B"). For example, **getbands** on an RGB image returns ("R", "G", "B").
@ -1162,6 +1227,7 @@ class Image(object):
return ImageMode.getmode(self.mode).bands return ImageMode.getmode(self.mode).bands
def getbbox(self): def getbbox(self):
# type: () -> Optional[LURD]
""" """
Calculates the bounding box of the non-zero regions in the Calculates the bounding box of the non-zero regions in the
image. image.
@ -1176,6 +1242,7 @@ class Image(object):
return self.im.getbbox() return self.im.getbbox()
def getcolors(self, maxcolors=256): def getcolors(self, maxcolors=256):
# type: (int) -> Optional[List[Tuple[int, int]]]
""" """
Returns a list of colors used in this image. Returns a list of colors used in this image.
@ -1198,6 +1265,7 @@ class Image(object):
return self.im.getcolors(maxcolors) return self.im.getcolors(maxcolors)
def getdata(self, band=None): def getdata(self, band=None):
# type: (Optional[int]) -> Sequence
""" """
Returns the contents of this image as a sequence object Returns the contents of this image as a sequence object
containing pixel values. The sequence object is flattened, so containing pixel values. The sequence object is flattened, so
@ -1221,6 +1289,7 @@ class Image(object):
return self.im # could be abused return self.im # could be abused
def getextrema(self): def getextrema(self):
# type: () -> Tuple
""" """
Gets the the minimum and maximum pixel values for each band in Gets the the minimum and maximum pixel values for each band in
the image. the image.
@ -1239,6 +1308,7 @@ class Image(object):
return self.im.getextrema() return self.im.getextrema()
def getim(self): def getim(self):
# type: () -> Any
""" """
Returns a capsule that points to the internal image memory. Returns a capsule that points to the internal image memory.
@ -1249,6 +1319,7 @@ class Image(object):
return self.im.ptr return self.im.ptr
def getpalette(self): def getpalette(self):
# type: () -> Optional[List[int]]
""" """
Returns the image palette as a list. Returns the image palette as a list.
@ -1266,6 +1337,7 @@ class Image(object):
return None # no palette return None # no palette
def getpixel(self, xy): def getpixel(self, xy):
# type: (Coord) -> Tuple[Any]
""" """
Returns the pixel value at a given position. Returns the pixel value at a given position.
@ -1280,6 +1352,7 @@ class Image(object):
return self.im.getpixel(xy) return self.im.getpixel(xy)
def getprojection(self): def getprojection(self):
# type: () -> Tuple[List[Any], List[Any]]
""" """
Get projection to x and y axes Get projection to x and y axes
@ -1292,6 +1365,7 @@ class Image(object):
return [i8(c) for c in x], [i8(c) for c in y] return [i8(c) for c in x], [i8(c) for c in y]
def histogram(self, mask=None, extrema=None): def histogram(self, mask=None, extrema=None):
# type: (Optional[Image], Optional[Any]) -> List[int]
""" """
Returns a histogram for the image. The histogram is returned as Returns a histogram for the image. The histogram is returned as
a list of pixel counts, one for each pixel value in the source a list of pixel counts, one for each pixel value in the source
@ -1321,10 +1395,12 @@ class Image(object):
return self.im.histogram() return self.im.histogram()
def offset(self, xoffset, yoffset=None): def offset(self, xoffset, yoffset=None):
# type: (Any, Any) -> Any
raise NotImplementedError("offset() has been removed. " raise NotImplementedError("offset() has been removed. "
"Please call ImageChops.offset() instead.") "Please call ImageChops.offset() instead.")
def paste(self, im, box=None, mask=None): def paste(self, im, box=None, mask=None):
# type: (Union[Image, int, Tuple, Text], Optional[Union[LURD, Coord]], Optional[Image]) -> None
""" """
Pastes another image into this image. The box argument is either Pastes another image into this image. The box argument is either
a 2-tuple giving the upper left corner, a 4-tuple defining the a 2-tuple giving the upper left corner, a 4-tuple defining the
@ -1406,6 +1482,7 @@ class Image(object):
self.im.paste(im, box) self.im.paste(im, box)
def alpha_composite(self, im, dest=(0,0), source=(0,0)): def alpha_composite(self, im, dest=(0,0), source=(0,0)):
# type: (Image, Coord, Union[Coord, LURD]) -> None
""" 'In-place' analog of Image.alpha_composite. Composites an image """ 'In-place' analog of Image.alpha_composite. Composites an image
onto this image. onto this image.
@ -1454,6 +1531,7 @@ class Image(object):
self.paste(result, box) self.paste(result, box)
def point(self, lut, mode=None): def point(self, lut, mode=None):
# type: (Union[List, Callable[[Any], Any]], Optional[Text]) -> Image
""" """
Maps this image through a lookup table or function. Maps this image through a lookup table or function.
@ -1493,6 +1571,7 @@ class Image(object):
return self._new(self.im.point(lut, mode)) return self._new(self.im.point(lut, mode))
def putalpha(self, alpha): def putalpha(self, alpha):
# type: (Union[Image, int, Tuple]) -> None
""" """
Adds or replaces the alpha layer in this image. If the image Adds or replaces the alpha layer in this image. If the image
does not have an alpha layer, it's converted to "LA" or "RGBA". does not have an alpha layer, it's converted to "LA" or "RGBA".
@ -1547,6 +1626,7 @@ class Image(object):
self.im.putband(alpha.im, band) self.im.putband(alpha.im, band)
def putdata(self, data, scale=1.0, offset=0.0): def putdata(self, data, scale=1.0, offset=0.0):
# type: (Sequence[Any], float, float) -> None
""" """
Copies pixel data to this image. This method copies data from a Copies pixel data to this image. This method copies data from a
sequence object into the image, starting at the upper left sequence object into the image, starting at the upper left
@ -1564,6 +1644,7 @@ class Image(object):
self.im.putdata(data, scale, offset) self.im.putdata(data, scale, offset)
def putpalette(self, data, rawmode="RGB"): def putpalette(self, data, rawmode="RGB"):
# type: (Sequence[Union[int, bytes]], Text) -> None
""" """
Attaches a palette to this image. The image must be a "P" or Attaches a palette to this image. The image must be a "P" or
"L" image, and the palette sequence must contain 768 integer "L" image, and the palette sequence must contain 768 integer
@ -1595,6 +1676,7 @@ class Image(object):
self.load() # install new palette self.load() # install new palette
def putpixel(self, xy, value): def putpixel(self, xy, value):
# type: (Coord, Union[int, Tuple]) -> Any
""" """
Modifies the pixel at the given position. The color is given as Modifies the pixel at the given position. The color is given as
a single numerical value for single-band images, and a tuple for a single numerical value for single-band images, and a tuple for
@ -1623,6 +1705,7 @@ class Image(object):
return self.im.putpixel(xy, value) return self.im.putpixel(xy, value)
def remap_palette(self, dest_map, source_palette=None): def remap_palette(self, dest_map, source_palette=None):
# type: (Sequence[int], Optional[bytes]) -> Image
""" """
Rewrites the image to reorder the palette. Rewrites the image to reorder the palette.
@ -1699,6 +1782,7 @@ class Image(object):
return m_im return m_im
def resize(self, size, resample=NEAREST, box=None): def resize(self, size, resample=NEAREST, box=None):
# type: (Size, int) -> Image
""" """
Returns a resized copy of this image. Returns a resized copy of this image.
@ -1748,6 +1832,7 @@ class Image(object):
def rotate(self, angle, resample=NEAREST, expand=0, center=None, def rotate(self, angle, resample=NEAREST, expand=0, center=None,
translate=None): translate=None):
# type: (float, int, bool, Optional[Coord], Optional[XY]) -> Image
""" """
Returns a rotated copy of this image. This method returns a Returns a rotated copy of this image. This method returns a
copy of this image, rotated the given number of degrees counter copy of this image, rotated the given number of degrees counter
@ -1822,6 +1907,7 @@ class Image(object):
] ]
def transform(x, y, matrix): def transform(x, y, matrix):
# type: (float, float, Sequence[float]) -> Tuple[float, float]
(a, b, c, d, e, f) = matrix (a, b, c, d, e, f) = matrix
return a*x + b*y + c, d*x + e*y + f return a*x + b*y + c, d*x + e*y + f
@ -1852,6 +1938,7 @@ class Image(object):
return self.transform((w, h), AFFINE, matrix, resample) return self.transform((w, h), AFFINE, matrix, resample)
def save(self, fp, format=None, **params): def save(self, fp, format=None, **params):
# type: (Union[Text, pathlib.Path, BytesIO], Optional[Text], **Any) -> None
""" """
Saves this image under the given filename. If no format is Saves this image under the given filename. If no format is
specified, the format to use is determined from the filename specified, the format to use is determined from the filename
@ -1934,6 +2021,7 @@ class Image(object):
fp.close() fp.close()
def seek(self, frame): def seek(self, frame):
# type: (int) -> None
""" """
Seeks to the given frame in this sequence file. If you seek Seeks to the given frame in this sequence file. If you seek
beyond the end of the sequence, the method raises an beyond the end of the sequence, the method raises an
@ -1955,6 +2043,7 @@ class Image(object):
raise EOFError raise EOFError
def show(self, title=None, command=None): def show(self, title=None, command=None):
# type: (Optional[Text], Optional[Text]) -> None
""" """
Displays this image. This method is mainly intended for Displays this image. This method is mainly intended for
debugging purposes. debugging purposes.
@ -1977,6 +2066,7 @@ class Image(object):
_show(self, title=title, command=command) _show(self, title=title, command=command)
def split(self): def split(self):
# type: () -> Tuple
""" """
Split this image into individual bands. This method returns a Split this image into individual bands. This method returns a
tuple of individual image bands from an image. For example, tuple of individual image bands from an image. For example,
@ -1998,6 +2088,7 @@ class Image(object):
return tuple(ims) return tuple(ims)
def getchannel(self, channel): def getchannel(self, channel):
# type: (Union[int, str]) -> Image
""" """
Returns an image containing a single channel of the source image. Returns an image containing a single channel of the source image.
@ -2020,6 +2111,7 @@ class Image(object):
return self._new(self.im.getband(channel)) return self._new(self.im.getband(channel))
def tell(self): def tell(self):
# type: () -> int
""" """
Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`. Returns the current frame number. See :py:meth:`~PIL.Image.Image.seek`.
@ -2028,6 +2120,7 @@ class Image(object):
return 0 return 0
def thumbnail(self, size, resample=BICUBIC): def thumbnail(self, size, resample=BICUBIC):
# type: (Size, int) -> None
""" """
Make this image into a thumbnail. This method modifies the Make this image into a thumbnail. This method modifies the
image to contain a thumbnail version of itself, no larger than image to contain a thumbnail version of itself, no larger than
@ -2078,6 +2171,7 @@ class Image(object):
# instead of bloating the method docs, add a separate chapter. # instead of bloating the method docs, add a separate chapter.
def transform(self, size, method, data=None, resample=NEAREST, def transform(self, size, method, data=None, resample=NEAREST,
fill=1, fillcolor=None): fill=1, fillcolor=None):
# type: (Size, int, Optional[Any], int, Any, Optional[Union[int, float, Tuple, Text]]) -> Image
""" """
Transforms this image. This method creates a new image with the Transforms this image. This method creates a new image with the
given size, and the same mode as the original, and copies data given size, and the same mode as the original, and copies data
@ -2135,6 +2229,7 @@ class Image(object):
def __transformer(self, box, image, method, data, def __transformer(self, box, image, method, data,
resample=NEAREST, fill=1): resample=NEAREST, fill=1):
# type: (LURD, Image, int, Any, int, Any) -> None
w = box[2] - box[0] w = box[2] - box[0]
h = box[3] - box[1] h = box[3] - box[1]
@ -2183,6 +2278,7 @@ class Image(object):
self.im.transform2(box, image.im, method, data, resample, fill) self.im.transform2(box, image.im, method, data, resample, fill)
def transpose(self, method): def transpose(self, method):
# type: (int) -> Image
""" """
Transpose image (flip or rotate in 90 degree steps) Transpose image (flip or rotate in 90 degree steps)
@ -2197,6 +2293,7 @@ class Image(object):
return self._new(self.im.transpose(method)) return self._new(self.im.transpose(method))
def effect_spread(self, distance): def effect_spread(self, distance):
# type: (int) -> Image
""" """
Randomly spread pixels in an image. Randomly spread pixels in an image.
@ -2206,6 +2303,7 @@ class Image(object):
return self._new(self.im.effect_spread(distance)) return self._new(self.im.effect_spread(distance))
def toqimage(self): def toqimage(self):
# type: () -> QImage
"""Returns a QImage copy of this image""" """Returns a QImage copy of this image"""
from . import ImageQt from . import ImageQt
if not ImageQt.qt_is_installed: if not ImageQt.qt_is_installed:
@ -2213,6 +2311,7 @@ class Image(object):
return ImageQt.toqimage(self) return ImageQt.toqimage(self)
def toqpixmap(self): def toqpixmap(self):
# type: () -> QPixmap
"""Returns a QPixmap copy of this image""" """Returns a QPixmap copy of this image"""
from . import ImageQt from . import ImageQt
if not ImageQt.qt_is_installed: if not ImageQt.qt_is_installed:
@ -2240,12 +2339,14 @@ class ImageTransformHandler(object):
# Debugging # Debugging
def _wedge(): def _wedge():
# type: () -> Image
"Create greyscale wedge (for debugging only)" "Create greyscale wedge (for debugging only)"
return Image()._new(core.wedge("L")) return Image()._new(core.wedge("L"))
def _check_size(size): def _check_size(size):
# type: (Size) -> bool
""" """
Common check to enforce type and sanity check on size tuples Common check to enforce type and sanity check on size tuples
@ -2264,6 +2365,7 @@ def _check_size(size):
def new(mode, size, color=0): def new(mode, size, color=0):
# type: (Text, Size, Optional[Union[int, float, Tuple, Text]]) -> Image
""" """
Creates a new image with the given mode and size. Creates a new image with the given mode and size.
@ -2295,6 +2397,7 @@ def new(mode, size, color=0):
def frombytes(mode, size, data, decoder_name="raw", *args): def frombytes(mode, size, data, decoder_name="raw", *args):
# type: (Text, Size, Sequence[bytes], Text, *Any) -> Image
""" """
Creates a copy of an image memory from pixel data in a buffer. Creates a copy of an image memory from pixel data in a buffer.
@ -2333,11 +2436,13 @@ def frombytes(mode, size, data, decoder_name="raw", *args):
def fromstring(*args, **kw): def fromstring(*args, **kw):
# type: (*Any, **Any) -> Any
raise NotImplementedError("fromstring() has been removed. " + raise NotImplementedError("fromstring() has been removed. " +
"Please call frombytes() instead.") "Please call frombytes() instead.")
def frombuffer(mode, size, data, decoder_name="raw", *args): def frombuffer(mode, size, data, decoder_name="raw", *args):
# type: (Text, Size, Sequence[bytes], Text, *Any) -> Image
""" """
Creates an image memory referencing pixel data in a byte buffer. Creates an image memory referencing pixel data in a byte buffer.
@ -2399,6 +2504,7 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
def fromarray(obj, mode=None): def fromarray(obj, mode=None):
# type: (object, Optional[Text]) -> Image
""" """
Creates an image memory from an object exporting the array interface Creates an image memory from an object exporting the array interface
(using the buffer protocol). (using the buffer protocol).
@ -2446,6 +2552,7 @@ def fromarray(obj, mode=None):
def fromqimage(im): def fromqimage(im):
# type: (QImage) -> Image
"""Creates an image instance from a QImage image""" """Creates an image instance from a QImage image"""
from . import ImageQt from . import ImageQt
if not ImageQt.qt_is_installed: if not ImageQt.qt_is_installed:
@ -2454,6 +2561,7 @@ def fromqimage(im):
def fromqpixmap(im): def fromqpixmap(im):
# type: (QPixmap) -> Image
"""Creates an image instance from a QPixmap image""" """Creates an image instance from a QPixmap image"""
from . import ImageQt from . import ImageQt
if not ImageQt.qt_is_installed: if not ImageQt.qt_is_installed:
@ -2490,6 +2598,7 @@ _fromarray_typemap[((1, 1), _ENDIAN + "f4")] = ("F", "F")
def _decompression_bomb_check(size): def _decompression_bomb_check(size):
# type: (Size) -> None
if MAX_IMAGE_PIXELS is None: if MAX_IMAGE_PIXELS is None:
return return
@ -2510,6 +2619,7 @@ def _decompression_bomb_check(size):
def open(fp, mode="r"): def open(fp, mode="r"):
# type: (Union[Text, pathlib.Path, BytesIO], Text) -> Image
""" """
Opens and identifies the given image file. Opens and identifies the given image file.
@ -2554,6 +2664,7 @@ def open(fp, mode="r"):
preinit() preinit()
def _open_core(fp, filename, prefix): def _open_core(fp, filename, prefix):
# # type: (Any, Text, Text): -> Optional[Image]
for i in ID: for i in ID:
try: try:
factory, accept = OPEN[i] factory, accept = OPEN[i]
@ -2589,6 +2700,7 @@ def open(fp, mode="r"):
def alpha_composite(im1, im2): def alpha_composite(im1, im2):
# type: (Image, Image) -> Image
""" """
Alpha composite im2 over im1. Alpha composite im2 over im1.
@ -2604,6 +2716,7 @@ def alpha_composite(im1, im2):
def blend(im1, im2, alpha): def blend(im1, im2, alpha):
# type: (Image, Image, float) -> Image
""" """
Creates a new image by interpolating between two input images, using Creates a new image by interpolating between two input images, using
a constant alpha.:: a constant alpha.::
@ -2627,6 +2740,7 @@ def blend(im1, im2, alpha):
def composite(image1, image2, mask): def composite(image1, image2, mask):
# type: (Image, Image, Image) -> Image
""" """
Create composite image by blending images using a transparency mask. Create composite image by blending images using a transparency mask.
@ -2644,6 +2758,7 @@ def composite(image1, image2, mask):
def eval(image, *args): def eval(image, *args):
# type: (Image, *Any) -> Image
""" """
Applies the function (which should take one argument) to each pixel Applies the function (which should take one argument) to each pixel
in the given image. If the image has more than one band, the same in the given image. If the image has more than one band, the same
@ -2660,6 +2775,7 @@ def eval(image, *args):
def merge(mode, bands): def merge(mode, bands):
# type: (Text, Sequence[Image]) -> Image
""" """
Merge a set of single band images into a new multiband image. Merge a set of single band images into a new multiband image.
@ -2687,6 +2803,7 @@ def merge(mode, bands):
# Plugin registry # Plugin registry
def register_open(id, factory, accept=None): def register_open(id, factory, accept=None):
# type: (Text, Callable, Optional[Callable[..., bool]]) -> None
""" """
Register an image file plugin. This function should not be used Register an image file plugin. This function should not be used
in application code. in application code.
@ -2702,6 +2819,7 @@ def register_open(id, factory, accept=None):
def register_mime(id, mimetype): def register_mime(id, mimetype):
# type: (Text, Text) -> None
""" """
Registers an image MIME type. This function should not be used Registers an image MIME type. This function should not be used
in application code. in application code.
@ -2713,6 +2831,7 @@ def register_mime(id, mimetype):
def register_save(id, driver): def register_save(id, driver):
# type: (Text, Callable) -> None
""" """
Registers an image save function. This function should not be Registers an image save function. This function should not be
used in application code. used in application code.
@ -2724,6 +2843,7 @@ def register_save(id, driver):
def register_save_all(id, driver): def register_save_all(id, driver):
# type: (Text, Callable) -> None
""" """
Registers an image function to save all the frames Registers an image function to save all the frames
of a multiframe format. This function should not be of a multiframe format. This function should not be
@ -2736,6 +2856,7 @@ def register_save_all(id, driver):
def register_extension(id, extension): def register_extension(id, extension):
# type: (Text, Text) -> None
""" """
Registers an image extension. This function should not be Registers an image extension. This function should not be
used in application code. used in application code.
@ -2757,6 +2878,7 @@ def register_extensions(id, extensions):
register_extension(id, extension) register_extension(id, extension)
def registered_extensions(): def registered_extensions():
# type: () -> Dict[Text, Text]
""" """
Returns a dictionary containing all file extensions belonging Returns a dictionary containing all file extensions belonging
to registered plugins to registered plugins
@ -2767,6 +2889,7 @@ def registered_extensions():
def register_decoder(name, decoder): def register_decoder(name, decoder):
# type: (Text, Callable[..., PyDecoder]) -> None
""" """
Registers an image decoder. This function should not be Registers an image decoder. This function should not be
used in application code. used in application code.
@ -2781,6 +2904,7 @@ def register_decoder(name, decoder):
def register_encoder(name, encoder): def register_encoder(name, encoder):
# type: (Text, Callable[..., PyEncoder]) -> None
""" """
Registers an image encoder. This function should not be Registers an image encoder. This function should not be
used in application code. used in application code.
@ -2811,6 +2935,7 @@ def _showxv(image, title=None, **options):
# Effects # Effects
def effect_mandelbrot(size, extent, quality): def effect_mandelbrot(size, extent, quality):
# type: (Size, LURD, int) -> Image
""" """
Generate a Mandelbrot set covering the given extent. Generate a Mandelbrot set covering the given extent.
@ -2824,6 +2949,7 @@ def effect_mandelbrot(size, extent, quality):
def effect_noise(size, sigma): def effect_noise(size, sigma):
# type: (Size, float) -> Image
""" """
Generate Gaussian noise centered around 128. Generate Gaussian noise centered around 128.
@ -2835,6 +2961,7 @@ def effect_noise(size, sigma):
def linear_gradient(mode): def linear_gradient(mode):
# type: (Text) -> Image
""" """
Generate 256x256 linear gradient from black to white, top to bottom. Generate 256x256 linear gradient from black to white, top to bottom.
@ -2844,6 +2971,7 @@ def linear_gradient(mode):
def radial_gradient(mode): def radial_gradient(mode):
# type: (Text) -> Image
""" """
Generate 256x256 radial gradient from black to white, centre to edge. Generate 256x256 radial gradient from black to white, centre to edge.