Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions Tests/test_image_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,8 @@ 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)})
with pytest.warns(DeprecationWarning, match="'mode' parameter"):
Image.fromarray(wrapped, "L")
wrapped = Wrapper({"shape": (1, 1), "strides": (1, 1), "typestr": "|u1"})
Image.fromarray(wrapped, "L")


def test_fromarray_palette() -> None:
Expand All @@ -112,9 +111,16 @@ def test_fromarray_palette() -> None:
a = numpy.array(i)

# Act
with pytest.warns(DeprecationWarning, match="'mode' parameter"):
out = Image.fromarray(a, "P")
out = Image.fromarray(a, "P")

# Assert that the Python and C palettes match
assert out.palette is not None
assert len(out.palette.colors) == len(out.im.getpalette()) / 3


def test_deprecation() -> None:
a = numpy.array(im.convert("L"))
with pytest.warns(
DeprecationWarning, match="'mode' parameter for changing data types"
):
Image.fromarray(a, "1")
8 changes: 6 additions & 2 deletions docs/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ Image.fromarray mode parameter

.. deprecated:: 11.3.0

The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
mode can be automatically determined from the object's shape and type instead.
Using the ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` was deprecated in
Pillow 11.3.0. In Pillow 12.0.0, this was partially reverted, and it is now only
deprecated when changing data types. Since pixel values do not contain information
about palettes or color spaces, the parameter can still be used to place grayscale L
mode data within a P mode image, or read RGB data as YCbCr for example. If omitted, the
mode will be automatically determined from the object's shape and type.

Saving I mode images as PNG
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
7 changes: 7 additions & 0 deletions docs/releasenotes/11.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ Image.fromarray mode parameter
The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
mode can be automatically determined from the object's shape and type instead.

.. note::

Since pixel values do not contain information about palettes or color spaces, part
of this functionality was restored in Pillow 12.0.0. The parameter can be used to
place grayscale L mode data within a P mode image, or read RGB data as YCbCr for
example.

Saving I mode images as PNG
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
9 changes: 9 additions & 0 deletions docs/releasenotes/12.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ of 3.14.0 final (2025-10-07, :pep:`745`).

Pillow 12.0.0 now officially supports Python 3.14.

Image.fromarray mode parameter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In Pillow 11.3.0, the ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` was
deprecated. Part of this functionality has been restored in Pillow 12.0.0. Since pixel
values do not contain information about palettes or color spaces, the parameter can be
used to place grayscale L mode data within a P mode image, or read RGB data as YCbCr
for example.

ImageMorph operations must have length 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
80 changes: 39 additions & 41 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -3257,19 +3257,10 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
transferred. This means that P and PA mode images will lose their palette.

:param obj: Object with array interface
:param mode: Optional mode to use when reading ``obj``. Will be determined from
type if ``None``. Deprecated.

This will not be used to convert the data after reading, but will be used to
change how the data is read::

from PIL import Image
import numpy as np
a = np.full((1, 1), 300)
im = Image.fromarray(a, mode="L")
im.getpixel((0, 0)) # 44
im = Image.fromarray(a, mode="RGB")
im.getpixel((0, 0)) # (44, 1, 0)
:param mode: Optional mode to use when reading ``obj``. Since pixel values do not
contain information about palettes or color spaces, this can be used to place
grayscale L mode data within a P mode image, or read RGB data as YCbCr for
example.

See: :ref:`concept-modes` for general information about modes.
:returns: An image object.
Expand All @@ -3280,21 +3271,28 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
shape = arr["shape"]
ndim = len(shape)
strides = arr.get("strides", None)
if mode is None:
try:
typekey = (1, 1) + shape[2:], arr["typestr"]
except KeyError as e:
try:
typekey = (1, 1) + shape[2:], arr["typestr"]
except KeyError as e:
if mode is not None:
typekey = None
color_modes: list[str] = []
else:
msg = "Cannot handle this data type"
raise TypeError(msg) from e
if typekey is not None:
try:
mode, rawmode = _fromarray_typemap[typekey]
typemode, rawmode, color_modes = _fromarray_typemap[typekey]
except KeyError as e:
typekey_shape, typestr = typekey
msg = f"Cannot handle this data type: {typekey_shape}, {typestr}"
raise TypeError(msg) from e
else:
deprecate("'mode' parameter", 13)
if mode is not None:
if mode != typemode and mode not in color_modes:
deprecate("'mode' parameter for changing data types", 13)
rawmode = mode
else:
mode = typemode
if mode in ["1", "L", "I", "P", "F"]:
ndmax = 2
elif mode == "RGB":
Expand Down Expand Up @@ -3391,29 +3389,29 @@ def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile:


_fromarray_typemap = {
# (shape, typestr) => mode, rawmode
# (shape, typestr) => mode, rawmode, color modes
# first two members of shape are set to one
((1, 1), "|b1"): ("1", "1;8"),
((1, 1), "|u1"): ("L", "L"),
((1, 1), "|i1"): ("I", "I;8"),
((1, 1), "<u2"): ("I", "I;16"),
((1, 1), ">u2"): ("I", "I;16B"),
((1, 1), "<i2"): ("I", "I;16S"),
((1, 1), ">i2"): ("I", "I;16BS"),
((1, 1), "<u4"): ("I", "I;32"),
((1, 1), ">u4"): ("I", "I;32B"),
((1, 1), "<i4"): ("I", "I;32S"),
((1, 1), ">i4"): ("I", "I;32BS"),
((1, 1), "<f4"): ("F", "F;32F"),
((1, 1), ">f4"): ("F", "F;32BF"),
((1, 1), "<f8"): ("F", "F;64F"),
((1, 1), ">f8"): ("F", "F;64BF"),
((1, 1, 2), "|u1"): ("LA", "LA"),
((1, 1, 3), "|u1"): ("RGB", "RGB"),
((1, 1, 4), "|u1"): ("RGBA", "RGBA"),
((1, 1), "|b1"): ("1", "1;8", []),
((1, 1), "|u1"): ("L", "L", ["P"]),
((1, 1), "|i1"): ("I", "I;8", []),
((1, 1), "<u2"): ("I", "I;16", []),
((1, 1), ">u2"): ("I", "I;16B", []),
((1, 1), "<i2"): ("I", "I;16S", []),
((1, 1), ">i2"): ("I", "I;16BS", []),
((1, 1), "<u4"): ("I", "I;32", []),
((1, 1), ">u4"): ("I", "I;32B", []),
((1, 1), "<i4"): ("I", "I;32S", []),
((1, 1), ">i4"): ("I", "I;32BS", []),
((1, 1), "<f4"): ("F", "F;32F", []),
((1, 1), ">f4"): ("F", "F;32BF", []),
((1, 1), "<f8"): ("F", "F;64F", []),
((1, 1), ">f8"): ("F", "F;64BF", []),
((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]),
((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]),
((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]),
# shortcuts:
((1, 1), f"{_ENDIAN}i4"): ("I", "I"),
((1, 1), f"{_ENDIAN}f4"): ("F", "F"),
((1, 1), f"{_ENDIAN}i4"): ("I", "I", []),
((1, 1), f"{_ENDIAN}f4"): ("F", "F", []),
}


Expand Down
Loading