Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/PIL/Image.py
diff options
context:
space:
mode:
Diffstat (limited to 'PIL/Image.py')
-rw-r--r--PIL/Image.py2093
1 files changed, 0 insertions, 2093 deletions
diff --git a/PIL/Image.py b/PIL/Image.py
deleted file mode 100644
index 04ed316..0000000
--- a/PIL/Image.py
+++ /dev/null
@@ -1,2093 +0,0 @@
-#
-# The Python Imaging Library.
-# $Id: Image.py 2933 2006-12-03 12:08:22Z fredrik $
-#
-# the Image class wrapper
-#
-# partial release history:
-# 1995-09-09 fl Created
-# 1996-03-11 fl PIL release 0.0 (proof of concept)
-# 1996-04-30 fl PIL release 0.1b1
-# 1999-07-28 fl PIL release 1.0 final
-# 2000-06-07 fl PIL release 1.1
-# 2000-10-20 fl PIL release 1.1.1
-# 2001-05-07 fl PIL release 1.1.2
-# 2002-03-15 fl PIL release 1.1.3
-# 2003-05-10 fl PIL release 1.1.4
-# 2005-03-28 fl PIL release 1.1.5
-# 2006-12-02 fl PIL release 1.1.6
-#
-# Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved.
-# Copyright (c) 1995-2006 by Fredrik Lundh.
-#
-# See the README file for information on usage and redistribution.
-#
-
-VERSION = "1.1.6"
-
-try:
- import warnings
-except ImportError:
- warnings = None
-
-class _imaging_not_installed:
- # module placeholder
- def __getattr__(self, id):
- raise ImportError("The _imaging C module is not installed")
-
-try:
- # give Tk a chance to set up the environment, in case we're
- # using an _imaging module linked against libtcl/libtk (use
- # __import__ to hide this from naive packagers; we don't really
- # depend on Tk unless ImageTk is used, and that module already
- # imports Tkinter)
- __import__("FixTk")
-except ImportError:
- pass
-
-try:
- # If the _imaging C module is not present, you can still use
- # the "open" function to identify files, but you cannot load
- # them. Note that other modules should not refer to _imaging
- # directly; import Image and use the Image.core variable instead.
- import _imaging
- core = _imaging
- del _imaging
-except ImportError, v:
- core = _imaging_not_installed()
- if str(v)[:20] == "Module use of python" and warnings:
- # The _imaging C module is present, but not compiled for
- # the right version (windows only). Print a warning, if
- # possible.
- warnings.warn(
- "The _imaging extension was built for another version "
- "of Python; most PIL functions will be disabled",
- RuntimeWarning
- )
-
-import ImageMode
-import ImagePalette
-
-import os, string, sys
-
-# type stuff
-from types import IntType, StringType, TupleType
-
-try:
- UnicodeStringType = type(unicode(""))
- ##
- # (Internal) Checks if an object is a string. If the current
- # Python version supports Unicode, this checks for both 8-bit
- # and Unicode strings.
- def isStringType(t):
- return isinstance(t, StringType) or isinstance(t, UnicodeStringType)
-except NameError:
- def isStringType(t):
- return isinstance(t, StringType)
-
-##
-# (Internal) Checks if an object is a tuple.
-
-def isTupleType(t):
- return isinstance(t, TupleType)
-
-##
-# (Internal) Checks if an object is an image object.
-
-def isImageType(t):
- return hasattr(t, "im")
-
-##
-# (Internal) Checks if an object is a string, and that it points to a
-# directory.
-
-def isDirectory(f):
- return isStringType(f) and os.path.isdir(f)
-
-from operator import isNumberType, isSequenceType
-
-#
-# Debug level
-
-DEBUG = 0
-
-#
-# Constants (also defined in _imagingmodule.c!)
-
-NONE = 0
-
-# transpose
-FLIP_LEFT_RIGHT = 0
-FLIP_TOP_BOTTOM = 1
-ROTATE_90 = 2
-ROTATE_180 = 3
-ROTATE_270 = 4
-
-# transforms
-AFFINE = 0
-EXTENT = 1
-PERSPECTIVE = 2
-QUAD = 3
-MESH = 4
-
-# resampling filters
-NONE = 0
-NEAREST = 0
-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
-
-# palettes/quantizers
-WEB = 0
-ADAPTIVE = 1
-
-# categories
-NORMAL = 0
-SEQUENCE = 1
-CONTAINER = 2
-
-# --------------------------------------------------------------------
-# Registries
-
-ID = []
-OPEN = {}
-MIME = {}
-SAVE = {}
-EXTENSION = {}
-
-# --------------------------------------------------------------------
-# Modes supported by this version
-
-_MODEINFO = {
- # NOTE: this table will be removed in future versions. use
- # getmode* functions or ImageMode descriptors instead.
-
- # official modes
- "1": ("L", "L", ("1",)),
- "L": ("L", "L", ("L",)),
- "I": ("L", "I", ("I",)),
- "F": ("L", "F", ("F",)),
- "P": ("RGB", "L", ("P",)),
- "RGB": ("RGB", "L", ("R", "G", "B")),
- "RGBX": ("RGB", "L", ("R", "G", "B", "X")),
- "RGBA": ("RGB", "L", ("R", "G", "B", "A")),
- "CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
- "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
-
- # Experimental modes include I;16, I;16B, RGBa, BGR;15,
- # and BGR;24. Use these modes only if you know exactly
- # what you're doing...
-
-}
-
-if sys.byteorder == 'little':
- _ENDIAN = '<'
-else:
- _ENDIAN = '>'
-
-_MODE_CONV = {
- # official modes
- "1": ('|b1', None),
- "L": ('|u1', None),
- "I": ('%si4' % _ENDIAN, None), # FIXME: is this correct?
- "F": ('%sf4' % _ENDIAN, None), # FIXME: is this correct?
- "P": ('|u1', None),
- "RGB": ('|u1', 3),
- "RGBX": ('|u1', 4),
- "RGBA": ('|u1', 4),
- "CMYK": ('|u1', 4),
- "YCbCr": ('|u1', 4),
-}
-
-def _conv_type_shape(im):
- shape = im.size[::-1]
- typ, extra = _MODE_CONV[im.mode]
- if extra is None:
- return shape, typ
- else:
- return shape+(extra,), typ
-
-
-MODES = _MODEINFO.keys()
-MODES.sort()
-
-# raw modes that may be memory mapped. NOTE: if you change this, you
-# may have to modify the stride calculation in map.c too!
-_MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16B")
-
-##
-# Gets the "base" mode for given mode. This function returns "L" for
-# images that contain grayscale data, and "RGB" for images that
-# contain color data.
-#
-# @param mode Input mode.
-# @return "L" or "RGB".
-# @exception KeyError If the input mode was not a standard mode.
-
-def getmodebase(mode):
- return ImageMode.getmode(mode).basemode
-
-##
-# Gets the storage type mode. Given a mode, this function returns a
-# single-layer mode suitable for storing individual bands.
-#
-# @param mode Input mode.
-# @return "L", "I", or "F".
-# @exception KeyError If the input mode was not a standard mode.
-
-def getmodetype(mode):
- return ImageMode.getmode(mode).basetype
-
-##
-# Gets a list of individual band names. Given a mode, this function
-# returns a tuple containing the names of individual bands (use
-# {@link #getmodetype} to get the mode used to store each individual
-# band.
-#
-# @param mode Input mode.
-# @return A tuple containing band names. The length of the tuple
-# gives the number of bands in an image of the given mode.
-# @exception KeyError If the input mode was not a standard mode.
-
-def getmodebandnames(mode):
- return ImageMode.getmode(mode).bands
-
-##
-# Gets the number of individual bands for this mode.
-#
-# @param mode Input mode.
-# @return The number of bands in this mode.
-# @exception KeyError If the input mode was not a standard mode.
-
-def getmodebands(mode):
- return len(ImageMode.getmode(mode).bands)
-
-# --------------------------------------------------------------------
-# Helpers
-
-_initialized = 0
-
-##
-# Explicitly loads standard file format drivers.
-
-def preinit():
- "Load standard file format drivers."
-
- global _initialized
- if _initialized >= 1:
- return
-
- try:
- import BmpImagePlugin
- except ImportError:
- pass
- try:
- import GifImagePlugin
- except ImportError:
- pass
- try:
- import JpegImagePlugin
- except ImportError:
- pass
- try:
- import PpmImagePlugin
- except ImportError:
- pass
- try:
- import PngImagePlugin
- except ImportError:
- pass
-# try:
-# import TiffImagePlugin
-# except ImportError:
-# pass
-
- _initialized = 1
-
-##
-# Explicitly initializes the Python Imaging Library. This function
-# loads all available file format drivers.
-
-def init():
- "Load all file format drivers."
-
- global _initialized
- if _initialized >= 2:
- return
-
- visited = {}
-
- directories = sys.path
-
- try:
- directories = directories + [os.path.dirname(__file__)]
- except NameError:
- pass
-
- # only check directories (including current, if present in the path)
- for directory in filter(isDirectory, directories):
- fullpath = os.path.abspath(directory)
- if visited.has_key(fullpath):
- continue
- for file in os.listdir(directory):
- if file[-14:] == "ImagePlugin.py":
- f, e = os.path.splitext(file)
- try:
- sys.path.insert(0, directory)
- try:
- __import__(f, globals(), locals(), [])
- finally:
- del sys.path[0]
- except ImportError:
- if DEBUG:
- print "Image: failed to import",
- print f, ":", sys.exc_value
- visited[fullpath] = None
-
- if OPEN or SAVE:
- _initialized = 2
-
-
-# --------------------------------------------------------------------
-# Codec factories (used by tostring/fromstring and ImageFile.load)
-
-def _getdecoder(mode, decoder_name, args, extra=()):
-
- # tweak arguments
- if args is None:
- args = ()
- elif not isTupleType(args):
- args = (args,)
-
- try:
- # get decoder
- decoder = getattr(core, decoder_name + "_decoder")
- # print decoder, (mode,) + args + extra
- return apply(decoder, (mode,) + args + extra)
- except AttributeError:
- raise IOError("decoder %s not available" % decoder_name)
-
-def _getencoder(mode, encoder_name, args, extra=()):
-
- # tweak arguments
- if args is None:
- args = ()
- elif not isTupleType(args):
- args = (args,)
-
- try:
- # get encoder
- encoder = getattr(core, encoder_name + "_encoder")
- # print encoder, (mode,) + args + extra
- return apply(encoder, (mode,) + args + extra)
- except AttributeError:
- raise IOError("encoder %s not available" % encoder_name)
-
-
-# --------------------------------------------------------------------
-# Simple expression analyzer
-
-class _E:
- def __init__(self, data): self.data = data
- def __coerce__(self, other): return self, _E(other)
- def __add__(self, other): return _E((self.data, "__add__", other.data))
- def __mul__(self, other): return _E((self.data, "__mul__", other.data))
-
-def _getscaleoffset(expr):
- stub = ["stub"]
- data = expr(_E(stub)).data
- try:
- (a, b, c) = data # simplified syntax
- if (a is stub and b == "__mul__" and isNumberType(c)):
- return c, 0.0
- if (a is stub and b == "__add__" and isNumberType(c)):
- return 1.0, c
- except TypeError: pass
- try:
- ((a, b, c), d, e) = data # full syntax
- if (a is stub and b == "__mul__" and isNumberType(c) and
- d == "__add__" and isNumberType(e)):
- return c, e
- except TypeError: pass
- raise ValueError("illegal expression")
-
-
-# --------------------------------------------------------------------
-# Implementation wrapper
-
-##
-# This class represents an image object. To create Image objects, use
-# the appropriate factory functions. There's hardly ever any reason
-# to call the Image constructor directly.
-#
-# @see #open
-# @see #new
-# @see #fromstring
-
-class Image:
-
- format = None
- format_description = None
-
- def __init__(self):
- self.im = None
- self.mode = ""
- self.size = (0, 0)
- self.palette = None
- self.info = {}
- self.category = NORMAL
- self.readonly = 0
-
- def _new(self, im):
- new = Image()
- new.im = im
- new.mode = im.mode
- new.size = im.size
- new.palette = self.palette
- if im.mode == "P":
- new.palette = ImagePalette.ImagePalette()
- try:
- new.info = self.info.copy()
- except AttributeError:
- # fallback (pre-1.5.2)
- new.info = {}
- for k, v in self.info:
- new.info[k] = v
- return new
-
- _makeself = _new # compatibility
-
- def _copy(self):
- self.load()
- self.im = self.im.copy()
- self.readonly = 0
-
- def _dump(self, file=None, format=None):
- import tempfile
- if not file:
- file = tempfile.mktemp()
- self.load()
- if not format or format == "PPM":
- self.im.save_ppm(file)
- else:
- file = file + "." + format
- self.save(file, format)
- return file
-
- def __getattr__(self, name):
- if name == "__array_interface__":
- # numpy array interface support
- new = {}
- shape, typestr = _conv_type_shape(self)
- new['shape'] = shape
- new['typestr'] = typestr
- new['data'] = self.tostring()
- return new
- raise AttributeError(name)
-
- ##
- # Returns a string containing pixel data.
- #
- # @param encoder_name What encoder to use. The default is to
- # use the standard "raw" encoder.
- # @param *args Extra arguments to the encoder.
- # @return An 8-bit string.
-
- def tostring(self, encoder_name="raw", *args):
- "Return image as a binary string"
-
- # may pass tuple instead of argument list
- if len(args) == 1 and isTupleType(args[0]):
- args = args[0]
-
- if encoder_name == "raw" and args == ():
- args = self.mode
-
- self.load()
-
- # unpack data
- e = _getencoder(self.mode, encoder_name, args)
- e.setimage(self.im)
-
- bufsize = max(65536, self.size[0] * 4) # see RawEncode.c
-
- data = []
- while 1:
- l, s, d = e.encode(bufsize)
- data.append(d)
- if s:
- break
- if s < 0:
- raise RuntimeError("encoder error %d in tostring" % s)
-
- return string.join(data, "")
-
- ##
- # Returns the image converted to an X11 bitmap. This method
- # only works for mode "1" images.
- #
- # @param name The name prefix to use for the bitmap variables.
- # @return A string containing an X11 bitmap.
- # @exception ValueError If the mode is not "1"
-
- def tobitmap(self, name="image"):
- "Return image as an XBM bitmap"
-
- self.load()
- if self.mode != "1":
- raise ValueError("not a bitmap")
- data = self.tostring("xbm")
- return string.join(["#define %s_width %d\n" % (name, self.size[0]),
- "#define %s_height %d\n"% (name, self.size[1]),
- "static char %s_bits[] = {\n" % name, data, "};"], "")
-
- ##
- # Loads this image with pixel data from a string.
- # <p>
- # This method is similar to the {@link #fromstring} function, but
- # loads data into this image instead of creating a new image
- # object.
-
- def fromstring(self, data, decoder_name="raw", *args):
- "Load data to image from binary string"
-
- # may pass tuple instead of argument list
- if len(args) == 1 and isTupleType(args[0]):
- args = args[0]
-
- # default format
- if decoder_name == "raw" and args == ():
- args = self.mode
-
- # unpack data
- d = _getdecoder(self.mode, decoder_name, args)
- d.setimage(self.im)
- s = d.decode(data)
-
- if s[0] >= 0:
- raise ValueError("not enough image data")
- if s[1] != 0:
- raise ValueError("cannot decode image data")
-
- ##
- # Allocates storage for the image and loads the pixel data. In
- # normal cases, you don't need to call this method, since the
- # Image class automatically loads an opened image when it is
- # accessed for the first time.
- #
- # @return An image access object.
-
- def load(self):
- "Explicitly load pixel data."
- if self.im and self.palette and self.palette.dirty:
- # realize palette
- apply(self.im.putpalette, self.palette.getdata())
- self.palette.dirty = 0
- self.palette.mode = "RGB"
- self.palette.rawmode = None
- if self.info.has_key("transparency"):
- self.im.putpalettealpha(self.info["transparency"], 0)
- self.palette.mode = "RGBA"
- if self.im:
- return self.im.pixel_access(self.readonly)
-
- ##
- # Verifies the contents of a file. For data read from a file, this
- # method attempts to determine if the file is broken, without
- # actually decoding the image data. If this method finds any
- # problems, it raises suitable exceptions. If you need to load
- # the image after using this method, you must reopen the image
- # file.
-
- def verify(self):
- "Verify file contents."
- pass
-
-
- ##
- # Returns a converted copy of this image. For the "P" mode, this
- # method translates pixels through the palette. If mode is
- # omitted, a mode is chosen so that all information in the image
- # and the palette can be represented without a palette.
- # <p>
- # The current version supports all possible conversions between
- # "L", "RGB" and "CMYK."
- # <p>
- # When translating a colour image to black and white (mode "L"),
- # the library uses the ITU-R 601-2 luma transform:
- # <p>
- # <b>L = R * 299/1000 + G * 587/1000 + B * 114/1000</b>
- # <p>
- # When translating a greyscale image into a bilevel image (mode
- # "1"), all non-zero values are set to 255 (white). To use other
- # thresholds, use the {@link #Image.point} method.
- #
- # @def convert(mode, matrix=None)
- # @param mode The requested mode.
- # @param matrix An optional conversion matrix. If given, this
- # should be 4- or 16-tuple containing floating point values.
- # @return An Image object.
-
- def convert(self, mode=None, data=None, dither=None,
- palette=WEB, colors=256):
- "Convert to other pixel format"
-
- if not mode:
- # determine default mode
- if self.mode == "P":
- self.load()
- if self.palette:
- mode = self.palette.mode
- else:
- mode = "RGB"
- else:
- return self.copy()
-
- self.load()
-
- if data:
- # matrix conversion
- if mode not in ("L", "RGB"):
- raise ValueError("illegal conversion")
- im = self.im.convert_matrix(mode, data)
- return self._new(im)
-
- if mode == "P" and palette == ADAPTIVE:
- im = self.im.quantize(colors)
- return self._new(im)
-
- # colourspace conversion
- if dither is None:
- dither = FLOYDSTEINBERG
-
- try:
- im = self.im.convert(mode, dither)
- except ValueError:
- try:
- # normalize source image and try again
- im = self.im.convert(getmodebase(self.mode))
- im = im.convert(mode, dither)
- except KeyError:
- raise ValueError("illegal conversion")
-
- return self._new(im)
-
- def quantize(self, colors=256, method=0, kmeans=0, palette=None):
-
- # methods:
- # 0 = median cut
- # 1 = maximum coverage
-
- # NOTE: this functionality will be moved to the extended
- # quantizer interface in a later version of PIL.
-
- self.load()
-
- if palette:
- # use palette from reference image
- palette.load()
- if palette.mode != "P":
- raise ValueError("bad mode for palette image")
- if self.mode != "RGB" and self.mode != "L":
- raise ValueError(
- "only RGB or L mode images can be quantized to a palette"
- )
- im = self.im.convert("P", 1, palette.im)
- return self._makeself(im)
-
- im = self.im.quantize(colors, method, kmeans)
- return self._new(im)
-
- ##
- # Copies this image. Use this method if you wish to paste things
- # into an image, but still retain the original.
- #
- # @return An Image object.
-
- def copy(self):
- "Copy raster data"
-
- self.load()
- im = self.im.copy()
- return self._new(im)
-
- ##
- # Returns a rectangular region from this image. The box is a
- # 4-tuple defining the left, upper, right, and lower pixel
- # coordinate.
- # <p>
- # This is a lazy operation. Changes to the source image may or
- # may not be reflected in the cropped image. To break the
- # connection, call the {@link #Image.load} method on the cropped
- # copy.
- #
- # @param The crop rectangle, as a (left, upper, right, lower)-tuple.
- # @return An Image object.
-
- def crop(self, box=None):
- "Crop region from image"
-
- self.load()
- if box is None:
- return self.copy()
-
- # lazy operation
- return _ImageCrop(self, box)
-
- ##
- # Configures the image file loader so it returns a version of the
- # image that as closely as possible matches the given mode and
- # size. For example, you can use this method to convert a colour
- # JPEG to greyscale while loading it, or to extract a 128x192
- # version from a PCD file.
- # <p>
- # Note that this method modifies the Image object in place. If
- # the image has already been loaded, this method has no effect.
- #
- # @param mode The requested mode.
- # @param size The requested size.
-
- def draft(self, mode, size):
- "Configure image decoder"
-
- pass
-
- def _expand(self, xmargin, ymargin=None):
- if ymargin is None:
- ymargin = xmargin
- self.load()
- return self._new(self.im.expand(xmargin, ymargin, 0))
-
- ##
- # Filters this image using the given filter. For a list of
- # available filters, see the <b>ImageFilter</b> module.
- #
- # @param filter Filter kernel.
- # @return An Image object.
- # @see ImageFilter
-
- def filter(self, filter):
- "Apply environment filter to image"
-
- self.load()
-
- from ImageFilter import Filter
- if not isinstance(filter, Filter):
- filter = filter()
-
- if self.im.bands == 1:
- return self._new(filter.filter(self.im))
- # fix to handle multiband images since _imaging doesn't
- ims = []
- for c in range(self.im.bands):
- ims.append(self._new(filter.filter(self.im.getband(c))))
- return merge(self.mode, ims)
-
- ##
- # Returns a tuple containing the name of each band in this image.
- # For example, <b>getbands</b> on an RGB image returns ("R", "G", "B").
- #
- # @return A tuple containing band names.
-
- def getbands(self):
- "Get band names"
-
- return ImageMode.getmode(self.mode).bands
-
- ##
- # Calculates the bounding box of the non-zero regions in the
- # image.
- #
- # @return The bounding box is returned as a 4-tuple defining the
- # left, upper, right, and lower pixel coordinate. If the image
- # is completely empty, this method returns None.
-
- def getbbox(self):
- "Get bounding box of actual data (non-zero pixels) in image"
-
- self.load()
- return self.im.getbbox()
-
- ##
- # Returns a list of colors used in this image.
- #
- # @param maxcolors Maximum number of colors. If this number is
- # exceeded, this method returns None. The default limit is
- # 256 colors.
- # @return An unsorted list of (count, pixel) values.
-
- def getcolors(self, maxcolors=256):
- "Get colors from image, up to given limit"
-
- self.load()
- if self.mode in ("1", "L", "P"):
- h = self.im.histogram()
- out = []
- for i in range(256):
- if h[i]:
- out.append((h[i], i))
- if len(out) > maxcolors:
- return None
- return out
- return self.im.getcolors(maxcolors)
-
- ##
- # Returns the contents of this image as a sequence object
- # containing pixel values. The sequence object is flattened, so
- # that values for line one follow directly after the values of
- # line zero, and so on.
- # <p>
- # Note that the sequence object returned by this method is an
- # internal PIL data type, which only supports certain sequence
- # operations. To convert it to an ordinary sequence (e.g. for
- # printing), use <b>list(im.getdata())</b>.
- #
- # @param band What band to return. The default is to return
- # all bands. To return a single band, pass in the index
- # value (e.g. 0 to get the "R" band from an "RGB" image).
- # @return A sequence-like object.
-
- def getdata(self, band = None):
- "Get image data as sequence object."
-
- self.load()
- if band is not None:
- return self.im.getband(band)
- return self.im # could be abused
-
- ##
- # Gets the the minimum and maximum pixel values for each band in
- # the image.
- #
- # @return For a single-band image, a 2-tuple containing the
- # minimum and maximum pixel value. For a multi-band image,
- # a tuple containing one 2-tuple for each band.
-
- def getextrema(self):
- "Get min/max value"
-
- self.load()
- if self.im.bands > 1:
- extrema = []
- for i in range(self.im.bands):
- extrema.append(self.im.getband(i).getextrema())
- return tuple(extrema)
- return self.im.getextrema()
-
- ##
- # Returns a PyCObject that points to the internal image memory.
- #
- # @return A PyCObject object.
-
- def getim(self):
- "Get PyCObject pointer to internal image memory"
-
- self.load()
- return self.im.ptr
-
-
- ##
- # Returns the image palette as a list.
- #
- # @return A list of color values [r, g, b, ...], or None if the
- # image has no palette.
-
- def getpalette(self):
- "Get palette contents."
-
- self.load()
- try:
- return map(ord, self.im.getpalette())
- except ValueError:
- return None # no palette
-
-
- ##
- # Returns the pixel value at a given position.
- #
- # @param xy The coordinate, given as (x, y).
- # @return The pixel value. If the image is a multi-layer image,
- # this method returns a tuple.
-
- def getpixel(self, xy):
- "Get pixel value"
-
- self.load()
- return self.im.getpixel(xy)
-
- ##
- # Returns the horizontal and vertical projection.
- #
- # @return Two sequences, indicating where there are non-zero
- # pixels along the X-axis and the Y-axis, respectively.
-
- def getprojection(self):
- "Get projection to x and y axes"
-
- self.load()
- x, y = self.im.getprojection()
- return map(ord, x), map(ord, y)
-
- ##
- # Returns a histogram for the image. The histogram is returned as
- # a list of pixel counts, one for each pixel value in the source
- # image. If the image has more than one band, the histograms for
- # all bands are concatenated (for example, the histogram for an
- # "RGB" image contains 768 values).
- # <p>
- # A bilevel image (mode "1") is treated as a greyscale ("L") image
- # by this method.
- # <p>
- # If a mask is provided, the method returns a histogram for those
- # parts of the image where the mask image is non-zero. The mask
- # image must have the same size as the image, and be either a
- # bi-level image (mode "1") or a greyscale image ("L").
- #
- # @def histogram(mask=None)
- # @param mask An optional mask.
- # @return A list containing pixel counts.
-
- def histogram(self, mask=None, extrema=None):
- "Take histogram of image"
-
- self.load()
- if mask:
- mask.load()
- return self.im.histogram((0, 0), mask.im)
- if self.mode in ("I", "F"):
- if extrema is None:
- extrema = self.getextrema()
- return self.im.histogram(extrema)
- return self.im.histogram()
-
- ##
- # (Deprecated) Returns a copy of the image where the data has been
- # offset by the given distances. Data wraps around the edges. If
- # yoffset is omitted, it is assumed to be equal to xoffset.
- # <p>
- # This method is deprecated. New code should use the <b>offset</b>
- # function in the <b>ImageChops</b> module.
- #
- # @param xoffset The horizontal distance.
- # @param yoffset The vertical distance. If omitted, both
- # distances are set to the same value.
- # @return An Image object.
-
- def offset(self, xoffset, yoffset=None):
- "(deprecated) Offset image in horizontal and/or vertical direction"
- if warnings:
- warnings.warn(
- "'offset' is deprecated; use 'ImageChops.offset' instead",
- DeprecationWarning, stacklevel=2
- )
- import ImageChops
- return ImageChops.offset(self, xoffset, yoffset)
-
- ##
- # Pastes another image into this image. The box argument is either
- # a 2-tuple giving the upper left corner, a 4-tuple defining the
- # left, upper, right, and lower pixel coordinate, or None (same as
- # (0, 0)). If a 4-tuple is given, the size of the pasted image
- # must match the size of the region.
- # <p>
- # If the modes don't match, the pasted image is converted to the
- # mode of this image (see the {@link #Image.convert} method for
- # details).
- # <p>
- # Instead of an image, the source can be a integer or tuple
- # containing pixel values. The method then fills the region
- # with the given colour. When creating RGB images, you can
- # also use colour strings as supported by the ImageColor module.
- # <p>
- # If a mask is given, this method updates only the regions
- # indicated by the mask. You can use either "1", "L" or "RGBA"
- # images (in the latter case, the alpha band is used as mask).
- # Where the mask is 255, the given image is copied as is. Where
- # the mask is 0, the current value is preserved. Intermediate
- # values can be used for transparency effects.
- # <p>
- # Note that if you paste an "RGBA" image, the alpha band is
- # ignored. You can work around this by using the same image as
- # both source image and mask.
- #
- # @param im Source image or pixel value (integer or tuple).
- # @param box An optional 4-tuple giving the region to paste into.
- # If a 2-tuple is used instead, it's treated as the upper left
- # corner. If omitted or None, the source is pasted into the
- # upper left corner.
- # <p>
- # If an image is given as the second argument and there is no
- # third, the box defaults to (0, 0), and the second argument
- # is interpreted as a mask image.
- # @param mask An optional mask image.
- # @return An Image object.
-
- def paste(self, im, box=None, mask=None):
- "Paste other image into region"
-
- if isImageType(box) and mask is None:
- # abbreviated paste(im, mask) syntax
- mask = box; box = None
-
- if box is None:
- # cover all of self
- box = (0, 0) + self.size
-
- if len(box) == 2:
- # lower left corner given; get size from image or mask
- if isImageType(im):
- size = im.size
- elif isImageType(mask):
- size = mask.size
- else:
- # FIXME: use self.size here?
- raise ValueError(
- "cannot determine region size; use 4-item box"
- )
- box = box + (box[0]+size[0], box[1]+size[1])
-
- if isStringType(im):
- import ImageColor
- im = ImageColor.getcolor(im, self.mode)
-
- elif isImageType(im):
- im.load()
- if self.mode != im.mode:
- if self.mode != "RGB" or im.mode not in ("RGBA", "RGBa"):
- # should use an adapter for this!
- im = im.convert(self.mode)
- im = im.im
-
- self.load()
- if self.readonly:
- self._copy()
-
- if mask:
- mask.load()
- self.im.paste(im, box, mask.im)
- else:
- self.im.paste(im, box)
-
- ##
- # Maps this image through a lookup table or function.
- #
- # @param lut A lookup table, containing 256 values per band in the
- # image. A function can be used instead, it should take a single
- # argument. The function is called once for each possible pixel
- # value, and the resulting table is applied to all bands of the
- # image.
- # @param mode Output mode (default is same as input). In the
- # current version, this can only be used if the source image
- # has mode "L" or "P", and the output has mode "1".
- # @return An Image object.
-
- def point(self, lut, mode=None):
- "Map image through lookup table"
-
- self.load()
-
- if not isSequenceType(lut):
- # if it isn't a list, it should be a function
- if self.mode in ("I", "I;16", "F"):
- # check if the function can be used with point_transform
- scale, offset = _getscaleoffset(lut)
- return self._new(self.im.point_transform(scale, offset))
- # for other modes, convert the function to a table
- lut = map(lut, range(256)) * self.im.bands
-
- if self.mode == "F":
- # FIXME: _imaging returns a confusing error message for this case
- raise ValueError("point operation not supported for this mode")
-
- return self._new(self.im.point(lut, mode))
-
- ##
- # 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".
- # The new layer must be either "L" or "1".
- #
- # @param im The new alpha layer. This can either be an "L" or "1"
- # image having the same size as this image, or an integer or
- # other color value.
-
- def putalpha(self, alpha):
- "Set alpha layer"
-
- self.load()
- if self.readonly:
- self._copy()
-
- if self.mode not in ("LA", "RGBA"):
- # attempt to promote self to a matching alpha mode
- try:
- mode = getmodebase(self.mode) + "A"
- try:
- self.im.setmode(mode)
- except (AttributeError, ValueError):
- # do things the hard way
- im = self.im.convert(mode)
- if im.mode not in ("LA", "RGBA"):
- raise ValueError # sanity check
- self.im = im
- self.mode = self.im.mode
- except (KeyError, ValueError):
- raise ValueError("illegal image mode")
-
- if self.mode == "LA":
- band = 1
- else:
- band = 3
-
- if isImageType(alpha):
- # alpha layer
- if alpha.mode not in ("1", "L"):
- raise ValueError("illegal image mode")
- alpha.load()
- if alpha.mode == "1":
- alpha = alpha.convert("L")
- else:
- # constant alpha
- try:
- self.im.fillband(band, alpha)
- except (AttributeError, ValueError):
- # do things the hard way
- alpha = new("L", self.size, alpha)
- else:
- return
-
- self.im.putband(alpha.im, band)
-
- ##
- # Copies pixel data to this image. This method copies data from a
- # sequence object into the image, starting at the upper left
- # corner (0, 0), and continuing until either the image or the
- # sequence ends. The scale and offset values are used to adjust
- # the sequence values: <b>pixel = value*scale + offset</b>.
- #
- # @param data A sequence object.
- # @param scale An optional scale value. The default is 1.0.
- # @param offset An optional offset value. The default is 0.0.
-
- def putdata(self, data, scale=1.0, offset=0.0):
- "Put data from a sequence object into an image."
-
- self.load()
- if self.readonly:
- self._copy()
-
- self.im.putdata(data, scale, offset)
-
- ##
- # Attaches a palette to this image. The image must be a "P" or
- # "L" image, and the palette sequence must contain 768 integer
- # values, where each group of three values represent the red,
- # green, and blue values for the corresponding pixel
- # index. Instead of an integer sequence, you can use an 8-bit
- # string.
- #
- # @def putpalette(data)
- # @param data A palette sequence (either a list or a string).
-
- def putpalette(self, data, rawmode="RGB"):
- "Put palette data into an image."
-
- self.load()
- if self.mode not in ("L", "P"):
- raise ValueError("illegal image mode")
- if not isStringType(data):
- data = string.join(map(chr, data), "")
- self.mode = "P"
- self.palette = ImagePalette.raw(rawmode, data)
- self.palette.mode = "RGB"
- self.load() # install new palette
-
- ##
- # Modifies the pixel at the given position. The colour is given as
- # a single numerical value for single-band images, and a tuple for
- # multi-band images.
- # <p>
- # Note that this method is relatively slow. For more extensive
- # changes, use {@link #Image.paste} or the <b>ImageDraw</b> module
- # instead.
- #
- # @param xy The pixel coordinate, given as (x, y).
- # @param value The pixel value.
- # @see #Image.paste
- # @see #Image.putdata
- # @see ImageDraw
-
- def putpixel(self, xy, value):
- "Set pixel value"
-
- self.load()
- if self.readonly:
- self._copy()
-
- return self.im.putpixel(xy, value)
-
- ##
- # Returns a resized copy of this image.
- #
- # @def resize(size, filter=NEAREST)
- # @param size The requested size in pixels, as a 2-tuple:
- # (width, height).
- # @param filter An optional resampling filter. This can be
- # one of <b>NEAREST</b> (use nearest neighbour), <b>BILINEAR</b>
- # (linear interpolation in a 2x2 environment), <b>BICUBIC</b>
- # (cubic spline interpolation in a 4x4 environment), or
- # <b>ANTIALIAS</b> (a high-quality downsampling filter).
- # If omitted, or if the image has mode "1" or "P", it is
- # set <b>NEAREST</b>.
- # @return An Image object.
-
- def resize(self, size, resample=NEAREST):
- "Resize image"
-
- if resample not in (NEAREST, BILINEAR, BICUBIC, ANTIALIAS):
- raise ValueError("unknown resampling filter")
-
- self.load()
-
- if self.mode in ("1", "P"):
- resample = NEAREST
-
- if resample == ANTIALIAS:
- # requires stretch support (imToolkit & PIL 1.1.3)
- try:
- im = self.im.stretch(size, resample)
- except AttributeError:
- raise ValueError("unsupported resampling filter")
- else:
- im = self.im.resize(size, resample)
-
- return self._new(im)
-
- ##
- # Returns a rotated copy of this image. This method returns a
- # copy of this image, rotated the given number of degrees counter
- # clockwise around its centre.
- #
- # @def rotate(angle, filter=NEAREST)
- # @param angle In degrees counter clockwise.
- # @param filter An optional resampling filter. This can be
- # one of <b>NEAREST</b> (use nearest neighbour), <b>BILINEAR</b>
- # (linear interpolation in a 2x2 environment), or <b>BICUBIC</b>
- # (cubic spline interpolation in a 4x4 environment).
- # If omitted, or if the image has mode "1" or "P", it is
- # set <b>NEAREST</b>.
- # @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
- # input image.
- # @return An Image object.
-
- def rotate(self, angle, resample=NEAREST, expand=0):
- "Rotate image. Angle given as degrees counter-clockwise."
-
- if expand:
- import math
- angle = -angle * math.pi / 180
- matrix = [
- math.cos(angle), math.sin(angle), 0.0,
- -math.sin(angle), math.cos(angle), 0.0
- ]
- def transform(x, y, (a, b, c, d, e, f)=matrix):
- return a*x + b*y + c, d*x + e*y + f
-
- # calculate output size
- w, h = self.size
- xx = []
- yy = []
- for x, y in ((0, 0), (w, 0), (w, h), (0, h)):
- x, y = transform(x, y)
- xx.append(x)
- yy.append(y)
- w = int(math.ceil(max(xx)) - math.floor(min(xx)))
- h = int(math.ceil(max(yy)) - math.floor(min(yy)))
-
- # adjust center
- x, y = transform(w / 2.0, h / 2.0)
- matrix[2] = self.size[0] / 2.0 - x
- matrix[5] = self.size[1] / 2.0 - y
-
- return self.transform((w, h), AFFINE, matrix)
-
- if resample not in (NEAREST, BILINEAR, BICUBIC):
- raise ValueError("unknown resampling filter")
-
- self.load()
-
- if self.mode in ("1", "P"):
- resample = NEAREST
-
- return self._new(self.im.rotate(angle, resample))
-
- ##
- # Saves this image under the given filename. If no format is
- # specified, the format to use is determined from the filename
- # extension, if possible.
- # <p>
- # Keyword options can be used to provide additional instructions
- # to the writer. If a writer doesn't recognise an option, it is
- # silently ignored. The available options are described later in
- # this handbook.
- # <p>
- # You can use a file object instead of a filename. In this case,
- # you must always specify the format. The file object must
- # implement the <b>seek</b>, <b>tell</b>, and <b>write</b>
- # methods, and be opened in binary mode.
- #
- # @def save(file, format=None, **options)
- # @param file File name or file object.
- # @param format Optional format override. If omitted, the
- # format to use is determined from the filename extension.
- # If a file object was used instead of a filename, this
- # parameter should always be used.
- # @param **options Extra parameters to the image writer.
- # @return None
- # @exception KeyError If the output format could not be determined
- # from the file name. Use the format option to solve this.
- # @exception IOError If the file could not be written. The file
- # may have been created, and may contain partial data.
-
- def save(self, fp, format=None, **params):
- "Save image to file or stream"
-
- if isStringType(fp):
- filename = fp
- else:
- if hasattr(fp, "name") and isStringType(fp.name):
- filename = fp.name
- else:
- filename = ""
-
- # may mutate self!
- self.load()
-
- self.encoderinfo = params
- self.encoderconfig = ()
-
- preinit()
-
- ext = string.lower(os.path.splitext(filename)[1])
-
- if not format:
- try:
- format = EXTENSION[ext]
- except KeyError:
- init()
- try:
- format = EXTENSION[ext]
- except KeyError:
- raise KeyError(ext) # unknown extension
-
- try:
- save_handler = SAVE[string.upper(format)]
- except KeyError:
- init()
- save_handler = SAVE[string.upper(format)] # unknown format
-
- if isStringType(fp):
- import __builtin__
- fp = __builtin__.open(fp, "wb")
- close = 1
- else:
- close = 0
-
- try:
- save_handler(self, fp, filename)
- finally:
- # do what we can to clean up
- if close:
- fp.close()
-
- ##
- # Seeks to the given frame in this sequence file. If you seek
- # beyond the end of the sequence, the method raises an
- # <b>EOFError</b> exception. When a sequence file is opened, the
- # library automatically seeks to frame 0.
- # <p>
- # Note that in the current version of the library, most sequence
- # formats only allows you to seek to the next frame.
- #
- # @param frame Frame number, starting at 0.
- # @exception EOFError If the call attempts to seek beyond the end
- # of the sequence.
- # @see #Image.tell
-
- def seek(self, frame):
- "Seek to given frame in sequence file"
-
- # overridden by file handlers
- if frame != 0:
- raise EOFError
-
- ##
- # Displays this image. This method is mainly intended for
- # debugging purposes.
- # <p>
- # On Unix platforms, this method saves the image to a temporary
- # PPM file, and calls the <b>xv</b> utility.
- # <p>
- # On Windows, it saves the image to a temporary BMP file, and uses
- # the standard BMP display utility to show it (usually Paint).
- #
- # @def show(title=None)
- # @param title Optional title to use for the image window,
- # where possible.
-
- def show(self, title=None, command=None):
- "Display image (for debug purposes only)"
-
- _showxv(self, title, command)
-
- ##
- # Split this image into individual bands. This method returns a
- # tuple of individual image bands from an image. For example,
- # splitting an "RGB" image creates three new images each
- # containing a copy of one of the original bands (red, green,
- # blue).
- #
- # @return A tuple containing bands.
-
- def split(self):
- "Split image into bands"
-
- ims = []
- self.load()
- for i in range(self.im.bands):
- ims.append(self._new(self.im.getband(i)))
- return tuple(ims)
-
- ##
- # Returns the current frame number.
- #
- # @return Frame number, starting with 0.
- # @see #Image.seek
-
- def tell(self):
- "Return current frame number"
-
- return 0
-
- ##
- # Make this image into a thumbnail. This method modifies the
- # image to contain a thumbnail version of itself, no larger than
- # the given size. This method calculates an appropriate thumbnail
- # size to preserve the aspect of the image, calls the {@link
- # #Image.draft} method to configure the file reader (where
- # applicable), and finally resizes the image.
- # <p>
- # Note that the bilinear and bicubic filters in the current
- # version of PIL are not well-suited for thumbnail generation.
- # You should use <b>ANTIALIAS</b> unless speed is much more
- # important than quality.
- # <p>
- # Also note that this function modifies the Image object in place.
- # If you need to use the full resolution image as well, apply this
- # method to a {@link #Image.copy} of the original image.
- #
- # @param size Requested size.
- # @param resample Optional resampling filter. This can be one
- # of <b>NEAREST</b>, <b>BILINEAR</b>, <b>BICUBIC</b>, or
- # <b>ANTIALIAS</b> (best quality). If omitted, it defaults
- # to <b>NEAREST</b> (this will be changed to ANTIALIAS in a
- # future version).
- # @return None
-
- def thumbnail(self, size, resample=NEAREST):
- "Create thumbnail representation (modifies image in place)"
-
- # 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 = max(y * size[0] / x, 1); x = size[0]
- if y > size[1]: x = max(x * size[1] / y, 1); y = size[1]
- size = x, y
-
- if size == self.size:
- return
-
- self.draft(None, size)
-
- self.load()
-
- try:
- im = self.resize(size, resample)
- except ValueError:
- if resample != ANTIALIAS:
- raise
- im = self.resize(size, NEAREST) # fallback
-
- self.im = im.im
- self.mode = im.mode
- self.size = size
-
- self.readonly = 0
-
- # FIXME: the different tranform methods need further explanation
- # instead of bloating the method docs, add a separate chapter.
-
- ##
- # Transforms this image. This method creates a new image with the
- # given size, and the same mode as the original, and copies data
- # to the new image using the given transform.
- # <p>
- # @def transform(size, method, data, resample=NEAREST)
- # @param size The output size.
- # @param method The transformation method. This is one of
- # <b>EXTENT</b> (cut out a rectangular subregion), <b>AFFINE</b>
- # (affine transform), <b>PERSPECTIVE</b> (perspective
- # transform), <b>QUAD</b> (map a quadrilateral to a
- # rectangle), or <b>MESH</b> (map a number of source quadrilaterals
- # in one operation).
- # @param data Extra data to the transformation method.
- # @param resample Optional resampling filter. It can be one of
- # <b>NEAREST</b> (use nearest neighbour), <b>BILINEAR</b>
- # (linear interpolation in a 2x2 environment), or
- # <b>BICUBIC</b> (cubic spline interpolation in a 4x4
- # environment). If omitted, or if the image has mode
- # "1" or "P", it is set to <b>NEAREST</b>.
- # @return An Image object.
-
- def transform(self, size, method, data=None, resample=NEAREST, fill=1):
- "Transform image"
-
- import ImageTransform
- if isinstance(method, ImageTransform.Transform):
- method, data = method.getdata()
- if data is None:
- raise ValueError("missing method data")
- im = new(self.mode, size, None)
- if method == MESH:
- # list of quads
- for box, quad in data:
- im.__transformer(box, self, QUAD, quad, resample, fill)
- else:
- im.__transformer((0, 0)+size, self, method, data, resample, fill)
-
- return im
-
- def __transformer(self, box, image, method, data,
- resample=NEAREST, fill=1):
-
- # FIXME: this should be turned into a lazy operation (?)
-
- w = box[2]-box[0]
- h = box[3]-box[1]
-
- if method == AFFINE:
- # change argument order to match implementation
- data = (data[2], data[0], data[1],
- data[5], data[3], data[4])
- elif method == EXTENT:
- # convert extent to an affine transform
- x0, y0, x1, y1 = data
- xs = float(x1 - x0) / w
- ys = float(y1 - y0) / h
- method = AFFINE
- data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys)
- elif method == PERSPECTIVE:
- # change argument order to match implementation
- data = (data[2], data[0], data[1],
- data[5], data[3], data[4],
- data[6], data[7])
- 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
- 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,
- (se[1]-sw[1]-ne[1]+y0)*As*At)
- else:
- raise ValueError("unknown transformation method")
-
- if resample not in (NEAREST, BILINEAR, BICUBIC):
- raise ValueError("unknown resampling filter")
-
- image.load()
-
- self.load()
-
- if image.mode in ("1", "P"):
- resample = NEAREST
-
- self.im.transform2(box, image.im, method, data, resample, fill)
-
- ##
- # Returns a flipped or rotated copy of this image.
- #
- # @param method One of <b>FLIP_LEFT_RIGHT</b>, <b>FLIP_TOP_BOTTOM</b>,
- # <b>ROTATE_90</b>, <b>ROTATE_180</b>, or <b>ROTATE_270</b>.
-
- def transpose(self, method):
- "Transpose image (flip or rotate in 90 degree steps)"
-
- self.load()
- im = self.im.transpose(method)
- return self._new(im)
-
-# --------------------------------------------------------------------
-# Lazy operations
-
-class _ImageCrop(Image):
-
- def __init__(self, im, box):
-
- Image.__init__(self)
-
- x0, y0, x1, y1 = box
- if x1 < x0:
- x1 = x0
- if y1 < y0:
- y1 = y0
-
- self.mode = im.mode
- self.size = x1-x0, y1-y0
-
- self.__crop = x0, y0, x1, y1
-
- self.im = im.im
-
- def load(self):
-
- # lazy evaluation!
- if self.__crop:
- self.im = self.im.crop(self.__crop)
- self.__crop = None
-
- # FIXME: future versions should optimize crop/paste
- # sequences!
-
-# --------------------------------------------------------------------
-# Factories
-
-#
-# Debugging
-
-def _wedge():
- "Create greyscale wedge (for debugging only)"
-
- return Image()._new(core.wedge("L"))
-
-##
-# Creates a new image with the given mode and size.
-#
-# @param mode The mode to use for the new image.
-# @param size A 2-tuple, containing (width, height) in pixels.
-# @param color What colour to use for the image. Default is black.
-# If given, this should be a single integer or floating point value
-# for single-band modes, and a tuple for multi-band modes (one value
-# per band). When creating RGB images, you can also use colour
-# strings as supported by the ImageColor module. If the colour is
-# None, the image is not initialised.
-# @return An Image object.
-
-def new(mode, size, color=0):
- "Create a new image"
-
- if color is None:
- # don't initialize
- return Image()._new(core.new(mode, size))
-
- if isStringType(color):
- # css3-style specifier
-
- import ImageColor
- color = ImageColor.getcolor(color, mode)
-
- return Image()._new(core.fill(mode, size, color))
-
-##
-# Creates an image memory from pixel data in a string.
-# <p>
-# In its simplest form, this function takes three arguments
-# (mode, size, and unpacked pixel data).
-# <p>
-# You can also use any pixel decoder supported by PIL. For more
-# information on available decoders, see the section <a
-# href="pil-decoder.htm"><i>Writing Your Own File Decoder</i></a>.
-# <p>
-# Note that this function decodes pixel data only, not entire images.
-# If you have an entire image in a string, wrap it in a
-# <b>StringIO</b> object, and use {@link #open} to load it.
-#
-# @param mode The image mode.
-# @param size The image size.
-# @param data An 8-bit string containing raw data for the given mode.
-# @param decoder_name What decoder to use.
-# @param *args Additional parameters for the given decoder.
-# @return An Image object.
-
-def fromstring(mode, size, data, decoder_name="raw", *args):
- "Load image from string"
-
- # may pass tuple instead of argument list
- if len(args) == 1 and isTupleType(args[0]):
- args = args[0]
-
- if decoder_name == "raw" and args == ():
- args = mode
-
- im = new(mode, size)
- im.fromstring(data, decoder_name, args)
- return im
-
-##
-# (New in 1.1.4) Creates an image memory from pixel data in a string
-# or byte buffer.
-# <p>
-# This function is similar to {@link #fromstring}, but uses data in
-# the byte buffer, where possible. This means that changes to the
-# original buffer object are reflected in this image). Not all modes
-# can share memory; supported modes include "L", "RGBX", "RGBA", and
-# "CMYK".
-# <p>
-# Note that this function decodes pixel data only, not entire images.
-# If you have an entire image file in a string, wrap it in a
-# <b>StringIO</b> object, and use {@link #open} to load it.
-# <p>
-# In the current version, the default parameters used for the "raw"
-# decoder differs from that used for {@link fromstring}. This is a
-# bug, and will probably be fixed in a future release. The current
-# release issues a warning if you do this; to disable the warning,
-# you should provide the full set of parameters. See below for
-# details.
-#
-# @param mode The image mode.
-# @param size The image size.
-# @param data An 8-bit string or other buffer object containing raw
-# data for the given mode.
-# @param decoder_name What decoder to use.
-# @param *args Additional parameters for the given decoder. For the
-# default encoder ("raw"), it's recommended that you provide the
-# full set of parameters:
-# <b>frombuffer(mode, size, data, "raw", mode, 0, 1)</b>.
-# @return An Image object.
-# @since 1.1.4
-
-def frombuffer(mode, size, data, decoder_name="raw", *args):
- "Load image from string or buffer"
-
- # may pass tuple instead of argument list
- if len(args) == 1 and isTupleType(args[0]):
- args = args[0]
-
- if decoder_name == "raw":
- if args == ():
- if warnings:
- warnings.warn(
- "the frombuffer defaults may change in a future release; "
- "for portability, change the call to read:\n"
- " 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
- if args[0] in _MAPMODES:
- im = new(mode, (1,1))
- im = im._new(
- core.map_buffer(data, size, decoder_name, None, 0, args)
- )
- im.readonly = 1
- return im
-
- return apply(fromstring, (mode, size, data, decoder_name, args))
-
-
-##
-# (New in 1.1.6) Create an image memory from an object exporting
-# the array interface (using the buffer protocol).
-#
-# If obj is not contiguous, then the tostring method is called
-# and {@link frombuffer} is used.
-#
-# @param obj Object with array interface
-# @param mode Mode to use (will be determined from type if None)
-# @return An image memory.
-
-def fromarray(obj, mode=None):
- arr = obj.__array_interface__
- shape = arr['shape']
- ndim = len(shape)
- try:
- strides = arr['strides']
- except KeyError:
- strides = None
- if mode is None:
- typestr = arr['typestr']
- if not (typestr[0] == '|' or typestr[0] == _ENDIAN or
- typestr[1:] not in ['u1', 'b1', 'i4', 'f4']):
- raise TypeError("cannot handle data-type")
- typestr = typestr[:2]
- if typestr == 'i4':
- mode = 'I'
- elif typestr == 'f4':
- mode = 'F'
- elif typestr == 'b1':
- mode = '1'
- elif ndim == 2:
- mode = 'L'
- elif ndim == 3:
- mode = 'RGB'
- elif ndim == 4:
- mode = 'RGBA'
- else:
- raise TypeError("Do not understand data.")
- ndmax = 4
- bad_dims=0
- if mode in ['1','L','I','P','F']:
- ndmax = 2
- elif mode == 'RGB':
- ndmax = 3
- if ndim > ndmax:
- raise ValueError("Too many dimensions.")
-
- size = shape[:2][::-1]
- if strides is not None:
- obj = obj.tostring()
-
- return frombuffer(mode, size, obj, "raw", mode, 0, 1)
-
-##
-# Opens and identifies the given image file.
-# <p>
-# This is a lazy operation; this function identifies the file, but the
-# actual image data is not read from the file until you try to process
-# the data (or call the {@link #Image.load} method).
-#
-# @def open(file, mode="r")
-# @param file A filename (string) or a file object. The file object
-# must implement <b>read</b>, <b>seek</b>, and <b>tell</b> methods,
-# and be opened in binary mode.
-# @param mode The mode. If given, this argument must be "r".
-# @return An Image object.
-# @exception IOError If the file cannot be found, or the image cannot be
-# opened and identified.
-# @see #new
-
-def open(fp, mode="r"):
- "Open an image file, without loading the raster data"
-
- if mode != "r":
- raise ValueError("bad mode")
-
- if isStringType(fp):
- import __builtin__
- filename = fp
- fp = __builtin__.open(fp, "rb")
- else:
- filename = ""
-
- prefix = fp.read(16)
-
- preinit()
-
- for i in ID:
- try:
- factory, accept = OPEN[i]
- if not accept or accept(prefix):
- fp.seek(0)
- return factory(fp, filename)
- except (SyntaxError, IndexError, TypeError):
- pass
-
- init()
-
- for i in ID:
- try:
- factory, accept = OPEN[i]
- if not accept or accept(prefix):
- fp.seek(0)
- return factory(fp, filename)
- except (SyntaxError, IndexError, TypeError):
- pass
-
- raise IOError("cannot identify image file")
-
-#
-# Image processing.
-
-##
-# Creates a new image by interpolating between two input images, using
-# a constant alpha.
-#
-# <pre>
-# out = image1 * (1.0 - alpha) + image2 * alpha
-# </pre>
-#
-# @param im1 The first image.
-# @param im2 The second image. Must have the same mode and size as
-# the first image.
-# @param alpha The interpolation alpha factor. If alpha is 0.0, a
-# copy of the first image is returned. If alpha is 1.0, a copy of
-# the second image is returned. There are no restrictions on the
-# alpha value. If necessary, the result is clipped to fit into
-# the allowed output range.
-# @return An Image object.
-
-def blend(im1, im2, alpha):
- "Interpolate between images."
-
- im1.load()
- im2.load()
- return im1._new(core.blend(im1.im, im2.im, alpha))
-
-##
-# Creates a new image by interpolating between two input images,
-# using the mask as alpha.
-#
-# @param image1 The first image.
-# @param image2 The second image. Must have the same mode and
-# size as the first image.
-# @param mask A mask image. This image can can have mode
-# "1", "L", or "RGBA", and must have the same size as the
-# other two images.
-
-def composite(image1, image2, mask):
- "Create composite image by blending images using a transparency mask"
-
- image = image2.copy()
- image.paste(image1, None, mask)
- return image
-
-##
-# 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
-# function is applied to each band. Note that the function is
-# evaluated once for each possible pixel value, so you cannot use
-# random components or other generators.
-#
-# @def eval(image, function)
-# @param image The input image.
-# @param function A function object, taking one integer argument.
-# @return An Image object.
-
-def eval(image, *args):
- "Evaluate image expression"
-
- return image.point(args[0])
-
-##
-# Creates a new image from a number of single-band images.
-#
-# @param mode The mode to use for the output image.
-# @param bands A sequence containing one single-band image for
-# each band in the output image. All bands must have the
-# same size.
-# @return An Image object.
-
-def merge(mode, bands):
- "Merge a set of single band images into a new multiband image."
-
- if getmodebands(mode) != len(bands) or "*" in mode:
- raise ValueError("wrong number of bands")
- for im in bands[1:]:
- if im.mode != getmodetype(mode):
- raise ValueError("mode mismatch")
- if im.size != bands[0].size:
- raise ValueError("size mismatch")
- im = core.new(mode, bands[0].size)
- for i in range(getmodebands(mode)):
- bands[i].load()
- im.putband(bands[i].im, i)
- return bands[0]._new(im)
-
-# --------------------------------------------------------------------
-# Plugin registry
-
-##
-# Register an image file plugin. This function should not be used
-# in application code.
-#
-# @param id An image format identifier.
-# @param factory An image file factory method.
-# @param accept An optional function that can be used to quickly
-# reject images having another format.
-
-def register_open(id, factory, accept=None):
- id = string.upper(id)
- ID.append(id)
- OPEN[id] = factory, accept
-
-##
-# Registers an image MIME type. This function should not be used
-# in application code.
-#
-# @param id An image format identifier.
-# @param mimetype The image MIME type for this format.
-
-def register_mime(id, mimetype):
- MIME[string.upper(id)] = mimetype
-
-##
-# Registers an image save function. This function should not be
-# used in application code.
-#
-# @param id An image format identifier.
-# @param driver A function to save images in this format.
-
-def register_save(id, driver):
- SAVE[string.upper(id)] = driver
-
-##
-# Registers an image extension. This function should not be
-# used in application code.
-#
-# @param id An image format identifier.
-# @param extension An extension used for this format.
-
-def register_extension(id, extension):
- EXTENSION[string.lower(extension)] = string.upper(id)
-
-
-# --------------------------------------------------------------------
-# Simple display support
-
-def _showxv(image, title=None, command=None):
-
- if os.name == "nt":
- format = "BMP"
- elif sys.platform == "darwin":
- format = "JPEG"
- if not command:
- command = "open -a /Applications/Preview.app"
- else:
- format = None
- if not command:
- command = "xv"
- if title:
- command = command + " -name \"%s\"" % title
-
- if image.mode == "I;16":
- # @PIL88 @PIL101
- # "I;16" isn't an 'official' mode, but we still want to
- # provide a simple way to show 16-bit images.
- base = "L"
- else:
- base = getmodebase(image.mode)
- if base != image.mode and image.mode != "1":
- file = image.convert(base)._dump(format=format)
- else:
- file = image._dump(format=format)
-
- if os.name == "nt":
- command = "start /wait %s && del /f %s" % (file, file)
- elif sys.platform == "darwin":
- # on darwin open returns immediately resulting in the temp
- # file removal while app is opening
- command = "(%s %s; sleep 20; rm -f %s)&" % (command, file, file)
- else:
- command = "(%s %s; rm -f %s)&" % (command, file, file)
-
- os.system(command)