Pillow: Save a multipage .tiff documents from a list of .tiff images

Created on 3 Nov 2016  路  24Comments  路  Source: python-pillow/Pillow

Hi there,

I am using the following setup:
Windows 7
python 2.7.12 (Anaconda)
Pillow 3.4.2
I am using scanned documents in .tiff format (TIFF, mode="1")

I am trying to merge .tiff images to one singe document with multi-pages with the following code:

                    im=Image.open(path_tmp+'/'+list_file[0])
                    im.load()
                    for i in list_file[1:]:
                        print i
                        tmp_im = Image.open(path_tmp+'/'+i)
                        tmp_im.load()
                        print tmp_im.format, tmp_im.size, tmp_im.mode
                        list_im.append(tmp_im) 
                    print list_im      
                    im.save("test.tiff", save_all=True,append_images=list_im)

I was expecting that the "test.tiff" document will contain all the .tiff images that are in the list: "list_im" (one page per tiff image). But I see a one page document with the first .tiff from the list and no message and no warning.

here what the above code is displaying:

42526530005_1032__1.tiff
TIFF (2455, 3462) 1
42526530005_1032__2.tiff
TIFF (2462, 3474) 1
42526530005_1032__3.tiff
TIFF (2451, 3470) 1
42526530005_1032__4.tiff
TIFF (2455, 3481) 1
[<PIL.TiffImagePlugin.TiffImageFile image mode=1 size=2455x3462 at 0x36137898>, <PIL.TiffImagePlugin.TiffImageFile image mode=1 size=2462x3474 at 0x36137DA0>, <PIL.TiffImagePlugin.TiffImageFile image mode
gePlugin.TiffImageFile image mode=1 size=2455x3481 at 0x361477F0>]

I was thinking that save_all=True and append_images=list_im will add the other image from the list. Did I misunderstood the documentation ? Should I resize each image to have all the same size ?

I also realized that on windows, using im.close() is not working as I was expecting and when I try later the remove the file, Windows crashed and complain that the file is used by another application. Using im.close() do the trick.

Thanks a lot
Cheers
Fabien

TIFF

Most helpful comment

@tarrade if you don't have a multipage tiff to begin with, you use the AppendingTiffWriter directly.
@piranna: You need to call new_frame on the AppendingTiffWriter like this:

    with AppendingTiffWriter(OUTFILE) as tf:
        for extend in extends:
            im = Image.effect_mandelbrot(size, extend, 100)
            im.save(tf)
            tf.newFrame()

All 24 comments

https://pillow.readthedocs.io/en/3.4.x/handbook/image-file-formats.html#saving-sequences - I can tell you that at the moment, append_images is currently only supported for GIF.

Hi Andrew,
ah, ok. I saw the save_all option so I was thinking that append_images was present too for TIFF

https://pillow.readthedocs.io/en/3.4.x/handbook/image-file-formats.html#tiff
save_all
If true, Pillow will save all frames of the image to a multiframe tiff document.
New in version 3.4.0.

I also saw this discussion and I got the impression that it was done and working for TIFF as well:
https://github.com/python-pillow/Pillow/issues/733

I guess I didn't undertood the difference between a multiframe image and a list of image

Thanks
Cheers
Fabien

There was a patch for tiffs that was merged late in the 3.4 cycle

Hi Eric,

is the patch already available ? I am using Pillow 3.4.2 and using pip it say that Pillow is already up-to-date.

Thanks
Cheers
Fabien

@tarrade Here is a stand-alone version, that also shows how to use it (see main at the end). save_all is also supported, see Tests/test_file_tiff.py::test_tiff_save_all. https://gist.github.com/lambdafu/6d537cf30a6430535593f2d31b05d68a

@tarrade Reading the conversation again, I think wiredfool referred to save_all, not append_images. So I guess my previous post was redundantly redundant :)

Hi there,

Sorry I never worked with images before and I am a little bit confuse by what is the difference between save_all and append_images options and what is a multi-frame image

@lambdafu : can explain to me the difference between these 2 options ?
I have many one page document .tiff images and I want to put all of them in one single multi-page document (one page = one .tiff image).

Thanks again
Cheers
Fabien

I'm having the same problem, I have been able to create a multipage tiff file from a folder full of tiff files with ImageMagik, but when doing it with Pillow 3.4.2 and the AppendingTiffWriter helper class I get a tiff file of more-or-less same size as the ImageMagik one, but contains a single page with a big black image.The code I'm using to generate the tiff file is:

with AppendingTiffWriter(outdir+'.tiff', True) as tiff_out:
    for tiff_in in listdir(outdir):
        with open(join(outdir, tiff_in)) as tiff_in:
            for idx in range(tiff_in.n_frames):
                tiff_in.seek(idx)
                tiff_in.save(tiff_out, 'tiff')

This way I run over all the frames of the input tiff files (although the have a single page) and save them on the output tiff file. Could I be doing something wrong here?

@tarrade if you don't have a multipage tiff to begin with, you use the AppendingTiffWriter directly.
@piranna: You need to call new_frame on the AppendingTiffWriter like this:

    with AppendingTiffWriter(OUTFILE) as tf:
        for extend in extends:
            im = Image.effect_mandelbrot(size, extend, 100)
            im.save(tf)
            tf.newFrame()

@piranna: You need to call new_frame on the AppendingTiffWriter

By doing so with

with AppendingTiffWriter(outdir+'.tiff', True) as tiff_out:
    for tiff_in in listdir(outdir):
        with open(join(outdir, tiff_in)) as tiff_in:
            for idx in range(tiff_in.n_frames):
                tiff_in.seek(idx)
                tiff_in.save(tiff_out, 'tiff')
                tiff_out.newFrame()

y get the next exceptions:

multiprocessing.pool.RemoteTraceback: 
"""
Traceback (most recent call last):
  File "./imagextractor.py", line 96, in cutAndSave
    tiff_out.newFrame()
  File "/home/piranna/Trabajo/HBP/imagextractor/multiPageTiff.py", line 113, in newFrame
    self.setup()
  File "/home/piranna/Trabajo/HBP/imagextractor/multiPageTiff.py", line 81, in setup
    raise RuntimeError("Invalid TIFF file header")
RuntimeError: Invalid TIFF file header

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 44, in mapstar
    return list(map(*args))
  File "./imagextractor.py", line 117, in cutAndSave_multiprocessing
    return cutAndSave(CziFile(argv[0]), argv[1], argv[2], argv[3])
  File "./imagextractor.py", line 96, in cutAndSave
    tiff_out.newFrame()
  File "/home/piranna/Trabajo/HBP/imagextractor/multiPageTiff.py", line 120, in __exit__
    self.close()
  File "/home/piranna/Trabajo/HBP/imagextractor/multiPageTiff.py", line 205, in close
    self.finalize()
  File "/home/piranna/Trabajo/HBP/imagextractor/multiPageTiff.py", line 103, in finalize
    IFDoffset = self.readLong()
  File "/home/piranna/Trabajo/HBP/imagextractor/multiPageTiff.py", line 168, in readLong
    value, = unpack(self.longFmt, self.f.read(4))
AttributeError: 'AppendingTiffWriter' object has no attribute 'longFmt'
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "./imagextractor.py", line 156, in <module>
    main(parser.parse_args())
  File "./imagextractor.py", line 138, in main
    regions = pool.map(cutAndSave_multiprocessing, process_params)
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 260, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 608, in get
    raise self._value
AttributeError: 'AppendingTiffWriter' object has no attribute 'longFmt'

Seems AppendingTiffWriter would need to have add longFmt... what's that used for?

Also, shouldn't newFrame be called internally?

Ok, I was using an outdated version of the standalone class, I changed the code to use the one included with Pillow 3.4.2 but now I get the next error:

multiprocessing.pool.RemoteTraceback: 
"""
Traceback (most recent call last):
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 119, in worker
    result = (True, func(*args, **kwds))
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 44, in mapstar
    return list(map(*args))
  File "./imagextractor.py", line 122, in cutAndSave_multiprocessing
    return cutAndSave(CziFile(argv[0]), argv[1], argv[2], argv[3])
  File "./imagextractor.py", line 101, in cutAndSave
    tiff_in.save(tiff_out, format="tiff", save_all=True)
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 1667, in save
    save_handler = SAVE_ALL[format.upper()]
KeyError: 'TIFF'
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "./imagextractor.py", line 161, in <module>
    main(parser.parse_args())
  File "./imagextractor.py", line 143, in main
    regions = pool.map(cutAndSave_multiprocessing, process_params)
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 260, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "/usr/lib/python3.5/multiprocessing/pool.py", line 608, in get
    raise self._value
KeyError: 'TIFF'

The code I'm using is taken from the Pillow tests:

with open(outdir+'.tiff', 'w') as tiff_out:
    for tiff_in in listdir(outdir):
        with Image.open(join(outdir, tiff_in)) as tiff_in:
            tiff_in.save(tiff_out, format="tiff", save_all=True)

@lambdafu thanks and sorry for the delay. By using a modified version of your suggestion it works:

with PIL.TiffImagePlugin.AppendingTiffWriter("./test.tiff",True) as tf:        
    for tiff_in in list_file:
        with open(tiff_in) as tiff_in:
            im= Image.open(tiff_in)
            im.save(tf)
            tf.newFrame()

today I tried with pillow 4.0.0
On my side, I can do what I want so this issue can be closed and maybe some example added to the doc to help other user.

Thanks
Cheers
Fabien

@tarrade, could you be able to provide a complete example? I'm using pillow 4.0.0 installed with PIP but I'm not able to import anyway the AppendingTiffWriter class... :-/

Hi @piranna,

I am using pillow 3.4.2 (on Windows but I tried with 4.0.0 on Mac)

from PIL import Image
from PIL import TiffImagePlugin

                    with TiffImagePlugin.AppendingTiffWriter(path_tmp+'/'+merged_file_name,True) as tf:        
                        for tiff_in in list_file:
                            try:
                                im= Image.open(path_tmp+'/'+tiff_in)
                                im.save(tf)
                                tf.newFrame()
                                im.close()

the name of my output file is: path_tmp+'/'+merged_file_name
list_file is a list of my file (only the file name, not the path)

Hope this help
Cheers
Fabien

Thank you @tarrade :-) The problem was not about the code itself but about the importing, since I'm using Python3 and used the regular pip of Python2 to install Pillow, thanks to your code I was conscious of my dumb error :-P

Hi , I am using below code (same as above) to merge tiff files into one tiff file. But , after merging , I see only one tiff file/image in the result. Kindly help asap. Thanks in advance.

from PIL import Image
from PIL import TiffImagePlugin

with TiffImagePlugin.AppendingTiffWriter(SRC_FILES_FOLDER_PATH +'\\Merged.tif',True) as tf:        
        for tiff_in in fileNames:
                im= Image.open(SRC_FILES_FOLDER_PATH +'\\'+tiff_in,"r")
                im.save(tf)
                tf.newFrame()
                print('in')
                im.close()

@sureshdarsru I'm able to adjust and run your code successfully. Would you be able to provide some of the images that you are opening?

Hi Andrew

Really I am happy to see your response. I have got the confidence that I
can resolve this issue quickly. Pls find attached few TIFF files created
using MSPAINT.

After the merging done ,I see the size of resulting file got increased. But
I see always the first file's image.

Kind Note: If it will work for you then , issue could be over PIL / PILLOW
Installation. I had PIL. Later , I installed Pillow. I am using Python 3*.

Regards
Suresh

The files did not appear. I suggest you try adding them through the GitHub site, rather than attaching them to a reply e-mail.

Hi Andrew

I see the issue with Image viewer. I think think , I am facing this issue ie I can see only one page after I have installed OpenText suite of products.

Meanwhile, I have one more request. I have one more requirement. I would need to combine multiple AFP type of files into one AFP file. Please let me know which python's library I have to use for the same. If you have any sample code , can I get it pls.

Thanks in advance again.

Regards
Suresh

Hi Andrews

Missed to mention that my TIFF image files combining issue got resolved. Thanks for your help.

As mentioned above , could you reply on AFP issue.

Regards
Suresh

I'm not familiar with the AFP file format. If you have a Pillow question unrelated to this thread, please create a new issue.

Yes. I will do . Thanks Andrew for your quickest responses :-)

Was this page helpful?
0 / 5 - 0 ratings