home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 April / enter-2004-04.iso / files / EVE_1424_100181.exe / Image.py < prev    next >
Encoding:
Python Source  |  2004-04-20  |  29.4 KB  |  1,088 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: //modules/pil/PIL/Image.py#17 $
  4. #
  5. # the Image class wrapper
  6. #
  7. # history:
  8. # 1995-09-09 fl   Created
  9. # 1996-03-11 fl   PIL release 0.0 (proof of concept)
  10. # 1996-04-30 fl   PIL release 0.1b1
  11. # 1996-05-27 fl   PIL release 0.1b2
  12. # 1996-11-04 fl   PIL release 0.2b1
  13. # 1996-12-08 fl   PIL release 0.2b2
  14. # 1996-12-16 fl   PIL release 0.2b3
  15. # 1997-01-14 fl   PIL release 0.2b4
  16. # 1998-07-02 fl   PIL release 0.3b1
  17. # 1998-07-17 fl   PIL release 0.3b2
  18. # 1999-01-01 fl   PIL release 1.0b1
  19. # 1999-02-08 fl   PIL release 1.0b2
  20. # 1999-07-28 fl   PIL release 1.0 final
  21. # 1999-08-15 fl   PIL release 1.0.1 (internal maintenance release)
  22. # 2000-06-07 fl   PIL release 1.1
  23. # 2000-10-20 fl   PIL release 1.1.1
  24. # 2001-05-07 fl   PIL release 1.1.2
  25. # 2002-01-14 fl   PIL release 1.2b1 (imToolkit)
  26. # 2002-03-15 fl   PIL release 1.1.3
  27. #
  28. # Copyright (c) 1997-2002 by Secret Labs AB.  All rights reserved.
  29. # Copyright (c) 1995-2002 by Fredrik Lundh.
  30. #
  31. # See the README file for information on usage and redistribution.
  32. #
  33.  
  34. VERSION = "1.1.3"
  35.  
  36. class _imaging_not_installed:
  37.     # module placeholder
  38.     def __getattr__(self, id):
  39.         raise ImportError, "The _imaging C module is not installed"
  40.  
  41. try:
  42.     # give Tk a chance to set up the environment, in case we're
  43.     # using an _imaging module linked against libtcl/libtk
  44.     import FixTk
  45. except ImportError:
  46.     pass
  47.  
  48. try:
  49.     # If the _imaging C module is not present, you can still use
  50.     # the "open" function to identify files, but you cannot load
  51.     # them.  Note that other modules should not refer to _imaging
  52.     # directly; import Image and use the Image.core variable instead.
  53.     import _imaging
  54.     core = _imaging
  55.     del _imaging
  56. except ImportError:
  57.     core = _imaging_not_installed()
  58.  
  59. import ImagePalette
  60. import os, string, sys
  61.  
  62. # type stuff
  63. from types import IntType, StringType, TupleType
  64.  
  65. try:
  66.     UnicodeStringType = type(unicode(""))
  67.     def isStringType(t):
  68.         return isinstance(t, StringType) or isinstance(t, UnicodeStringType)
  69. except NameError:
  70.     def isStringType(t):
  71.         return isinstance(t, StringType)
  72.  
  73. def isTupleType(t):
  74.     return isinstance(t, TupleType)
  75.  
  76. def isImageType(t):
  77.     return hasattr(t, "im")
  78.  
  79. def isDirectory(f):
  80.     return isStringType(f) and os.path.isdir(f)
  81.  
  82. from operator import isNumberType, isSequenceType
  83.  
  84. #
  85. # Debug level
  86.  
  87. DEBUG = 0
  88.  
  89. #
  90. # Constants (also defined in _imagingmodule.c!)
  91.  
  92. NONE = 0
  93.  
  94. # transpose
  95. FLIP_LEFT_RIGHT = 0
  96. FLIP_TOP_BOTTOM = 1
  97. ROTATE_90 = 2
  98. ROTATE_180 = 3
  99. ROTATE_270 = 4
  100.  
  101. # transforms
  102. AFFINE = 0
  103. EXTENT = 1
  104. PERSPECTIVE = 2 # Not yet implemented
  105. QUAD = 3
  106. MESH = 4
  107.  
  108. # resampling filters
  109. NONE = 0
  110. NEAREST = 0
  111. ANTIALIAS = 1 # 3-lobed lanczos
  112. LINEAR = BILINEAR = 2
  113. CUBIC = BICUBIC = 3
  114.  
  115. # dithers
  116. NONE = 0
  117. NEAREST = 0
  118. ORDERED = 1 # Not yet implemented
  119. RASTERIZE = 2 # Not yet implemented
  120. FLOYDSTEINBERG = 3 # default
  121.  
  122. # palettes/quantizers
  123. WEB = 0
  124. ADAPTIVE = 1
  125.  
  126. # categories
  127. NORMAL = 0
  128. SEQUENCE = 1
  129. CONTAINER = 2
  130.  
  131. # --------------------------------------------------------------------
  132. # Registries
  133.  
  134. ID = []
  135. OPEN = {}
  136. MIME = {}
  137. SAVE = {}
  138. EXTENSION = {}
  139.  
  140. # --------------------------------------------------------------------
  141. # Modes supported by this version
  142.  
  143. _MODEINFO = {
  144.  
  145.     # official modes
  146.     "1": ("L", "L", ("1",)),
  147.     "L": ("L", "L", ("L",)),
  148.     "I": ("L", "I", ("I",)),
  149.     "F": ("L", "F", ("F",)),
  150.     "P": ("RGB", "L", ("P",)),
  151.     "RGB": ("RGB", "L", ("R", "G", "B")),
  152.     "RGBX": ("RGB", "L", ("R", "G", "B", "X")),
  153.     "RGBA": ("RGB", "L", ("R", "G", "B", "A")),
  154.     "CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
  155.     "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
  156.  
  157.     # Experimental modes include I;16, I;16B, RGBa, BGR;15,
  158.     # and BGR;24.  Use these modes only if you know exactly
  159.     # what you're doing...
  160.  
  161. }
  162.  
  163. MODES = _MODEINFO.keys()
  164. MODES.sort()
  165.  
  166. def getmodebase(mode):
  167.     # corresponding "base" mode (grayscale or colour)
  168.     return _MODEINFO[mode][0]
  169.  
  170. def getmodetype(mode):
  171.     # storage type (per band)
  172.     return _MODEINFO[mode][1]
  173.  
  174. def getmodebands(mode):
  175.     # subcomponents
  176.     return len(_MODEINFO[mode][2])
  177.  
  178. # --------------------------------------------------------------------
  179. # Helpers
  180.  
  181. _initialized = 0
  182.  
  183. def preinit():
  184.     "Load standard file format drivers."
  185.  
  186.     global _initialized
  187.     if _initialized >= 1:
  188.         return
  189.  
  190.     for m in ("Bmp", "Gif", "Jpeg", "Ppm", "Png", "Tiff"):
  191.         try:
  192.             __import__("%sImagePlugin" % m, globals(), locals(), [])
  193.         except ImportError:
  194.             pass # ignore missing driver for now
  195.  
  196.     _initialized = 1
  197.  
  198. def init():
  199.     "Load all file format drivers."
  200.  
  201.     global _initialized
  202.     if _initialized >= 2:
  203.         return
  204.  
  205.     visited = {}
  206.  
  207.     directories = sys.path
  208.  
  209.     try:
  210.         directories = directories + [os.path.dirname(__file__)]
  211.     except NameError:
  212.         pass
  213.  
  214.     # only check directories (including current, if present in the path)
  215.     for directory in filter(isDirectory, directories):
  216.         fullpath = os.path.abspath(directory)
  217.         if visited.has_key(fullpath):
  218.             continue
  219.         for file in os.listdir(directory):
  220.             if file[-14:] == "ImagePlugin.py":
  221.                 f, e = os.path.splitext(file)
  222.                 try:
  223.                     sys.path.insert(0, directory)
  224.                     try:
  225.                         __import__(f, globals(), locals(), [])
  226.                     finally:
  227.                         del sys.path[0]
  228.                 except ImportError:
  229.                     if DEBUG:
  230.                         print "Image: failed to import",
  231.                         print f, ":", sys.exc_value
  232.         visited[fullpath] = None
  233.  
  234.     if OPEN or SAVE:
  235.         _initialized = 2
  236.  
  237.  
  238. # --------------------------------------------------------------------
  239. # Codec factories (used by tostring/fromstring and ImageFile.load)
  240.  
  241. def _getdecoder(mode, decoder_name, args, extra=()):
  242.  
  243.     # tweak arguments
  244.     if args is None:
  245.         args = ()
  246.     elif not isTupleType(args):
  247.         args = (args,)
  248.  
  249.     try:
  250.         # get decoder
  251.         decoder = getattr(core, decoder_name + "_decoder")
  252.         # print decoder, (mode,) + args + extra
  253.         return apply(decoder, (mode,) + args + extra)
  254.     except AttributeError:
  255.         raise IOError("decoder %s not available" % decoder_name)
  256.  
  257. def _getencoder(mode, encoder_name, args, extra=()):
  258.  
  259.     # tweak arguments
  260.     if args is None:
  261.         args = ()
  262.     elif not isTupleType(args):
  263.         args = (args,)
  264.  
  265.     try:
  266.         # get encoder
  267.         encoder = getattr(core, encoder_name + "_encoder")
  268.         # print encoder, (mode,) + args + extra
  269.         return apply(encoder, (mode,) + args + extra)
  270.     except AttributeError:
  271.         raise IOError("encoder %s not available" % encoder_name)
  272.  
  273.  
  274. # --------------------------------------------------------------------
  275. # Simple expression analyzer
  276.  
  277. class _E:
  278.     def __init__(self, data): self.data = data
  279.     def __coerce__(self, other): return self, _E(other)
  280.     def __add__(self, other): return _E((self.data, "__add__", other.data))
  281.     def __mul__(self, other): return _E((self.data, "__mul__", other.data))
  282.  
  283. def _getscaleoffset(expr):
  284.     stub = ["stub"]
  285.     data = expr(_E(stub)).data
  286.     try:
  287.         (a, b, c) = data # simplified syntax
  288.         if (a is stub and b == "__mul__" and isNumberType(c)):
  289.             return c, 0.0
  290.         if (a is stub and b == "__add__" and isNumberType(c)):
  291.             return 1.0, c
  292.     except TypeError: pass
  293.     try:
  294.         ((a, b, c), d, e) = data # full syntax
  295.         if (a is stub and b == "__mul__" and isNumberType(c) and
  296.             d == "__add__" and isNumberType(e)):
  297.             return c, e
  298.     except TypeError: pass
  299.     raise ValueError("illegal expression")
  300.  
  301.  
  302. # --------------------------------------------------------------------
  303. # Implementation wrapper
  304.  
  305. class Image:
  306.  
  307.     format = None
  308.     format_description = None
  309.  
  310.     def __init__(self):
  311.         self.im = None
  312.         self.mode = ""
  313.         self.size = (0, 0)
  314.         self.palette = None
  315.         self.info = {}
  316.         self.category = NORMAL
  317.         self.readonly = 0
  318.  
  319.     def _new(self, im):
  320.         new = Image()
  321.         new.im = im
  322.         new.mode = im.mode
  323.         new.size = im.size
  324.         new.palette = self.palette
  325.         try:
  326.             new.info = self.info.copy()
  327.         except AttributeError:
  328.             # fallback (pre-1.5.2)
  329.             new.info = {}
  330.             for k, v in self.info:
  331.                 new.info[k] = v
  332.         return new
  333.  
  334.     _makeself = _new # compatibility
  335.  
  336.     def _copy(self):
  337.         self.load()
  338.         self.im = self.im.copy()
  339.         self.readonly = 0
  340.  
  341.     def _dump(self, file=None, format=None):
  342.         import tempfile
  343.         if not file:
  344.             file = tempfile.mktemp()
  345.         self.load()
  346.         if not format or format == "PPM":
  347.             self.im.save_ppm(file)
  348.         else:
  349.             file = file + "." + format
  350.             self.save(file, format)
  351.         return file
  352.  
  353.     def tostring(self, encoder_name="raw", *args):
  354.         "Return image as a binary string"
  355.  
  356.         # may pass tuple instead of argument list
  357.         if len(args) == 1 and isTupleType(args[0]):
  358.             args = args[0]
  359.  
  360.         if encoder_name == "raw" and args == ():
  361.             args = self.mode
  362.  
  363.         self.load()
  364.  
  365.         # unpack data
  366.         e = _getencoder(self.mode, encoder_name, args)
  367.         e.setimage(self.im)
  368.  
  369.         data = []
  370.         while 1:
  371.             l, s, d = e.encode(65536)
  372.             data.append(d)
  373.             if s:
  374.                 break
  375.         if s < 0:
  376.             raise RuntimeError("encoder error %d in tostring" % s)
  377.  
  378.         return string.join(data, "")
  379.  
  380.     def tobitmap(self, name="image"):
  381.         "Return image as an XBM bitmap"
  382.  
  383.         self.load()
  384.         if self.mode != "1":
  385.             raise ValueError("not a bitmap")
  386.         data = self.tostring("xbm")
  387.         return string.join(["#define %s_width %d\n" % (name, self.size[0]),
  388.                 "#define %s_height %d\n"% (name, self.size[1]),
  389.                 "static char %s_bits[] = {\n" % name, data, "};"], "")
  390.  
  391.     def fromstring(self, data, decoder_name="raw", *args):
  392.         "Load data to image from binary string"
  393.  
  394.         # may pass tuple instead of argument list
  395.         if len(args) == 1 and isTupleType(args[0]):
  396.             args = args[0]
  397.  
  398.         # default format
  399.         if decoder_name == "raw" and args == ():
  400.             args = self.mode
  401.  
  402.         # unpack data
  403.         d = _getdecoder(self.mode, decoder_name, args)
  404.         d.setimage(self.im)
  405.         s = d.decode(data)
  406.  
  407.         if s[0] >= 0:
  408.             raise ValueError("not enough image data")
  409.         if s[1] != 0:
  410.             raise ValueError("cannot decode image data")
  411.  
  412.     def load(self):
  413.         if self.im and self.palette and self.palette.rawmode:
  414.             self.im.putpalette(self.palette.rawmode, self.palette.data)
  415.             self.palette.mode = "RGB"
  416.             self.palette.rawmode = None
  417.             if self.info.has_key("transparency"):
  418.                 self.im.putpalettealpha(self.info["transparency"], 0)
  419.                 self.palette.mode = "RGBA"
  420.  
  421.     #
  422.     # function wrappers
  423.  
  424.     def convert(self, mode=None, data=None, dither=None,
  425.                 palette=WEB, colors=256):
  426.         "Convert to other pixel format"
  427.  
  428.         if not mode:
  429.             # determine default mode
  430.             if self.mode == "P":
  431.                 self.load()
  432.                 if self.palette:
  433.                     mode = self.palette.mode
  434.                 else:
  435.                     mode = "RGB"
  436.             else:
  437.                 return self.copy()
  438.  
  439.         self.load()
  440.  
  441.         if data:
  442.             # matrix conversion
  443.             if mode not in ("L", "RGB"):
  444.                 raise ValueError("illegal conversion")
  445.             im = self.im.convert_matrix(mode, data)
  446.             return self._new(im)
  447.  
  448.         if mode == "P" and palette == ADAPTIVE:
  449.             im = self.im.quantize(colors)
  450.             return self._new(im)
  451.  
  452.         # colourspace conversion
  453.         if dither is None:
  454.             dither = FLOYDSTEINBERG
  455.  
  456.         try:
  457.             im = self.im.convert(mode, dither)
  458.         except ValueError:
  459.             try:
  460.                 # normalize source image and try again
  461.                 im = self.im.convert(getmodebase(self.mode))
  462.                 im = im.convert(mode, dither)
  463.             except KeyError:
  464.                 raise ValueError("illegal conversion")
  465.  
  466.         return self._new(im)
  467.  
  468.     def quantize(self, colors=256, method=0, kmeans=0, palette=None):
  469.  
  470.         # methods:
  471.         #    0 = median cut
  472.         #    1 = maximum coverage
  473.  
  474.         # NOTE: this functionality will be moved to the extended
  475.         # quantizer interface in a later versions of PIL.
  476.  
  477.         self.load()
  478.  
  479.         if palette:
  480.             # use palette from reference image
  481.             palette.load()
  482.             if palette.mode != "P":
  483.                 raise ValueError("bad mode for palette image")
  484.             if self.mode != "RGB" and self.mode != "L":
  485.                 raise ValueError(
  486.                     "only RGB or L mode images can be quantized to a palette"
  487.                     )
  488.             im = self.im.convert("P", 1, palette.im)
  489.             return self._makeself(im)
  490.  
  491.         im = self.im.quantize(colors, method, kmeans)
  492.         return self._new(im)
  493.  
  494.     def copy(self):
  495.         "Copy raster data"
  496.  
  497.         self.load()
  498.         im = self.im.copy()
  499.         return self._new(im)
  500.  
  501.     def crop(self, box=None):
  502.         "Crop region from image"
  503.  
  504.         self.load()
  505.         if box is None:
  506.             return self.copy()
  507.  
  508.         # lazy operation
  509.         return _ImageCrop(self, box)
  510.  
  511.     def draft(self, mode, size):
  512.         "Configure image decoder"
  513.  
  514.         pass
  515.  
  516.     def filter(self, kernel):
  517.         "Apply environment filter to image"
  518.  
  519.         if self.mode == "P":
  520.             raise ValueError("cannot filter palette images")
  521.         self.load()
  522.         id = kernel.id
  523.         if self.im.bands == 1:
  524.             return self._new(self.im.filter(id))
  525.         # fix to handle multiband images since _imaging doesn't
  526.         ims = []
  527.         for c in range(self.im.bands):
  528.             ims.append(self._new(self.im.getband(c).filter(id)))
  529.         return merge(self.mode, ims)
  530.  
  531.     def getbands(self):
  532.         "Get band names"
  533.  
  534.         return _MODEINFO[self.mode][2]
  535.  
  536.     def getbbox(self):
  537.         "Get bounding box of actual data (non-zero pixels) in image"
  538.  
  539.         self.load()
  540.         return self.im.getbbox()
  541.  
  542.     def getdata(self, band = None):
  543.         "Get image data as sequence object."
  544.  
  545.         self.load()
  546.         if band is not None:
  547.             return self.im.getband(band)
  548.         return self.im # could be abused
  549.  
  550.     def getextrema(self):
  551.         "Get min/max value"
  552.  
  553.         self.load()
  554.         if self.im.bands > 1:
  555.             extrema = []
  556.             for i in range(self.im.bands):
  557.                 extrema.append(self.im.getband(i).getextrema())
  558.             return tuple(extrema)
  559.         return self.im.getextrema()
  560.  
  561.     def getpixel(self, xy):
  562.         "Get pixel value"
  563.  
  564.         self.load()
  565.         return self.im.getpixel(xy)
  566.  
  567.     def getprojection(self):
  568.         "Get projection to x and y axes"
  569.  
  570.         self.load()
  571.         x, y = self.im.getprojection()
  572.         return map(ord, x), map(ord, y)
  573.  
  574.     def histogram(self, mask=None, extrema=None):
  575.         "Take histogram of image"
  576.  
  577.         self.load()
  578.         if mask:
  579.             mask.load()
  580.             return self.im.histogram((0, 0), mask.im)
  581.         if self.mode in ("I", "F"):
  582.             if extrema is None:
  583.                 extrema = self.getextrema()
  584.             return self.im.histogram(extrema)
  585.         return self.im.histogram()
  586.  
  587.     def offset(self, xoffset, yoffset=None):
  588.         "(deprecated) Offset image in horizontal and/or vertical direction"
  589.         import ImageChops
  590.         return ImageChops.offset(self, xoffset, yoffset)
  591.  
  592.     def paste(self, im, box=None, mask=None):
  593.         "Paste other image into region"
  594.  
  595.         if box is None:
  596.             # cover all of self
  597.             box = (0, 0) + self.size
  598.  
  599.         if len(box) == 2:
  600.             # lower left corner given; get size from image or mask
  601.             if isImageType(im):
  602.                 box = box + (box[0]+im.size[0], box[1]+im.size[1])
  603.             else:
  604.                 box = box + (box[0]+mask.size[0], box[1]+mask.size[1])
  605.  
  606.         if isImageType(im):
  607.             im.load()
  608.             if self.mode != im.mode:
  609.                 if self.mode != "RGB" or im.mode not in ("RGBA", "RGBa"):
  610.                     # should use an adapter for this!
  611.                     im = im.convert(self.mode)
  612.             im = im.im
  613.  
  614.         self.load()
  615.  
  616.         if self.readonly:
  617.             self._copy()
  618.  
  619.         if mask:
  620.             mask.load()
  621.             self.im.paste(im, box, mask.im)
  622.         else:
  623.             self.im.paste(im, box)
  624.  
  625.     def point(self, lut, mode=None):
  626.         "Map image through lookup table"
  627.  
  628.         if self.mode in ("I", "F"):
  629.             # floating point; lut must be a valid expression
  630.             scale, offset = _getscaleoffset(lut)
  631.             self.load()
  632.             im = self.im.point_transform(scale, offset);
  633.         else:
  634.             # integer image; use lut and mode
  635.             self.load()
  636.             if not isSequenceType(lut):
  637.                 # if it isn't a list, it should be a function
  638.                 lut = map(lut, range(256)) * self.im.bands
  639.             im = self.im.point(lut, mode)
  640.  
  641.         return self._new(im)
  642.  
  643.     def putalpha(self, im):
  644.         "Set alpha layer"
  645.  
  646.         if self.mode != "RGBA" or im.mode not in ("1", "L"):
  647.             raise ValueError("illegal image mode")
  648.  
  649.         im.load()
  650.         self.load()
  651.  
  652.         if im.mode == "1":
  653.             im = im.convert("L")
  654.  
  655.         self.im.putband(im.im, 3)
  656.  
  657.     def putdata(self, data, scale=1.0, offset=0.0):
  658.         "Put data from a sequence object into an image."
  659.  
  660.         self.load() # hmm...
  661.         self.im.putdata(data, scale, offset)
  662.  
  663.     def putpalette(self, data, rawmode="RGB"):
  664.         "Put palette data into an image."
  665.  
  666.         if self.mode not in ("L", "P"):
  667.             raise ValueError("illegal image mode")
  668.         if not isStringType(data):
  669.             data = string.join(map(chr, data), "")
  670.         self.mode = "P"
  671.         self.palette = ImagePalette.raw(rawmode, data)
  672.         self.palette.mode = "RGB"
  673.  
  674.     def putpixel(self, xy, value):
  675.         "Set pixel value"
  676.  
  677.         self.load()
  678.         return self.im.putpixel(xy, value)
  679.  
  680.     def resize(self, size, resample=NEAREST):
  681.         "Resize image"
  682.  
  683.         if resample not in (NEAREST, BILINEAR, BICUBIC, ANTIALIAS):
  684.             raise ValueError("unknown resampling filter")
  685.  
  686.         self.load()
  687.  
  688.         if self.mode in ("1", "P"):
  689.             resample = NEAREST
  690.  
  691.         if resample == ANTIALIAS:
  692.             # requires stretch support (imToolkit & PIL 1.1.3)
  693.             try:
  694.                 im = self.im.stretch(size, resample)
  695.             except AttributeError:
  696.                 raise ValueError("unsupported resampling filter")
  697.         else:
  698.             im = self.im.resize(size, resample)
  699.  
  700.         return self._new(im)
  701.  
  702.     def rotate(self, angle, resample=NEAREST):
  703.         "Rotate image.  Angle given as degrees counter-clockwise."
  704.  
  705.         if resample not in (NEAREST, BILINEAR, BICUBIC):
  706.             raise ValueError("unknown resampling filter")
  707.  
  708.         self.load()
  709.  
  710.         if self.mode in ("1", "P"):
  711.             resample = NEAREST
  712.  
  713.         return self._new(self.im.rotate(angle, resample))
  714.  
  715.     def save(self, fp, format=None, **params):
  716.         "Save image to file or stream"
  717.  
  718.         if isStringType(fp):
  719.             import __builtin__
  720.             filename = fp
  721.             fp = __builtin__.open(fp, "wb")
  722.             close = 1
  723.         else:
  724.             filename = ""
  725.             close = 0
  726.  
  727.         self.encoderinfo = params
  728.         self.encoderconfig = ()
  729.  
  730.         self.load()
  731.  
  732.         preinit()
  733.  
  734.         ext = string.lower(os.path.splitext(filename)[1])
  735.  
  736.         try:
  737.  
  738.             if not format:
  739.                 format = EXTENSION[ext]
  740.  
  741.             SAVE[string.upper(format)](self, fp, filename)
  742.  
  743.         except KeyError, v:
  744.  
  745.             init()
  746.  
  747.             if not format:
  748.                 format = EXTENSION[ext]
  749.  
  750.             SAVE[string.upper(format)](self, fp, filename)
  751.  
  752.         if close:
  753.             fp.close()
  754.  
  755.     def seek(self, frame):
  756.         "Seek to given frame in sequence file"
  757.  
  758.         # overridden by file handlers
  759.         if frame != 0:
  760.             raise EOFError
  761.  
  762.     def show(self, title=None, command=None):
  763.         "Display image (for debug purposes only)"
  764.  
  765.         try:
  766.             import ImageTk
  767.             ImageTk._show(self, title)
  768.             # note: caller must enter mainloop!
  769.         except:
  770.             _showxv(self, title, command)
  771.  
  772.     def split(self):
  773.         "Split image into bands"
  774.  
  775.         ims = []
  776.         self.load()
  777.         for i in range(self.im.bands):
  778.             ims.append(self._new(self.im.getband(i)))
  779.         return tuple(ims)
  780.  
  781.     def tell(self):
  782.         "Return current frame number"
  783.  
  784.         return 0
  785.  
  786.     def thumbnail(self, size, resample=NEAREST):
  787.         "Create thumbnail representation (modifies image in place)"
  788.  
  789.         # FIXME: the default resampling filter will be changed
  790.         # to ANTIALIAS in future versions
  791.  
  792.         # preserve aspect ratio
  793.         x, y = self.size
  794.         if x > size[0]: y = y * size[0] / x; x = size[0]
  795.         if y > size[1]: x = x * size[1] / y; y = size[1]
  796.         size = x, y
  797.  
  798.         if size == self.size:
  799.             return
  800.  
  801.         self.draft(None, size)
  802.  
  803.         self.load()
  804.  
  805.         try:
  806.             im = self.resize(size, resample)
  807.         except ValueError:
  808.             if resample != ANTIALIAS:
  809.                 raise
  810.             im = self.resize(size, NEAREST) # fallback
  811.  
  812.         self.im = im.im
  813.         self.mode = im.mode
  814.         self.size = size
  815.  
  816.         self.readonly = 0
  817.  
  818.     def transform(self, size, method, data, resample=NEAREST, fill=1):
  819.         "Transform image"
  820.  
  821.         im = new(self.mode, size, None)
  822.         if method == MESH:
  823.             # list of quads
  824.             for box, quad in data:
  825.                 im.__transformer(box, self, QUAD, quad, resample, fill)
  826.         else:
  827.             im.__transformer((0, 0)+size, self, method, data, resample, fill)
  828.  
  829.         return im
  830.  
  831.     def __transformer(self, box, image, method, data,
  832.                       resample=NEAREST, fill=1):
  833.         "Transform into current image"
  834.  
  835.         # FIXME: this should be turned into a lazy operation (?)
  836.  
  837.         w = box[2]-box[0]
  838.         h = box[3]-box[1]
  839.  
  840.         if method == AFFINE:
  841.             # change argument order to match implementation
  842.             data = (data[2], data[0], data[1],
  843.                     data[5], data[3], data[4])
  844.         elif method == EXTENT:
  845.             # convert extent to an affine transform
  846.             x0, y0, x1, y1 = data
  847.             xs = float(x1 - x0) / w
  848.             ys = float(y1 - y0) / h
  849.             method = AFFINE
  850.             data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys)
  851.         elif method == QUAD:
  852.             # quadrilateral warp.  data specifies the four corners
  853.             # given as NW, SW, SE, and NE.
  854.             nw = data[0:2]; sw = data[2:4]; se = data[4:6]; ne = data[6:8]
  855.             x0, y0 = nw; As = 1.0 / w; At = 1.0 / h
  856.             data = (x0, (ne[0]-x0)*As, (sw[0]-x0)*At,
  857.                     (se[0]-sw[0]-ne[0]+x0)*As*At,
  858.                     y0, (ne[1]-y0)*As, (sw[1]-y0)*At,
  859.                     (se[1]-sw[1]-ne[1]+y0)*As*At)
  860.         else:
  861.             raise ValueError("unknown transformation method")
  862.  
  863.         if resample not in (NEAREST, BILINEAR, BICUBIC):
  864.             raise ValueError("unknown resampling filter")
  865.  
  866.         image.load()
  867.  
  868.         self.load()
  869.  
  870.         if image.mode in ("1", "P"):
  871.             resample = NEAREST
  872.  
  873.         self.im.transform2(box, image.im, method, data, resample, fill)
  874.  
  875.     def transpose(self, method):
  876.         "Transpose image (flip or rotate in 90 degree steps)"
  877.  
  878.         self.load()
  879.         im = self.im.transpose(method)
  880.         return self._new(im)
  881.  
  882.     #
  883.     # test/extension hooks (don't use in production code!)
  884.  
  885.     def _stretch(self, size, resample=NEAREST):
  886.         # same as resize
  887.  
  888.         if resample not in (NEAREST, BILINEAR, BICUBIC, ANTIALIAS):
  889.             raise ValueError("unknown resampling filter")
  890.  
  891.         self.load()
  892.  
  893.         if self.mode in ("1", "P"):
  894.             resample = NEAREST
  895.  
  896.         return self._new(self.im.stretch(size, resample))
  897.  
  898. # --------------------------------------------------------------------
  899. # Lazy operations
  900.  
  901. class _ImageCrop(Image):
  902.  
  903.     def __init__(self, im, box):
  904.  
  905.         Image.__init__(self)
  906.  
  907.         self.mode = im.mode
  908.         self.size = box[2]-box[0], box[3]-box[1]
  909.  
  910.         self.__crop = box
  911.  
  912.         self.im = im.im
  913.  
  914.     def load(self):
  915.  
  916.         # lazy evaluation!
  917.         if self.__crop:
  918.             self.im = self.im.crop(self.__crop)
  919.             self.__crop = None
  920.  
  921.         # FIXME: future versions should optimize crop/paste
  922.         # sequences!
  923.  
  924. # --------------------------------------------------------------------
  925. # Factories
  926.  
  927. #
  928. # Debugging
  929.  
  930. def _wedge():
  931.     "Create greyscale wedge (for debugging only)"
  932.  
  933.     return Image()._new(core.wedge("L"))
  934.  
  935. #
  936. # Create/open images.
  937.  
  938. def new(mode, size, color=0):
  939.     "Create a new image"
  940.  
  941.     if color is None:
  942.         # don't initialize
  943.         return Image()._new(core.new(mode, size))
  944.  
  945.     return Image()._new(core.fill(mode, size, color))
  946.  
  947.  
  948. def fromstring(mode, size, data, decoder_name="raw", *args):
  949.     "Load image from string"
  950.  
  951.     # may pass tuple instead of argument list
  952.     if len(args) == 1 and isTupleType(args[0]):
  953.         args = args[0]
  954.  
  955.     if decoder_name == "raw" and args == ():
  956.         args = mode
  957.  
  958.     im = new(mode, size)
  959.     im.fromstring(data, decoder_name, args)
  960.     return im
  961.  
  962. def open(fp, mode="r"):
  963.     "Open an image file, without loading the raster data"
  964.  
  965.     if mode != "r":
  966.         raise ValueError("bad mode")
  967.  
  968.     if isStringType(fp):
  969.         import __builtin__
  970.         filename = fp
  971.         fp = __builtin__.open(fp, "rb")
  972.     else:
  973.         filename = ""
  974.  
  975.     prefix = fp.read(16)
  976.  
  977.     preinit()
  978.  
  979.     for i in ID:
  980.         try:
  981.             factory, accept = OPEN[i]
  982.             if not accept or accept(prefix):
  983.                 fp.seek(0)
  984.                 return factory(fp, filename)
  985.         except (SyntaxError, IndexError, TypeError):
  986.             pass
  987.  
  988.     init()
  989.  
  990.     for i in ID:
  991.         try:
  992.             factory, accept = OPEN[i]
  993.             if not accept or accept(prefix):
  994.                 fp.seek(0)
  995.                 return factory(fp, filename)
  996.         except (SyntaxError, IndexError, TypeError):
  997.             pass
  998.  
  999.     raise IOError("cannot identify image file")
  1000.  
  1001. #
  1002. # Image processing.
  1003.  
  1004. def blend(im1, im2, alpha):
  1005.     "Interpolate between images."
  1006.  
  1007.     if alpha <= 0.0:
  1008.         return im1
  1009.     elif alpha >= 1.0:
  1010.         return im2
  1011.     im1.load()
  1012.     im2.load()
  1013.     return im1._new(core.blend(im1.im, im2.im, alpha))
  1014.  
  1015. def composite(image1, image2, mask):
  1016.     "Create composite image by blending images using a transparency mask"
  1017.  
  1018.     image = image2.copy()
  1019.     image.paste(image1, None, mask)
  1020.     return image
  1021.  
  1022. def eval(image, *args):
  1023.     "Evaluate image expression"
  1024.  
  1025.     return image.point(args[0])
  1026.  
  1027. def merge(mode, bands):
  1028.     "Merge a set of single band images into a new multiband image."
  1029.  
  1030.     if getmodebands(mode) != len(bands) or "*" in mode:
  1031.         raise ValueError("wrong number of bands")
  1032.     for im in bands[1:]:
  1033.         if im.mode != getmodetype(mode):
  1034.             raise ValueError("mode mismatch")
  1035.         if im.size != bands[0].size:
  1036.             raise ValueError("size mismatch")
  1037.     im = core.new(mode, bands[0].size)
  1038.     for i in range(getmodebands(mode)):
  1039.         bands[i].load()
  1040.         im.putband(bands[i].im, i)
  1041.     return bands[0]._new(im)
  1042.  
  1043. # --------------------------------------------------------------------
  1044. # Plugin registry
  1045.  
  1046. def register_open(id, factory, accept=None):
  1047.     id = string.upper(id)
  1048.     ID.append(id)
  1049.     OPEN[id] = factory, accept
  1050.  
  1051. def register_mime(id, mimetype):
  1052.     MIME[string.upper(id)] = mimetype
  1053.  
  1054. def register_save(id, driver):
  1055.     SAVE[string.upper(id)] = driver
  1056.  
  1057. def register_extension(id, extension):
  1058.     EXTENSION[string.lower(extension)] = string.upper(id)
  1059.  
  1060.  
  1061. # --------------------------------------------------------------------
  1062. # Simple display support
  1063.  
  1064. def _showxv(self, title=None, command=None):
  1065.  
  1066.     if os.name == "nt":
  1067.         format = "BMP"
  1068.         if not command:
  1069.             command = "start"
  1070.     else:
  1071.         format = None
  1072.         if not command:
  1073.             command = "xv"
  1074.             if title:
  1075.                 command = command + " -name \"%s\"" % title
  1076.  
  1077.     base = getmodebase(self.mode)
  1078.     if base != self.mode and self.mode != "1":
  1079.         file = self.convert(base)._dump(format=format)
  1080.     else:
  1081.         file = self._dump(format=format)
  1082.  
  1083.     if os.name == "nt":
  1084.         os.system("%s %s" % (command, file))
  1085.         # FIXME: this leaves temporary files around...
  1086.     else:
  1087.         os.system("(%s %s; rm -f %s)&" % (command, file, file))
  1088.