5

I am trying to save an image with negative values using PIL, however, after saving, the image files has all negative values clipped to 0.

from PIL import Image
import numpy as np

# generate random image for demo
img_arr = np.random.random_integers(-1000,1000, size=[10,10]).astype(np.int32)
print "original min {}, max: {}".format(img_arr.min(),img_arr.max())

# create PIL image
img1 = Image.fromarray(img_arr)
print "PIL min {}, max: {}".format(np.array(img1.getdata()).min(),np.array(img1.getdata()).max())

# save image
img1.save("test_file.png", "PNG")

# reload image
img_file = Image.open("test_file.png")
print "img_file min {}, max: {}".format(np.array(img_file.getdata()).min(),np.array(img_file.getdata()).max())

This results in output:

original min -983, max: 965
PIL min -983, max: 965
img_file min 0, max: 965

How can I save this image and maintain the negative values?

Greg Samson
  • 1,267
  • 2
  • 11
  • 21
  • 4
    If you could save an image with negative values, what would it look like if you opened it? If (255,255,255) is white and (0,0,0) is black, what is (-1000, -1000, -1000)? Quadruple nega-white? – Kevin Jul 26 '16 at 18:10
  • The colors of an image are defined pixels comprised of one or more 8-bit _unsigned_ integers, so there's no way to create one with pixel that have components with values outside the range 0..255. You need to scale your result into this range to maintain them. PIL does support larger ranges, such as 0..4095, so you could preserve the data with more precision. I also think it supports positive floating-point values, but have never tried it. – martineau Jul 26 '16 at 18:29
  • Most browsers only allow 0-255, images in general do no have this restriction. – Greg Samson Jul 26 '16 at 19:39

1 Answers1

7

Note that there is such a thing as storing your pixels as 32-bit signed integers according to PIL, and the image mode 'I' is meant to handle this in PIL. So the comments saying this makes no sense due to technical reasons are mistaken.

I don't think the PNG format supports this mode(Despite no errors being thrown when you write an Image in mode 'I'). However, the .tif extension seems to:

img1.save("test_file.tif")

Changing that (and the read to get the correct file) seems to work:

original min -993, max: 990
PIL min -993, max: 990
img_file min -993, max: 990
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Thank you, this works. BTW here is a good link describing data types and their ranges. http://scikit-image.org/docs/dev/user_guide/data_types.html – Greg Samson Jul 26 '16 at 19:39
  • Note that this will fail when you want to save a multichannel image (like RGB image). That is when `size=[10,10, 3]`, `img1.save("test_file.tif")` fails! – Swaroop May 10 '20 at 21:04