Skip to content

Commit 92dfb02

Browse files
authored
Merge pull request #1 from radarhere/types/fromarray
Added SupportsArrayInterface
2 parents 5d19151 + e85a84b commit 92dfb02

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

Tests/test_image_array.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ def test(mode: str) -> tuple[str, tuple[int, int], bool]:
9191
Image.fromarray(wrapped)
9292

9393

94+
def test_fromarray_strides_without_tobytes() -> None:
95+
class Wrapper:
96+
def __init__(self, arr_params: dict[str, Any]) -> None:
97+
self.__array_interface__ = arr_params
98+
99+
with pytest.raises(ValueError):
100+
wrapped = Wrapper({"shape": (1, 1), "strides": (1, 1)})
101+
Image.fromarray(wrapped, "L")
102+
103+
94104
def test_fromarray_palette() -> None:
95105
# Arrange
96106
i = im.convert("L")

docs/reference/Image.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ Constructing images
7878
^^^^^^^^^^^^^^^^^^^
7979

8080
.. autofunction:: new
81+
.. autoclass:: SupportsArrayInterface
82+
:show-inheritance:
8183
.. autofunction:: fromarray
8284
.. autofunction:: frombytes
8385
.. autofunction:: frombuffer

src/PIL/Image.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from collections.abc import Callable, MutableMapping
4242
from enum import IntEnum
4343
from types import ModuleType
44-
from typing import IO, TYPE_CHECKING, Any
44+
from typing import IO, TYPE_CHECKING, Any, Protocol
4545

4646
# VERSION was removed in Pillow 6.0.0.
4747
# PILLOW_VERSION was removed in Pillow 9.0.0.
@@ -3013,7 +3013,7 @@ def frombytes(mode, size, data, decoder_name="raw", *args) -> Image:
30133013
return im
30143014

30153015

3016-
def frombuffer(mode, size, data, decoder_name="raw", *args):
3016+
def frombuffer(mode, size, data, decoder_name="raw", *args) -> Image:
30173017
"""
30183018
Creates an image memory referencing pixel data in a byte buffer.
30193019
@@ -3069,10 +3069,15 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
30693069
return frombytes(mode, size, data, decoder_name, args)
30703070

30713071

3072-
def fromarray(
3073-
obj, # type: numpy.typing.ArrayLike
3074-
mode: str | None = None,
3075-
) -> Image:
3072+
class SupportsArrayInterface(Protocol):
3073+
"""
3074+
An object that has an ``__array_interface__`` dictionary.
3075+
"""
3076+
3077+
__array_interface__: dict[str, Any]
3078+
3079+
3080+
def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
30763081
"""
30773082
Creates an image memory from an object exporting the array interface
30783083
(using the buffer protocol)::
@@ -3151,8 +3156,11 @@ def fromarray(
31513156
if strides is not None:
31523157
if hasattr(obj, "tobytes"):
31533158
obj = obj.tobytes()
3154-
else:
3159+
elif hasattr(obj, "tostring"):
31553160
obj = obj.tostring()
3161+
else:
3162+
msg = "'strides' requires either tobytes() or tostring()"
3163+
raise ValueError(msg)
31563164

31573165
return frombuffer(mode, size, obj, "raw", rawmode, 0, 1)
31583166

0 commit comments

Comments
 (0)