5

How would I go about creating a new image, using python PIL, which has multiple frames in it.

new_Image = Image.new("I;16", (num_pixels,num_rows))

for frame in range((len(final_rows)/num_rows)):
    pixels = new_Image.load()

    for row in range(num_rows):
        row_pixel = final_rows[row].getPixels()
        for pixel in range(num_pixels):
            pixels[pixel,row] = row_pixel[pixel]
    print frame
    new_Image.seek(frame)

I tried using the above code but it gives me a EOFError. The code gets the number of frames by dividing the total number of rows that I have by the number of rows per frame. It then uses the data as pixel data. I was trying to seek a new frame but I guess it hasn't been created. How do I create these frames?

Edit: I would like a .tif file format

2
  • Have you tried this: stackoverflow.com/questions/753190/…
    – Paul
    Commented Oct 23, 2013 at 13:27
  • @Paul No I haven't tried that. I don't really want to create a Movie or Gif. The file format that I want is .tif.
    – Marmstrong
    Commented Oct 23, 2013 at 13:37

2 Answers 2

2

Start with a PIL image of the first frame, then save that and pass the other frame images in a list to the append_images parameter and save them all. It works with webp, gif, and tiff formats, though tiff appears to ignore the duration and loop parameters:

im1.save(save_to, format="tiff", append_images=[im2], save_all=True, duration=500, loop=0)

See also the documentation.

1

new_Image is what you have loaded, i.e. read - if it doesn't have more than one frame you can not move on the the next.

For the moment PIL does not have support for creating Multi-Frame GIFs so you would need to switch to pillow which does - there is some sample code on GitHub.

Update

Took the time to investigate further and found a bug fixed version of images2gif so what I did was to use pip install images2gif and then downloaded the bug fixed version from here and overwrote the one installed by pip but you could just download that bug fix version and put it in the same directory as your development file.

I then created a CreateGif.py file:

# coding: utf-8
from __future__ import print_function # Python 2/3 compatibility
import glob
from PIL import Image
from images2gif import writeGif

DELAY=0.75  # How long between frames
FRAMES = [] # Empty list of frames
FIRST_SIZE = None # I am going to say that the first file is the right size
OUT_NAME = "test.gif" # Name to save to
filelist = glob.glob("*.jpg") # For this test I am just using the images in the current directory in the order they are

for fn in filelist:  # For each name in the list
    img = Image.open(fn) # Read the image
    if FIRST_SIZE is None:  # Don't have a size
        FIRST_SIZE = img.size  # So use this one
    if img.size == FIRST_SIZE: # Check the current image size if it is OK we can use it
        print ("Adding:", fn)  # Show some progress
        FRAMES.append(img)   # Add it to our frames list
    else:
        print ("Discard:", fn, img.size, "<>", FIRST_SIZE) # You could resize and append here!

print("Writing", len(FRAMES), "frames to", OUT_NAME)
writeGif(OUT_NAME, FRAMES, duration=DELAY, dither=0)
print("Done")

Running this in my test directory resulted in:

F:\Uploads>python CreateGif.py
Adding: Hidden.jpg
Adding: NewJar.jpg
Adding: P1000063.JPG
Adding: P1000065.JPG
Adding: P1000089.JPG
Discard: WiFi_Virgin.jpg (370, 370) <> (800, 600)
Writing 5 frames to test.gif
Done

And produced: enter image description here

And Now For TiFF files

First I installed tiffile, pip install -U tiffile, I already had numpy installed, then:

# coding: utf-8
from __future__ import print_function # Python 2/3 compatibility
import glob
from PIL import Image
import tifffile
import numpy

def PIL2array(img):
    """ Convert a PIL/Pillow image to a numpy array """
    return numpy.array(img.getdata(),
        numpy.uint8).reshape(img.size[1], img.size[0], 3)
FRAMES = [] # Empty list of frames
FIRST_SIZE = None # I am going to say that the first file is the right size
OUT_NAME = "test.tiff" # Name to save to
filelist = glob.glob("*.jpg") # For this test I am just using the images in the current directory in the order they are
# Get the images into an array
for fn in filelist:  # For each name in the list
    img = Image.open(fn) # Read the image
    if FIRST_SIZE is None:  # Don't have a size
        FIRST_SIZE = img.size  # So use this one
    if img.size == FIRST_SIZE: # Check the current image size if it is OK we can use it
        print ("Adding:", fn)  # Show some progress
        FRAMES.append(img)   # Add it to our frames list
    else:
        print ("Discard:", fn, img.size, "<>", FIRST_SIZE) # You could resize and append here!

print("Writing", len(FRAMES), "frames to", OUT_NAME)
with tifffile.TiffWriter(OUT_NAME) as tiff:
    for img in FRAMES:
        tiff.save(PIL2array(img),  compress=6)
print("Done")

Which produced a nice tiff file, but unfortunately the SO viewer does not display multi-page tiff files that windows at least thinks is acceptable as can be seen below. enter image description here

5
  • new image is what I created using new_Image = Image.new("I;16", (num_pixels,num_rows)). That sample code doesn't seem to create a new image only access an existing one im = Image.open(infile).
    – Marmstrong
    Commented Oct 23, 2013 at 13:17
  • You are expected to supply a set of images as input to the example. Image.new is NOT what is in your sample code BTW. Commented Oct 23, 2013 at 15:10
  • Sorry it was in the line above
    – Marmstrong
    Commented Oct 23, 2013 at 15:16
  • As gifmaker has been merged in pillow, the second URL is no longer relevant :p (and I'm still struggling to create one multi-framed image) Commented Apr 24, 2016 at 8:22
  • @RomualdBrunet - Some worked examples for both gif and tiff added. Commented Apr 25, 2016 at 11:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.