| # | 
| # The Python Imaging Library. | 
| # $Id$ | 
| # | 
| # 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 | 
| # 2009-11-15 fl   PIL release 1.1.7 | 
| # | 
| # Copyright (c) 1997-2009 by Secret Labs AB.  All rights reserved. | 
| # Copyright (c) 1995-2009 by Fredrik Lundh. | 
| # | 
| # See the README file for information on usage and redistribution. | 
| # | 
|   | 
| VERSION = "1.1.7" | 
|   | 
| 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;16L, I;16B, RGBa, BGR;15, and | 
|     # BGR;24.  Use these modes only if you know exactly what you're | 
|     # doing... | 
|   | 
| } | 
|   | 
| try: | 
|     byteorder = sys.byteorder | 
| except AttributeError: | 
|     import struct | 
|     if struct.unpack("h", "\0\1")[0] == 1: | 
|         byteorder = "big" | 
|     else: | 
|         byteorder = "little" | 
|   | 
| if byteorder == 'little': | 
|     _ENDIAN = '<' | 
| else: | 
|     _ENDIAN = '>' | 
|   | 
| _MODE_CONV = { | 
|     # official modes | 
|     "1": ('|b1', None), # broken | 
|     "L": ('|u1', None), | 
|     "I": (_ENDIAN + 'i4', None), | 
|     "F": (_ENDIAN + 'f4', None), | 
|     "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], im.size[0] | 
|     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;16L", "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 0 | 
|   | 
|     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 | 
|         return 1 | 
|   | 
| # -------------------------------------------------------------------- | 
| # 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): | 
|         # FIXME: take "new" parameters / other image? | 
|         # FIXME: turn mode and size into delegating properties? | 
|         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 __repr__(self): | 
|         return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( | 
|             self.__class__.__module__, self.__class__.__name__, | 
|             self.mode, self.size[0], self.size[1], | 
|             id(self) | 
|             ) | 
|   | 
|     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, **options) | 
|     # @param mode The requested mode. | 
|     # @param matrix An optional conversion matrix.  If given, this | 
|     #    should be 4- or 16-tuple containing floating point values. | 
|     # @param options Additional options, given as keyword arguments. | 
|     # @keyparam dither Dithering method, used when converting from | 
|     #    mode "RGB" to "P". | 
|     #    Available methods are NONE or FLOYDSTEINBERG (default). | 
|     # @keyparam palette Palette to use when converting from mode "RGB" | 
|     #    to "P".  Available palettes are WEB or ADAPTIVE. | 
|     # @keyparam colors Number of colors to use for the ADAPTIVE palette. | 
|     #    Defaults to 256. | 
|     # @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() | 
|   | 
|         if callable(filter): | 
|             filter = filter() | 
|         if not hasattr(filter, "filter"): | 
|             raise TypeError("filter argument should be ImageFilter.Filter instance or class") | 
|   | 
|         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 isinstance(lut, ImagePointHandler): | 
|             return lut.point(self) | 
|   | 
|         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." | 
|   | 
|         if self.mode not in ("L", "P"): | 
|             raise ValueError("illegal image mode") | 
|         self.load() | 
|         if isinstance(data, ImagePalette.ImagePalette): | 
|             palette = ImagePalette.raw(data.rawmode, data.palette) | 
|         else: | 
|             if not isStringType(data): | 
|                 data = string.join(map(chr, data), "") | 
|             palette = ImagePalette.raw(rawmode, data) | 
|         self.mode = "P" | 
|         self.palette = palette | 
|         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, resample) | 
|   | 
|         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)" | 
|   | 
|         _show(self, title=title, command=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" | 
|   | 
|         if self.im.bands == 1: | 
|             ims = [self.copy()] | 
|         else: | 
|             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" | 
|   | 
|         if isinstance(method, ImageTransformHandler): | 
|             return method.transform(size, self, resample=resample, fill=fill) | 
|         if hasattr(method, "getdata"): | 
|             # compatibility w. old-style transform objects | 
|             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 | 
|   | 
|         if self.im: | 
|             return self.im.pixel_access(self.readonly) | 
|   | 
|         # FIXME: future versions should optimize crop/paste | 
|         # sequences! | 
|   | 
| # -------------------------------------------------------------------- | 
| # Abstract handlers. | 
|   | 
| 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 | 
|   | 
| # | 
| # 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 fromstring(mode, size, data, decoder_name, args) | 
|   | 
|   | 
| ## | 
| # (New in 1.1.6) Creates 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: | 
|         try: | 
|             typekey = (1, 1) + shape[2:], arr['typestr'] | 
|             mode, rawmode = _fromarray_typemap[typekey] | 
|         except KeyError: | 
|             # print typekey | 
|             raise TypeError("Cannot handle this data type") | 
|     else: | 
|         rawmode = mode | 
|     if mode in ["1", "L", "I", "P", "F"]: | 
|         ndmax = 2 | 
|     elif mode == "RGB": | 
|         ndmax = 3 | 
|     else: | 
|         ndmax = 4 | 
|     if ndim > ndmax: | 
|         raise ValueError("Too many dimensions.") | 
|   | 
|     size = shape[1], shape[0] | 
|     if strides is not None: | 
|         obj = obj.tostring() | 
|   | 
|     return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) | 
|   | 
| _fromarray_typemap = { | 
|     # (shape, typestr) => mode, rawmode | 
|     # first two members of shape are set to one | 
|     # ((1, 1), "|b1"): ("1", "1"), # broken | 
|     ((1, 1), "|u1"): ("L", "L"), | 
|     ((1, 1), "|i1"): ("I", "I;8"), | 
|     ((1, 1), "<i2"): ("I", "I;16"), | 
|     ((1, 1), ">i2"): ("I", "I;16B"), | 
|     ((1, 1), "<i4"): ("I", "I;32"), | 
|     ((1, 1), ">i4"): ("I", "I;32B"), | 
|     ((1, 1), "<f4"): ("F", "F;32F"), | 
|     ((1, 1), ">f4"): ("F", "F;32BF"), | 
|     ((1, 1), "<f8"): ("F", "F;64F"), | 
|     ((1, 1), ">f8"): ("F", "F;64BF"), | 
|     ((1, 1, 3), "|u1"): ("RGB", "RGB"), | 
|     ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), | 
|     } | 
|   | 
| # shortcuts | 
| _fromarray_typemap[((1, 1), _ENDIAN + "i4")] = ("I", "I") | 
| _fromarray_typemap[((1, 1), _ENDIAN + "f4")] = ("F", "F") | 
|   | 
| ## | 
| # 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 | 
|   | 
|     if 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.  User code may override this. | 
|   | 
| def _show(image, **options): | 
|     # override me, as necessary | 
|     apply(_showxv, (image,), options) | 
|   | 
| def _showxv(image, title=None, **options): | 
|     import ImageShow | 
|     apply(ImageShow.show, (image, title), options) |