Python Imaging Library (Fork) providing comprehensive image processing capabilities for reading, writing, and manipulating images across dozens of formats.
—
Animation and multi-frame image support for iterating through frames in animated GIFs, multi-page TIFFs, and other sequence-based image formats.
Iterate through frames in multi-frame images with support for both sequential iteration and random access.
class Iterator:
def __init__(self, im: Image.Image) -> None:
"""
Create an iterator for an image sequence.
Parameters:
- im: Image object with seek capability (animated GIF, multi-page TIFF, etc.)
Raises:
AttributeError: If the image doesn't support seeking (no seek method)
"""
def __getitem__(self, ix: int) -> Image.Image:
"""
Access a specific frame by index.
Parameters:
- ix: Frame index (0-based)
Returns:
Image.Image: The image positioned at the specified frame
Raises:
IndexError: If the frame index is out of range
"""
def __iter__(self) -> Iterator:
"""
Return the iterator object itself.
Returns:
Iterator: Self for iteration protocol
"""
def __next__(self) -> Image.Image:
"""
Get the next frame in the sequence.
Returns:
Image.Image: The next frame in the sequence
Raises:
StopIteration: When the end of the sequence is reached
"""Process all frames in an image sequence with optional transformation functions.
def all_frames(
im: Image.Image | list[Image.Image],
func: Callable[[Image.Image], Image.Image] | None = None,
) -> list[Image.Image]:
"""
Extract all frames from an image sequence, optionally applying a function to each.
Parameters:
- im: Single image object or list of image objects
- func: Optional function to apply to each frame
Returns:
list[Image.Image]: List of all frames (copied) with optional transformation applied
Note:
- Original image position is restored after processing
- All returned frames are copies, safe to modify independently
- Function is applied to each frame if provided
"""from PIL import Image, ImageSequence
# Open an animated GIF
gif = Image.open("animated.gif")
# Iterate through all frames
for frame in ImageSequence.Iterator(gif):
# Process each frame
print(f"Frame size: {frame.size}")
# frame is the same Image object, positioned at different frames
# Access specific frames by index
iterator = ImageSequence.Iterator(gif)
first_frame = iterator[0] # First frame
third_frame = iterator[2] # Third frame
# Get all frames as separate Image objects
all_frame_copies = ImageSequence.all_frames(gif)
print(f"Total frames: {len(all_frame_copies)}")
# Apply transformation to all frames
def resize_frame(frame):
return frame.resize((100, 100))
resized_frames = ImageSequence.all_frames(gif, resize_frame)
# Process multiple images at once
images = [gif1, gif2, gif3]
all_frames_from_multiple = ImageSequence.all_frames(images)
# Practical example: Extract frames for analysis
gif = Image.open("animation.gif")
frames = ImageSequence.all_frames(gif)
# Analyze each frame individually
for i, frame in enumerate(frames):
# Save individual frames
frame.save(f"frame_{i:03d}.png")
# Get frame statistics
mean_color = frame.convert("RGB").resize((1, 1)).getpixel((0, 0))
print(f"Frame {i} average color: {mean_color}")
# Working with multi-page TIFF
tiff = Image.open("multipage.tiff")
for page_num, page in enumerate(ImageSequence.Iterator(tiff)):
print(f"Page {page_num}: {page.size}, {page.mode}")
page.save(f"page_{page_num}.png")The ImageSequence module works with any image format that supports multiple frames or pages:
iterator[index] syntax for random accessall_frames() creates copies of each frame, safe for independent modificationall_frames() completesInstall with Tessl CLI
npx tessl i tessl/pypi-pillow