Spaces:
Sleeping
Sleeping
| # | |
| # 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. | |
| # | |
| from __future__ import annotations | |
| import tkinter | |
| from io import BytesIO | |
| from typing import TYPE_CHECKING, Any, cast | |
| from . import Image, ImageFile | |
| if TYPE_CHECKING: | |
| from ._typing import CapsuleType | |
| # -------------------------------------------------------------------- | |
| # Check for Tkinter interface hooks | |
| def _get_image_from_kw(kw: dict[str, Any]) -> ImageFile.ImageFile | None: | |
| source = None | |
| if "file" in kw: | |
| source = kw.pop("file") | |
| elif "data" in kw: | |
| source = BytesIO(kw.pop("data")) | |
| if not source: | |
| return None | |
| return Image.open(source) | |
| def _pyimagingtkcall( | |
| command: str, photo: PhotoImage | tkinter.PhotoImage, ptr: CapsuleType | |
| ) -> None: | |
| tk = photo.tk | |
| try: | |
| tk.call(command, photo, repr(ptr)) | |
| except tkinter.TclError: | |
| # activate Tkinter hook | |
| # may raise an error if it cannot attach to Tkinter | |
| from . import _imagingtk | |
| _imagingtk.tkinit(tk.interpaddr()) | |
| tk.call(command, photo, repr(ptr)) | |
| # -------------------------------------------------------------------- | |
| # PhotoImage | |
| class PhotoImage: | |
| """ | |
| 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: Image.Image | str | None = None, | |
| size: tuple[int, int] | None = None, | |
| **kw: Any, | |
| ) -> None: | |
| # Tk compatibility: file or data | |
| if image is None: | |
| image = _get_image_from_kw(kw) | |
| if image is None: | |
| msg = "Image is required" | |
| raise ValueError(msg) | |
| elif isinstance(image, str): | |
| mode = image | |
| image = None | |
| if size is None: | |
| msg = "If first argument is mode, size is required" | |
| raise ValueError(msg) | |
| else: | |
| # got an image instead of a mode | |
| mode = image.mode | |
| if mode == "P": | |
| # palette mapped data | |
| image.apply_transparency() | |
| image.load() | |
| mode = image.palette.mode if image.palette else "RGB" | |
| size = image.size | |
| kw["width"], kw["height"] = size | |
| 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) -> None: | |
| try: | |
| name = self.__photo.name | |
| except AttributeError: | |
| return | |
| self.__photo.name = None | |
| try: | |
| self.__photo.tk.call("image", "delete", name) | |
| except Exception: | |
| pass # ignore internal errors | |
| def __str__(self) -> str: | |
| """ | |
| 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) -> int: | |
| """ | |
| Get the width of the image. | |
| :return: The width, in pixels. | |
| """ | |
| return self.__size[0] | |
| def height(self) -> int: | |
| """ | |
| Get the height of the image. | |
| :return: The height, in pixels. | |
| """ | |
| return self.__size[1] | |
| def paste(self, im: Image.Image) -> 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. | |
| """ | |
| # convert to blittable | |
| ptr = im.getim() | |
| image = im.im | |
| if not image.isblock() or im.mode != self.__mode: | |
| block = Image.core.new_block(self.__mode, im.size) | |
| image.convert2(block, image) # convert directly between buffers | |
| ptr = block.ptr | |
| _pyimagingtkcall("PyImagingPhoto", self.__photo, ptr) | |
| # -------------------------------------------------------------------- | |
| # BitmapImage | |
| class BitmapImage: | |
| """ | |
| 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: Image.Image | None = None, **kw: Any) -> None: | |
| # Tk compatibility: file or data | |
| if image is None: | |
| image = _get_image_from_kw(kw) | |
| if image is None: | |
| msg = "Image is required" | |
| raise ValueError(msg) | |
| self.__mode = image.mode | |
| self.__size = image.size | |
| self.__photo = tkinter.BitmapImage(data=image.tobitmap(), **kw) | |
| def __del__(self) -> None: | |
| try: | |
| name = self.__photo.name | |
| except AttributeError: | |
| return | |
| self.__photo.name = None | |
| try: | |
| self.__photo.tk.call("image", "delete", name) | |
| except Exception: | |
| pass # ignore internal errors | |
| def width(self) -> int: | |
| """ | |
| Get the width of the image. | |
| :return: The width, in pixels. | |
| """ | |
| return self.__size[0] | |
| def height(self) -> int: | |
| """ | |
| Get the height of the image. | |
| :return: The height, in pixels. | |
| """ | |
| return self.__size[1] | |
| def __str__(self) -> str: | |
| """ | |
| 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: PhotoImage) -> Image.Image: | |
| """Copies the contents of a PhotoImage to a PIL image memory.""" | |
| im = Image.new("RGBA", (photo.width(), photo.height())) | |
| _pyimagingtkcall("PyImagingPhotoGet", photo, im.getim()) | |
| return im | |
| def _show(image: Image.Image, title: str | None) -> None: | |
| """Helper for the Image.show method.""" | |
| class UI(tkinter.Label): | |
| def __init__(self, master: tkinter.Toplevel, im: Image.Image) -> None: | |
| self.image: BitmapImage | PhotoImage | |
| if im.mode == "1": | |
| self.image = BitmapImage(im, foreground="white", master=master) | |
| else: | |
| self.image = PhotoImage(im, master=master) | |
| if TYPE_CHECKING: | |
| image = cast(tkinter._Image, self.image) | |
| else: | |
| image = self.image | |
| super().__init__(master, image=image, bg="black", bd=0) | |
| if not getattr(tkinter, "_default_root"): | |
| msg = "tkinter not initialized" | |
| raise OSError(msg) | |
| top = tkinter.Toplevel() | |
| if title: | |
| top.title(title) | |
| UI(top, image).pack() | |