Skip to content

Image.putdata() NumPy usability suggestion #5858

@rlevine

Description

@rlevine

This could be a feature request, an ask for a doc change or for better error reporting.

When I grab an image, suck it into a numpy array, process it, and then spit it back into an image, I hit what appears to be a silent fail when the data given to Image.putdata() is a 2D numpy array instead of 1D (nominally a sequence), or is a float array instead of uint8.

My naive expectation was to do this:

image_array = np.array(source_image)
# ...do something to the data via numpy that might inadvertently 
# change it to float64, still with int-equivalent values...
new_image = Image.new('P', (source_image.size))
new_image.putdata(image_array)

If I don't coerce the array to uint8 and 1D, I still get an image, but with all values set to 0, and Pillow is silent on what (again, naively) appears to be a failure.

(I now know new_image.putdata(image_array.ravel().astype(int)) works, but it wan't obvious. :)

While making the docs more precise or adding better error reporting are both easier responses, it would seem that this isn't an uncommon use case, and it might be a nice ease-of-use change to have putdata accept a 2D array if it's the same size as the image, and also to coerce the data to ints, as a better silent option.

I'm running Pillow 8.4.0, python 3.10 on osx Mojave 10.14.6.

Thanks!


Test code:

from PIL import Image
import numpy as np


palette_data = [
		0, 0, 192,
		0, 33, 76,
		0, 192, 0,
		0, 192, 192,
		9, 9, 9,
		19, 19, 19,
		29, 29, 29,
		50, 0, 106,
		192, 0, 0,
		192, 0, 192,
		192, 192, 0,
		192, 192, 192,
		255, 255, 255
		]

image_data = np.array([
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [11., 11., 11., 11., 10., 10., 10., 10., 3., 3., 3., 3., 2., 2., 2., 2., 9., 9., 9., 9., 8., 8., 8., 8., 0., 0., 0., 0.],
                      [ 0., 0., 0., 0., 5., 5., 5., 5., 9., 9., 9., 9., 5., 5., 5., 5., 3., 3., 3., 3., 5., 5., 5., 5., 11., 11., 11., 11.],
                      [ 0., 0., 0., 0., 5., 5., 5., 5., 9., 9., 9., 9., 5., 5., 5., 5., 3., 3., 3., 3., 5., 5., 5., 5., 11., 11., 11., 11.],
                      [ 0., 0., 0., 0., 5., 5., 5., 5., 9., 9., 9., 9., 5., 5., 5., 5., 3., 3., 3., 3., 5., 5., 5., 5., 11., 11., 11., 11.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.],
                      [ 1., 1., 1., 1., 1., 12., 12., 12., 12., 12., 7., 7., 7., 7., 7., 5., 5., 5., 5., 5., 4., 5., 5., 6., 5., 5., 5., 5.]
                      ], dtype=np.float64)

new_image = Image.new('P', (28, 28), color=None)
new_image.putpalette(palette_data)

new_image.putdata(image_data.astype(int))
# Resulting image data is all zeroes.
new_image.show()
new_image.save('int_data_array.png')

new_image.putdata(image_data.ravel())
# Resulting image data is all zeroes.
new_image.show()
new_image.save('float_data_sequence.png')

new_image.putdata(image_data.ravel().astype(int))
# Resulting image data is correct, as expected.
new_image.show()
new_image.save('int_data_sequence.png')

Correct image:

int_data_sequence

Bad image cases:

int_data_array

float_data_sequence

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions