mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +03:00 
			
		
		
		
	Merge pull request #8032 from nulano/type_hints
Added type hints for PixelAccess related methods and others
This commit is contained in:
		
						commit
						d2b5e11d2b
					
				|  | @ -89,6 +89,7 @@ $bmp = New-Object Drawing.Bitmap 200, 200 | |||
|         p.communicate() | ||||
| 
 | ||||
|         im = ImageGrab.grabclipboard() | ||||
|         assert isinstance(im, list) | ||||
|         assert len(im) == 1 | ||||
|         assert os.path.samefile(im[0], "Tests/images/hopper.gif") | ||||
| 
 | ||||
|  | @ -105,6 +106,7 @@ $ms = new-object System.IO.MemoryStream(, $bytes) | |||
|         p.communicate() | ||||
| 
 | ||||
|         im = ImageGrab.grabclipboard() | ||||
|         assert isinstance(im, Image.Image) | ||||
|         assert_image_equal_tofile(im, "Tests/images/hopper.png") | ||||
| 
 | ||||
|     @pytest.mark.skipif( | ||||
|  | @ -120,6 +122,7 @@ $ms = new-object System.IO.MemoryStream(, $bytes) | |||
|         with open(image_path, "rb") as fp: | ||||
|             subprocess.call(["wl-copy"], stdin=fp) | ||||
|         im = ImageGrab.grabclipboard() | ||||
|         assert isinstance(im, Image.Image) | ||||
|         assert_image_equal_tofile(im, image_path) | ||||
| 
 | ||||
|     @pytest.mark.skipif( | ||||
|  |  | |||
|  | @ -691,23 +691,7 @@ Methods | |||
|     :param hints: An optional list of hints. | ||||
|     :returns: A (drawing context, drawing resource factory) tuple. | ||||
| 
 | ||||
| .. py:method:: floodfill(image, xy, value, border=None, thresh=0) | ||||
| 
 | ||||
|     .. warning:: This method is experimental. | ||||
| 
 | ||||
|     Fills a bounded region with a given color. | ||||
| 
 | ||||
|     :param image: Target image. | ||||
|     :param xy: Seed position (a 2-item coordinate tuple). | ||||
|     :param value: Fill color. | ||||
|     :param border: Optional border value.  If given, the region consists of | ||||
|         pixels with a color different from the border color.  If not given, | ||||
|         the region consists of pixels having the same color as the seed | ||||
|         pixel. | ||||
|     :param thresh: Optional threshold value which specifies a maximum | ||||
|         tolerable difference of a pixel value from the 'background' in | ||||
|         order for it to be replaced. Useful for filling regions of non- | ||||
|         homogeneous, but similar, colors. | ||||
| .. autofunction:: PIL.ImageDraw.floodfill | ||||
| 
 | ||||
| .. _BCP 47 language code: https://www.w3.org/International/articles/language-tags/ | ||||
| .. _OpenType docs: https://learn.microsoft.com/en-us/typography/opentype/spec/featurelist | ||||
|  |  | |||
|  | @ -44,42 +44,23 @@ Access using negative indexes is also possible. :: | |||
| ----------------------------- | ||||
| 
 | ||||
| .. class:: PixelAccess | ||||
|   :canonical: PIL.Image.core.PixelAccess | ||||
| 
 | ||||
|   .. method:: __setitem__(self, xy, color): | ||||
|   .. method:: __getitem__(self, xy: tuple[int, int]) -> float | tuple[int, ...] | ||||
| 
 | ||||
|         Modifies the pixel at x,y. The color is given as a single | ||||
|         numerical value for single band images, and a tuple for | ||||
|         multi-band images | ||||
| 
 | ||||
|         :param xy: The pixel coordinate, given as (x, y). | ||||
|         :param color: The pixel value according to its mode. e.g. tuple (r, g, b) for RGB mode) | ||||
| 
 | ||||
|   .. method:: __getitem__(self, xy): | ||||
| 
 | ||||
|        Returns the pixel at x,y. The pixel is returned as a single | ||||
|         value for single band images or a tuple for multiple band | ||||
|         images | ||||
|         Returns the pixel at x,y. The pixel is returned as a single | ||||
|         value for single band images or a tuple for multi-band images. | ||||
| 
 | ||||
|         :param xy: The pixel coordinate, given as (x, y). | ||||
|         :returns: a pixel value for single band images, a tuple of | ||||
|           pixel values for multiband images. | ||||
|                   pixel values for multiband images. | ||||
| 
 | ||||
|   .. method:: putpixel(self, xy, color): | ||||
|   .. method:: __setitem__(self, xy: tuple[int, int], color: float | tuple[int, ...]) -> None | ||||
| 
 | ||||
|         Modifies the pixel at x,y. The color is given as a single | ||||
|         numerical value for single band images, and a tuple for | ||||
|         multi-band images. In addition to this, RGB and RGBA tuples | ||||
|         are accepted for P and PA images. | ||||
|         multi-band images. | ||||
| 
 | ||||
|         :param xy: The pixel coordinate, given as (x, y). | ||||
|         :param color: The pixel value according to its mode. e.g. tuple (r, g, b) for RGB mode) | ||||
| 
 | ||||
|   .. method:: getpixel(self, xy): | ||||
| 
 | ||||
|        Returns the pixel at x,y. The pixel is returned as a single | ||||
|         value for single band images or a tuple for multiple band | ||||
|         images | ||||
| 
 | ||||
|         :param xy: The pixel coordinate, given as (x, y). | ||||
|         :returns: a pixel value for single band images, a tuple of | ||||
|           pixel values for multiband images. | ||||
|         :param color: The pixel value according to its mode, | ||||
|                       e.g. tuple (r, g, b) for RGB mode. | ||||
|  |  | |||
|  | @ -44,3 +44,4 @@ Access using negative indexes is also possible. :: | |||
| 
 | ||||
| .. autoclass:: PIL.PyAccess.PyAccess() | ||||
|     :members: | ||||
|     :special-members: __getitem__, __setitem__ | ||||
|  |  | |||
|  | @ -41,7 +41,16 @@ import warnings | |||
| from collections.abc import Callable, MutableMapping | ||||
| from enum import IntEnum | ||||
| from types import ModuleType | ||||
| from typing import IO, TYPE_CHECKING, Any, Literal, Protocol, Sequence, Tuple, cast | ||||
| from typing import ( | ||||
|     IO, | ||||
|     TYPE_CHECKING, | ||||
|     Any, | ||||
|     Literal, | ||||
|     Protocol, | ||||
|     Sequence, | ||||
|     Tuple, | ||||
|     cast, | ||||
| ) | ||||
| 
 | ||||
| # VERSION was removed in Pillow 6.0.0. | ||||
| # PILLOW_VERSION was removed in Pillow 9.0.0. | ||||
|  | @ -218,7 +227,7 @@ if hasattr(core, "DEFAULT_STRATEGY"): | |||
| # Registries | ||||
| 
 | ||||
| if TYPE_CHECKING: | ||||
|     from . import ImageFile | ||||
|     from . import ImageFile, PyAccess | ||||
| ID: list[str] = [] | ||||
| OPEN: dict[ | ||||
|     str, | ||||
|  | @ -871,7 +880,7 @@ class Image: | |||
|             msg = "cannot decode image data" | ||||
|             raise ValueError(msg) | ||||
| 
 | ||||
|     def load(self): | ||||
|     def load(self) -> core.PixelAccess | PyAccess.PyAccess | None: | ||||
|         """ | ||||
|         Allocates storage for the image and loads the pixel data.  In | ||||
|         normal cases, you don't need to call this method, since the | ||||
|  | @ -884,7 +893,7 @@ class Image: | |||
|         operations. See :ref:`file-handling` for more information. | ||||
| 
 | ||||
|         :returns: An image access object. | ||||
|         :rtype: :ref:`PixelAccess` or :py:class:`PIL.PyAccess` | ||||
|         :rtype: :py:class:`.PixelAccess` or :py:class:`.PyAccess` | ||||
|         """ | ||||
|         if self.im is not None and self.palette and self.palette.dirty: | ||||
|             # realize palette | ||||
|  | @ -913,6 +922,7 @@ class Image: | |||
|                 if self.pyaccess: | ||||
|                     return self.pyaccess | ||||
|             return self.im.pixel_access(self.readonly) | ||||
|         return None | ||||
| 
 | ||||
|     def verify(self) -> None: | ||||
|         """ | ||||
|  | @ -1102,7 +1112,10 @@ class Image: | |||
|                 del new_im.info["transparency"] | ||||
|             if trns is not None: | ||||
|                 try: | ||||
|                     new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) | ||||
|                     new_im.info["transparency"] = new_im.palette.getcolor( | ||||
|                         cast(Tuple[int, int, int], trns),  # trns was converted to RGB | ||||
|                         new_im, | ||||
|                     ) | ||||
|                 except Exception: | ||||
|                     # if we can't make a transparent color, don't leave the old | ||||
|                     # transparency hanging around to mess us up. | ||||
|  | @ -1152,7 +1165,10 @@ class Image: | |||
|         if trns is not None: | ||||
|             if new_im.mode == "P": | ||||
|                 try: | ||||
|                     new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) | ||||
|                     new_im.info["transparency"] = new_im.palette.getcolor( | ||||
|                         cast(Tuple[int, int, int], trns),  # trns was converted to RGB | ||||
|                         new_im, | ||||
|                     ) | ||||
|                 except ValueError as e: | ||||
|                     del new_im.info["transparency"] | ||||
|                     if str(e) != "cannot allocate more than 256 colors": | ||||
|  | @ -1657,7 +1673,9 @@ class Image: | |||
| 
 | ||||
|         del self.info["transparency"] | ||||
| 
 | ||||
|     def getpixel(self, xy): | ||||
|     def getpixel( | ||||
|         self, xy: tuple[int, int] | list[int] | ||||
|     ) -> float | tuple[int, ...] | None: | ||||
|         """ | ||||
|         Returns the pixel value at a given position. | ||||
| 
 | ||||
|  | @ -1941,15 +1959,14 @@ class Image: | |||
|             flatLut = [round(i) for i in flatLut] | ||||
|         return self._new(self.im.point(flatLut, mode)) | ||||
| 
 | ||||
|     def putalpha(self, alpha): | ||||
|     def putalpha(self, alpha: Image | int) -> None: | ||||
|         """ | ||||
|         Adds or replaces the alpha layer in this image.  If the image | ||||
|         does not have an alpha layer, it's converted to "LA" or "RGBA". | ||||
|         The new layer must be either "L" or "1". | ||||
| 
 | ||||
|         :param alpha: The new alpha layer.  This can either be an "L" or "1" | ||||
|            image having the same size as this image, or an integer or | ||||
|            other color value. | ||||
|            image having the same size as this image, or an integer. | ||||
|         """ | ||||
| 
 | ||||
|         self._ensure_mutable() | ||||
|  | @ -1988,6 +2005,7 @@ class Image: | |||
|                 alpha = alpha.convert("L") | ||||
|         else: | ||||
|             # constant alpha | ||||
|             alpha = cast(int, alpha)  # see python/typing#1013 | ||||
|             try: | ||||
|                 self.im.fillband(band, alpha) | ||||
|             except (AttributeError, ValueError): | ||||
|  | @ -2056,7 +2074,9 @@ class Image: | |||
|         self.palette.mode = "RGBA" if "A" in rawmode else "RGB" | ||||
|         self.load()  # install new palette | ||||
| 
 | ||||
|     def putpixel(self, xy, value): | ||||
|     def putpixel( | ||||
|         self, xy: tuple[int, int], value: float | tuple[int, ...] | list[int] | ||||
|     ) -> None: | ||||
|         """ | ||||
|         Modifies the pixel at the given position. The color is given as | ||||
|         a single numerical value for single-band images, and a tuple for | ||||
|  | @ -2094,9 +2114,8 @@ class Image: | |||
|             if self.mode == "PA": | ||||
|                 alpha = value[3] if len(value) == 4 else 255 | ||||
|                 value = value[:3] | ||||
|             value = self.palette.getcolor(value, self) | ||||
|             if self.mode == "PA": | ||||
|                 value = (value, alpha) | ||||
|             palette_index = self.palette.getcolor(value, self) | ||||
|             value = (palette_index, alpha) if self.mode == "PA" else palette_index | ||||
|         return self.im.putpixel(xy, value) | ||||
| 
 | ||||
|     def remap_palette(self, dest_map, source_palette=None): | ||||
|  |  | |||
|  | @ -1007,7 +1007,9 @@ def floodfill( | |||
|     thresh: float = 0, | ||||
| ) -> None: | ||||
|     """ | ||||
|     (experimental) Fills a bounded region with a given color. | ||||
|     .. warning:: This method is experimental. | ||||
| 
 | ||||
|     Fills a bounded region with a given color. | ||||
| 
 | ||||
|     :param image: Target image. | ||||
|     :param xy: Seed position (a 2-item coordinate tuple). See | ||||
|  | @ -1025,6 +1027,7 @@ def floodfill( | |||
|     # based on an implementation by Eric S. Raymond | ||||
|     # amended by yo1995 @20180806 | ||||
|     pixel = image.load() | ||||
|     assert pixel is not None | ||||
|     x, y = xy | ||||
|     try: | ||||
|         background = pixel[x, y] | ||||
|  |  | |||
|  | @ -26,7 +26,13 @@ import tempfile | |||
| from . import Image | ||||
| 
 | ||||
| 
 | ||||
| def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=None): | ||||
| def grab( | ||||
|     bbox: tuple[int, int, int, int] | None = None, | ||||
|     include_layered_windows: bool = False, | ||||
|     all_screens: bool = False, | ||||
|     xdisplay: str | None = None, | ||||
| ) -> Image.Image: | ||||
|     im: Image.Image | ||||
|     if xdisplay is None: | ||||
|         if sys.platform == "darwin": | ||||
|             fh, filepath = tempfile.mkstemp(".png") | ||||
|  | @ -63,14 +69,16 @@ def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=N | |||
|                 left, top, right, bottom = bbox | ||||
|                 im = im.crop((left - x0, top - y0, right - x0, bottom - y0)) | ||||
|             return im | ||||
|     # Cast to Optional[str] needed for Windows and macOS. | ||||
|     display_name: str | None = xdisplay | ||||
|     try: | ||||
|         if not Image.core.HAVE_XCB: | ||||
|             msg = "Pillow was built without XCB support" | ||||
|             raise OSError(msg) | ||||
|         size, data = Image.core.grabscreen_x11(xdisplay) | ||||
|         size, data = Image.core.grabscreen_x11(display_name) | ||||
|     except OSError: | ||||
|         if ( | ||||
|             xdisplay is None | ||||
|             display_name is None | ||||
|             and sys.platform not in ("darwin", "win32") | ||||
|             and shutil.which("gnome-screenshot") | ||||
|         ): | ||||
|  | @ -94,7 +102,7 @@ def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=N | |||
|         return im | ||||
| 
 | ||||
| 
 | ||||
| def grabclipboard(): | ||||
| def grabclipboard() -> Image.Image | list[str] | None: | ||||
|     if sys.platform == "darwin": | ||||
|         fh, filepath = tempfile.mkstemp(".png") | ||||
|         os.close(fh) | ||||
|  |  | |||
|  | @ -77,7 +77,11 @@ class PyAccess: | |||
|     def _post_init(self) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def __setitem__(self, xy, color): | ||||
|     def __setitem__( | ||||
|         self, | ||||
|         xy: tuple[int, int] | list[int], | ||||
|         color: float | tuple[int, ...] | list[int], | ||||
|     ) -> None: | ||||
|         """ | ||||
|         Modifies the pixel at x,y. The color is given as a single | ||||
|         numerical value for single band images, and a tuple for | ||||
|  | @ -107,13 +111,12 @@ class PyAccess: | |||
|             if self._im.mode == "PA": | ||||
|                 alpha = color[3] if len(color) == 4 else 255 | ||||
|                 color = color[:3] | ||||
|             color = self._palette.getcolor(color, self._img) | ||||
|             if self._im.mode == "PA": | ||||
|                 color = (color, alpha) | ||||
|             palette_index = self._palette.getcolor(color, self._img) | ||||
|             color = (palette_index, alpha) if self._im.mode == "PA" else palette_index | ||||
| 
 | ||||
|         return self.set_pixel(x, y, color) | ||||
| 
 | ||||
|     def __getitem__(self, xy: tuple[int, int]) -> float | tuple[int, ...]: | ||||
|     def __getitem__(self, xy: tuple[int, int] | list[int]) -> float | tuple[int, ...]: | ||||
|         """ | ||||
|         Returns the pixel at x,y. The pixel is returned as a single | ||||
|         value for single band images or a tuple for multiple band | ||||
|  | @ -145,7 +148,9 @@ class PyAccess: | |||
|     def get_pixel(self, x: int, y: int) -> float | tuple[int, ...]: | ||||
|         raise NotImplementedError() | ||||
| 
 | ||||
|     def set_pixel(self, x: int, y: int, color: float | tuple[int, ...]) -> None: | ||||
|     def set_pixel( | ||||
|         self, x: int, y: int, color: float | tuple[int, ...] | list[int] | ||||
|     ) -> None: | ||||
|         raise NotImplementedError() | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,7 +10,10 @@ class ImagingDraw: | |||
|     def __getattr__(self, name: str) -> Any: ... | ||||
| 
 | ||||
| class PixelAccess: | ||||
|     def __getattr__(self, name: str) -> Any: ... | ||||
|     def __getitem__(self, xy: tuple[int, int]) -> float | tuple[int, ...]: ... | ||||
|     def __setitem__( | ||||
|         self, xy: tuple[int, int], color: float | tuple[int, ...] | ||||
|     ) -> None: ... | ||||
| 
 | ||||
| class ImagingDecoder: | ||||
|     def __getattr__(self, name: str) -> Any: ... | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user