Playing animated GIFs was added to CircuitPython in early 2023 and I had successfully had them running on TFT displays and even to a monitor via HDMI. I recently setup my MatrixPortal and two 64x32 matrices that I had been using to show animated GIFs. But the MatrixPortal was running Arduino code.
Time for an update and to take the code from Using Animated GIF Files in CircuitPython and Creating Projects with-the CircuitPython MatrixPortal Library and smush them together to play animated GIFs on a MatrixPortal with CircuitPython. Both guides do a great job of explaining the details of their own area and the code here combines them both.
The first half of the code sets up the matrix on DisplayIO
and the second half uses OnDiskGif
from the gifio
module to display the animated GIF.
The code displays all GIFs found in the /gifs/ directory on the MatrixPortal. Each animated GIF will display for 30 seconds before moving to the next animation.
One major difference from the Animated GIF guide: for speed, the code in the guide sends the raw bitmap data directly to an attached display. In theory that is possible to do on the MatrixPortal but it is more complicated and likely would be slower then using DisplayIO
. This is because the matrices have fewer pixels then most screens and the speed of the protomatter
library that powers the matrix display.
import displayio import board import rgbmatrix import framebufferio import time import gifio import os # Get a dictionary of GIF filenames at the passed base directory def get_files(base): allfiles = os.listdir(base) file_names = [] for _, filetext in enumerate(allfiles): if not filetext.startswith("."): if filetext not in ('boot_out.txt', 'System Volume Information'): if filetext.endswith(".gif"): file_names.append(filetext) return file_names # Set for 2 matrix bit_depth = 6 base_width = 64 base_height = 32 chain_across = 1 tile_down = 2 serpentine = True width = base_width * chain_across height = base_height * tile_down addr_pins = [board.MTX_ADDRA, board.MTX_ADDRB, board.MTX_ADDRC, board.MTX_ADDRD] rgb_pins = [ board.MTX_R1, board.MTX_G1, board.MTX_B1, board.MTX_R2, board.MTX_G2, board.MTX_B2, ] clock_pin = board.MTX_CLK latch_pin = board.MTX_LAT oe_pin = board.MTX_OE displayio.release_displays() matrix = rgbmatrix.RGBMatrix( width=width, height=height, bit_depth=bit_depth, rgb_pins=rgb_pins, addr_pins=addr_pins, clock_pin=clock_pin, latch_pin=latch_pin, output_enable_pin=oe_pin, tile=tile_down, serpentine=serpentine, ) display = framebufferio.FramebufferDisplay(matrix) splash = displayio.Group() display.root_group = splash DIRECTORY = "/gifs/" files = get_files(DIRECTORY) while True: for i in range(len(files)): odg = gifio.OnDiskGif(DIRECTORY+files[i]) # Load the first frame start = time.monotonic() next_delay = odg.next_frame() end = time.monotonic() overhead = end - start # how long did loading a frame take gif_tile = displayio.TileGrid( odg.bitmap, pixel_shader=displayio.ColorConverter( input_colorspace=displayio.Colorspace.RGB565_SWAPPED ), ) splash.append(gif_tile) start = time.monotonic() # Display the GIF for 30 seconds while time.monotonic() < start + 30: frame_shown = time.monotonic() display.refresh() next_delay = odg.next_frame() time.sleep(max(0, next_delay - overhead)) splash.remove(gif_tile)


