mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-31 16:07:30 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			304 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			304 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #
 | |
| # 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.
 | |
| #
 | |
| 
 | |
| try:
 | |
|     import tkinter
 | |
| except ImportError:
 | |
|     import Tkinter
 | |
|     tkinter = Tkinter
 | |
|     del Tkinter
 | |
| 
 | |
| from PIL import 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 "file" in kw:
 | |
|                 image = Image.open(kw["file"])
 | |
|                 del kw["file"]
 | |
|             elif "data" in kw:
 | |
|                 from io import BytesIO
 | |
|                 image = Image.open(BytesIO(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 = 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 as v:
 | |
|             # activate Tkinter hook
 | |
|             try:
 | |
|                 from PIL 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 "file" in kw:
 | |
|                 image = Image.open(kw["file"])
 | |
|                 del kw["file"]
 | |
|             elif "data" in kw:
 | |
|                 from io import BytesIO
 | |
|                 image = Image.open(BytesIO(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 = 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()
 |