Spaces:
Running
Running
# | |
# The Python Imaging Library. | |
# $Id$ | |
# | |
# a Windows DIB display interface | |
# | |
# History: | |
# 1996-05-20 fl Created | |
# 1996-09-20 fl Fixed subregion exposure | |
# 1997-09-21 fl Added draw primitive (for tzPrint) | |
# 2003-05-21 fl Added experimental Window/ImageWindow classes | |
# 2003-09-05 fl Added fromstring/tostring methods | |
# | |
# Copyright (c) Secret Labs AB 1997-2003. | |
# Copyright (c) Fredrik Lundh 1996-2003. | |
# | |
# See the README file for information on usage and redistribution. | |
# | |
from __future__ import annotations | |
from . import Image | |
class HDC: | |
""" | |
Wraps an HDC integer. The resulting object can be passed to the | |
:py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` | |
methods. | |
""" | |
def __init__(self, dc: int) -> None: | |
self.dc = dc | |
def __int__(self) -> int: | |
return self.dc | |
class HWND: | |
""" | |
Wraps an HWND integer. The resulting object can be passed to the | |
:py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose` | |
methods, instead of a DC. | |
""" | |
def __init__(self, wnd: int) -> None: | |
self.wnd = wnd | |
def __int__(self) -> int: | |
return self.wnd | |
class Dib: | |
""" | |
A Windows bitmap with the given mode and size. The mode can be one of "1", | |
"L", "P", or "RGB". | |
If the display requires a palette, this constructor creates a suitable | |
palette and associates it with the image. For an "L" image, 128 graylevels | |
are allocated. For an "RGB" image, a 6x6x6 colour cube is used, together | |
with 20 graylevels. | |
To make sure that palettes work properly under Windows, you must call the | |
``palette`` method upon certain events from Windows. | |
:param image: Either a PIL image, or a mode string. If a mode string is | |
used, a size must also be given. The mode can be one of "1", | |
"L", "P", or "RGB". | |
:param size: If the first argument is a mode string, this | |
defines the size of the image. | |
""" | |
def __init__( | |
self, image: Image.Image | str, size: tuple[int, int] | list[int] | None = None | |
) -> None: | |
if isinstance(image, str): | |
mode = image | |
image = "" | |
else: | |
mode = image.mode | |
size = image.size | |
if mode not in ["1", "L", "P", "RGB"]: | |
mode = Image.getmodebase(mode) | |
self.image = Image.core.display(mode, size) | |
self.mode = mode | |
self.size = size | |
if image: | |
assert not isinstance(image, str) | |
self.paste(image) | |
def expose(self, handle): | |
""" | |
Copy the bitmap contents to a device context. | |
:param handle: Device context (HDC), cast to a Python integer, or an | |
HDC or HWND instance. In PythonWin, you can use | |
``CDC.GetHandleAttrib()`` to get a suitable handle. | |
""" | |
if isinstance(handle, HWND): | |
dc = self.image.getdc(handle) | |
try: | |
result = self.image.expose(dc) | |
finally: | |
self.image.releasedc(handle, dc) | |
else: | |
result = self.image.expose(handle) | |
return result | |
def draw(self, handle, dst, src=None): | |
""" | |
Same as expose, but allows you to specify where to draw the image, and | |
what part of it to draw. | |
The destination and source areas are given as 4-tuple rectangles. If | |
the source is omitted, the entire image is copied. If the source and | |
the destination have different sizes, the image is resized as | |
necessary. | |
""" | |
if not src: | |
src = (0, 0) + self.size | |
if isinstance(handle, HWND): | |
dc = self.image.getdc(handle) | |
try: | |
result = self.image.draw(dc, dst, src) | |
finally: | |
self.image.releasedc(handle, dc) | |
else: | |
result = self.image.draw(handle, dst, src) | |
return result | |
def query_palette(self, handle): | |
""" | |
Installs the palette associated with the image in the given device | |
context. | |
This method should be called upon **QUERYNEWPALETTE** and | |
**PALETTECHANGED** events from Windows. If this method returns a | |
non-zero value, one or more display palette entries were changed, and | |
the image should be redrawn. | |
:param handle: Device context (HDC), cast to a Python integer, or an | |
HDC or HWND instance. | |
:return: A true value if one or more entries were changed (this | |
indicates that the image should be redrawn). | |
""" | |
if isinstance(handle, HWND): | |
handle = self.image.getdc(handle) | |
try: | |
result = self.image.query_palette(handle) | |
finally: | |
self.image.releasedc(handle, handle) | |
else: | |
result = self.image.query_palette(handle) | |
return result | |
def paste( | |
self, im: Image.Image, box: tuple[int, int, int, int] | None = None | |
) -> None: | |
""" | |
Paste a PIL image into the bitmap image. | |
: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. | |
""" | |
im.load() | |
if self.mode != im.mode: | |
im = im.convert(self.mode) | |
if box: | |
self.image.paste(im.im, box) | |
else: | |
self.image.paste(im.im) | |
def frombytes(self, buffer: bytes) -> None: | |
""" | |
Load display memory contents from byte data. | |
:param buffer: A buffer containing display data (usually | |
data returned from :py:func:`~PIL.ImageWin.Dib.tobytes`) | |
""" | |
self.image.frombytes(buffer) | |
def tobytes(self) -> bytes: | |
""" | |
Copy display memory contents to bytes object. | |
:return: A bytes object containing display data. | |
""" | |
return self.image.tobytes() | |
class Window: | |
"""Create a Window with the given title size.""" | |
def __init__( | |
self, title: str = "PIL", width: int | None = None, height: int | None = None | |
) -> None: | |
self.hwnd = Image.core.createwindow( | |
title, self.__dispatcher, width or 0, height or 0 | |
) | |
def __dispatcher(self, action, *args): | |
return getattr(self, f"ui_handle_{action}")(*args) | |
def ui_handle_clear(self, dc, x0, y0, x1, y1): | |
pass | |
def ui_handle_damage(self, x0, y0, x1, y1): | |
pass | |
def ui_handle_destroy(self) -> None: | |
pass | |
def ui_handle_repair(self, dc, x0, y0, x1, y1): | |
pass | |
def ui_handle_resize(self, width, height): | |
pass | |
def mainloop(self) -> None: | |
Image.core.eventloop() | |
class ImageWindow(Window): | |
"""Create an image window which displays the given image.""" | |
def __init__(self, image, title="PIL"): | |
if not isinstance(image, Dib): | |
image = Dib(image) | |
self.image = image | |
width, height = image.size | |
super().__init__(title, width=width, height=height) | |
def ui_handle_repair(self, dc, x0, y0, x1, y1): | |
self.image.draw(dc, (x0, y0, x1, y1)) | |