Skip to content

Commit ba04d58

Browse files
authored
Only deprecate fromarray mode for changing data types (#9063)
2 parents 54d329f + 73490e1 commit ba04d58

File tree

5 files changed

+72
-48
lines changed

5 files changed

+72
-48
lines changed

Tests/test_image_array.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,8 @@ def __init__(self, arr_params: dict[str, Any]) -> None:
101101
self.__array_interface__ = arr_params
102102

103103
with pytest.raises(ValueError):
104-
wrapped = Wrapper({"shape": (1, 1), "strides": (1, 1)})
105-
with pytest.warns(DeprecationWarning, match="'mode' parameter"):
106-
Image.fromarray(wrapped, "L")
104+
wrapped = Wrapper({"shape": (1, 1), "strides": (1, 1), "typestr": "|u1"})
105+
Image.fromarray(wrapped, "L")
107106

108107

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

114113
# Act
115-
with pytest.warns(DeprecationWarning, match="'mode' parameter"):
116-
out = Image.fromarray(a, "P")
114+
out = Image.fromarray(a, "P")
117115

118116
# Assert that the Python and C palettes match
119117
assert out.palette is not None
120118
assert len(out.palette.colors) == len(out.im.getpalette()) / 3
119+
120+
121+
def test_deprecation() -> None:
122+
a = numpy.array(im.convert("L"))
123+
with pytest.warns(
124+
DeprecationWarning, match="'mode' parameter for changing data types"
125+
):
126+
Image.fromarray(a, "1")

docs/deprecations.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ Image.fromarray mode parameter
3535

3636
.. deprecated:: 11.3.0
3737

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

4145
Saving I mode images as PNG
4246
^^^^^^^^^^^^^^^^^^^^^^^^^^^

docs/releasenotes/11.3.0.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ Image.fromarray mode parameter
2929
The ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` has been deprecated. The
3030
mode can be automatically determined from the object's shape and type instead.
3131

32+
.. note::
33+
34+
Since pixel values do not contain information about palettes or color spaces, part
35+
of this functionality was restored in Pillow 12.0.0. The parameter can be used to
36+
place grayscale L mode data within a P mode image, or read RGB data as YCbCr for
37+
example.
38+
3239
Saving I mode images as PNG
3340
^^^^^^^^^^^^^^^^^^^^^^^^^^^
3441

docs/releasenotes/12.0.0.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ of 3.14.0 final (2025-10-07, :pep:`745`).
157157

158158
Pillow 12.0.0 now officially supports Python 3.14.
159159

160+
Image.fromarray mode parameter
161+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
162+
163+
In Pillow 11.3.0, the ``mode`` parameter in :py:meth:`~PIL.Image.fromarray()` was
164+
deprecated. Part of this functionality has been restored in Pillow 12.0.0. Since pixel
165+
values do not contain information about palettes or color spaces, the parameter can be
166+
used to place grayscale L mode data within a P mode image, or read RGB data as YCbCr
167+
for example.
168+
160169
ImageMorph operations must have length 1
161170
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
162171

src/PIL/Image.py

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3259,19 +3259,10 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
32593259
transferred. This means that P and PA mode images will lose their palette.
32603260
32613261
:param obj: Object with array interface
3262-
:param mode: Optional mode to use when reading ``obj``. Will be determined from
3263-
type if ``None``. Deprecated.
3264-
3265-
This will not be used to convert the data after reading, but will be used to
3266-
change how the data is read::
3267-
3268-
from PIL import Image
3269-
import numpy as np
3270-
a = np.full((1, 1), 300)
3271-
im = Image.fromarray(a, mode="L")
3272-
im.getpixel((0, 0)) # 44
3273-
im = Image.fromarray(a, mode="RGB")
3274-
im.getpixel((0, 0)) # (44, 1, 0)
3262+
:param mode: Optional mode to use when reading ``obj``. Since pixel values do not
3263+
contain information about palettes or color spaces, this can be used to place
3264+
grayscale L mode data within a P mode image, or read RGB data as YCbCr for
3265+
example.
32753266
32763267
See: :ref:`concept-modes` for general information about modes.
32773268
:returns: An image object.
@@ -3282,21 +3273,28 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image:
32823273
shape = arr["shape"]
32833274
ndim = len(shape)
32843275
strides = arr.get("strides", None)
3285-
if mode is None:
3286-
try:
3287-
typekey = (1, 1) + shape[2:], arr["typestr"]
3288-
except KeyError as e:
3276+
try:
3277+
typekey = (1, 1) + shape[2:], arr["typestr"]
3278+
except KeyError as e:
3279+
if mode is not None:
3280+
typekey = None
3281+
color_modes: list[str] = []
3282+
else:
32893283
msg = "Cannot handle this data type"
32903284
raise TypeError(msg) from e
3285+
if typekey is not None:
32913286
try:
3292-
mode, rawmode = _fromarray_typemap[typekey]
3287+
typemode, rawmode, color_modes = _fromarray_typemap[typekey]
32933288
except KeyError as e:
32943289
typekey_shape, typestr = typekey
32953290
msg = f"Cannot handle this data type: {typekey_shape}, {typestr}"
32963291
raise TypeError(msg) from e
3297-
else:
3298-
deprecate("'mode' parameter", 13)
3292+
if mode is not None:
3293+
if mode != typemode and mode not in color_modes:
3294+
deprecate("'mode' parameter for changing data types", 13)
32993295
rawmode = mode
3296+
else:
3297+
mode = typemode
33003298
if mode in ["1", "L", "I", "P", "F"]:
33013299
ndmax = 2
33023300
elif mode == "RGB":
@@ -3393,29 +3391,29 @@ def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile:
33933391

33943392

33953393
_fromarray_typemap = {
3396-
# (shape, typestr) => mode, rawmode
3394+
# (shape, typestr) => mode, rawmode, color modes
33973395
# first two members of shape are set to one
3398-
((1, 1), "|b1"): ("1", "1;8"),
3399-
((1, 1), "|u1"): ("L", "L"),
3400-
((1, 1), "|i1"): ("I", "I;8"),
3401-
((1, 1), "<u2"): ("I", "I;16"),
3402-
((1, 1), ">u2"): ("I", "I;16B"),
3403-
((1, 1), "<i2"): ("I", "I;16S"),
3404-
((1, 1), ">i2"): ("I", "I;16BS"),
3405-
((1, 1), "<u4"): ("I", "I;32"),
3406-
((1, 1), ">u4"): ("I", "I;32B"),
3407-
((1, 1), "<i4"): ("I", "I;32S"),
3408-
((1, 1), ">i4"): ("I", "I;32BS"),
3409-
((1, 1), "<f4"): ("F", "F;32F"),
3410-
((1, 1), ">f4"): ("F", "F;32BF"),
3411-
((1, 1), "<f8"): ("F", "F;64F"),
3412-
((1, 1), ">f8"): ("F", "F;64BF"),
3413-
((1, 1, 2), "|u1"): ("LA", "LA"),
3414-
((1, 1, 3), "|u1"): ("RGB", "RGB"),
3415-
((1, 1, 4), "|u1"): ("RGBA", "RGBA"),
3396+
((1, 1), "|b1"): ("1", "1;8", []),
3397+
((1, 1), "|u1"): ("L", "L", ["P"]),
3398+
((1, 1), "|i1"): ("I", "I;8", []),
3399+
((1, 1), "<u2"): ("I", "I;16", []),
3400+
((1, 1), ">u2"): ("I", "I;16B", []),
3401+
((1, 1), "<i2"): ("I", "I;16S", []),
3402+
((1, 1), ">i2"): ("I", "I;16BS", []),
3403+
((1, 1), "<u4"): ("I", "I;32", []),
3404+
((1, 1), ">u4"): ("I", "I;32B", []),
3405+
((1, 1), "<i4"): ("I", "I;32S", []),
3406+
((1, 1), ">i4"): ("I", "I;32BS", []),
3407+
((1, 1), "<f4"): ("F", "F;32F", []),
3408+
((1, 1), ">f4"): ("F", "F;32BF", []),
3409+
((1, 1), "<f8"): ("F", "F;64F", []),
3410+
((1, 1), ">f8"): ("F", "F;64BF", []),
3411+
((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]),
3412+
((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]),
3413+
((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]),
34163414
# shortcuts:
3417-
((1, 1), f"{_ENDIAN}i4"): ("I", "I"),
3418-
((1, 1), f"{_ENDIAN}f4"): ("F", "F"),
3415+
((1, 1), f"{_ENDIAN}i4"): ("I", "I", []),
3416+
((1, 1), f"{_ENDIAN}f4"): ("F", "F", []),
34193417
}
34203418

34213419

0 commit comments

Comments
 (0)