How to insert animated gif into pygame

Asked

Viewed 524 times

3

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 image of the gif frozen, getting only one image in png. Someone can 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")
  • Erick, please post your code as example, what you have done so far, how you tried etc.

1 answer

2

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

So - come on:

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 frames.

Even now using PIL, it is not possible to get how much time is expected to each frame (the GIF format allows each image to be displayed for a custom time -so you can have one image stopped for 3 seconds, and one animation in quick sequence). 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 that reason.

It turns out that PIL Image objects are not compatible with Pygame "Surface" objects - it is necessary to convert from one type to the other. The two libraries allow translating images to and from a sequence of bytes - (in PIL the method calls "tobytes", and in pygame, because the method has been created in Python2, it is called "fromstring" - (but accepts a bytes object)) In addition, GIF images use "palette" image mode with a reduced number of colors, they have to be converted to RGB before the conversion is made. (Working with direct pallets might be possible, but it would be more complicated).

The best way to do these two small operations is to write a little 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()

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

If it is necessary to have the timing of frames from within the GIF this has to be adapted, and we have to 'descend' to the code of the PIL that reads the Gifs and take the data from there - at the limit, after researching it, we would do a suggested improvement (with pull request) to Pillow itself.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.