mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-11 04:07:21 +03:00
Merge pull request #7786 from radarhere/type_hints_imageops
Added type hints to ImageOps
This commit is contained in:
commit
80d4fc14b8
|
@ -1430,7 +1430,7 @@ class Image:
|
|||
root = ElementTree.fromstring(xmp_tags)
|
||||
return {get_name(root.tag): get_value(root)}
|
||||
|
||||
def getexif(self):
|
||||
def getexif(self) -> Exif:
|
||||
"""
|
||||
Gets EXIF data from the image.
|
||||
|
||||
|
@ -1438,7 +1438,6 @@ class Image:
|
|||
"""
|
||||
if self._exif is None:
|
||||
self._exif = Exif()
|
||||
self._exif._loaded = False
|
||||
elif self._exif._loaded:
|
||||
return self._exif
|
||||
self._exif._loaded = True
|
||||
|
@ -1525,7 +1524,7 @@ class Image:
|
|||
self.load()
|
||||
return self.im.ptr
|
||||
|
||||
def getpalette(self, rawmode="RGB"):
|
||||
def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None:
|
||||
"""
|
||||
Returns the image palette as a list.
|
||||
|
||||
|
@ -1615,7 +1614,7 @@ class Image:
|
|||
x, y = self.im.getprojection()
|
||||
return list(x), list(y)
|
||||
|
||||
def histogram(self, mask=None, extrema=None):
|
||||
def histogram(self, mask=None, extrema=None) -> list[int]:
|
||||
"""
|
||||
Returns a histogram for the image. The histogram is returned as a
|
||||
list of pixel counts, one for each pixel value in the source
|
||||
|
@ -1804,7 +1803,7 @@ class Image:
|
|||
result = alpha_composite(background, overlay)
|
||||
self.paste(result, box)
|
||||
|
||||
def point(self, lut, mode=None):
|
||||
def point(self, lut, mode: str | None = None) -> Image:
|
||||
"""
|
||||
Maps this image through a lookup table or function.
|
||||
|
||||
|
@ -1928,7 +1927,7 @@ class Image:
|
|||
|
||||
self.im.putdata(data, scale, offset)
|
||||
|
||||
def putpalette(self, data, rawmode="RGB"):
|
||||
def putpalette(self, data, rawmode="RGB") -> None:
|
||||
"""
|
||||
Attaches a palette to this image. The image must be a "P", "PA", "L"
|
||||
or "LA" image.
|
||||
|
@ -2108,7 +2107,7 @@ class Image:
|
|||
min(self.size[1], math.ceil(box[3] + support_y)),
|
||||
)
|
||||
|
||||
def resize(self, size, resample=None, box=None, reducing_gap=None):
|
||||
def resize(self, size, resample=None, box=None, reducing_gap=None) -> Image:
|
||||
"""
|
||||
Returns a resized copy of this image.
|
||||
|
||||
|
@ -2200,10 +2199,11 @@ class Image:
|
|||
if factor_x > 1 or factor_y > 1:
|
||||
reduce_box = self._get_safe_box(size, resample, box)
|
||||
factor = (factor_x, factor_y)
|
||||
if callable(self.reduce):
|
||||
self = self.reduce(factor, box=reduce_box)
|
||||
else:
|
||||
self = Image.reduce(self, factor, box=reduce_box)
|
||||
self = (
|
||||
self.reduce(factor, box=reduce_box)
|
||||
if callable(self.reduce)
|
||||
else Image.reduce(self, factor, box=reduce_box)
|
||||
)
|
||||
box = (
|
||||
(box[0] - reduce_box[0]) / factor_x,
|
||||
(box[1] - reduce_box[1]) / factor_y,
|
||||
|
@ -2818,7 +2818,7 @@ class Image:
|
|||
|
||||
self.im.transform2(box, image.im, method, data, resample, fill)
|
||||
|
||||
def transpose(self, method):
|
||||
def transpose(self, method: Transpose) -> Image:
|
||||
"""
|
||||
Transpose image (flip or rotate in 90 degree steps)
|
||||
|
||||
|
@ -2870,7 +2870,9 @@ class ImagePointHandler:
|
|||
(for use with :py:meth:`~PIL.Image.Image.point`)
|
||||
"""
|
||||
|
||||
pass
|
||||
@abc.abstractmethod
|
||||
def point(self, im: Image) -> Image:
|
||||
pass
|
||||
|
||||
|
||||
class ImageTransformHandler:
|
||||
|
@ -3690,6 +3692,7 @@ class Exif(_ExifBase):
|
|||
|
||||
endian = None
|
||||
bigtiff = False
|
||||
_loaded = False
|
||||
|
||||
def __init__(self):
|
||||
self._data = {}
|
||||
|
@ -3805,7 +3808,7 @@ class Exif(_ExifBase):
|
|||
|
||||
return merged_dict
|
||||
|
||||
def tobytes(self, offset=8):
|
||||
def tobytes(self, offset: int = 8) -> bytes:
|
||||
from . import TiffImagePlugin
|
||||
|
||||
head = self._get_head()
|
||||
|
@ -3960,7 +3963,7 @@ class Exif(_ExifBase):
|
|||
del self._info[tag]
|
||||
self._data[tag] = value
|
||||
|
||||
def __delitem__(self, tag):
|
||||
def __delitem__(self, tag: int) -> None:
|
||||
if self._info is not None and tag in self._info:
|
||||
del self._info[tag]
|
||||
else:
|
||||
|
|
|
@ -124,7 +124,7 @@ def getrgb(color):
|
|||
|
||||
|
||||
@lru_cache
|
||||
def getcolor(color, mode):
|
||||
def getcolor(color, mode: str) -> tuple[int, ...]:
|
||||
"""
|
||||
Same as :py:func:`~PIL.ImageColor.getrgb` for most modes. However, if
|
||||
``mode`` is HSV, converts the RGB value to a HSV value, or if ``mode`` is
|
||||
|
|
|
@ -21,6 +21,7 @@ from __future__ import annotations
|
|||
import functools
|
||||
import operator
|
||||
import re
|
||||
from typing import Protocol, Sequence, cast
|
||||
|
||||
from . import ExifTags, Image, ImagePalette
|
||||
|
||||
|
@ -28,7 +29,7 @@ from . import ExifTags, Image, ImagePalette
|
|||
# helpers
|
||||
|
||||
|
||||
def _border(border):
|
||||
def _border(border: int | tuple[int, ...]) -> tuple[int, int, int, int]:
|
||||
if isinstance(border, tuple):
|
||||
if len(border) == 2:
|
||||
left, top = right, bottom = border
|
||||
|
@ -39,7 +40,7 @@ def _border(border):
|
|||
return left, top, right, bottom
|
||||
|
||||
|
||||
def _color(color, mode):
|
||||
def _color(color: str | int | tuple[int, ...], mode: str) -> int | tuple[int, ...]:
|
||||
if isinstance(color, str):
|
||||
from . import ImageColor
|
||||
|
||||
|
@ -47,7 +48,7 @@ def _color(color, mode):
|
|||
return color
|
||||
|
||||
|
||||
def _lut(image, lut):
|
||||
def _lut(image: Image.Image, lut: list[int]) -> Image.Image:
|
||||
if image.mode == "P":
|
||||
# FIXME: apply to lookup table, not image data
|
||||
msg = "mode P support coming soon"
|
||||
|
@ -65,7 +66,13 @@ def _lut(image, lut):
|
|||
# actions
|
||||
|
||||
|
||||
def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False):
|
||||
def autocontrast(
|
||||
image: Image.Image,
|
||||
cutoff: float | tuple[float, float] = 0,
|
||||
ignore: int | Sequence[int] | None = None,
|
||||
mask: Image.Image | None = None,
|
||||
preserve_tone: bool = False,
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Maximize (normalize) image contrast. This function calculates a
|
||||
histogram of the input image (or mask region), removes ``cutoff`` percent of the
|
||||
|
@ -97,10 +104,9 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False):
|
|||
h = histogram[layer : layer + 256]
|
||||
if ignore is not None:
|
||||
# get rid of outliers
|
||||
try:
|
||||
if isinstance(ignore, int):
|
||||
h[ignore] = 0
|
||||
except TypeError:
|
||||
# assume sequence
|
||||
else:
|
||||
for ix in ignore:
|
||||
h[ix] = 0
|
||||
if cutoff:
|
||||
|
@ -112,7 +118,7 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False):
|
|||
for ix in range(256):
|
||||
n = n + h[ix]
|
||||
# remove cutoff% pixels from the low end
|
||||
cut = n * cutoff[0] // 100
|
||||
cut = int(n * cutoff[0] // 100)
|
||||
for lo in range(256):
|
||||
if cut > h[lo]:
|
||||
cut = cut - h[lo]
|
||||
|
@ -123,7 +129,7 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False):
|
|||
if cut <= 0:
|
||||
break
|
||||
# remove cutoff% samples from the high end
|
||||
cut = n * cutoff[1] // 100
|
||||
cut = int(n * cutoff[1] // 100)
|
||||
for hi in range(255, -1, -1):
|
||||
if cut > h[hi]:
|
||||
cut = cut - h[hi]
|
||||
|
@ -156,7 +162,15 @@ def autocontrast(image, cutoff=0, ignore=None, mask=None, preserve_tone=False):
|
|||
return _lut(image, lut)
|
||||
|
||||
|
||||
def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoint=127):
|
||||
def colorize(
|
||||
image: Image.Image,
|
||||
black: str | tuple[int, ...],
|
||||
white: str | tuple[int, ...],
|
||||
mid: str | int | tuple[int, ...] | None = None,
|
||||
blackpoint: int = 0,
|
||||
whitepoint: int = 255,
|
||||
midpoint: int = 127,
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Colorize grayscale image.
|
||||
This function calculates a color wedge which maps all black pixels in
|
||||
|
@ -188,10 +202,9 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
|
|||
assert 0 <= blackpoint <= midpoint <= whitepoint <= 255
|
||||
|
||||
# Define colors from arguments
|
||||
black = _color(black, "RGB")
|
||||
white = _color(white, "RGB")
|
||||
if mid is not None:
|
||||
mid = _color(mid, "RGB")
|
||||
rgb_black = cast(Sequence[int], _color(black, "RGB"))
|
||||
rgb_white = cast(Sequence[int], _color(white, "RGB"))
|
||||
rgb_mid = cast(Sequence[int], _color(mid, "RGB")) if mid is not None else None
|
||||
|
||||
# Empty lists for the mapping
|
||||
red = []
|
||||
|
@ -200,18 +213,24 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
|
|||
|
||||
# Create the low-end values
|
||||
for i in range(0, blackpoint):
|
||||
red.append(black[0])
|
||||
green.append(black[1])
|
||||
blue.append(black[2])
|
||||
red.append(rgb_black[0])
|
||||
green.append(rgb_black[1])
|
||||
blue.append(rgb_black[2])
|
||||
|
||||
# Create the mapping (2-color)
|
||||
if mid is None:
|
||||
if rgb_mid is None:
|
||||
range_map = range(0, whitepoint - blackpoint)
|
||||
|
||||
for i in range_map:
|
||||
red.append(black[0] + i * (white[0] - black[0]) // len(range_map))
|
||||
green.append(black[1] + i * (white[1] - black[1]) // len(range_map))
|
||||
blue.append(black[2] + i * (white[2] - black[2]) // len(range_map))
|
||||
red.append(
|
||||
rgb_black[0] + i * (rgb_white[0] - rgb_black[0]) // len(range_map)
|
||||
)
|
||||
green.append(
|
||||
rgb_black[1] + i * (rgb_white[1] - rgb_black[1]) // len(range_map)
|
||||
)
|
||||
blue.append(
|
||||
rgb_black[2] + i * (rgb_white[2] - rgb_black[2]) // len(range_map)
|
||||
)
|
||||
|
||||
# Create the mapping (3-color)
|
||||
else:
|
||||
|
@ -219,26 +238,36 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
|
|||
range_map2 = range(0, whitepoint - midpoint)
|
||||
|
||||
for i in range_map1:
|
||||
red.append(black[0] + i * (mid[0] - black[0]) // len(range_map1))
|
||||
green.append(black[1] + i * (mid[1] - black[1]) // len(range_map1))
|
||||
blue.append(black[2] + i * (mid[2] - black[2]) // len(range_map1))
|
||||
red.append(
|
||||
rgb_black[0] + i * (rgb_mid[0] - rgb_black[0]) // len(range_map1)
|
||||
)
|
||||
green.append(
|
||||
rgb_black[1] + i * (rgb_mid[1] - rgb_black[1]) // len(range_map1)
|
||||
)
|
||||
blue.append(
|
||||
rgb_black[2] + i * (rgb_mid[2] - rgb_black[2]) // len(range_map1)
|
||||
)
|
||||
for i in range_map2:
|
||||
red.append(mid[0] + i * (white[0] - mid[0]) // len(range_map2))
|
||||
green.append(mid[1] + i * (white[1] - mid[1]) // len(range_map2))
|
||||
blue.append(mid[2] + i * (white[2] - mid[2]) // len(range_map2))
|
||||
red.append(rgb_mid[0] + i * (rgb_white[0] - rgb_mid[0]) // len(range_map2))
|
||||
green.append(
|
||||
rgb_mid[1] + i * (rgb_white[1] - rgb_mid[1]) // len(range_map2)
|
||||
)
|
||||
blue.append(rgb_mid[2] + i * (rgb_white[2] - rgb_mid[2]) // len(range_map2))
|
||||
|
||||
# Create the high-end values
|
||||
for i in range(0, 256 - whitepoint):
|
||||
red.append(white[0])
|
||||
green.append(white[1])
|
||||
blue.append(white[2])
|
||||
red.append(rgb_white[0])
|
||||
green.append(rgb_white[1])
|
||||
blue.append(rgb_white[2])
|
||||
|
||||
# Return converted image
|
||||
image = image.convert("RGB")
|
||||
return _lut(image, red + green + blue)
|
||||
|
||||
|
||||
def contain(image, size, method=Image.Resampling.BICUBIC):
|
||||
def contain(
|
||||
image: Image.Image, size: tuple[int, int], method: int = Image.Resampling.BICUBIC
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Returns a resized version of the image, set to the maximum width and height
|
||||
within the requested size, while maintaining the original aspect ratio.
|
||||
|
@ -267,7 +296,9 @@ def contain(image, size, method=Image.Resampling.BICUBIC):
|
|||
return image.resize(size, resample=method)
|
||||
|
||||
|
||||
def cover(image, size, method=Image.Resampling.BICUBIC):
|
||||
def cover(
|
||||
image: Image.Image, size: tuple[int, int], method: int = Image.Resampling.BICUBIC
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Returns a resized version of the image, so that the requested size is
|
||||
covered, while maintaining the original aspect ratio.
|
||||
|
@ -296,7 +327,13 @@ def cover(image, size, method=Image.Resampling.BICUBIC):
|
|||
return image.resize(size, resample=method)
|
||||
|
||||
|
||||
def pad(image, size, method=Image.Resampling.BICUBIC, color=None, centering=(0.5, 0.5)):
|
||||
def pad(
|
||||
image: Image.Image,
|
||||
size: tuple[int, int],
|
||||
method: int = Image.Resampling.BICUBIC,
|
||||
color: str | int | tuple[int, ...] | None = None,
|
||||
centering: tuple[float, float] = (0.5, 0.5),
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Returns a resized and padded version of the image, expanded to fill the
|
||||
requested aspect ratio and size.
|
||||
|
@ -334,7 +371,7 @@ def pad(image, size, method=Image.Resampling.BICUBIC, color=None, centering=(0.5
|
|||
return out
|
||||
|
||||
|
||||
def crop(image, border=0):
|
||||
def crop(image: Image.Image, border: int = 0) -> Image.Image:
|
||||
"""
|
||||
Remove border from image. The same amount of pixels are removed
|
||||
from all four sides. This function works on all image modes.
|
||||
|
@ -349,7 +386,9 @@ def crop(image, border=0):
|
|||
return image.crop((left, top, image.size[0] - right, image.size[1] - bottom))
|
||||
|
||||
|
||||
def scale(image, factor, resample=Image.Resampling.BICUBIC):
|
||||
def scale(
|
||||
image: Image.Image, factor: float, resample: int = Image.Resampling.BICUBIC
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Returns a rescaled image by a specific factor given in parameter.
|
||||
A factor greater than 1 expands the image, between 0 and 1 contracts the
|
||||
|
@ -372,7 +411,19 @@ def scale(image, factor, resample=Image.Resampling.BICUBIC):
|
|||
return image.resize(size, resample)
|
||||
|
||||
|
||||
def deform(image, deformer, resample=Image.Resampling.BILINEAR):
|
||||
class _SupportsGetMesh(Protocol):
|
||||
def getmesh(
|
||||
self, image: Image.Image
|
||||
) -> list[
|
||||
tuple[tuple[int, int, int, int], tuple[int, int, int, int, int, int, int, int]]
|
||||
]: ...
|
||||
|
||||
|
||||
def deform(
|
||||
image: Image.Image,
|
||||
deformer: _SupportsGetMesh,
|
||||
resample: int = Image.Resampling.BILINEAR,
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Deform the image.
|
||||
|
||||
|
@ -388,7 +439,7 @@ def deform(image, deformer, resample=Image.Resampling.BILINEAR):
|
|||
)
|
||||
|
||||
|
||||
def equalize(image, mask=None):
|
||||
def equalize(image: Image.Image, mask: Image.Image | None = None) -> Image.Image:
|
||||
"""
|
||||
Equalize the image histogram. This function applies a non-linear
|
||||
mapping to the input image, in order to create a uniform
|
||||
|
@ -419,7 +470,11 @@ def equalize(image, mask=None):
|
|||
return _lut(image, lut)
|
||||
|
||||
|
||||
def expand(image, border=0, fill=0):
|
||||
def expand(
|
||||
image: Image.Image,
|
||||
border: int | tuple[int, ...] = 0,
|
||||
fill: str | int | tuple[int, ...] = 0,
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Add border to the image
|
||||
|
||||
|
@ -445,7 +500,13 @@ def expand(image, border=0, fill=0):
|
|||
return out
|
||||
|
||||
|
||||
def fit(image, size, method=Image.Resampling.BICUBIC, bleed=0.0, centering=(0.5, 0.5)):
|
||||
def fit(
|
||||
image: Image.Image,
|
||||
size: tuple[int, int],
|
||||
method: int = Image.Resampling.BICUBIC,
|
||||
bleed: float = 0.0,
|
||||
centering: tuple[float, float] = (0.5, 0.5),
|
||||
) -> Image.Image:
|
||||
"""
|
||||
Returns a resized and cropped version of the image, cropped to the
|
||||
requested aspect ratio and size.
|
||||
|
@ -479,13 +540,12 @@ def fit(image, size, method=Image.Resampling.BICUBIC, bleed=0.0, centering=(0.5,
|
|||
# kevin@cazabon.com
|
||||
# https://www.cazabon.com
|
||||
|
||||
# ensure centering is mutable
|
||||
centering = list(centering)
|
||||
centering_x, centering_y = centering
|
||||
|
||||
if not 0.0 <= centering[0] <= 1.0:
|
||||
centering[0] = 0.5
|
||||
if not 0.0 <= centering[1] <= 1.0:
|
||||
centering[1] = 0.5
|
||||
if not 0.0 <= centering_x <= 1.0:
|
||||
centering_x = 0.5
|
||||
if not 0.0 <= centering_y <= 1.0:
|
||||
centering_y = 0.5
|
||||
|
||||
if not 0.0 <= bleed < 0.5:
|
||||
bleed = 0.0
|
||||
|
@ -522,8 +582,8 @@ def fit(image, size, method=Image.Resampling.BICUBIC, bleed=0.0, centering=(0.5,
|
|||
crop_height = live_size[0] / output_ratio
|
||||
|
||||
# make the crop
|
||||
crop_left = bleed_pixels[0] + (live_size[0] - crop_width) * centering[0]
|
||||
crop_top = bleed_pixels[1] + (live_size[1] - crop_height) * centering[1]
|
||||
crop_left = bleed_pixels[0] + (live_size[0] - crop_width) * centering_x
|
||||
crop_top = bleed_pixels[1] + (live_size[1] - crop_height) * centering_y
|
||||
|
||||
crop = (crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)
|
||||
|
||||
|
@ -531,7 +591,7 @@ def fit(image, size, method=Image.Resampling.BICUBIC, bleed=0.0, centering=(0.5,
|
|||
return image.resize(size, method, box=crop)
|
||||
|
||||
|
||||
def flip(image):
|
||||
def flip(image: Image.Image) -> Image.Image:
|
||||
"""
|
||||
Flip the image vertically (top to bottom).
|
||||
|
||||
|
@ -541,7 +601,7 @@ def flip(image):
|
|||
return image.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
|
||||
|
||||
|
||||
def grayscale(image):
|
||||
def grayscale(image: Image.Image) -> Image.Image:
|
||||
"""
|
||||
Convert the image to grayscale.
|
||||
|
||||
|
@ -551,7 +611,7 @@ def grayscale(image):
|
|||
return image.convert("L")
|
||||
|
||||
|
||||
def invert(image):
|
||||
def invert(image: Image.Image) -> Image.Image:
|
||||
"""
|
||||
Invert (negate) the image.
|
||||
|
||||
|
@ -562,7 +622,7 @@ def invert(image):
|
|||
return image.point(lut) if image.mode == "1" else _lut(image, lut)
|
||||
|
||||
|
||||
def mirror(image):
|
||||
def mirror(image: Image.Image) -> Image.Image:
|
||||
"""
|
||||
Flip image horizontally (left to right).
|
||||
|
||||
|
@ -572,7 +632,7 @@ def mirror(image):
|
|||
return image.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
|
||||
|
||||
|
||||
def posterize(image, bits):
|
||||
def posterize(image: Image.Image, bits: int) -> Image.Image:
|
||||
"""
|
||||
Reduce the number of bits for each color channel.
|
||||
|
||||
|
@ -585,7 +645,7 @@ def posterize(image, bits):
|
|||
return _lut(image, lut)
|
||||
|
||||
|
||||
def solarize(image, threshold=128):
|
||||
def solarize(image: Image.Image, threshold: int = 128) -> Image.Image:
|
||||
"""
|
||||
Invert all pixel values above a threshold.
|
||||
|
||||
|
@ -602,7 +662,7 @@ def solarize(image, threshold=128):
|
|||
return _lut(image, lut)
|
||||
|
||||
|
||||
def exif_transpose(image, *, in_place=False):
|
||||
def exif_transpose(image: Image.Image, *, in_place: bool = False) -> Image.Image | None:
|
||||
"""
|
||||
If an image has an EXIF Orientation tag, other than 1, transpose the image
|
||||
accordingly, and remove the orientation data.
|
||||
|
@ -616,7 +676,7 @@ def exif_transpose(image, *, in_place=False):
|
|||
"""
|
||||
image.load()
|
||||
image_exif = image.getexif()
|
||||
orientation = image_exif.get(ExifTags.Base.Orientation)
|
||||
orientation = image_exif.get(ExifTags.Base.Orientation, 1)
|
||||
method = {
|
||||
2: Image.Transpose.FLIP_LEFT_RIGHT,
|
||||
3: Image.Transpose.ROTATE_180,
|
||||
|
@ -653,3 +713,4 @@ def exif_transpose(image, *, in_place=False):
|
|||
return transposed_image
|
||||
elif not in_place:
|
||||
return image.copy()
|
||||
return None
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import array
|
||||
from typing import Sequence
|
||||
|
||||
from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
|
||||
|
||||
|
@ -34,11 +35,11 @@ class ImagePalette:
|
|||
Defaults to an empty palette.
|
||||
"""
|
||||
|
||||
def __init__(self, mode="RGB", palette=None):
|
||||
def __init__(self, mode: str = "RGB", palette: Sequence[int] | None = None) -> None:
|
||||
self.mode = mode
|
||||
self.rawmode = None # if set, palette contains raw data
|
||||
self.palette = palette or bytearray()
|
||||
self.dirty = None
|
||||
self.dirty: int | None = None
|
||||
|
||||
@property
|
||||
def palette(self):
|
||||
|
@ -127,7 +128,7 @@ class ImagePalette:
|
|||
raise ValueError(msg) from e
|
||||
return index
|
||||
|
||||
def getcolor(self, color, image=None):
|
||||
def getcolor(self, color, image=None) -> int:
|
||||
"""Given an rgb tuple, allocate palette entry.
|
||||
|
||||
.. warning:: This method is experimental.
|
||||
|
|
Loading…
Reference in New Issue
Block a user