How to insert animated gif in pygame

Good afternoon, I'm doing a college job, it's a python game and I need to insert a gif in the code but when I use the command pygame.image.load("correr.gif") it shows the frozen gif image, getting only a png image. Can anyone help me

Follows the initial Code:

import pygame
pygame.init()
x = 352
y = 500
velocidade = 15
fundo = pygame.image.load("fundo_pista.png")
homem = pygame.image.load("correr.gif")
Author: jsbueno, 2020-05-06

1 answers

The pygame library can read images and display still images with few calls. But it doesn't support animated GIFs. If you want to display a gif animation in Pygame, you will have to use a library with more complete GIF support - for example, the "pillow", extract the desired frames and time indications, and display each frame manually (calling the" blit " method of your screen in pygame, and pygame.display.flip ())

So - come on:

The Pillow can be installed as "pip install pillow" - and then, she knows how to load an image, check if it's an animation, and extract all the frames.

Right now using PIL, it is not possible to get how long it is expected to each frame (the GIF format allows each image to be displayed for a custom time-so you can have a still image for 3 seconds, and a quick sequence animation). I believe it is reasonable to work with 100 milliseconds (10fps) for each frame - we can use the method .tick() of an instance of pygame.time.Clock for this.

Then it happens that objects of the Image type of Pil are not compatible with "surface" objects of Pygame - it is necessary to convert from one type to another. Both libraries allow you to translate images to and from a byte sequence - (in PIL the method calls "tobytes" , and in pygame, because the method has been created still in Python2, it is called "fromstring" - (but accepts a bytes object)) In addition, GIF images use the image mode of "palette" with a small number of colors, they have to be converted to RGB before the conversion is made. (Working with Palettes straight could be possible, but it would be more complicated).

The best way to do these two small operations is to write a small function for each of these things:

import sys

import pygame
from PIL import Image

size=(800,600)
FORMAT = "RGBA"


def pil_to_game(img):
    data = img.tobytes("raw", FORMAT)
    return pygame.image.fromstring(data, img.size, FORMAT)

def get_gif_frame(img, frame):
    img.seek(frame)
    return  img.convert(FORMAT)


def init():
    return pygame.display.set_mode(size)

def exit():
    pygame.quit()


def main(screen, path_to_image):
    gif_img = Image.open(path_to_image)
    if not getattr(gif_img, "is_animated", False):
        print(f"Imagem em {path_to_image} não é um gif animado")
        return
    current_frame = 0
    clock = pygame.time.Clock()
    while True:
        frame = pil_to_game(get_gif_frame(gif_img, current_frame))
        screen.blit(frame, (0, 0))
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        current_frame = (current_frame + 1) % gif_img.n_frames

        pygame.display.flip()
        clock.tick(10)


if __name__ == "__main__":
    try:
        screen = init()
        main(screen, sys.argv[1])
    finally:
        exit()

(converting images between PIL and pygame, I adapted from from the code here: https://riptutorial.com/pygame/example/21220/using-with-pil , to documentation for reading frames in PIL here: https://pythontic.com/image-processing/pillow/extract%20frames%20from%20animated%20gif )

If it is necessary to have the timing of frames from inside the GIF this has to be adapted, and we have to 'go down' to the PIL code that reads the GIFs and take the data from there-at the limit, after researching this, we would a suggestion for improvement (with pull request), to Pillow itself.

 2
Author: jsbueno, 2020-05-08 20:21:48