|
104 | 104 | from __future__ import annotations |
105 | 105 |
|
106 | 106 | __docformat__ = 'google' |
107 | | -__version__ = '1.2.0' |
| 107 | +__version__ = '1.2.1' |
108 | 108 | __version_info__ = tuple(int(num) for num in __version__.split('.')) |
109 | 109 |
|
110 | 110 | import base64 |
|
116 | 116 | import itertools |
117 | 117 | import math |
118 | 118 | import numbers |
| 119 | +import os # Package only needed for typing.TYPE_CHECKING. |
119 | 120 | import pathlib |
120 | 121 | import re |
121 | 122 | import shlex |
|
134 | 135 | import PIL.Image |
135 | 136 | import PIL.ImageOps |
136 | 137 |
|
137 | | -if typing.TYPE_CHECKING: |
138 | | - import os # pylint: disable=g-bad-import-order |
139 | 138 |
|
140 | 139 | if not hasattr(PIL.Image, 'Resampling'): # Allow Pillow<9.0. |
141 | | - PIL.Image.Resampling = PIL.Image |
| 140 | + PIL.Image.Resampling = PIL.Image # type: ignore |
142 | 141 |
|
143 | 142 | # Selected and reordered here for pdoc documentation. |
144 | 143 | __all__ = [ |
|
189 | 188 |
|
190 | 189 | _IPYTHON_HTML_SIZE_LIMIT = 20_000_000 |
191 | 190 | _T = typing.TypeVar('_T') |
192 | | -_Path = typing.Union[str, 'os.PathLike[str]'] |
| 191 | +_Path = typing.Union[str, os.PathLike[str]] |
193 | 192 |
|
194 | 193 | _IMAGE_COMPARISON_HTML = """\ |
195 | 194 | <script |
@@ -420,7 +419,8 @@ def to_type(array: _ArrayLike, dtype: _DTypeLike) -> _NDArray: |
420 | 419 | a = a.astype(np.float64) * (dst_max / src_max) + 0.5 |
421 | 420 | dst = np.atleast_1d(a) |
422 | 421 | values_too_large = dst >= np.float64(dst_max) |
423 | | - dst = dst.astype(dtype) |
| 422 | + with np.errstate(invalid='ignore'): |
| 423 | + dst = dst.astype(dtype) |
424 | 424 | dst[values_too_large] = dst_max |
425 | 425 | result = dst if a.ndim > 0 else dst[0] |
426 | 426 | else: |
@@ -606,7 +606,8 @@ def _pil_image(image: _ArrayLike, mode: str | None = None) -> PIL.Image.Image: |
606 | 606 | image = _as_valid_media_array(image) |
607 | 607 | if image.ndim not in (2, 3): |
608 | 608 | raise ValueError(f'Image shape {image.shape} is neither 2D nor 3D.') |
609 | | - return PIL.Image.fromarray(image, mode=mode) |
| 609 | + pil_image: PIL.Image.Image = PIL.Image.fromarray(image, mode=mode) # type: ignore[no-untyped-call] |
| 610 | + return pil_image |
610 | 611 |
|
611 | 612 |
|
612 | 613 | def resize_image(image: _ArrayLike, shape: tuple[int, int]) -> _NDArray: |
@@ -884,9 +885,11 @@ def decompress_image( |
884 | 885 | """ |
885 | 886 | pil_image = PIL.Image.open(io.BytesIO(data)) |
886 | 887 | if apply_exif_transpose: |
887 | | - pil_image = PIL.ImageOps.exif_transpose(pil_image) |
| 888 | + tmp_image = PIL.ImageOps.exif_transpose(pil_image) # Future: in_place=True. |
| 889 | + assert tmp_image |
| 890 | + pil_image = tmp_image |
888 | 891 | if dtype is None: |
889 | | - dtype = np.uint16 if pil_image.mode == 'I' else np.uint8 |
| 892 | + dtype = np.uint16 if pil_image.mode.startswith('I') else np.uint8 |
890 | 893 | return np.array(pil_image, dtype=dtype) |
891 | 894 |
|
892 | 895 |
|
@@ -1222,15 +1225,15 @@ def _get_video_metadata(path: _Path) -> VideoMetadata: |
1222 | 1225 | _, err = proc.communicate() |
1223 | 1226 | bps = fps = num_images = width = height = rotation = None |
1224 | 1227 | for line in err.split('\n'): |
1225 | | - if match := re.search(r', bitrate: *([0-9.]+) kb/s', line): |
| 1228 | + if match := re.search(r', bitrate: *([\d.]+) kb/s', line): |
1226 | 1229 | bps = int(match.group(1)) * 1000 |
1227 | | - if matches := re.findall(r'frame= *([0-9]+) ', line): |
| 1230 | + if matches := re.findall(r'frame= *(\d+) ', line): |
1228 | 1231 | num_images = int(matches[-1]) |
1229 | 1232 | if 'Stream #0:' in line and ': Video:' in line: |
1230 | | - if not (match := re.search(r', ([0-9]+)x([0-9]+)', line)): |
| 1233 | + if not (match := re.search(r', (\d+)x(\d+)', line)): |
1231 | 1234 | raise RuntimeError(f'Unable to parse video dimensions in line {line}') |
1232 | 1235 | width, height = int(match.group(1)), int(match.group(2)) |
1233 | | - if match := re.search(r', ([0-9.]+) fps', line): |
| 1236 | + if match := re.search(r', ([\d.]+) fps', line): |
1234 | 1237 | fps = float(match.group(1)) |
1235 | 1238 | elif str(path).endswith('.gif'): |
1236 | 1239 | # Some GIF files lack a framerate attribute; use a reasonable default. |
|
0 commit comments