| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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)) |
|
|