-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
I work with georeferenced images as TIFs and have never had any problems with standard PIL opening and saving them.
When upgrading our codebase to Pillow a few days ago, lots of stuff broke. In nearly all cases, it comes down to the fact that Pillow is extremely anal about how it saves TIF files. Any misunderstood tags or tags with what it thinks are incorrect values according to the spec will result in exceptions and a refusal to write the file, an issue which PIL never had.
Now, georef'd TIFs contain several nonstandard tags. Here's an example image for you to work with: https://dl.dropboxusercontent.com/u/40538551/FtHood.tif
When working with the image above:
from PIL import Image
img = Image.open('FtHood.tif')
img.save('test.tif')
Pillow produces this output:
TIFFSetField: test.tif: Unknown tag 42112.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/sam/.virtualenvs/ff/lib/python2.7/site-packages/PIL/Image.py", line 1685, in save
save_handler(self, fp, filename)
File "/Users/sam/.virtualenvs/ff/lib/python2.7/site-packages/PIL/TiffImagePlugin.py", line 1185, in _save
e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
File "/Users/sam/.virtualenvs/ff/lib/python2.7/site-packages/PIL/Image.py", line 430, in _getencoder
return encoder(mode, *args + extra)
RuntimeError: Error setting from dictionary
Notice the TIFFSetField: test.tif: Unknown tag 42112. This error seems to be coming from the included libtiff.so library that Pillow calls out to for the encoding of the TIF when saving the image.
42112 is a metadata tag that GDAL produces when it works with TIFs: http://www.awaresystems.be/imaging/tiff/tifftags/gdal_metadata.html The tag itself is common in georeferenced images, but the key takeaway here is that Pillow throws an exception whenever its included libtiff encounters any unknown tag! Imagemagick, for example, will throw warnings when working with this image, but it still writes output and works with it just fine- no exceptions, no explosions. PIL also works with the image. If I replace Pillow with PIL in my virtual environment, the above 3-liner python code works perfectly.
Here's how to get the above image to save when using Pillow:
from PIL import Image
img = Image.open('FtHood.tif')
del img.tag[339]
del img.tag[42112]
del img.tag[34735]
del img.tag[34737]
del img.tag[34264]
img.save('test.tif')
Notice that I had to delete a whole variety of tags. These are all related to georeferencing (except for the first delete, 339, I'll get to that in a second). So any image with nonstandard tags will have to have an arbitrary number of them deleted before Pillow will actually save the image. As you could imagine, this is very impractical to work with and causes a codebase using Pillow to become filled with random exceptions based on image input. I think it would be better behavior for Pillow to work like PIL and lots of other TIF-handling software: if you don't specifically know what the TIF tag is, just write it to the file anyway. There are so many different tags, it's impossible to understand them all and some software even defines its own application-specific ones.
Now, I also had to delete 339. 339 is the SampleFormat tag: http://www.awaresystems.be/imaging/tiff/tifftags/sampleformat.html and in this case, it's set to Unsigned, Unsigned, Unsigned: one 'Unsigned' for each bit sample. From my understanding, Unsigned is a valid value for the tag and there should be no reason to throw an exception concerning it: _TIFFVSetField: test.tif: Bad value 29680 for "SampleFormat" tag. Just like with the georef tags, vanilla PIL has no problems with SampleFormat in the example image.
Note that I'm using Python 2.7.8 and Pillow 2.6.1