Displaying more than one GIF isn't too much different than a single GIF. This page provides some tips. Memory management becomes more important.
This example also shows writing directly to the built-in display, which can save time in displaying frames for a smoother feel. The trade-off is researching how to write directly to the display as that can vary from one display chipset to another.
Download the Project Bundle
The example uses the code file and two sample animated GIF images. To get everything you need, click on the Download Project Bundle link below, and uncompress the .zip file.
Hook the Feather to your computer via a known good USB data+power cable. It should show up as a thumb drive named CIRCUITPY.
Using File Explorer/Finder (depending on your Operating System), drag the contents of the uncompressed bundle directory onto your board's CIRCUITPY drive, replacing any existing files or directories with the same names, and adding any new ones that are necessary.
The code below displays multiple GIFs, sequentially as you press the BOOT button. Copy the file code-multi-feather-direct.py to code.py.
# SPDX-FileCopyrightText: 2023 Anne Barela for Adafruit Industries # # SPDX-License-Identifier: MIT # # Play Multiple GIF files on an ESP32-S2 Feather TFT # Requires CircuitPython 8.1.0-beta.1 or later # Updated 4/4/2023 import time import gc import os import struct import board import gifio import digitalio # 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 BOOT button on ESP32-S2 Feather TFT to advance to next GIF button = digitalio.DigitalInOut(board.BUTTON) button.switch_to_input(pull=digitalio.Pull.UP) display = board.DISPLAY display.auto_refresh = False COL_OFFSET = 40 # The Feather TFT needs to have the display ROW_OFFSET = 53 # offset by these values for direct writes files = get_files("/") for i in range(len(files)): odg = gifio.OnDiskGif(files[i]) # Skip PyPortal GIFs if put on ESP32-S2 Feather TFT if odg.width != board.DISPLAY.width: print("File "+files[i]+" not right width, skipping\n") continue start = time.monotonic() next_delay = odg.next_frame() # Load the first frame end = time.monotonic() call_delay = end - start # Display GIF file frames until screen touched (for PyPortal) while True: sleeptime = max(0, next_delay - call_delay) time.sleep(sleeptime) # If the BOOT button is pressed, advance to next GIF file if button.value is False: print("Button Press, Advance\n") break next_delay = odg.next_frame() display.bus.send(42, struct.pack(">hh", COL_OFFSET, odg.bitmap.width - 1 + COL_OFFSET)) display.bus.send(43, struct.pack(">hh", ROW_OFFSET, odg.bitmap.height - 1 + ROW_OFFSET)) display.bus.send(44, odg.bitmap) # End while # Clean up memory odg.deinit() odg = None gc.collect() # End for
How It Works
First the code imports all the libraries needed for the example. All are included inside CircuitPython. The BOOT button on the Feather is used programmably. It cycles between GIF files in this example, so it is defined as an input as shown in the user guide for this board.
The display is addressed directly through display.bus
.
The function get_files()
gets the names of all the GIF files in the root (main) directory on the device. This is a convenience - if you only want a predefined list, make a dictionary named files with the filenames, like this:
files = ['/file1.gif', '/file2.gif']
To signal user input, the BOOT button is pressed. This isn't necessary in most applications but having a convenient input method can be handy.
Each GIF file found on the Feather (there are two demonstration files) is opened via gifio
. The first frame of the current file is loaded using odg.next_frame()
. The time it takes to call the function is noted to make an adjustment for the time between frames later.
A While
loop constantly fetches frames and displays them with a file-defined pause between frames. As calling the next_frame
takes time (measured earlier), that time is subtracted from the frame rate specified in the file.
The frame contents are sent direct to the display via calls to display.bus.send
rather than using displayio
. This makes displaying frames faster, making for smoother playback. Note for the Feather, which is different than the PyPortal, the display needs X and Y offsets to get the images to display on the right place on the screen. Without them, the image would be tucked in the upper left corner.
When the BOOT button is pressed, the memory is cleaned up and the next file on the Feather is played until they all have been played and the program ends.
If you wish to put the GIF files in a subdirectory, change the line files = get_files("/"
)
to your preferred directory name, for example files = get_files("/Images")
.
Text editor powered by tinymce.