ImageTk.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # a Tk display interface
  6. #
  7. # History:
  8. # 96-04-08 fl Created
  9. # 96-09-06 fl Added getimage method
  10. # 96-11-01 fl Rewritten, removed image attribute and crop method
  11. # 97-05-09 fl Use PyImagingPaste method instead of image type
  12. # 97-05-12 fl Minor tweaks to match the IFUNC95 interface
  13. # 97-05-17 fl Support the "pilbitmap" booster patch
  14. # 97-06-05 fl Added file= and data= argument to image constructors
  15. # 98-03-09 fl Added width and height methods to Image classes
  16. # 98-07-02 fl Use default mode for "P" images without palette attribute
  17. # 98-07-02 fl Explicitly destroy Tkinter image objects
  18. # 99-07-24 fl Support multiple Tk interpreters (from Greg Couch)
  19. # 99-07-26 fl Automatically hook into Tkinter (if possible)
  20. # 99-08-15 fl Hook uses _imagingtk instead of _imaging
  21. #
  22. # Copyright (c) 1997-1999 by Secret Labs AB
  23. # Copyright (c) 1996-1997 by Fredrik Lundh
  24. #
  25. # See the README file for information on usage and redistribution.
  26. #
  27. from __future__ import annotations
  28. import tkinter
  29. from io import BytesIO
  30. from typing import TYPE_CHECKING, Any, cast
  31. from . import Image, ImageFile
  32. if TYPE_CHECKING:
  33. from ._typing import CapsuleType
  34. # --------------------------------------------------------------------
  35. # Check for Tkinter interface hooks
  36. def _get_image_from_kw(kw: dict[str, Any]) -> ImageFile.ImageFile | None:
  37. source = None
  38. if "file" in kw:
  39. source = kw.pop("file")
  40. elif "data" in kw:
  41. source = BytesIO(kw.pop("data"))
  42. if not source:
  43. return None
  44. return Image.open(source)
  45. def _pyimagingtkcall(
  46. command: str, photo: PhotoImage | tkinter.PhotoImage, ptr: CapsuleType
  47. ) -> None:
  48. tk = photo.tk
  49. try:
  50. tk.call(command, photo, repr(ptr))
  51. except tkinter.TclError:
  52. # activate Tkinter hook
  53. # may raise an error if it cannot attach to Tkinter
  54. from . import _imagingtk
  55. _imagingtk.tkinit(tk.interpaddr())
  56. tk.call(command, photo, repr(ptr))
  57. # --------------------------------------------------------------------
  58. # PhotoImage
  59. class PhotoImage:
  60. """
  61. A Tkinter-compatible photo image. This can be used
  62. everywhere Tkinter expects an image object. If the image is an RGBA
  63. image, pixels having alpha 0 are treated as transparent.
  64. The constructor takes either a PIL image, or a mode and a size.
  65. Alternatively, you can use the ``file`` or ``data`` options to initialize
  66. the photo image object.
  67. :param image: Either a PIL image, or a mode string. If a mode string is
  68. used, a size must also be given.
  69. :param size: If the first argument is a mode string, this defines the size
  70. of the image.
  71. :keyword file: A filename to load the image from (using
  72. ``Image.open(file)``).
  73. :keyword data: An 8-bit string containing image data (as loaded from an
  74. image file).
  75. """
  76. def __init__(
  77. self,
  78. image: Image.Image | str | None = None,
  79. size: tuple[int, int] | None = None,
  80. **kw: Any,
  81. ) -> None:
  82. # Tk compatibility: file or data
  83. if image is None:
  84. image = _get_image_from_kw(kw)
  85. if image is None:
  86. msg = "Image is required"
  87. raise ValueError(msg)
  88. elif isinstance(image, str):
  89. mode = image
  90. image = None
  91. if size is None:
  92. msg = "If first argument is mode, size is required"
  93. raise ValueError(msg)
  94. else:
  95. # got an image instead of a mode
  96. mode = image.mode
  97. if mode == "P":
  98. # palette mapped data
  99. image.apply_transparency()
  100. image.load()
  101. mode = image.palette.mode if image.palette else "RGB"
  102. size = image.size
  103. kw["width"], kw["height"] = size
  104. if mode not in ["1", "L", "RGB", "RGBA"]:
  105. mode = Image.getmodebase(mode)
  106. self.__mode = mode
  107. self.__size = size
  108. self.__photo = tkinter.PhotoImage(**kw)
  109. self.tk = self.__photo.tk
  110. if image:
  111. self.paste(image)
  112. def __del__(self) -> None:
  113. try:
  114. name = self.__photo.name
  115. except AttributeError:
  116. return
  117. self.__photo.name = None
  118. try:
  119. self.__photo.tk.call("image", "delete", name)
  120. except Exception:
  121. pass # ignore internal errors
  122. def __str__(self) -> str:
  123. """
  124. Get the Tkinter photo image identifier. This method is automatically
  125. called by Tkinter whenever a PhotoImage object is passed to a Tkinter
  126. method.
  127. :return: A Tkinter photo image identifier (a string).
  128. """
  129. return str(self.__photo)
  130. def width(self) -> int:
  131. """
  132. Get the width of the image.
  133. :return: The width, in pixels.
  134. """
  135. return self.__size[0]
  136. def height(self) -> int:
  137. """
  138. Get the height of the image.
  139. :return: The height, in pixels.
  140. """
  141. return self.__size[1]
  142. def paste(self, im: Image.Image) -> None:
  143. """
  144. Paste a PIL image into the photo image. Note that this can
  145. be very slow if the photo image is displayed.
  146. :param im: A PIL image. The size must match the target region. If the
  147. mode does not match, the image is converted to the mode of
  148. the bitmap image.
  149. """
  150. # convert to blittable
  151. ptr = im.getim()
  152. image = im.im
  153. if not image.isblock() or im.mode != self.__mode:
  154. block = Image.core.new_block(self.__mode, im.size)
  155. image.convert2(block, image) # convert directly between buffers
  156. ptr = block.ptr
  157. _pyimagingtkcall("PyImagingPhoto", self.__photo, ptr)
  158. # --------------------------------------------------------------------
  159. # BitmapImage
  160. class BitmapImage:
  161. """
  162. A Tkinter-compatible bitmap image. This can be used everywhere Tkinter
  163. expects an image object.
  164. The given image must have mode "1". Pixels having value 0 are treated as
  165. transparent. Options, if any, are passed on to Tkinter. The most commonly
  166. used option is ``foreground``, which is used to specify the color for the
  167. non-transparent parts. See the Tkinter documentation for information on
  168. how to specify colours.
  169. :param image: A PIL image.
  170. """
  171. def __init__(self, image: Image.Image | None = None, **kw: Any) -> None:
  172. # Tk compatibility: file or data
  173. if image is None:
  174. image = _get_image_from_kw(kw)
  175. if image is None:
  176. msg = "Image is required"
  177. raise ValueError(msg)
  178. self.__mode = image.mode
  179. self.__size = image.size
  180. self.__photo = tkinter.BitmapImage(data=image.tobitmap(), **kw)
  181. def __del__(self) -> None:
  182. try:
  183. name = self.__photo.name
  184. except AttributeError:
  185. return
  186. self.__photo.name = None
  187. try:
  188. self.__photo.tk.call("image", "delete", name)
  189. except Exception:
  190. pass # ignore internal errors
  191. def width(self) -> int:
  192. """
  193. Get the width of the image.
  194. :return: The width, in pixels.
  195. """
  196. return self.__size[0]
  197. def height(self) -> int:
  198. """
  199. Get the height of the image.
  200. :return: The height, in pixels.
  201. """
  202. return self.__size[1]
  203. def __str__(self) -> str:
  204. """
  205. Get the Tkinter bitmap image identifier. This method is automatically
  206. called by Tkinter whenever a BitmapImage object is passed to a Tkinter
  207. method.
  208. :return: A Tkinter bitmap image identifier (a string).
  209. """
  210. return str(self.__photo)
  211. def getimage(photo: PhotoImage) -> Image.Image:
  212. """Copies the contents of a PhotoImage to a PIL image memory."""
  213. im = Image.new("RGBA", (photo.width(), photo.height()))
  214. _pyimagingtkcall("PyImagingPhotoGet", photo, im.getim())
  215. return im
  216. def _show(image: Image.Image, title: str | None) -> None:
  217. """Helper for the Image.show method."""
  218. class UI(tkinter.Label):
  219. def __init__(self, master: tkinter.Toplevel, im: Image.Image) -> None:
  220. self.image: BitmapImage | PhotoImage
  221. if im.mode == "1":
  222. self.image = BitmapImage(im, foreground="white", master=master)
  223. else:
  224. self.image = PhotoImage(im, master=master)
  225. if TYPE_CHECKING:
  226. image = cast(tkinter._Image, self.image)
  227. else:
  228. image = self.image
  229. super().__init__(master, image=image, bg="black", bd=0)
  230. if not getattr(tkinter, "_default_root"):
  231. msg = "tkinter not initialized"
  232. raise OSError(msg)
  233. top = tkinter.Toplevel()
  234. if title:
  235. top.title(title)
  236. UI(top, image).pack()