Search code examples
pythonanimated-gifdearpygui

How to display a GIF in Dearpygui


Since importing and displaying GIF is not natively supported in dearpygui, how would one go about to render and animate a GIF in dpg using the existing tools?


Solution

  • One can use imageio or Pillow to load all the frames of a GIF into memory. From there, the trick is to change the frame loaded into a texture using dpg.set_value to the next gif frame, and then call dpg.render_dearpygui_frame() to render the new frame into the window. Using time.sleep, we can adjust the frame rate.

    Here is a working example code to load, render and animate a GIF:

    import dearpygui.dearpygui as dpg
    import numpy as np
    import imageio
    import threading
    import time
    
    path_to_gif = "/path/to/your/gif/file.gif"
    
    dpg.create_context()
    dpg.create_viewport(title="Custom Title", width=600, height=800)
    dpg.setup_dearpygui()
    
    # Load the GIF using imageio
    gif = imageio.mimread(path_to_gif)
    
    # Function to adapt numpy image to dpg texture image
    def adapt_frame_to_dpg(frame: np.ndarray) -> np.ndarray:
        data = frame.ravel()  # Flatten the data
        data = np.asarray(data, dtype="float32")  # Change data type to 32-bit floats
        return np.true_divide(data, 255.0)  # Normalize the image data
    
    
    # Get the dimensions of the GIF
    frame_width, frame_height = gif[0].shape[1], gif[0].shape[0]
    frame = gif[0][:, :, :3]  # Extract RGB channels
    
    texture_data = adapt_frame_to_dpg(frame)
    
    with dpg.texture_registry(show=False):
        dpg.add_raw_texture(
            frame_width,
            frame_height,
            texture_data,
            tag="texture_tag",
            format=dpg.mvFormat_Float_rgb,
        )
    
    with dpg.window(label="Animating a gif !"):
        with dpg.drawlist(400, 265):
            dpg.draw_image("texture_tag", (0, 0), (400, 265))
    
    dpg.show_viewport()
    
    frame_index = 0
    
    # The animation function : Update the texture with the next frame of the GIF
    def animate_gifs() -> None:
        global frame_index, gif
        desired_fps = 30
        frame = gif[frame_index % len(gif)][:, :, :3]  # Extract RGB channels
        texture_data = adapt_frame_to_dpg(frame)
        dpg.set_value("texture_tag", texture_data)
    
        frame_index += 1
        time.sleep(1 / desired_fps)
    
    animation_thread = None
    
    while dpg.is_dearpygui_running():
        dpg.render_dearpygui_frame()
        
        # Put the animation work in a thread to not slow the eventual inputs
        if (
            animation_thread != None
            and not animation_thread.is_alive()
            or animation_thread == None
        ):
            animation_thread = threading.Thread(target=animate_gifs)
            animation_thread.start()
    dpg.destroy_context()
    

    The code also works for videos, you only need to adapt the loading part:

    max_frames = 500 # Needed as imageio has a threshold on the amount of loadable data
    video = imageio.get_reader(path_to_video)
    gif = []
    for f in range(min(max_frames, video.count_frames())):
        gif.append(video.get_data(f))