[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