# 
 | 
# 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() 
 |