Pillow is a Python library used for creating, editing, and processing images. It provides the Image module for creating image objects and the ImageDraw module for drawing shapes, making it possible to generate individual frames and combine them into an animated GIF.
Installation
pip install pillow
Creating and Saving an Animated GIF
An animated GIF can be created by generating multiple images with small visual changes and combining them into a single file. Pillow's save() method supports multiple frames through the save_all and append_images parameters.
1. Importing the Required Modules
Import Image and ImageDraw from Pillow to create images and draw shapes on them.
from PIL import Image, ImageDraw
2. Creating Animation Frames
Create a sequence of images with a green circle that gradually expands and contracts against a red background. Each image represents one frame of the animation.
frames = []
width, height = 240, 240
center_x, center_y = width // 2, height // 2
background = (255, 0, 0)
circle_color = (0, 255, 0)
radii = list(range(8, 101, 8)) + list(range(92, 8, -8))
for radius in radii:
image = Image.new("RGB", (width, height), background)
draw = ImageDraw.Draw(image)
draw.ellipse(
(
center_x - radius,
center_y - radius,
center_x + radius,
center_y + radius
),
fill=circle_color
)
frames.append(image)
Explanation:
- Image.new() creates a new RGB image with a red background for each frame.
- ImageDraw.Draw() creates a drawing object, while ellipse() draws a green circle using the specified bounding box.
- radii sequence controls the circle's size, first increasing and then decreasing to create a repeating visual effect.
Step 3: Save the Animated GIF
Use the save() method on the first frame and append the remaining images to create the animation.
frames[0].save(
"animated_circle.gif",
save_all=True,
append_images=frames[1:],
duration=100,
loop=0,
optimize=False
)
print("Animated GIF saved successfully!")
Output:

Explanation:
- save_all=True ensures that all frames are included, while append_images adds the remaining frames after the first.
- duration=100 sets each frame's display time to 100 milliseconds, and loop=0 makes the animation repeat indefinitely.
- optimize=False disables the encoder's palette optimization, which is useful for keeping the generated frames straightforward.
Step 4: Verify the GIF
Open the saved file using Pillow to check the number of frames and the animation duration.
with Image.open("animated_circle.gif") as gif:
print("Number of frames:", gif.n_frames)
print("Frame duration:", gif.info.get("duration"), "ms")
Output:
Number of frames: 23
Frame duration: 100 ms
GIF contains 23 frames. Open animated_circle.gif in a web browser or GIF viewer to see the circle expand and contract.