[Image-SIG] 16-bit TIFF decoding and endianness problem

Zachary Pincus zpincus at stanford.edu
Mon Dec 8 01:07:39 EST 2003


I've encountered an issue in PIL-1.1.4 having to do with decoding 
16-bit TIFFs.

Specifically, it appears that the TIFF decoder does not properly 
process the byte ordering of 16-bit integers in TIFF files. The decoder 
can detect big-endian files, but then decodes them in a little-endian 
manner.

Problem:
--------
I have a TIFF that uses 16 bit unsigned integers stored in big-endian 
format. The first bytes of the TIFF file are ASCII "MM" which indicates 
the fact that the format is indeed in "Motorola" (big-endian) format. 
So the file itself conforms to the spec vis a vis endianness.
(TIFF spec is here: 
http://partners.adobe.com/asn/developer/pdfs/tn/TIFF6.pdf -- see page 
13ff.)

Nevertheless, when I open the file with PIL, the image's mode is "I;16" 
-- not "I;16B"
Further, pixels retrieved with the getpixel() method are incorrect and 
reflect an inappropriate byte-swap. (E.g. the correct value of a 
certain pixel is 1001 [0x03E9], but the returned value is 59651 
[0xE903].)

I can get PIL to treat the data properly by grabbing the raw data with 
the tostring() method and then feeding it back into the raw decoder 
with the proper parameters. (See below.) So the decoder will work fine 
when it knows the endianness of the image. It appears that it just 
doesn't detect the TIFF endianness properly.

 >>> test16b = 
Image.open("/Volumes/Atlotl/zpincus/Desktop/sample1imagesPhase.tif")
 >>> test16b.getpixel((0,0))
59651
 >>> #This is the wrong value. It should be 1001.
 >>> test16b.mode
'I;16'
 >>> #This is the wrong mode. It shoule be I;16B
 >>> raw16b = test16b.tostring()
 >>> new16b = Image.fromstring("I;16B", test16b.size, raw16b)
 >>> new16b.getpixel((0,0))
1001
 >>> new16b.mode
'I;16B'

Strangely, the test16b.ifd object (of class ImageFileDirectory, defined 
in TiffImagePlugin.py) knows what format the file is in!
 >>> test16b.ifd.i16  #this is the 16-byte reader
<function ib16 at 0x1128630>

We can see that the i16 pointer is directed at the ib16 function (which 
reads big-endian 16-bit bytes) defined in TiffImagePlugin. I tested 
ib16 and it works correctly.

Moreover, the ifd object knows the right endian-ness prefix.
 >>> test16b.ifd.prefix
'MM'

So somehow, in a place I cannot find, this knowledge of the byte 
ordering is being ignored. Sorry I don't know the code well enough to 
find it.

Finally, I can send anyone who wishes to look into this problem some 
sample 16-bit TIFF images.

Zach Pincus
Program in Biomedical Informatics
Stanford University School of Medicine




More information about the Image-SIG mailing list