| # | 
| # The Python Imaging Library. | 
| # $Id$ | 
| # | 
| # a Tk display interface | 
| # | 
| # History: | 
| # 96-04-08 fl   Created | 
| # 96-09-06 fl   Added getimage method | 
| # 96-11-01 fl   Rewritten, removed image attribute and crop method | 
| # 97-05-09 fl   Use PyImagingPaste method instead of image type | 
| # 97-05-12 fl   Minor tweaks to match the IFUNC95 interface | 
| # 97-05-17 fl   Support the "pilbitmap" booster patch | 
| # 97-06-05 fl   Added file= and data= argument to image constructors | 
| # 98-03-09 fl   Added width and height methods to Image classes | 
| # 98-07-02 fl   Use default mode for "P" images without palette attribute | 
| # 98-07-02 fl   Explicitly destroy Tkinter image objects | 
| # 99-07-24 fl   Support multiple Tk interpreters (from Greg Couch) | 
| # 99-07-26 fl   Automatically hook into Tkinter (if possible) | 
| # 99-08-15 fl   Hook uses _imagingtk instead of _imaging | 
| # | 
| # Copyright (c) 1997-1999 by Secret Labs AB | 
| # Copyright (c) 1996-1997 by Fredrik Lundh | 
| # | 
| # See the README file for information on usage and redistribution. | 
| # | 
|   | 
| import Tkinter, Image | 
|   | 
| ## | 
| # The <b>ImageTk</b> module contains support to create and modify | 
| # Tkinter <b>BitmapImage</b> and <b>PhotoImage</b> objects. | 
| # <p> | 
| # For examples, see the demo programs in the <i>Scripts</i> | 
| # directory. | 
| ## | 
|   | 
| # -------------------------------------------------------------------- | 
| # Check for Tkinter interface hooks | 
|   | 
| _pilbitmap_ok = None | 
|   | 
| def _pilbitmap_check(): | 
|     global _pilbitmap_ok | 
|     if _pilbitmap_ok is None: | 
|         try: | 
|             im = Image.new("1", (1,1)) | 
|             Tkinter.BitmapImage(data="PIL:%d" % im.im.id) | 
|             _pilbitmap_ok = 1 | 
|         except Tkinter.TclError: | 
|             _pilbitmap_ok = 0 | 
|     return _pilbitmap_ok | 
|   | 
| # -------------------------------------------------------------------- | 
| # PhotoImage | 
|   | 
| ## | 
| # Creates a Tkinter-compatible photo image.  This can be used | 
| # everywhere Tkinter expects an image object.  If the image is an RGBA | 
| # image, pixels having alpha 0 are treated as transparent. | 
|   | 
| class PhotoImage: | 
|   | 
|     ## | 
|     # Create a photo image object. The constructor takes either | 
|     # a PIL image, or a mode and a size.  Alternatively, you can | 
|     # use the <b>file</b> or <b>data</b> options to initialize | 
|     # the photo image object. | 
|     # <p> | 
|     # @def __init__(image=None, size=None, **options) | 
|     # @param image Either a PIL image, or a mode string.  If a | 
|     #    mode string is used, a size must also be given. | 
|     # @param size If the first argument is a mode string, this | 
|     #    defines the size of the image. | 
|     # @keyparam file A filename to load the image from (using | 
|     #    Image.open(file)). | 
|     # @keyparam data An 8-bit string containing image data (as | 
|     #    loaded from an image file). | 
|   | 
|     def __init__(self, image=None, size=None, **kw): | 
|   | 
|         # Tk compatibility: file or data | 
|         if image is None: | 
|             if kw.has_key("file"): | 
|                 image = Image.open(kw["file"]) | 
|                 del kw["file"] | 
|             elif kw.has_key("data"): | 
|                 from StringIO import StringIO | 
|                 image = Image.open(StringIO(kw["data"])) | 
|                 del kw["data"] | 
|   | 
|         if hasattr(image, "mode") and hasattr(image, "size"): | 
|             # got an image instead of a mode | 
|             mode = image.mode | 
|             if mode == "P": | 
|                 # palette mapped data | 
|                 image.load() | 
|                 try: | 
|                     mode = image.palette.mode | 
|                 except AttributeError: | 
|                     mode = "RGB" # default | 
|             size = image.size | 
|             kw["width"], kw["height"] = size | 
|         else: | 
|             mode = image | 
|             image = None | 
|   | 
|         if mode not in ["1", "L", "RGB", "RGBA"]: | 
|             mode = Image.getmodebase(mode) | 
|   | 
|         self.__mode = mode | 
|         self.__size = size | 
|         self.__photo = apply(Tkinter.PhotoImage, (), kw) | 
|         self.tk = self.__photo.tk | 
|         if image: | 
|             self.paste(image) | 
|   | 
|     def __del__(self): | 
|         name = self.__photo.name | 
|         self.__photo.name = None | 
|         try: | 
|             self.__photo.tk.call("image", "delete", name) | 
|         except: | 
|             pass # ignore internal errors | 
|   | 
|     ## | 
|     # Get the Tkinter photo image identifier.  This method is | 
|     # automatically called by Tkinter whenever a PhotoImage object is | 
|     # passed to a Tkinter method. | 
|     # | 
|     # @return A Tkinter photo image identifier (a string). | 
|   | 
|     def __str__(self): | 
|         return str(self.__photo) | 
|   | 
|     ## | 
|     # Get the width of the image. | 
|     # | 
|     # @return The width, in pixels. | 
|   | 
|     def width(self): | 
|         return self.__size[0] | 
|   | 
|     ## | 
|     # Get the height of the image. | 
|     # | 
|     # @return The height, in pixels. | 
|   | 
|     def height(self): | 
|         return self.__size[1] | 
|   | 
|     ## | 
|     # Paste a PIL image into the photo image.  Note that this can | 
|     # be very slow if the photo image is displayed. | 
|     # | 
|     # @param im A PIL image.  The size must match the target region. | 
|     #    If the mode does not match, the image is converted to the | 
|     #    mode of the bitmap image. | 
|     # @param box A 4-tuple defining the left, upper, right, and | 
|     #    lower pixel coordinate.  If None is given instead of a | 
|     #    tuple, all of the image is assumed. | 
|   | 
|     def paste(self, im, box=None): | 
|   | 
|         # convert to blittable | 
|         im.load() | 
|         image = im.im | 
|         if image.isblock() and im.mode == self.__mode: | 
|             block = image | 
|         else: | 
|             block = image.new_block(self.__mode, im.size) | 
|             image.convert2(block, image) # convert directly between buffers | 
|   | 
|         tk = self.__photo.tk | 
|   | 
|         try: | 
|             tk.call("PyImagingPhoto", self.__photo, block.id) | 
|         except Tkinter.TclError, v: | 
|             # activate Tkinter hook | 
|             try: | 
|                 import _imagingtk | 
|                 try: | 
|                     _imagingtk.tkinit(tk.interpaddr(), 1) | 
|                 except AttributeError: | 
|                     _imagingtk.tkinit(id(tk), 0) | 
|                 tk.call("PyImagingPhoto", self.__photo, block.id) | 
|             except (ImportError, AttributeError, Tkinter.TclError): | 
|                 raise # configuration problem; cannot attach to Tkinter | 
|   | 
| # -------------------------------------------------------------------- | 
| # BitmapImage | 
|   | 
| ## | 
| # Create a Tkinter-compatible bitmap image.  This can be used | 
| # everywhere Tkinter expects an image object. | 
|   | 
| class BitmapImage: | 
|   | 
|     ## | 
|     # Create a Tkinter-compatible bitmap image. | 
|     # <p> | 
|     # The given image must have mode "1".  Pixels having value 0 are | 
|     # treated as transparent.  Options, if any, are passed on to | 
|     # Tkinter.  The most commonly used option is <b>foreground</b>, | 
|     # which is used to specify the colour for the non-transparent | 
|     # parts.  See the Tkinter documentation for information on how to | 
|     # specify colours. | 
|     # | 
|     # @def __init__(image=None, **options) | 
|     # @param image A PIL image. | 
|   | 
|     def __init__(self, image=None, **kw): | 
|   | 
|         # Tk compatibility: file or data | 
|         if image is None: | 
|             if kw.has_key("file"): | 
|                 image = Image.open(kw["file"]) | 
|                 del kw["file"] | 
|             elif kw.has_key("data"): | 
|                 from StringIO import StringIO | 
|                 image = Image.open(StringIO(kw["data"])) | 
|                 del kw["data"] | 
|   | 
|         self.__mode = image.mode | 
|         self.__size = image.size | 
|   | 
|         if _pilbitmap_check(): | 
|             # fast way (requires the pilbitmap booster patch) | 
|             image.load() | 
|             kw["data"] = "PIL:%d" % image.im.id | 
|             self.__im = image # must keep a reference | 
|         else: | 
|             # slow but safe way | 
|             kw["data"] = image.tobitmap() | 
|         self.__photo = apply(Tkinter.BitmapImage, (), kw) | 
|   | 
|     def __del__(self): | 
|         name = self.__photo.name | 
|         self.__photo.name = None | 
|         try: | 
|             self.__photo.tk.call("image", "delete", name) | 
|         except: | 
|             pass # ignore internal errors | 
|   | 
|     ## | 
|     # Get the width of the image. | 
|     # | 
|     # @return The width, in pixels. | 
|   | 
|     def width(self): | 
|         return self.__size[0] | 
|   | 
|     ## | 
|     # Get the height of the image. | 
|     # | 
|     # @return The height, in pixels. | 
|   | 
|     def height(self): | 
|         return self.__size[1] | 
|   | 
|     ## | 
|     # Get the Tkinter bitmap image identifier.  This method is | 
|     # automatically called by Tkinter whenever a BitmapImage object | 
|     # is passed to a Tkinter method. | 
|     # | 
|     # @return A Tkinter bitmap image identifier (a string). | 
|   | 
|     def __str__(self): | 
|         return str(self.__photo) | 
|   | 
| ## | 
| # Copies the contents of a PhotoImage to a PIL image memory. | 
|   | 
| def getimage(photo): | 
|     photo.tk.call("PyImagingPhotoGet", photo) | 
|   | 
| # -------------------------------------------------------------------- | 
| # Helper for the Image.show method. | 
|   | 
| def _show(image, title): | 
|   | 
|     class UI(Tkinter.Label): | 
|         def __init__(self, master, im): | 
|             if im.mode == "1": | 
|                 self.image = BitmapImage(im, foreground="white", master=master) | 
|             else: | 
|                 self.image = PhotoImage(im, master=master) | 
|             Tkinter.Label.__init__(self, master, image=self.image, | 
|                 bg="black", bd=0) | 
|   | 
|     if not Tkinter._default_root: | 
|         raise IOError, "tkinter not initialized" | 
|     top = Tkinter.Toplevel() | 
|     if title: | 
|         top.title(title) | 
|     UI(top, image).pack() |