Allow to save tiff stacks from separate images

This is a quick solution that will allow to save tiff stacks from
separate images, e.g. from Numpy arrays.
Previously, tiff stacks could be saved only from multiframe images.
This behavior is similar to what is possible now with GIFs.

Note however, that for correct results, all the appended images should
have the same encoder{info,config} properties.

Example:

import numpy as np
from PIL import Image
a = np.ones((100,100,100), dtype=np.uint8)
imlist = []
for m in a:
    imlist.append(Image.fromarray(m))

imlist[0].save("test.tif", compression="tiff_deflate", save_all=True,
               append_images=imlist[1:])

(Should result in a 100-frame, 100x100 tiff stack.)

Signed-off-by: Leonid Bloch <leonid.bloch@esrf.fr>
This commit is contained in:
Leonid Bloch 2017-02-16 02:54:43 +02:00
parent 0f9233623e
commit 28b818974e
2 changed files with 29 additions and 6 deletions

View File

@ -1737,17 +1737,28 @@ class AppendingTiffWriter:
self.rewriteLastLong(offset)
def _save_all(im, fp, filename):
if not hasattr(im, "n_frames"):
encoderinfo = im.encoderinfo.copy()
encoderconfig = im.encoderconfig
append_images = encoderinfo.get("append_images", [])
if not hasattr(im, "n_frames") and not len(append_images):
return _save(im, fp, filename)
cur_idx = im.tell()
try:
with AppendingTiffWriter(fp) as tf:
for idx in range(im.n_frames):
im.seek(idx)
im.load()
_save(im, tf, filename)
tf.newFrame()
for ims in [im]+append_images:
ims.encoderinfo = encoderinfo
ims.encoderconfig = encoderconfig
if not hasattr(ims, "n_frames"):
nfr = 1
else:
nfr = ims.n_frames
for idx in range(nfr):
ims.seek(idx)
ims.load()
_save(ims, tf, filename)
tf.newFrame()
finally:
im.seek(cur_idx)

View File

@ -473,6 +473,18 @@ class TestFileTiff(PillowTestCase):
with Image.open(mp) as im:
self.assertEqual(im.n_frames, 3)
# Test appending images
mp = io.BytesIO()
im = Image.new('RGB', (100, 100), '#f00')
ims = [Image.new('RGB', (100, 100), color) for color
in ['#0f0', '#00f']]
im.save(mp, format="TIFF", save_all=True, append_images=ims)
mp.seek(0, os.SEEK_SET)
reread = Image.open(mp)
self.assertEqual(reread.n_frames, 3)
def test_saving_icc_profile(self):
# Tests saving TIFF with icc_profile set.
# At the time of writing this will only work for non-compressed tiffs