TL;DR;Summary
Extract the single frames of a GIF to repurpose them (for example to create a video) with the below code. As always, the most up-to-date version can be found in the GitHub gist
def gif2imgs(file,
save=False,
outpath='same',
outfilename='same',
):
"""
Extract image array from a GIF file.
Based on PIL, frames of a GIF file are extracted to a numpy array. If
more than one frame is present in the GIF, a list of numpy arrays is
returned. It is possible to save the images directy, by default in the
same path as the GIF and the same basename.
Parameters
----------
file : str
The GIF file containing one or more image frames.
save : bool, optional
Whether to save the image frames directy. The default is False, i.e.
the function returns a list of the image frames as seperate numpy arrays
outpath : str, optional
Where to save the extracted image frames.
The default is 'same', i.e. same folder
outfilename : str, optional
How to name the extracted image as files.
The default is 'same', i.e. taking the basename and adding _frameX
to it. If a string is passed, the same suffix is added but the basename
is taken as the passed in string.
Returns
-------
list of frames or two lists (of filenames of extracted image and images)
The extracted frames from the GIF and if saving was turned on also
the filenames of written out frames.
"""
import PIL
import numpy as np
import os
import matplotlib.image as img
pilIm = PIL.Image.open(file)
pilIm.seek(0)
# Read all images inside
images = []
try:
while True:
# Get image as numpy array
tmp = pilIm.convert() # Make without palette
a = np.asarray(tmp)
if len(a.shape) == 0:
continue
# Store, and next
images.append(a)
pilIm.seek(pilIm.tell()+1)
except EOFError:
pass
if save:
if outpath == 'same':
outpath = os.path.dirname(file) + os.sep
if outfilename == 'same':
outfilename = os.path.basename(file)
outfiles = []
for frameno, frame in enumerate(images):
_ = outpath+outfilename.rstrip('.gif') + f'_frame{frameno}.png'
img.imsave(_, frame, vmin=0, vmax=255)
outfiles.append(_)
return outfiles, images
else:
return images
if __name__ == '__main__':
import requests
import matplotlib.pyplot as plt
fileurl = 'https://gifdb.com/images/high/jumping-cat-typing-on-keyboard-2b15r60jnh8hn5sv.gif'
response = requests.get(fileurl)
filename = './example.gif'
with open(filename, 'wb') as fo:
fo.write(response.content)
frames = gif2imgs(filename)
plt.imshow(frames[0])
Recently I wanted to make a video for a talk. And that is where the trouble started.
Initially, I thought to place a video and GIF side by side. However, getting a synchronous playback was tricky because there are few to no control options for GIFs in most presentation software. As a result, I had to extract the frames from the GIF instead and had to convert them into a video. While I could do this with any of many online services I specifically needed a synchronised playback as the timing of the content needed to match. The code above does exactly these frame extractions and pairs up nicely with another utility, the img2vid (which converts image files to a video with a choosable frame rate.
Simply set the option to save the frames and then run the img2vid on the single images to make the video and you can use it with controls in your presentation software, be it PowerPoint, or anything else.
The above main part gets you an example GIF (it had to be a cat, right?) and shows you the first frame. Enjoy!