Reputation: 111
First of all, sorry if this is a duplicate. The answers that I found either seemed irrelevant but perhaps I'm searching with the wrong keywords. What I'd like to do is to take an animated GIF and split it up into a list of frames. Basically, something like this:
frames = []
for frame in split_animated_gif("some_animated_gif.gif"):
frames.append(frame)
where split_animated_gif returns a list of surfaces, each of which is a frame of the GIF, in order. Thank you for your help.
EDIT: After some more snooping, I found a piece of code that successfully displayed an animated GIF in pygame for me. It can be found at https://github.com/piantado/kelpy/blob/master/kelpy/GIFImage.py. Your help was much appreciated, though.
Upvotes: 9
Views: 10590
Reputation: 210968
PyGame respectively the pygame.image
module can only handle non-animated GIFs.
But on the PyGame homepage is introduced the GIFImage library:
This library adds GIF animation playback to pygame.
Another option is to use a library to load the GIF frame by frame to a list.
For instance use the Pillow library (pip install Pillow).
Write a function, that can convert a PIL image to a pygame.Surface
and use the PIL library to load a GIF frame by frame:
(see also Extracting The Frames Of An Animated GIF Using Pillow and PIL and pygame.image)
from PIL import Image, ImageSequence
def pilImageToSurface(pilImage):
mode, size, data = pilImage.mode, pilImage.size, pilImage.tobytes()
return pygame.image.fromstring(data, size, mode).convert_alpha()
def loadGIF(filename):
pilImage = Image.open(filename)
frames = []
if pilImage.format == 'GIF' and pilImage.is_animated:
for frame in ImageSequence.Iterator(pilImage):
pygameImage = pilImageToSurface(frame.convert('RGBA'))
frames.append(pygameImage)
else:
frames.append(pilImageToSurface(pilImage))
return frames
Or use OpenCV/opencv-python library and VideoCapture
Write a function, that can convert a cv2 pygame.image
image to a pygame.Surface
a nd use the library to load a GIF frame by frame:
(see also Read GIF files in Python and How do I convert an OpenCV (cv2) image (BGR and BGRA) to a pygame.Surface object)
import cv2
def cv2ImageToSurface(cv2Image):
size = cv2Image.shape[1::-1]
format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
return surface.convert_alpha() if format == 'RGBA' else surface.convert()
def loadGIF(filename):
gif = cv2.VideoCapture(filename)
frames = []
while True:
ret, cv2Image = gif.read()
if not ret:
break
pygameImage = cv2ImageToSurface(cv2Image)
frames.append(pygameImage)
return frames
See also Load animated GIF and a simple animated gif viewer example:
import pygame
import cv2
def cv2ImageToSurface(cv2Image):
size = cv2Image.shape[1::-1]
format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
return surface.convert_alpha() if format == 'RGBA' else surface.convert()
def loadGIF(filename):
gif = cv2.VideoCapture(filename)
frames = []
while True:
ret, cv2Image = gif.read()
if not ret:
break
pygameImage = cv2ImageToSurface(cv2Image)
frames.append(pygameImage)
return frames
pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
gifFrameList = loadGIF(r"rubber_ball.gif")
currentFrame = 0
run = True
while run:
clock.tick(20)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill(0)
rect = gifFrameList[currentFrame].get_rect(center = (250, 250))
window.blit(gifFrameList[currentFrame], rect)
currentFrame = (currentFrame + 1) % len(gifFrameList)
pygame.display.flip()
Upvotes: 0
Reputation: 2332
This code does it using PIL / pillow library.
from PIL import Image
def split_animated_gif(gif_file_path):
ret = []
gif = Image.open(gif_file_path)
for frame_index in range(gif.n_frames):
gif.seek(frame_index)
frame_rgba = gif.convert("RGBA")
pygame_image = pygame.image.fromstring(
frame_rgba.tobytes(), frame_rgba.size, frame_rgba.mode
)
ret.append(pygame_image)
return ret
Upvotes: 4
Reputation: 4507
Pygame itself does not support animated gifs, which is stated in the documentation. So you'll have to
1) use some other piece of code / library to split the gif when you're loading your sprites or images. Those you would find just by googling for "python split gif" or something. E.g. Python: Converting GIF frames to PNG
2) if you created the gif yourself, just export your sprites again frame by frame
Either way, you'll have to do the animating part by hand. Which for you'll find plenty of tutorials by googling "pygame animation". E.g. Animated sprite from few images
Upvotes: 5