Skip to content

Reading and converting 16-bit pixels #452

@igg

Description

@igg
>>> import PIL
>>> PIL.PILLOW_VERSION
'2.2.2'
>>> from PIL import Image
>>> im = Image.open('pil_pillow_16_bit_bug.tif')
>>> im
<PIL.TiffImagePlugin.TiffImageFile image mode=I;16B size=512x512 at 0x103125E60>

Note no 'S' in mode.
Then,

>>> im.getpixel((0,0))
-32768

Two problems: Other than using the extended SampleFormat tag (339, 0x0153), there is no way to store a signed value in a tiff file. The value stored in this image at 0,0 is 32768, and this file has no SampleFormat tag, so only unsigned integers are possible. Instead the value reported is the two's complement of the actual value.
Second problem unrelated to tiff peculiarities, you have an unsigned image mode with a signed pixel value.
Moving on,

>>> im2 = im.convert('I')
>>> im2.getpixel((0,0))
32768

This is the correct value.
Even more surprising is when we convert this 32-bit, presumably unsigned image back to unsigned 16 bit:

>>> im3 = im2.convert('I;16')
>>> im3.getpixel((0,0))
32767

???. Even better, a pixel at 32,16 has a value of 32769:

>>> im2.getpixel((32,16))
32769

Correct in the 32-bit unsigned image (is it really unsigned, BTW? didn't check), but in the 16-bit image converted from it, this pixel is still 32767!

>>> im3.getpixel((32,16))
32767

In fact, all of the pixels in the converted image are clipped to 32767. In the image as-read, this value is -32767 (two's complement of 32769):

>>>> >>> im.getpixel((32,16))
-32767

Does the problem originate from the fact that we went over the signed 16-bit max even though we were supposed to be dealing with unsigned values? Is the convert problem related to the tiff reader problem?

Sample file for the above: pil_pillow_16_bit_bug.tif

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions