diff --git a/PIL/Image.py b/PIL/Image.py index 333397701..80b7258c6 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -30,6 +30,7 @@ from PIL import VERSION, PILLOW_VERSION, _plugins import warnings + class _imaging_not_installed: # module placeholder def __getattr__(self, id): @@ -52,7 +53,7 @@ try: # directly; import Image and use the Image.core variable instead. from PIL import _imaging as core if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None): - raise ImportError("The _imaging extension was built for another " + raise ImportError("The _imaging extension was built for another " " version of Pillow or PIL") except ImportError as v: @@ -91,22 +92,26 @@ except ImportError: builtins = __builtin__ from PIL import ImageMode -from PIL._binary import i8, o8 -from PIL._util import isPath, isStringType, deferred_error +from PIL._binary import i8 +from PIL._util import isPath +from PIL._util import isStringType +from PIL._util import deferred_error -import os, sys +import os +import sys # type stuff import collections import numbers # works everywhere, win for pypy, not cpython -USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info') +USE_CFFI_ACCESS = hasattr(sys, 'pypy_version_info') try: import cffi - HAS_CFFI=True + HAS_CFFI = True except: - HAS_CFFI=False + HAS_CFFI = False + def isImageType(t): """ @@ -148,16 +153,16 @@ MESH = 4 # resampling filters NONE = 0 NEAREST = 0 -ANTIALIAS = 1 # 3-lobed lanczos +ANTIALIAS = 1 # 3-lobed lanczos LINEAR = BILINEAR = 2 CUBIC = BICUBIC = 3 # dithers NONE = 0 NEAREST = 0 -ORDERED = 1 # Not yet implemented -RASTERIZE = 2 # Not yet implemented -FLOYDSTEINBERG = 3 # default +ORDERED = 1 # Not yet implemented +RASTERIZE = 2 # Not yet implemented +FLOYDSTEINBERG = 3 # default # palettes/quantizers WEB = 0 @@ -222,7 +227,7 @@ else: _MODE_CONV = { # official modes - "1": ('|b1', None), # broken + "1": ('|b1', None), # broken "L": ('|u1', None), "I": (_ENDIAN + 'i4', None), "F": (_ENDIAN + 'f4', None), @@ -232,8 +237,8 @@ _MODE_CONV = { "RGBA": ('|u1', 4), "CMYK": ('|u1', 4), "YCbCr": ('|u1', 3), - "LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1 - # I;16 == I;16L, and I;32 == I;32L + "LAB": ('|u1', 3), # UNDONE - unsigned |u1i1i1 + # I;16 == I;16L, and I;32 == I;32L "I;16": ('u2', None), "I;16L": (' 8bit images. + # a gamma function point transform on > 8bit images. scale, offset = _getscaleoffset(lut) return self._new(self.im.point_transform(scale, offset)) # for other modes, convert the function to a table @@ -1315,7 +1330,7 @@ class Image: # do things the hard way im = self.im.convert(mode) if im.mode not in ("LA", "RGBA"): - raise ValueError # sanity check + raise ValueError # sanity check self.im = im self.pyaccess = None self.mode = self.im.mode @@ -1393,7 +1408,7 @@ class Image: self.mode = "P" self.palette = palette self.palette.mode = "RGB" - self.load() # install new palette + self.load() # install new palette def putpixel(self, xy, value): """ @@ -1420,9 +1435,9 @@ class Image: self._copy() self.pyaccess = None self.load() - - if self.pyaccess: - return self.pyaccess.putpixel(xy,value) + + if self.pyaccess: + return self.pyaccess.putpixel(xy, value) return self.im.putpixel(xy, value) def resize(self, size, resample=NEAREST): @@ -1492,6 +1507,7 @@ class Image: math.cos(angle), math.sin(angle), 0.0, -math.sin(angle), math.cos(angle), 0.0 ] + def transform(x, y, matrix=matrix): (a, b, c, d, e, f) = matrix return a*x + b*y + c, d*x + e*y + f @@ -1579,13 +1595,13 @@ class Image: try: format = EXTENSION[ext] except KeyError: - raise KeyError(ext) # unknown extension + raise KeyError(ext) # unknown extension try: save_handler = SAVE[format.upper()] except KeyError: init() - save_handler = SAVE[format.upper()] # unknown format + save_handler = SAVE[format.upper()] # unknown format if isPath(fp): fp = builtins.open(fp, "wb") @@ -1667,7 +1683,7 @@ class Image: """ return 0 - def thumbnail(self, size, resample=NEAREST): + def thumbnail(self, size, resample=ANTIALIAS): """ Make this image into a thumbnail. This method modifies the image to contain a thumbnail version of itself, no larger than @@ -1682,26 +1698,27 @@ class Image: important than quality. Also note that this function modifies the :py:class:`~PIL.Image.Image` - object in place. If you need to use the full resolution image as well, apply - this method to a :py:meth:`~PIL.Image.Image.copy` of the original image. + object in place. If you need to use the full resolution image as well, + apply this method to a :py:meth:`~PIL.Image.Image.copy` of the original + 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.ANTIALIAS` (best quality). If omitted, it defaults to - :py:attr:`PIL.Image.NEAREST` (this will be changed to ANTIALIAS in a - future version). + :py:attr:`PIL.Image.ANTIALIAS`. :returns: None """ - # FIXME: the default resampling filter will be changed - # to ANTIALIAS in future versions - # preserve aspect ratio x, y = self.size - if x > size[0]: y = int(max(y * size[0] / x, 1)); x = int(size[0]) - if y > size[1]: x = int(max(x * size[1] / y, 1)); y = int(size[1]) + if x > size[0]: + y = int(max(y * size[0] / x, 1)) + x = int(size[0]) + if y > size[1]: + x = int(max(x * size[1] / y, 1)) + y = int(size[1]) size = x, y if size == self.size: @@ -1716,7 +1733,7 @@ class Image: except ValueError: if resample != ANTIALIAS: raise - im = self.resize(size, NEAREST) # fallback + im = self.resize(size, NEAREST) # fallback self.im = im.im self.mode = im.mode @@ -1752,7 +1769,9 @@ class Image: """ if self.mode == 'RGBA': - return self.convert('RGBa').transform(size, method, data, resample, fill).convert('RGBA') + return self.convert('RGBa') \ + .transform(size, method, data, resample, fill) \ + .convert('RGBA') if isinstance(method, ImageTransformHandler): return method.transform(size, self, resample=resample, fill=fill) @@ -1799,8 +1818,13 @@ class Image: elif method == QUAD: # quadrilateral warp. data specifies the four corners # given as NW, SW, SE, and NE. - nw = data[0:2]; sw = data[2:4]; se = data[4:6]; ne = data[6:8] - x0, y0 = nw; As = 1.0 / w; At = 1.0 / h + nw = data[0:2] + sw = data[2:4] + se = data[4:6] + ne = data[6:8] + x0, y0 = nw + As = 1.0 / w + At = 1.0 / h data = (x0, (ne[0]-x0)*As, (sw[0]-x0)*At, (se[0]-sw[0]-ne[0]+x0)*As*At, y0, (ne[1]-y0)*As, (sw[1]-y0)*At, @@ -1834,6 +1858,7 @@ class Image: im = self.im.transpose(method) return self._new(im) + # -------------------------------------------------------------------- # Lazy operations @@ -1869,6 +1894,7 @@ class _ImageCrop(Image): # FIXME: future versions should optimize crop/paste # sequences! + # -------------------------------------------------------------------- # Abstract handlers. @@ -1876,10 +1902,12 @@ class ImagePointHandler: # used as a mixin by point transforms (for use with im.point) pass + class ImageTransformHandler: # used as a mixin by geometry transforms (for use with im.transform) pass + # -------------------------------------------------------------------- # Factories @@ -1955,6 +1983,7 @@ def frombytes(mode, size, data, decoder_name="raw", *args): im.frombytes(data, decoder_name, args) return im + def fromstring(*args, **kw): """Deprecated alias to frombytes. @@ -2017,9 +2046,9 @@ def frombuffer(mode, size, data, decoder_name="raw", *args): " frombuffer(mode, size, data, 'raw', mode, 0, 1)", RuntimeWarning, stacklevel=2 ) - args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6 + args = mode, 0, -1 # may change to (mode, 0, 1) post-1.1.6 if args[0] in _MAPMODES: - im = new(mode, (1,1)) + im = new(mode, (1, 1)) im = im._new( core.map_buffer(data, size, decoder_name, None, 0, args) ) @@ -2139,8 +2168,8 @@ def open(fp, mode="r"): fp.seek(0) return factory(fp, filename) except (SyntaxError, IndexError, TypeError): - #import traceback - #traceback.print_exc() + # import traceback + # traceback.print_exc() pass if init(): @@ -2152,13 +2181,14 @@ def open(fp, mode="r"): fp.seek(0) return factory(fp, filename) except (SyntaxError, IndexError, TypeError): - #import traceback - #traceback.print_exc() + # import traceback + # traceback.print_exc() pass raise IOError("cannot identify image file %r" % (filename if filename else fp)) + # # Image processing. @@ -2257,6 +2287,7 @@ def merge(mode, bands): im.putband(bands[i].im, i) return bands[0]._new(im) + # -------------------------------------------------------------------- # Plugin registry @@ -2315,6 +2346,7 @@ def _show(image, **options): # override me, as necessary _showxv(image, **options) + def _showxv(image, title=None, **options): from PIL import ImageShow ImageShow.show(image, title, **options)