mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-11-14 05:36:48 +03:00
Added type hints
This commit is contained in:
parent
f8a9a18e7d
commit
f624460321
|
@ -240,10 +240,11 @@ class TestFileLibTiff(LibTiffTestCase):
|
||||||
|
|
||||||
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
new_ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
for tag, info in core_items.items():
|
for tag, info in core_items.items():
|
||||||
if info.length == 1:
|
assert info.type is not None
|
||||||
new_ifd[tag] = values[info.type]
|
if not info.length:
|
||||||
if info.length == 0:
|
|
||||||
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
|
new_ifd[tag] = tuple(values[info.type] for _ in range(3))
|
||||||
|
elif info.length == 1:
|
||||||
|
new_ifd[tag] = values[info.type]
|
||||||
else:
|
else:
|
||||||
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
|
new_ifd[tag] = tuple(values[info.type] for _ in range(info.length))
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,11 @@ Example: Parse an image
|
||||||
Classes
|
Classes
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
.. autoclass:: PIL.ImageFile._Tile()
|
||||||
|
:member-order: bysource
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
.. autoclass:: PIL.ImageFile.Parser()
|
.. autoclass:: PIL.ImageFile.Parser()
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ class Dib:
|
||||||
assert not isinstance(image, str)
|
assert not isinstance(image, str)
|
||||||
self.paste(image)
|
self.paste(image)
|
||||||
|
|
||||||
def expose(self, handle):
|
def expose(self, handle: int | HDC | HWND) -> None:
|
||||||
"""
|
"""
|
||||||
Copy the bitmap contents to a device context.
|
Copy the bitmap contents to a device context.
|
||||||
|
|
||||||
|
@ -101,19 +101,18 @@ class Dib:
|
||||||
if isinstance(handle, HWND):
|
if isinstance(handle, HWND):
|
||||||
dc = self.image.getdc(handle)
|
dc = self.image.getdc(handle)
|
||||||
try:
|
try:
|
||||||
result = self.image.expose(dc)
|
self.image.expose(dc)
|
||||||
finally:
|
finally:
|
||||||
self.image.releasedc(handle, dc)
|
self.image.releasedc(handle, dc)
|
||||||
else:
|
else:
|
||||||
result = self.image.expose(handle)
|
self.image.expose(handle)
|
||||||
return result
|
|
||||||
|
|
||||||
def draw(
|
def draw(
|
||||||
self,
|
self,
|
||||||
handle,
|
handle: int | HDC | HWND,
|
||||||
dst: tuple[int, int, int, int],
|
dst: tuple[int, int, int, int],
|
||||||
src: tuple[int, int, int, int] | None = None,
|
src: tuple[int, int, int, int] | None = None,
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Same as expose, but allows you to specify where to draw the image, and
|
Same as expose, but allows you to specify where to draw the image, and
|
||||||
what part of it to draw.
|
what part of it to draw.
|
||||||
|
@ -128,14 +127,13 @@ class Dib:
|
||||||
if isinstance(handle, HWND):
|
if isinstance(handle, HWND):
|
||||||
dc = self.image.getdc(handle)
|
dc = self.image.getdc(handle)
|
||||||
try:
|
try:
|
||||||
result = self.image.draw(dc, dst, src)
|
self.image.draw(dc, dst, src)
|
||||||
finally:
|
finally:
|
||||||
self.image.releasedc(handle, dc)
|
self.image.releasedc(handle, dc)
|
||||||
else:
|
else:
|
||||||
result = self.image.draw(handle, dst, src)
|
self.image.draw(handle, dst, src)
|
||||||
return result
|
|
||||||
|
|
||||||
def query_palette(self, handle):
|
def query_palette(self, handle: int | HDC | HWND) -> int:
|
||||||
"""
|
"""
|
||||||
Installs the palette associated with the image in the given device
|
Installs the palette associated with the image in the given device
|
||||||
context.
|
context.
|
||||||
|
@ -147,8 +145,8 @@ class Dib:
|
||||||
|
|
||||||
:param handle: Device context (HDC), cast to a Python integer, or an
|
:param handle: Device context (HDC), cast to a Python integer, or an
|
||||||
HDC or HWND instance.
|
HDC or HWND instance.
|
||||||
:return: A true value if one or more entries were changed (this
|
:return: The number of entries that were changed (if one or more entries,
|
||||||
indicates that the image should be redrawn).
|
this indicates that the image should be redrawn).
|
||||||
"""
|
"""
|
||||||
if isinstance(handle, HWND):
|
if isinstance(handle, HWND):
|
||||||
handle = self.image.getdc(handle)
|
handle = self.image.getdc(handle)
|
||||||
|
@ -210,22 +208,22 @@ class Window:
|
||||||
title, self.__dispatcher, width or 0, height or 0
|
title, self.__dispatcher, width or 0, height or 0
|
||||||
)
|
)
|
||||||
|
|
||||||
def __dispatcher(self, action: str, *args):
|
def __dispatcher(self, action: str, *args: int) -> None:
|
||||||
return getattr(self, f"ui_handle_{action}")(*args)
|
getattr(self, f"ui_handle_{action}")(*args)
|
||||||
|
|
||||||
def ui_handle_clear(self, dc, x0, y0, x1, y1) -> None:
|
def ui_handle_clear(self, dc: int, x0: int, y0: int, x1: int, y1: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def ui_handle_damage(self, x0, y0, x1, y1) -> None:
|
def ui_handle_damage(self, x0: int, y0: int, x1: int, y1: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def ui_handle_destroy(self) -> None:
|
def ui_handle_destroy(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def ui_handle_repair(self, dc, x0, y0, x1, y1) -> None:
|
def ui_handle_repair(self, dc: int, x0: int, y0: int, x1: int, y1: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def ui_handle_resize(self, width, height) -> None:
|
def ui_handle_resize(self, width: int, height: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def mainloop(self) -> None:
|
def mainloop(self) -> None:
|
||||||
|
@ -235,12 +233,12 @@ class Window:
|
||||||
class ImageWindow(Window):
|
class ImageWindow(Window):
|
||||||
"""Create an image window which displays the given image."""
|
"""Create an image window which displays the given image."""
|
||||||
|
|
||||||
def __init__(self, image, title: str = "PIL") -> None:
|
def __init__(self, image: Image.Image | Dib, title: str = "PIL") -> None:
|
||||||
if not isinstance(image, Dib):
|
if not isinstance(image, Dib):
|
||||||
image = Dib(image)
|
image = Dib(image)
|
||||||
self.image = image
|
self.image = image
|
||||||
width, height = image.size
|
width, height = image.size
|
||||||
super().__init__(title, width=width, height=height)
|
super().__init__(title, width=width, height=height)
|
||||||
|
|
||||||
def ui_handle_repair(self, dc, x0, y0, x1, y1) -> None:
|
def ui_handle_repair(self, dc: int, x0: int, y0: int, x1: int, y1: int) -> None:
|
||||||
self.image.draw(dc, (x0, y0, x1, y1))
|
self.image.draw(dc, (x0, y0, x1, y1))
|
||||||
|
|
|
@ -19,6 +19,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import io
|
import io
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
from typing import IO
|
||||||
|
|
||||||
from . import Image, ImageFile, ImagePalette
|
from . import Image, ImageFile, ImagePalette
|
||||||
from ._binary import i8
|
from ._binary import i8
|
||||||
|
@ -142,7 +143,9 @@ class PsdImageFile(ImageFile.ImageFile):
|
||||||
self._min_frame = 1
|
self._min_frame = 1
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def layers(self):
|
def layers(
|
||||||
|
self,
|
||||||
|
) -> list[tuple[str, str, tuple[int, int, int, int], list[ImageFile._Tile]]]:
|
||||||
layers = []
|
layers = []
|
||||||
if self._layers_position is not None:
|
if self._layers_position is not None:
|
||||||
self._fp.seek(self._layers_position)
|
self._fp.seek(self._layers_position)
|
||||||
|
@ -181,7 +184,9 @@ class PsdImageFile(ImageFile.ImageFile):
|
||||||
return self.frame
|
return self.frame
|
||||||
|
|
||||||
|
|
||||||
def _layerinfo(fp, ct_bytes):
|
def _layerinfo(
|
||||||
|
fp: IO[bytes], ct_bytes: int
|
||||||
|
) -> list[tuple[str, str, tuple[int, int, int, int], list[ImageFile._Tile]]]:
|
||||||
# read layerinfo block
|
# read layerinfo block
|
||||||
layers = []
|
layers = []
|
||||||
|
|
||||||
|
@ -203,7 +208,7 @@ def _layerinfo(fp, ct_bytes):
|
||||||
x1 = si32(read(4))
|
x1 = si32(read(4))
|
||||||
|
|
||||||
# image info
|
# image info
|
||||||
mode = []
|
bands = []
|
||||||
ct_types = i16(read(2))
|
ct_types = i16(read(2))
|
||||||
if ct_types > 4:
|
if ct_types > 4:
|
||||||
fp.seek(ct_types * 6 + 12, io.SEEK_CUR)
|
fp.seek(ct_types * 6 + 12, io.SEEK_CUR)
|
||||||
|
@ -215,23 +220,23 @@ def _layerinfo(fp, ct_bytes):
|
||||||
type = i16(read(2))
|
type = i16(read(2))
|
||||||
|
|
||||||
if type == 65535:
|
if type == 65535:
|
||||||
m = "A"
|
b = "A"
|
||||||
else:
|
else:
|
||||||
m = "RGBA"[type]
|
b = "RGBA"[type]
|
||||||
|
|
||||||
mode.append(m)
|
bands.append(b)
|
||||||
read(4) # size
|
read(4) # size
|
||||||
|
|
||||||
# figure out the image mode
|
# figure out the image mode
|
||||||
mode.sort()
|
bands.sort()
|
||||||
if mode == ["R"]:
|
if bands == ["R"]:
|
||||||
mode = "L"
|
mode = "L"
|
||||||
elif mode == ["B", "G", "R"]:
|
elif bands == ["B", "G", "R"]:
|
||||||
mode = "RGB"
|
mode = "RGB"
|
||||||
elif mode == ["A", "B", "G", "R"]:
|
elif bands == ["A", "B", "G", "R"]:
|
||||||
mode = "RGBA"
|
mode = "RGBA"
|
||||||
else:
|
else:
|
||||||
mode = None # unknown
|
mode = "" # unknown
|
||||||
|
|
||||||
# skip over blend flags and extra information
|
# skip over blend flags and extra information
|
||||||
read(12) # filler
|
read(12) # filler
|
||||||
|
@ -258,19 +263,22 @@ def _layerinfo(fp, ct_bytes):
|
||||||
layers.append((name, mode, (x0, y0, x1, y1)))
|
layers.append((name, mode, (x0, y0, x1, y1)))
|
||||||
|
|
||||||
# get tiles
|
# get tiles
|
||||||
|
layerinfo = []
|
||||||
for i, (name, mode, bbox) in enumerate(layers):
|
for i, (name, mode, bbox) in enumerate(layers):
|
||||||
tile = []
|
tile = []
|
||||||
for m in mode:
|
for m in mode:
|
||||||
t = _maketile(fp, m, bbox, 1)
|
t = _maketile(fp, m, bbox, 1)
|
||||||
if t:
|
if t:
|
||||||
tile.extend(t)
|
tile.extend(t)
|
||||||
layers[i] = name, mode, bbox, tile
|
layerinfo.append((name, mode, bbox, tile))
|
||||||
|
|
||||||
return layers
|
return layerinfo
|
||||||
|
|
||||||
|
|
||||||
def _maketile(file, mode, bbox, channels):
|
def _maketile(
|
||||||
tile = None
|
file: IO[bytes], mode: str, bbox: tuple[int, int, int, int], channels: int
|
||||||
|
) -> list[ImageFile._Tile] | None:
|
||||||
|
tiles = None
|
||||||
read = file.read
|
read = file.read
|
||||||
|
|
||||||
compression = i16(read(2))
|
compression = i16(read(2))
|
||||||
|
@ -283,26 +291,26 @@ def _maketile(file, mode, bbox, channels):
|
||||||
if compression == 0:
|
if compression == 0:
|
||||||
#
|
#
|
||||||
# raw compression
|
# raw compression
|
||||||
tile = []
|
tiles = []
|
||||||
for channel in range(channels):
|
for channel in range(channels):
|
||||||
layer = mode[channel]
|
layer = mode[channel]
|
||||||
if mode == "CMYK":
|
if mode == "CMYK":
|
||||||
layer += ";I"
|
layer += ";I"
|
||||||
tile.append(("raw", bbox, offset, layer))
|
tiles.append(ImageFile._Tile("raw", bbox, offset, layer))
|
||||||
offset = offset + xsize * ysize
|
offset = offset + xsize * ysize
|
||||||
|
|
||||||
elif compression == 1:
|
elif compression == 1:
|
||||||
#
|
#
|
||||||
# packbits compression
|
# packbits compression
|
||||||
i = 0
|
i = 0
|
||||||
tile = []
|
tiles = []
|
||||||
bytecount = read(channels * ysize * 2)
|
bytecount = read(channels * ysize * 2)
|
||||||
offset = file.tell()
|
offset = file.tell()
|
||||||
for channel in range(channels):
|
for channel in range(channels):
|
||||||
layer = mode[channel]
|
layer = mode[channel]
|
||||||
if mode == "CMYK":
|
if mode == "CMYK":
|
||||||
layer += ";I"
|
layer += ";I"
|
||||||
tile.append(("packbits", bbox, offset, layer))
|
tiles.append(ImageFile._Tile("packbits", bbox, offset, layer))
|
||||||
for y in range(ysize):
|
for y in range(ysize):
|
||||||
offset = offset + i16(bytecount, i)
|
offset = offset + i16(bytecount, i)
|
||||||
i += 2
|
i += 2
|
||||||
|
@ -312,7 +320,7 @@ def _maketile(file, mode, bbox, channels):
|
||||||
if offset & 1:
|
if offset & 1:
|
||||||
read(1) # padding
|
read(1) # padding
|
||||||
|
|
||||||
return tile
|
return tiles
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
|
@ -445,7 +445,7 @@ class IFDRational(Rational):
|
||||||
__int__ = _delegate("__int__")
|
__int__ = _delegate("__int__")
|
||||||
|
|
||||||
|
|
||||||
def _register_loader(idx, size):
|
def _register_loader(idx: int, size: int):
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
from .TiffTags import TYPES
|
from .TiffTags import TYPES
|
||||||
|
|
||||||
|
@ -457,7 +457,7 @@ def _register_loader(idx, size):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def _register_writer(idx):
|
def _register_writer(idx: int):
|
||||||
def decorator(func):
|
def decorator(func):
|
||||||
_write_dispatch[idx] = func # noqa: F821
|
_write_dispatch[idx] = func # noqa: F821
|
||||||
return func
|
return func
|
||||||
|
@ -465,7 +465,7 @@ def _register_writer(idx):
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def _register_basic(idx_fmt_name):
|
def _register_basic(idx_fmt_name: tuple[int, str, str]) -> None:
|
||||||
from .TiffTags import TYPES
|
from .TiffTags import TYPES
|
||||||
|
|
||||||
idx, fmt, name = idx_fmt_name
|
idx, fmt, name = idx_fmt_name
|
||||||
|
@ -640,7 +640,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
def __contains__(self, tag: object) -> bool:
|
def __contains__(self, tag: object) -> bool:
|
||||||
return tag in self._tags_v2 or tag in self._tagdata
|
return tag in self._tags_v2 or tag in self._tagdata
|
||||||
|
|
||||||
def __setitem__(self, tag, value) -> None:
|
def __setitem__(self, tag: int, value) -> None:
|
||||||
self._setitem(tag, value, self.legacy_api)
|
self._setitem(tag, value, self.legacy_api)
|
||||||
|
|
||||||
def _setitem(self, tag, value, legacy_api) -> None:
|
def _setitem(self, tag, value, legacy_api) -> None:
|
||||||
|
@ -731,10 +731,10 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(set(self._tagdata) | set(self._tags_v2))
|
return iter(set(self._tagdata) | set(self._tags_v2))
|
||||||
|
|
||||||
def _unpack(self, fmt, data):
|
def _unpack(self, fmt: str, data):
|
||||||
return struct.unpack(self._endian + fmt, data)
|
return struct.unpack(self._endian + fmt, data)
|
||||||
|
|
||||||
def _pack(self, fmt, *values):
|
def _pack(self, fmt: str, *values):
|
||||||
return struct.pack(self._endian + fmt, *values)
|
return struct.pack(self._endian + fmt, *values)
|
||||||
|
|
||||||
list(
|
list(
|
||||||
|
@ -755,7 +755,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
)
|
)
|
||||||
|
|
||||||
@_register_loader(1, 1) # Basic type, except for the legacy API.
|
@_register_loader(1, 1) # Basic type, except for the legacy API.
|
||||||
def load_byte(self, data, legacy_api=True):
|
def load_byte(self, data, legacy_api: bool = True):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@_register_writer(1) # Basic type, except for the legacy API.
|
@_register_writer(1) # Basic type, except for the legacy API.
|
||||||
|
@ -767,7 +767,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@_register_loader(2, 1)
|
@_register_loader(2, 1)
|
||||||
def load_string(self, data, legacy_api=True):
|
def load_string(self, data: bytes, legacy_api: bool = True) -> str:
|
||||||
if data.endswith(b"\0"):
|
if data.endswith(b"\0"):
|
||||||
data = data[:-1]
|
data = data[:-1]
|
||||||
return data.decode("latin-1", "replace")
|
return data.decode("latin-1", "replace")
|
||||||
|
@ -797,7 +797,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
)
|
)
|
||||||
|
|
||||||
@_register_loader(7, 1)
|
@_register_loader(7, 1)
|
||||||
def load_undefined(self, data, legacy_api=True):
|
def load_undefined(self, data, legacy_api: bool = True):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@_register_writer(7)
|
@_register_writer(7)
|
||||||
|
@ -809,7 +809,7 @@ class ImageFileDirectory_v2(_IFDv2Base):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@_register_loader(10, 8)
|
@_register_loader(10, 8)
|
||||||
def load_signed_rational(self, data, legacy_api=True):
|
def load_signed_rational(self, data, legacy_api: bool = True):
|
||||||
vals = self._unpack(f"{len(data) // 4}l", data)
|
vals = self._unpack(f"{len(data) // 4}l", data)
|
||||||
|
|
||||||
def combine(a, b):
|
def combine(a, b):
|
||||||
|
@ -1030,7 +1030,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
||||||
"""Dictionary of tag types"""
|
"""Dictionary of tag types"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_v2(cls, original) -> ImageFileDirectory_v1:
|
def from_v2(cls, original: ImageFileDirectory_v2) -> ImageFileDirectory_v1:
|
||||||
"""Returns an
|
"""Returns an
|
||||||
:py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
|
:py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
|
||||||
instance with the same data as is contained in the original
|
instance with the same data as is contained in the original
|
||||||
|
@ -1073,7 +1073,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2):
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(set(self._tagdata) | set(self._tags_v1))
|
return iter(set(self._tagdata) | set(self._tags_v1))
|
||||||
|
|
||||||
def __setitem__(self, tag, value) -> None:
|
def __setitem__(self, tag: int, value) -> None:
|
||||||
for legacy_api in (False, True):
|
for legacy_api in (False, True):
|
||||||
self._setitem(tag, value, legacy_api)
|
self._setitem(tag, value, legacy_api)
|
||||||
|
|
||||||
|
@ -1212,7 +1212,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
"""Return the current frame number"""
|
"""Return the current frame number"""
|
||||||
return self.__frame
|
return self.__frame
|
||||||
|
|
||||||
def get_photoshop_blocks(self):
|
def get_photoshop_blocks(self) -> dict[int, dict[str, bytes]]:
|
||||||
"""
|
"""
|
||||||
Returns a dictionary of Photoshop "Image Resource Blocks".
|
Returns a dictionary of Photoshop "Image Resource Blocks".
|
||||||
The keys are the image resource ID. For more information, see
|
The keys are the image resource ID. For more information, see
|
||||||
|
@ -1259,7 +1259,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
if ExifTags.Base.Orientation in self.tag_v2:
|
if ExifTags.Base.Orientation in self.tag_v2:
|
||||||
del self.tag_v2[ExifTags.Base.Orientation]
|
del self.tag_v2[ExifTags.Base.Orientation]
|
||||||
|
|
||||||
def _load_libtiff(self):
|
def _load_libtiff(self) -> Image.core.PixelAccess | None:
|
||||||
"""Overload method triggered when we detect a compressed tiff
|
"""Overload method triggered when we detect a compressed tiff
|
||||||
Calls out to libtiff"""
|
Calls out to libtiff"""
|
||||||
|
|
||||||
|
|
|
@ -32,17 +32,24 @@ class _TagInfo(NamedTuple):
|
||||||
class TagInfo(_TagInfo):
|
class TagInfo(_TagInfo):
|
||||||
__slots__: list[str] = []
|
__slots__: list[str] = []
|
||||||
|
|
||||||
def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None):
|
def __new__(
|
||||||
|
cls,
|
||||||
|
value: int | None = None,
|
||||||
|
name: str = "unknown",
|
||||||
|
type: int | None = None,
|
||||||
|
length: int | None = None,
|
||||||
|
enum: dict[str, int] | None = None,
|
||||||
|
) -> TagInfo:
|
||||||
return super().__new__(cls, value, name, type, length, enum or {})
|
return super().__new__(cls, value, name, type, length, enum or {})
|
||||||
|
|
||||||
def cvt_enum(self, value):
|
def cvt_enum(self, value: str) -> int | str:
|
||||||
# Using get will call hash(value), which can be expensive
|
# Using get will call hash(value), which can be expensive
|
||||||
# for some types (e.g. Fraction). Since self.enum is rarely
|
# for some types (e.g. Fraction). Since self.enum is rarely
|
||||||
# used, it's usually better to test it first.
|
# used, it's usually better to test it first.
|
||||||
return self.enum.get(value, value) if self.enum else value
|
return self.enum.get(value, value) if self.enum else value
|
||||||
|
|
||||||
|
|
||||||
def lookup(tag, group=None):
|
def lookup(tag: int, group: int | None = None) -> TagInfo:
|
||||||
"""
|
"""
|
||||||
:param tag: Integer tag number
|
:param tag: Integer tag number
|
||||||
:param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in
|
:param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in
|
||||||
|
@ -89,7 +96,7 @@ DOUBLE = 12
|
||||||
IFD = 13
|
IFD = 13
|
||||||
LONG8 = 16
|
LONG8 = 16
|
||||||
|
|
||||||
_tags_v2 = {
|
_tags_v2: dict[int, tuple[str, int, int] | tuple[str, int, int, dict[str, int]]] = {
|
||||||
254: ("NewSubfileType", LONG, 1),
|
254: ("NewSubfileType", LONG, 1),
|
||||||
255: ("SubfileType", SHORT, 1),
|
255: ("SubfileType", SHORT, 1),
|
||||||
256: ("ImageWidth", LONG, 1),
|
256: ("ImageWidth", LONG, 1),
|
||||||
|
@ -233,7 +240,7 @@ _tags_v2 = {
|
||||||
50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one
|
50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one
|
||||||
50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006
|
50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006
|
||||||
}
|
}
|
||||||
TAGS_V2_GROUPS = {
|
_tags_v2_groups = {
|
||||||
# ExifIFD
|
# ExifIFD
|
||||||
34665: {
|
34665: {
|
||||||
36864: ("ExifVersion", UNDEFINED, 1),
|
36864: ("ExifVersion", UNDEFINED, 1),
|
||||||
|
@ -281,7 +288,7 @@ TAGS_V2_GROUPS = {
|
||||||
|
|
||||||
# Legacy Tags structure
|
# Legacy Tags structure
|
||||||
# these tags aren't included above, but were in the previous versions
|
# these tags aren't included above, but were in the previous versions
|
||||||
TAGS = {
|
TAGS: dict[int | tuple[int, int], str] = {
|
||||||
347: "JPEGTables",
|
347: "JPEGTables",
|
||||||
700: "XMP",
|
700: "XMP",
|
||||||
# Additional Exif Info
|
# Additional Exif Info
|
||||||
|
@ -426,9 +433,10 @@ TAGS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
TAGS_V2: dict[int, TagInfo] = {}
|
TAGS_V2: dict[int, TagInfo] = {}
|
||||||
|
TAGS_V2_GROUPS: dict[int, dict[int, TagInfo]] = {}
|
||||||
|
|
||||||
|
|
||||||
def _populate():
|
def _populate() -> None:
|
||||||
for k, v in _tags_v2.items():
|
for k, v in _tags_v2.items():
|
||||||
# Populate legacy structure.
|
# Populate legacy structure.
|
||||||
TAGS[k] = v[0]
|
TAGS[k] = v[0]
|
||||||
|
@ -438,9 +446,8 @@ def _populate():
|
||||||
|
|
||||||
TAGS_V2[k] = TagInfo(k, *v)
|
TAGS_V2[k] = TagInfo(k, *v)
|
||||||
|
|
||||||
for tags in TAGS_V2_GROUPS.values():
|
for group, tags in _tags_v2_groups.items():
|
||||||
for k, v in tags.items():
|
TAGS_V2_GROUPS[group] = {k: TagInfo(k, *v) for k, v in tags.items()}
|
||||||
tags[k] = TagInfo(k, *v)
|
|
||||||
|
|
||||||
|
|
||||||
_populate()
|
_populate()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user