|
|
- #
- # 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 sys
-
- if sys.version_info.major > 2:
- import tkinter
- else:
- import Tkinter as tkinter
-
- from . import Image
- from io import BytesIO
-
-
- # --------------------------------------------------------------------
- # 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
-
-
- def _get_image_from_kw(kw):
- source = None
- if "file" in kw:
- source = kw.pop("file")
- elif "data" in kw:
- source = BytesIO(kw.pop("data"))
- if source:
- return Image.open(source)
-
-
- # --------------------------------------------------------------------
- # PhotoImage
-
- class PhotoImage(object):
- """
- 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.
-
- The constructor takes either a PIL image, or a mode and a size.
- Alternatively, you can use the **file** or **data** options to initialize
- the photo image object.
-
- :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.
- :keyword file: A filename to load the image from (using
- ``Image.open(file)``).
- :keyword 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:
- image = _get_image_from_kw(kw)
-
- 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 = 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
-
- def __str__(self):
- """
- 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).
- """
- return str(self.__photo)
-
- def width(self):
- """
- Get the width of the image.
-
- :return: The width, in pixels.
- """
- return self.__size[0]
-
- def height(self):
- """
- Get the height of the image.
-
- :return: The height, in pixels.
- """
- return self.__size[1]
-
- def paste(self, im, box=None):
- """
- 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. See :ref:`coordinate-system`. If None is given
- instead of a tuple, all of the image is assumed.
- """
-
- # 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:
- # activate Tkinter hook
- try:
- from . import _imagingtk
- try:
- if hasattr(tk, 'interp'):
- # Required for PyPy, which always has CFFI installed
- from cffi import FFI
- ffi = FFI()
-
- # PyPy is using an FFI CDATA element
- # (Pdb) self.tk.interp
- # <cdata 'Tcl_Interp *' 0x3061b50>
- _imagingtk.tkinit(
- int(ffi.cast("uintptr_t", tk.interp)), 1)
- else:
- _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
-
-
- class BitmapImage(object):
- """
- A Tkinter-compatible bitmap image. This can be used everywhere Tkinter
- expects an image object.
-
- 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 **foreground**, which is used to specify the color for the
- non-transparent parts. See the Tkinter documentation for information on
- how to specify colours.
-
- :param image: A PIL image.
- """
-
- def __init__(self, image=None, **kw):
-
- # Tk compatibility: file or data
- if image is None:
- image = _get_image_from_kw(kw)
-
- 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 = 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
-
- def width(self):
- """
- Get the width of the image.
-
- :return: The width, in pixels.
- """
- return self.__size[0]
-
- def height(self):
- """
- Get the height of the image.
-
- :return: The height, in pixels.
- """
- return self.__size[1]
-
- def __str__(self):
- """
- 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).
- """
- return str(self.__photo)
-
-
- def getimage(photo):
- """ This function is unimplemented """
-
- """Copies the contents of a PhotoImage to a PIL image memory."""
- photo.tk.call("PyImagingPhotoGet", photo)
-
-
- def _show(image, title):
- """Helper for the Image.show method."""
-
- 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()
|