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