Skip to content

Issue with PIL.Image.fromarray(..., mode="1") returning a transposed image #9006

@guillaume-rochette-oxb

Description

@guillaume-rochette-oxb

What did you do?

I have an np.ndarray with shape=(h, w) and dtype=bool that I want to convert to a PIL.Image.Image (and later save on disk disk, although that is not relevant).
I have noticed that PIL.Image.fromarray(array, mode="1") does not work correctly, while PIL.Image.fromarray(array, mode=None) does behave correctly.

What did you expect to happen?

Referring to the sample code below, I expect that all the 3 arrays would be equal for all modes.

What actually happened?

It does not work for mode="1".

What are your OS, Python and Pillow versions?

Linux:

--------------------------------------------------------------------
Pillow 11.2.1
Python 3.12.9 | packaged by Anaconda, Inc. | (main, Feb  6 2025, 18:56:27) [GCC 11.2.0]
--------------------------------------------------------------------
Python executable is /home/***/miniconda3/envs/pil-env/bin/python3
System Python files loaded from /home/***/miniconda3/envs/pil-env
--------------------------------------------------------------------
Python Pillow modules loaded from /home/***/miniconda3/envs/pil-env/lib/python3.12/site-packages/PIL
Binary Pillow modules loaded from /home/***/miniconda3/envs/pil-env/lib/python3.12/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 11.2.1
--- TKINTER support ok, loaded 8.6
--- FREETYPE2 support ok, loaded 2.13.3
--- LITTLECMS2 support ok, loaded 2.17
--- WEBP support ok, loaded 1.5.0
*** AVIF support not installed
--- JPEG support ok, compiled for libjpeg-turbo 3.1.0
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.3
--- ZLIB (PNG/ZIP) support ok, loaded 1.2.13, compiled for zlib-ng 2.2.4
--- LIBTIFF support ok, loaded 4.7.0
--- RAQM (Bidirectional Text) support ok, loaded 0.10.1, fribidi 1.0.8, harfbuzz 11.0.1
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

macOS:

--------------------------------------------------------------------
Pillow 11.1.0
Python 3.12.9 | packaged by conda-forge | (main, Mar  4 2025, 22:44:42) [Clang 18.1.8 ]
--------------------------------------------------------------------
Python executable is /Users/***/miniconda3/envs/pil-env/bin/python3
System Python files loaded from /Users/***/miniconda3/envs/pil-env
--------------------------------------------------------------------
Python Pillow modules loaded from /Users/***/miniconda3/envs/pil-env/lib/python3.12/site-packages/PIL
Binary Pillow modules loaded from /Users/***/miniconda3/envs/pil-env/lib/python3.12/site-packages/PIL
--------------------------------------------------------------------
--- PIL CORE support ok, compiled for 11.1.0
--- TKINTER support ok, loaded 8.6
--- FREETYPE2 support ok, loaded 2.13.2
--- LITTLECMS2 support ok, loaded 2.16
--- WEBP support ok, loaded 1.5.0
--- JPEG support ok, compiled for libjpeg-turbo 3.1.0
--- OPENJPEG (JPEG2000) support ok, loaded 2.5.3
--- ZLIB (PNG/ZIP) support ok, loaded 1.3.1.zlib-ng, compiled for zlib-ng 2.2.2
--- LIBTIFF support ok, loaded 4.6.0
*** RAQM (Bidirectional Text) support not installed
*** LIBIMAGEQUANT (Quantization method) support not installed
--- XCB (X protocol) support ok
--------------------------------------------------------------------

Sample code

from PIL import Image
from urllib.request import urlopen
import numpy as np


def main():
    url = "https://python-pillow.github.io/assets/images/pillow-logo.png"

    base_image = Image.open(urlopen(url))
    print(base_image.size, base_image.mode)

    modes = [
        "RGBA",
        "RGB",
        "L",
        "I",
        "F",
        "1",
    ]
    for mode in modes:
        image_1 = base_image.convert(mode=mode)
        array_1 = np.array(image_1)
        image_2 = Image.fromarray(array_1, mode=mode)
        array_2 = np.array(image_2)
        image_3 = Image.fromarray(array_1)
        array_3 = np.array(image_3)

        size_equality = image_1.size == image_2.size == image_3.size
        mode_equality = image_1.mode == image_2.mode == image_3.mode
        shape_equality = array_1.shape == array_2.shape == array_3.shape
        dtype_equality = array_1.dtype == array_2.dtype == array_3.dtype

        print(f"image_1.size = {image_1.size}, image_2.size = {image_2.size}, image_3.size = {image_3.size}")
        print(f"image_1.mode = {image_1.mode}, image_2.mode = {image_2.mode}, image_3.mode = {image_3.mode}")
        print(f"array_1.shape = {array_1.shape}, array_2.shape = {array_2.shape}, array_3.shape = {array_3.shape}")
        print(f"array_1.dtype = {array_1.dtype}, array_2.dtype = {array_2.dtype}, array_3.dtype = {array_3.dtype}")
        print(f"size_equality = {size_equality}")
        print(f"mode_equality = {mode_equality}")
        print(f"shape_equality = {shape_equality}")
        print(f"dtype_equality = {dtype_equality}")

        array_1_and_array_2_equality = (array_1 == array_2).all()
        array_1_and_array_3_equality = (array_1 == array_3).all()
        array_2_and_array_3_equality = (array_2 == array_3).all()
        print(f"array_1_and_array_2_equality = {array_1_and_array_2_equality}")
        print(f"array_1_and_array_3_equality = {array_1_and_array_3_equality}")
        print(f"array_2_and_array_3_equality = {array_2_and_array_3_equality}")

        # uncomment to display images
        # if not all([array_1_and_array_2_equality, array_1_and_array_3_equality, array_2_and_array_3_equality]):
        #     image_1.show()
        #     image_2.show()
        #     image_3.show()

        print()


if __name__ == "__main__":
    main()

image_1: Image

image_2: Image

image_3: Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions