Skip to content

Commit

Permalink
Merge pull request #7936 from adamjstewart/types/fromarray
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk authored Apr 17, 2024
2 parents b3749e4 + c655dc0 commit f8160b8
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 4 deletions.
10 changes: 10 additions & 0 deletions Tests/test_image_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ def test(mode: str) -> tuple[str, tuple[int, int], bool]:
Image.fromarray(wrapped)


def test_fromarray_strides_without_tobytes() -> None:
class Wrapper:
def __init__(self, arr_params: dict[str, Any]) -> None:
self.__array_interface__ = arr_params

with pytest.raises(ValueError):
wrapped = Wrapper({"shape": (1, 1), "strides": (1, 1)})
Image.fromarray(wrapped, "L")


def test_fromarray_palette() -> None:
# Arrange
i = im.convert("L")
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/Image.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ Constructing images
^^^^^^^^^^^^^^^^^^^

.. autofunction:: new
.. autoclass:: SupportsArrayInterface
:show-inheritance:
.. autofunction:: fromarray
.. autofunction:: frombytes
.. autofunction:: frombuffer
Expand Down
21 changes: 17 additions & 4 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from collections.abc import Callable, MutableMapping
from enum import IntEnum
from types import ModuleType
from typing import IO, TYPE_CHECKING, Any, Literal, cast
from typing import IO, TYPE_CHECKING, Any, Literal, Protocol, cast

# VERSION was removed in Pillow 6.0.0.
# PILLOW_VERSION was removed in Pillow 9.0.0.
Expand Down Expand Up @@ -3018,7 +3018,7 @@ def frombytes(mode, size, data, decoder_name="raw", *args) -> Image:
return im


def frombuffer(mode, size, data, decoder_name="raw", *args):
def frombuffer(mode, size, data, decoder_name="raw", *args) -> Image:
"""
Creates an image memory referencing pixel data in a byte buffer.
Expand Down Expand Up @@ -3074,7 +3074,17 @@ def frombuffer(mode, size, data, decoder_name="raw", *args):
return frombytes(mode, size, data, decoder_name, args)


def fromarray(obj, mode=None):
class SupportsArrayInterface(Protocol):
"""
An object that has an ``__array_interface__`` dictionary.
"""

@property
def __array_interface__(self) -> dict[str, Any]:
raise NotImplementedError()


def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
"""
Creates an image memory from an object exporting the array interface
(using the buffer protocol)::
Expand Down Expand Up @@ -3153,8 +3163,11 @@ def fromarray(obj, mode=None):
if strides is not None:
if hasattr(obj, "tobytes"):
obj = obj.tobytes()
else:
elif hasattr(obj, "tostring"):
obj = obj.tostring()
else:
msg = "'strides' requires either tobytes() or tostring()"
raise ValueError(msg)

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

Expand Down

0 comments on commit f8160b8

Please sign in to comment.