Skip to content

Inconsistent Image.fromarray() behaviour with mode '1' #5723

@dtoniolo

Description

@dtoniolo

What did you do?

The following code can reproduce the issue:

import numpy as np
import PIL
from PIL import Image

print('Testing for Pillow version', PIL.__version__)


img_size = (2, 3)  # (w, h)
rng = np.random.default_rng()

test = rng.integers(0, 2, dtype=np.bool_, size=img_size[::-1])
no_mode = Image.fromarray(test)
no_mode_arr = np.array(no_mode)
outcome = np.all(no_mode_arr == test)
print('No mode specified. Mode:', no_mode.mode, 'dtype:',
      no_mode_arr.dtype, 'outcome:', outcome)
with_mode = Image.fromarray(test, mode='1')
with_mode_arr = np.array(with_mode)
outcome = np.all(with_mode_arr == test)
print('Mode specified. Mode:', with_mode.mode, 'dtype:',
      with_mode_arr.dtype, 'outcome:', outcome)

print('Input array:\n', test)
print('Output array with no mode specified:\n', no_mode_arr)
print('Output array with mode specified:\n', with_mode_arr)

Output:

Testing for Pillow version 8.3.2
No mode specified. Mode: 1 dtype: bool outcome: True
Mode specified. Mode: 1 dtype: bool outcome: False
Input array:
 [[ True False]
 [ True False]
 [False False]]
Output array with no mode specified:
 [[ True False]
 [ True False]
 [False False]]
Output array with mode specified:
 [[False False]
 [False False]
 [False False]]

What did you expect to happen?

When initialising an image from a boolean NumPy array, it is expected that True values are assigned to white pixels and False values to black ones. The resulting image should have mode '1' and if, converted back to an array, its contents should be equal to the initial input array.

What actually happened?

If Image.fromarray() is called with mode=None, the code works as expected. If instead it is called with mode='1', the array results in all False values. This is an issue for two reasons.

  1. The conversion of the data is incorrect.
  2. The behaviour of Image.fromarray() is inconsistent: given that when called with mode=None it detects the data as having mode='1', passing mode='1' as an input argument should not change the result.

What are your OS, Python and Pillow versions?

I have run the script with two different conda virtual environments. The OS is macOS Big Sur v11.5.2 (20G95).

  • Env 1:
      • Python: 3.8.10
      • Pillow: 8.3.2
  • Env 2:
      • Python: 3.8.10
      • Pillow: 7.1.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    AnacondaIssues with Anaconda's PillowNumPy

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions