ImageWin.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # a Windows DIB display interface
  6. #
  7. # History:
  8. # 1996-05-20 fl Created
  9. # 1996-09-20 fl Fixed subregion exposure
  10. # 1997-09-21 fl Added draw primitive (for tzPrint)
  11. # 2003-05-21 fl Added experimental Window/ImageWindow classes
  12. # 2003-09-05 fl Added fromstring/tostring methods
  13. #
  14. # Copyright (c) Secret Labs AB 1997-2003.
  15. # Copyright (c) Fredrik Lundh 1996-2003.
  16. #
  17. # See the README file for information on usage and redistribution.
  18. #
  19. from __future__ import annotations
  20. from . import Image
  21. class HDC:
  22. """
  23. Wraps an HDC integer. The resulting object can be passed to the
  24. :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
  25. methods.
  26. """
  27. def __init__(self, dc):
  28. self.dc = dc
  29. def __int__(self):
  30. return self.dc
  31. class HWND:
  32. """
  33. Wraps an HWND integer. The resulting object can be passed to the
  34. :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
  35. methods, instead of a DC.
  36. """
  37. def __init__(self, wnd):
  38. self.wnd = wnd
  39. def __int__(self):
  40. return self.wnd
  41. class Dib:
  42. """
  43. A Windows bitmap with the given mode and size. The mode can be one of "1",
  44. "L", "P", or "RGB".
  45. If the display requires a palette, this constructor creates a suitable
  46. palette and associates it with the image. For an "L" image, 128 graylevels
  47. are allocated. For an "RGB" image, a 6x6x6 colour cube is used, together
  48. with 20 graylevels.
  49. To make sure that palettes work properly under Windows, you must call the
  50. ``palette`` method upon certain events from Windows.
  51. :param image: Either a PIL image, or a mode string. If a mode string is
  52. used, a size must also be given. The mode can be one of "1",
  53. "L", "P", or "RGB".
  54. :param size: If the first argument is a mode string, this
  55. defines the size of the image.
  56. """
  57. def __init__(self, image, size=None):
  58. if hasattr(image, "mode") and hasattr(image, "size"):
  59. mode = image.mode
  60. size = image.size
  61. else:
  62. mode = image
  63. image = None
  64. if mode not in ["1", "L", "P", "RGB"]:
  65. mode = Image.getmodebase(mode)
  66. self.image = Image.core.display(mode, size)
  67. self.mode = mode
  68. self.size = size
  69. if image:
  70. self.paste(image)
  71. def expose(self, handle):
  72. """
  73. Copy the bitmap contents to a device context.
  74. :param handle: Device context (HDC), cast to a Python integer, or an
  75. HDC or HWND instance. In PythonWin, you can use
  76. ``CDC.GetHandleAttrib()`` to get a suitable handle.
  77. """
  78. if isinstance(handle, HWND):
  79. dc = self.image.getdc(handle)
  80. try:
  81. result = self.image.expose(dc)
  82. finally:
  83. self.image.releasedc(handle, dc)
  84. else:
  85. result = self.image.expose(handle)
  86. return result
  87. def draw(self, handle, dst, src=None):
  88. """
  89. Same as expose, but allows you to specify where to draw the image, and
  90. what part of it to draw.
  91. The destination and source areas are given as 4-tuple rectangles. If
  92. the source is omitted, the entire image is copied. If the source and
  93. the destination have different sizes, the image is resized as
  94. necessary.
  95. """
  96. if not src:
  97. src = (0, 0) + self.size
  98. if isinstance(handle, HWND):
  99. dc = self.image.getdc(handle)
  100. try:
  101. result = self.image.draw(dc, dst, src)
  102. finally:
  103. self.image.releasedc(handle, dc)
  104. else:
  105. result = self.image.draw(handle, dst, src)
  106. return result
  107. def query_palette(self, handle):
  108. """
  109. Installs the palette associated with the image in the given device
  110. context.
  111. This method should be called upon **QUERYNEWPALETTE** and
  112. **PALETTECHANGED** events from Windows. If this method returns a
  113. non-zero value, one or more display palette entries were changed, and
  114. the image should be redrawn.
  115. :param handle: Device context (HDC), cast to a Python integer, or an
  116. HDC or HWND instance.
  117. :return: A true value if one or more entries were changed (this
  118. indicates that the image should be redrawn).
  119. """
  120. if isinstance(handle, HWND):
  121. handle = self.image.getdc(handle)
  122. try:
  123. result = self.image.query_palette(handle)
  124. finally:
  125. self.image.releasedc(handle, handle)
  126. else:
  127. result = self.image.query_palette(handle)
  128. return result
  129. def paste(self, im, box=None):
  130. """
  131. Paste a PIL image into the bitmap image.
  132. :param im: A PIL image. The size must match the target region.
  133. If the mode does not match, the image is converted to the
  134. mode of the bitmap image.
  135. :param box: A 4-tuple defining the left, upper, right, and
  136. lower pixel coordinate. See :ref:`coordinate-system`. If
  137. None is given instead of a tuple, all of the image is
  138. assumed.
  139. """
  140. im.load()
  141. if self.mode != im.mode:
  142. im = im.convert(self.mode)
  143. if box:
  144. self.image.paste(im.im, box)
  145. else:
  146. self.image.paste(im.im)
  147. def frombytes(self, buffer):
  148. """
  149. Load display memory contents from byte data.
  150. :param buffer: A buffer containing display data (usually
  151. data returned from :py:func:`~PIL.ImageWin.Dib.tobytes`)
  152. """
  153. return self.image.frombytes(buffer)
  154. def tobytes(self):
  155. """
  156. Copy display memory contents to bytes object.
  157. :return: A bytes object containing display data.
  158. """
  159. return self.image.tobytes()
  160. class Window:
  161. """Create a Window with the given title size."""
  162. def __init__(self, title="PIL", width=None, height=None):
  163. self.hwnd = Image.core.createwindow(
  164. title, self.__dispatcher, width or 0, height or 0
  165. )
  166. def __dispatcher(self, action, *args):
  167. return getattr(self, "ui_handle_" + action)(*args)
  168. def ui_handle_clear(self, dc, x0, y0, x1, y1):
  169. pass
  170. def ui_handle_damage(self, x0, y0, x1, y1):
  171. pass
  172. def ui_handle_destroy(self):
  173. pass
  174. def ui_handle_repair(self, dc, x0, y0, x1, y1):
  175. pass
  176. def ui_handle_resize(self, width, height):
  177. pass
  178. def mainloop(self):
  179. Image.core.eventloop()
  180. class ImageWindow(Window):
  181. """Create an image window which displays the given image."""
  182. def __init__(self, image, title="PIL"):
  183. if not isinstance(image, Dib):
  184. image = Dib(image)
  185. self.image = image
  186. width, height = image.size
  187. super().__init__(title, width=width, height=height)
  188. def ui_handle_repair(self, dc, x0, y0, x1, y1):
  189. self.image.draw(dc, (x0, y0, x1, y1))