Skip to content

Commit

Permalink
Merge pull request #8099 from radarhere/types
Browse files Browse the repository at this point in the history
Added type hints
  • Loading branch information
radarhere committed Jun 3, 2024
2 parents 95a69ec + f5da04a commit 219add0
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 22 deletions.
10 changes: 4 additions & 6 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ def _reload_exif(self) -> None:
self._exif._loaded = False
self.getexif()

def get_child_images(self):
def get_child_images(self) -> list[ImageFile.ImageFile]:
child_images = []
exif = self.getexif()
ifds = []
Expand All @@ -1535,10 +1535,7 @@ def get_child_images(self):
fp = self.fp
thumbnail_offset = ifd.get(513)
if thumbnail_offset is not None:
try:
thumbnail_offset += self._exif_offset
except AttributeError:
pass
thumbnail_offset += getattr(self, "_exif_offset", 0)
self.fp.seek(thumbnail_offset)
data = self.fp.read(ifd.get(514))
fp = io.BytesIO(data)
Expand Down Expand Up @@ -1604,7 +1601,7 @@ def has_transparency_data(self) -> bool:
or "transparency" in self.info
)

def apply_transparency(self):
def apply_transparency(self) -> None:
"""
If a P mode image has a "transparency" key in the info dictionary,
remove the key and instead apply the transparency to the palette.
Expand All @@ -1616,6 +1613,7 @@ def apply_transparency(self):
from . import ImagePalette

palette = self.getpalette("RGBA")
assert palette is not None
transparency = self.info["transparency"]
if isinstance(transparency, bytes):
for i, alpha in enumerate(transparency):
Expand Down
8 changes: 7 additions & 1 deletion src/PIL/ImageDraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,13 @@ def getdraw(im=None, hints=None):
return im, handler


def floodfill(image: Image.Image, xy, value, border=None, thresh=0) -> None:
def floodfill(
image: Image.Image,
xy: tuple[int, int],
value: float | tuple[int, ...],
border: float | tuple[int, ...] | None = None,
thresh: float = 0,
) -> None:
"""
(experimental) Fills a bounded region with a given color.
Expand Down
41 changes: 26 additions & 15 deletions src/PIL/PyAccess.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import logging
import sys
from typing import TYPE_CHECKING

from ._deprecate import deprecate

Expand All @@ -48,9 +49,12 @@

logger = logging.getLogger(__name__)

if TYPE_CHECKING:
from . import Image


class PyAccess:
def __init__(self, img, readonly=False):
def __init__(self, img: Image.Image, readonly: bool = False) -> None:
deprecate("PyAccess", 11)
vals = dict(img.im.unsafe_ptrs)
self.readonly = readonly
Expand All @@ -77,7 +81,8 @@ def __setitem__(self, xy, color):
"""
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
multi-band images. In addition to this, RGB and RGBA tuples
are accepted for P and PA images.
:param xy: The pixel coordinate, given as (x, y). See
:ref:`coordinate-system`.
Expand Down Expand Up @@ -108,7 +113,7 @@ def __setitem__(self, xy, color):

return self.set_pixel(x, y, color)

def __getitem__(self, xy):
def __getitem__(self, xy: tuple[int, 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
Expand All @@ -130,21 +135,27 @@ def __getitem__(self, xy):
putpixel = __setitem__
getpixel = __getitem__

def check_xy(self, xy):
def check_xy(self, xy: tuple[int, int]) -> tuple[int, int]:
(x, y) = xy
if not (0 <= x < self.xsize and 0 <= y < self.ysize):
msg = "pixel location out of range"
raise ValueError(msg)
return xy

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:
raise NotImplementedError()


class _PyAccess32_2(PyAccess):
"""PA, LA, stored in first and last bytes of a 32 bit word"""

def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> tuple[int, int]:
pixel = self.pixels[y][x]
return pixel.r, pixel.a

Expand All @@ -161,7 +172,7 @@ class _PyAccess32_3(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> tuple[int, int, int]:
pixel = self.pixels[y][x]
return pixel.r, pixel.g, pixel.b

Expand All @@ -180,7 +191,7 @@ class _PyAccess32_4(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> tuple[int, int, int, int]:
pixel = self.pixels[y][x]
return pixel.r, pixel.g, pixel.b, pixel.a

Expand All @@ -199,7 +210,7 @@ class _PyAccess8(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = self.image8

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> int:
return self.pixels[y][x]

def set_pixel(self, x, y, color):
Expand All @@ -217,7 +228,7 @@ class _PyAccessI16_N(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("unsigned short **", self.image)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> int:
return self.pixels[y][x]

def set_pixel(self, x, y, color):
Expand All @@ -235,7 +246,7 @@ class _PyAccessI16_L(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_I16 **", self.image)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> int:
pixel = self.pixels[y][x]
return pixel.l + pixel.r * 256

Expand All @@ -256,7 +267,7 @@ class _PyAccessI16_B(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("struct Pixel_I16 **", self.image)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> int:
pixel = self.pixels[y][x]
return pixel.l * 256 + pixel.r

Expand All @@ -277,7 +288,7 @@ class _PyAccessI32_N(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = self.image32

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> int:
return self.pixels[y][x]

def set_pixel(self, x, y, color):
Expand All @@ -296,7 +307,7 @@ def reverse(self, i):
chars[0], chars[1], chars[2], chars[3] = chars[3], chars[2], chars[1], chars[0]
return ffi.cast("int *", chars)[0]

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> int:
return self.reverse(self.pixels[y][x])

def set_pixel(self, x, y, color):
Expand All @@ -309,7 +320,7 @@ class _PyAccessF(PyAccess):
def _post_init(self, *args, **kwargs):
self.pixels = ffi.cast("float **", self.image32)

def get_pixel(self, x, y):
def get_pixel(self, x: int, y: int) -> float:
return self.pixels[y][x]

def set_pixel(self, x, y, color):
Expand Down Expand Up @@ -357,7 +368,7 @@ def set_pixel(self, x, y, color):
mode_map["I;32B"] = _PyAccessI32_N


def new(img, readonly=False):
def new(img: Image.Image, readonly: bool = False) -> PyAccess | None:
access_type = mode_map.get(img.mode, None)
if not access_type:
logger.debug("PyAccess Not Implemented: %s", img.mode)
Expand Down

0 comments on commit 219add0

Please sign in to comment.