Added ImageType as alias for Image.Image

This commit is contained in:
Andrew Murray 2023-12-26 13:09:31 +11:00
parent f8e65ecfe0
commit 42f31be95e
3 changed files with 45 additions and 33 deletions

View File

@ -17,10 +17,10 @@
from __future__ import annotations from __future__ import annotations
from . import Image from . import Image, ImageType
def constant(image: Image.Image, value: int) -> Image.Image: def constant(image: ImageType, value: int) -> ImageType:
"""Fill a channel with a given gray level. """Fill a channel with a given gray level.
:rtype: :py:class:`~PIL.Image.Image` :rtype: :py:class:`~PIL.Image.Image`
@ -29,7 +29,7 @@ def constant(image: Image.Image, value: int) -> Image.Image:
return Image.new("L", image.size, value) return Image.new("L", image.size, value)
def duplicate(image: Image.Image) -> Image.Image: def duplicate(image: ImageType) -> ImageType:
"""Copy a channel. Alias for :py:meth:`PIL.Image.Image.copy`. """Copy a channel. Alias for :py:meth:`PIL.Image.Image.copy`.
:rtype: :py:class:`~PIL.Image.Image` :rtype: :py:class:`~PIL.Image.Image`
@ -38,7 +38,7 @@ def duplicate(image: Image.Image) -> Image.Image:
return image.copy() return image.copy()
def invert(image: Image.Image) -> Image.Image: def invert(image: ImageType) -> ImageType:
""" """
Invert an image (channel). :: Invert an image (channel). ::
@ -51,7 +51,7 @@ def invert(image: Image.Image) -> Image.Image:
return image._new(image.im.chop_invert()) return image._new(image.im.chop_invert())
def lighter(image1: Image.Image, image2: Image.Image) -> Image.Image: def lighter(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Compares the two images, pixel by pixel, and returns a new image containing Compares the two images, pixel by pixel, and returns a new image containing
the lighter values. :: the lighter values. ::
@ -66,7 +66,7 @@ def lighter(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_lighter(image2.im)) return image1._new(image1.im.chop_lighter(image2.im))
def darker(image1: Image.Image, image2: Image.Image) -> Image.Image: def darker(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Compares the two images, pixel by pixel, and returns a new image containing Compares the two images, pixel by pixel, and returns a new image containing
the darker values. :: the darker values. ::
@ -81,7 +81,7 @@ def darker(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_darker(image2.im)) return image1._new(image1.im.chop_darker(image2.im))
def difference(image1: Image.Image, image2: Image.Image) -> Image.Image: def difference(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Returns the absolute value of the pixel-by-pixel difference between the two Returns the absolute value of the pixel-by-pixel difference between the two
images. :: images. ::
@ -96,7 +96,7 @@ def difference(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_difference(image2.im)) return image1._new(image1.im.chop_difference(image2.im))
def multiply(image1: Image.Image, image2: Image.Image) -> Image.Image: def multiply(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Superimposes two images on top of each other. Superimposes two images on top of each other.
@ -113,7 +113,7 @@ def multiply(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_multiply(image2.im)) return image1._new(image1.im.chop_multiply(image2.im))
def screen(image1: Image.Image, image2: Image.Image) -> Image.Image: def screen(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Superimposes two inverted images on top of each other. :: Superimposes two inverted images on top of each other. ::
@ -127,7 +127,7 @@ def screen(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_screen(image2.im)) return image1._new(image1.im.chop_screen(image2.im))
def soft_light(image1: Image.Image, image2: Image.Image) -> Image.Image: def soft_light(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Superimposes two images on top of each other using the Soft Light algorithm Superimposes two images on top of each other using the Soft Light algorithm
@ -139,7 +139,7 @@ def soft_light(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_soft_light(image2.im)) return image1._new(image1.im.chop_soft_light(image2.im))
def hard_light(image1: Image.Image, image2: Image.Image) -> Image.Image: def hard_light(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Superimposes two images on top of each other using the Hard Light algorithm Superimposes two images on top of each other using the Hard Light algorithm
@ -151,7 +151,7 @@ def hard_light(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_hard_light(image2.im)) return image1._new(image1.im.chop_hard_light(image2.im))
def overlay(image1: Image.Image, image2: Image.Image) -> Image.Image: def overlay(image1: ImageType, image2: ImageType) -> ImageType:
""" """
Superimposes two images on top of each other using the Overlay algorithm Superimposes two images on top of each other using the Overlay algorithm
@ -164,8 +164,11 @@ def overlay(image1: Image.Image, image2: Image.Image) -> Image.Image:
def add( def add(
image1: Image.Image, image2: Image.Image, scale: float = 1.0, offset: float = 0 image1: ImageType,
) -> Image.Image: image2: ImageType,
scale: float = 1.0,
offset: float = 0,
) -> ImageType:
""" """
Adds two images, dividing the result by scale and adding the Adds two images, dividing the result by scale and adding the
offset. If omitted, scale defaults to 1.0, and offset to 0.0. :: offset. If omitted, scale defaults to 1.0, and offset to 0.0. ::
@ -181,8 +184,11 @@ def add(
def subtract( def subtract(
image1: Image.Image, image2: Image.Image, scale: float = 1.0, offset: float = 0 image1: ImageType,
) -> Image.Image: image2: ImageType,
scale: float = 1.0,
offset: float = 0,
) -> ImageType:
""" """
Subtracts two images, dividing the result by scale and adding the offset. Subtracts two images, dividing the result by scale and adding the offset.
If omitted, scale defaults to 1.0, and offset to 0.0. :: If omitted, scale defaults to 1.0, and offset to 0.0. ::
@ -197,7 +203,7 @@ def subtract(
return image1._new(image1.im.chop_subtract(image2.im, scale, offset)) return image1._new(image1.im.chop_subtract(image2.im, scale, offset))
def add_modulo(image1: Image.Image, image2: Image.Image) -> Image.Image: def add_modulo(image1: ImageType, image2: ImageType) -> ImageType:
"""Add two images, without clipping the result. :: """Add two images, without clipping the result. ::
out = ((image1 + image2) % MAX) out = ((image1 + image2) % MAX)
@ -210,7 +216,7 @@ def add_modulo(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_add_modulo(image2.im)) return image1._new(image1.im.chop_add_modulo(image2.im))
def subtract_modulo(image1: Image.Image, image2: Image.Image) -> Image.Image: def subtract_modulo(image1: ImageType, image2: ImageType) -> ImageType:
"""Subtract two images, without clipping the result. :: """Subtract two images, without clipping the result. ::
out = ((image1 - image2) % MAX) out = ((image1 - image2) % MAX)
@ -223,7 +229,7 @@ def subtract_modulo(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_subtract_modulo(image2.im)) return image1._new(image1.im.chop_subtract_modulo(image2.im))
def logical_and(image1: Image.Image, image2: Image.Image) -> Image.Image: def logical_and(image1: ImageType, image2: ImageType) -> ImageType:
"""Logical AND between two images. """Logical AND between two images.
Both of the images must have mode "1". If you would like to perform a Both of the images must have mode "1". If you would like to perform a
@ -241,7 +247,7 @@ def logical_and(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_and(image2.im)) return image1._new(image1.im.chop_and(image2.im))
def logical_or(image1: Image.Image, image2: Image.Image) -> Image.Image: def logical_or(image1: ImageType, image2: ImageType) -> ImageType:
"""Logical OR between two images. """Logical OR between two images.
Both of the images must have mode "1". :: Both of the images must have mode "1". ::
@ -256,7 +262,7 @@ def logical_or(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_or(image2.im)) return image1._new(image1.im.chop_or(image2.im))
def logical_xor(image1: Image.Image, image2: Image.Image) -> Image.Image: def logical_xor(image1: ImageType, image2: ImageType) -> ImageType:
"""Logical XOR between two images. """Logical XOR between two images.
Both of the images must have mode "1". :: Both of the images must have mode "1". ::
@ -271,7 +277,7 @@ def logical_xor(image1: Image.Image, image2: Image.Image) -> Image.Image:
return image1._new(image1.im.chop_xor(image2.im)) return image1._new(image1.im.chop_xor(image2.im))
def blend(image1: Image.Image, image2: Image.Image, alpha: float) -> Image.Image: def blend(image1: ImageType, image2: ImageType, alpha: float) -> ImageType:
"""Blend images using constant transparency weight. Alias for """Blend images using constant transparency weight. Alias for
:py:func:`PIL.Image.blend`. :py:func:`PIL.Image.blend`.
@ -281,9 +287,7 @@ def blend(image1: Image.Image, image2: Image.Image, alpha: float) -> Image.Image
return Image.blend(image1, image2, alpha) return Image.blend(image1, image2, alpha)
def composite( def composite(image1: ImageType, image2: ImageType, mask: ImageType) -> ImageType:
image1: Image.Image, image2: Image.Image, mask: Image.Image
) -> Image.Image:
"""Create composite using transparency mask. Alias for """Create composite using transparency mask. Alias for
:py:func:`PIL.Image.composite`. :py:func:`PIL.Image.composite`.
@ -293,7 +297,7 @@ def composite(
return Image.composite(image1, image2, mask) return Image.composite(image1, image2, mask)
def offset(image: Image.Image, xoffset: int, yoffset: int | None = None) -> Image.Image: def offset(image: ImageType, xoffset: int, yoffset: int | None = None) -> ImageType:
"""Returns a copy of the image where data has been offset by the given """Returns a copy of the image where data has been offset by the given
distances. Data wraps around the edges. If ``yoffset`` is omitted, it distances. Data wraps around the edges. If ``yoffset`` is omitted, it
is assumed to be equal to ``xoffset``. is assumed to be equal to ``xoffset``.

View File

@ -18,7 +18,7 @@ from __future__ import annotations
from typing import Callable from typing import Callable
from . import Image from . import ImageType
class Iterator: class Iterator:
@ -33,14 +33,14 @@ class Iterator:
:param im: An image object. :param im: An image object.
""" """
def __init__(self, im: Image.Image): def __init__(self, im: ImageType):
if not hasattr(im, "seek"): if not hasattr(im, "seek"):
msg = "im must have seek method" msg = "im must have seek method"
raise AttributeError(msg) raise AttributeError(msg)
self.im = im self.im = im
self.position = getattr(self.im, "_min_frame", 0) self.position = getattr(self.im, "_min_frame", 0)
def __getitem__(self, ix: int) -> Image.Image: def __getitem__(self, ix: int) -> ImageType:
try: try:
self.im.seek(ix) self.im.seek(ix)
return self.im return self.im
@ -51,7 +51,7 @@ class Iterator:
def __iter__(self) -> Iterator: def __iter__(self) -> Iterator:
return self return self
def __next__(self) -> Image.Image: def __next__(self) -> ImageType:
try: try:
self.im.seek(self.position) self.im.seek(self.position)
self.position += 1 self.position += 1
@ -62,9 +62,9 @@ class Iterator:
def all_frames( def all_frames(
im: Image.Image | list[Image.Image], im: ImageType | list[ImageType],
func: Callable[[Image.Image], Image.Image] | None = None, func: Callable[[ImageType], ImageType] | None = None,
) -> list[Image.Image]: ) -> list[ImageType]:
""" """
Applies a given function to all frames in an image or a list of images. Applies a given function to all frames in an image or a list of images.
The frames are returned as a list of separate images. The frames are returned as a list of separate images.

View File

@ -83,3 +83,11 @@ class UnidentifiedImageError(OSError):
""" """
pass pass
def __getattr__(name: str):
if name == "ImageType":
from . import Image
return Image.Image
raise AttributeError