Saving 16-bit TIFF images with Pillow in Python
- Pillow has sparse documentation and poor support for saving 16-bit images.
- Pillow is, however, a ubiquitous python package and simple to install and use.
- Presented is a consistent way to save 16-bit TIFF images from data using Pillow.
Introduction
Recently I had a scientific image application that needed the saving of real 16-bit TIFF images to preserve all of the information in the source image. (biorad1sc_reader) While it can be argued that people aren’t sensitive to more than 8-bits of information, quantitative analysis of images can make use of the extra information.
Disappointingly, Pillow, the main image manipulation package for python, doesn’t seem to have great support for 16-bit TIFF images, nor does support seem forthcoming in the near future. Luckily I found a mostly clean way of using Pillow to save 16-bit image data into a 16-bit TIFF.
Discussion
An issue when trying to save a new TIFF file as 16-bit in Pillow is that there doesn’t seem to be a native 16-bit unsigned integer format in the official “Modes” section of the Pillow documentation. However, internally there is such a format, which can be found in the Pillow source code.
At first I tried to use Image.fromarray() to send my image list data to the new Image. This seemed to run into many bugs of casting that resulted between my input numbers and the internal Pillow format.
In the end, the safest and least hack-ful way to send data to the new 16-bit Image turned out to use struct.pack() to create a bytestream and load that into the Pillow Image using Image.frombytes(). My code has versions for use with NumPy (“HAS_NUMPY”) or without NumPy support. Code is below.