# Playing Animated GIF Files in CircuitPython

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/120/180/medium800/circuitpython_sample-nyan-pyportal.gif?1681239809)

Frequent use of animated GIF files dates back to Netscape Navigator in the 1990's (remember twirling "under construction" signs for web sites?). These days, animated GIF files are most often used for meme display or in short video clips where a video file might not be playable.

The resources needed to play animated GIFs are lower than videos, but have often been more than what a microcontroller could provide.

![](https://cdn-learn.adafruit.com/assets/assets/000/120/193/medium800thumb/circuitpython_feather_2.jpg?1681247463)

Playing animated GIF image files using a microcontroller is a tough proposition. Here are the factors which need to be considered for a good experience:

- Microcontroller speed
- Microcontroller memory available
- A speedy interface between microcontroller memory and a display
- Animated GIF file size

Some more modern microcontrollers with a larger amount of memory and fast access to a local display can meet the requirements for animated GIF playback, as long as the file size and frame rate (the time between frames in the changing image) is not too small.

This guide will demonstrate displaying animated GIF files on two microcontroller boards with integrated displays. The Espressif ESP32-S2 and Microchip SAMD51 are modern processors capable of displaying GIF files at reasonable rates.

The CircuitPython `gifio` module is an addition to CircuitPython 8.1.0 and later versions providing GIF playback capability.

## Parts

This guide will use an Adafruit ESP32-S2 TFT Feather and an Adafruit PyPortal to demonstrate animated GIF playback. Only one of the boards is needed to try this process. The USB cable shown works with both USB micro B and USB C. Be sure you use a known good data+power cable.

You can choose another board - note the code may be slightly different from the code for these two boards in this guide. And also, if the other board does not have a modern, capable processor, GIF playback will be impaired or unacceptable.

### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

In Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
![Front view of a Adafruit PyPortal - CircuitPython Powered Internet Display with a pyportal logo image on the display. ](https://cdn-shop.adafruit.com/640x480/4116-00.jpeg)

### Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT

[Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT](https://www.adafruit.com/product/5300)
We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want unlimited mozzarella sticks? OK well, that's not something we can provide. But we can provide your...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5300)
[Related Guides to the Product](https://learn.adafruit.com/products/5300/guides)
![Adafruit ESP32-S2 TFT Feather powered on by a USB- C power source displaying the product tittle in a red, yellow, green, white and blue. ](https://cdn-shop.adafruit.com/640x480/5300-06.jpg)

# Playing Animated GIF Files in CircuitPython

## gifio

![](https://cdn-learn.adafruit.com/assets/assets/000/120/186/medium800thumb/circuitpython_amiga1.jpg?1681242827)

`gifio` is the new animated GIF module added to CircuitPython in version 8.1.0-beta.1 and later builds. It will not work with earlier versions. It provides methods to write and read animated GIF files. This guide will show how to read files and display them on an attached LCD display.

## Constraints

The `gifio` module is limited to working with images that are 320 pixels wide or less. The height is not specifically limited but very tall GIF's may run out of memory. Smaller dimensions are fine and will likely speed code execution on a smaller data set.

The GIF speed (time between frames) should be at least the time it takes the microcontroller to process and display one frame. You can benchmark this on your setup but generally the time between frames should be 4/100th of a second or longer. 7/100th of a second second or longer is likely better. A check in the code is best to ensure the GIF display function is passed a value greater or equal to zero, zero being "as fast as possible".

Info: 

## Usage

Our two example boards have integrated displays, such that `board.DISPLAY` is defined and connected via a defined display bus.

There are two methods for writing to the display: using the CircuitPython `displayio` module and writing to the display directly. There are times where one over the other may be desired. If using an entire display, the direct method is likely fastest, while if animation is in a `displayio.Tilegrid`, and a partial part of a display will be used for playback, `displayio` will be the route, although there will be slowdowns due to display code overhead to consider.

Primary: 

## gifio.OnDiskGif Constructor

This constructor creates an `OnDiskGif` object. You use that object to load one frame of a GIF image file into memory at a time.

The code can be used in cooperation with `displayio` but this mode is slower than writing directly to the display.

Parameters for the function are:

- File name: (required) The name of a file in the CircuitPython file system (most often on the **CIRCUITPY** drive for speed).&nbsp;

The `next_frame()` function is used to advance to the next frame in the animated GIF.

The `deinit()` function is used in conjunction with ensuring memory allocated by the `OnDiskGif` object is freed properly (important if multiple files are displayed or other memory activity is done.

## Issues

The library may not take into account the file size, so long GIFs should be cut into segments perhaps and read sequentially using the multi GIF method.

Error with memory allocation are indicative of a file size issue. Try a file with a smaller size for testing.

GIF files may be edited for size, frame duration, and length in a GIF file editor. The free web-based [https://ezgif.com/](https://ezgif.com/) does well.

&nbsp;

# Playing Animated GIF Files in CircuitPython

## CircuitPython

![](https://cdn-learn.adafruit.com/assets/assets/000/120/194/medium800/robotics___cnc_circuitpython_blinka-small.png?1681247571)

You will want to upload the latest version of CircuitPython for your microcontroller board. At the time of this guide, it is 8.1.0-beta.1 which is the minimum version `gifio` works on with the presented code.

Go to [circuitpython.org](https://circuitpython.org/), go to your board and download the .UF2 file under downloads (for microcontrollers) or Blinka (for single board computers).

For the two chosen boards, here are direct links:

[Adafruit PyPortal](https://circuitpython.org/board/pyportal/)
[Adafruit ESP32-S2 TFT Feather](https://circuitpython.org/board/adafruit_feather_esp32s2_tft/)
## Flashing the New Version of CircuitPython

Each Adafruit board has a handy guide on use at [https://learn.adafruit.com/](https://learn.adafruit.com/). The instructions for the two boards:

[Flash CircuitPython on the Adafruit PyPortal](https://learn.adafruit.com/adafruit-pyportal/install-circuitpython)
[Flash CircuitPython on the Adafruit ESP32-S2 TFT Feather](https://learn.adafruit.com/adafruit-esp32-s2-tft-feather/circuitpython)
When you plug your board into your computer via a known good USB data+power USB cable, a flash drive named **CIRCUITPY** should appear in your computer File Explorer or Finder (depending on your operating system). The **boot\_out.txt** will show your version of CircuitPython when you open it. Verify it is at least 8.1.0-beta.1:

```auto
Adafruit CircuitPython 8.1.0-beta.1 on 2023-03-30; Adafruit PyPortal with samd51j20
Board ID:pyportal
UID:9D6BC03935463953202020310A0E08FF
```

```auto
Adafruit CircuitPython 8.1.0-beta.1 on 2023-03-30; Adafruit Feather ESP32-S2 TFT with ESP32S2
Board ID:adafruit_feather_esp32s2_tft
UID:C7FD1A59112D
```

If your version of CircuitPython is less than 8.1.0-beta.1, please try to upload and flash a version at least 8.1.0-beta.1 (higher versions like 8.1.1, 8.2.0 or 9.0.0 are examples of versions that would be ok).

Next, to get the code and sample animated GIF files onto your board.

# Playing Animated GIF Files in CircuitPython

## PyPortal

![](https://cdn-learn.adafruit.com/assets/assets/000/120/191/medium800thumb/circuitpython_pyportal_1.jpg?1681247303)

The Adafruit PyPortal with a 320x240 pixel display makes a great GIF-playing platform with its snappy SAMD51 M4 processor.

## Download the Project Bundle

The example uses a code file and a sample animated GIF image. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Connect a PyPortal 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 unzipped 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.

![](https://cdn-learn.adafruit.com/assets/assets/000/120/201/medium800/circuitpython_CircuitPython_gifio_PyPortal.png?1681313246)

The code below displays a single GIF image. To run it, copy one of the GIF images to the name **sample.gif**. Copy the file **code-single-pyportal-displayio.py** to **code.py**.&nbsp;

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_gifio/PyPortal/code-single-pyportal-displayio.py

https://youtube.com/shorts/BQ0hYqjBrBg

## How It Works

First the code imports all the libraries needed for the example. Only the `Adafruit_Touchscreen` library needs an external file, the rest are included inside CircuitPython. Ensure **adafruit\_touchscreen.mpy** is in the **/lib** folder.&nbsp;Using `displayio`, the CircuitPython display library, the screen is defined (the parameters are in the PyPortal definition file so they don't need to be looked up, things like the screen width 320 px and height 240 px).

To signal user input, the touchscreen is used. This isn't necessary in most applications but having a convenient input method can be handy, especially if the PyPortal is in a case.

The file **sample.gif** is opened via `gifio`. You may get an error that **sample.gif** is not found, please copy one of the example GIF files to **sample.gif**.

The first frame 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 `displayio` `TileGrid` is made consisting of the first frame and the entire display.

Finally there is a loop which 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.

If the screen is touched, the memory is cleaned up and the program ends.

# Playing Animated GIF Files in CircuitPython

## PyPortal Multiple GIFs

https://youtu.be/pjJc81AIYqk

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 type to another.

## Download the Project Bundle

The example uses one code file and three sample animated GIF images. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Hook the PyPortal 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 tap the screen. Copy the file **code-multi-pyportal-direct.py** to **code.py**. You can leave the names of the GIF files as they are.

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_gifio/PyPortal/code-multi-pyportal-direct.py

## How It Works

First the code imports all the libraries needed for the example. Only the `Adafruit_Touchscreen` library needs an external file, the rest are included inside CircuitPython. Ensure **adafruit\_touchscreen.mpy** is in the **/lib** folder. The display is addressed directly through `display_bus`. The screen width of 320 px and height 240 px is retrieved through the internal board definition for the touchscreen definition.

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:

```auto
files = ['/file1.gif', '/file2.gif']
```

To register user input, the touchscreen is used. This isn't necessary in most applications but having a convenient input method can be handy, especially if the PyPortal is in a case.

Each GIF file found on the PyPortal is opened via `gifio`.&nbsp;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.

If the screen is touched, the memory is cleaned up and the next file on the PyPortal 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")`.

# Playing Animated GIF Files in CircuitPython

## Feather

![](https://cdn-learn.adafruit.com/assets/assets/000/120/187/medium800thumb/circuitpython_sample-parrot-small.jpg?1681244529)

The Adafruit ESP32-S2 Feather TFT with a 240x135 pixel display makes for a compact GIF playing platform.

## Download the Project Bundle

The examples use code files and sample animated GIF images. To get everything you need, click on the&nbsp; **Download Project Bundle** &nbsp;link below, and uncompress the .zip file.

Hook the Feather ESP32-S2 TFT 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.

![](https://cdn-learn.adafruit.com/assets/assets/000/120/202/medium800/circuitpython_CircuitPython_gifio_Feather.png?1681313953)

The code below displays a single GIF image. To run it, copy one of the GIF images to the name **sample.gif**. Copy the file **code-single-displayio-feather.py** to **code.py**.&nbsp;

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_gifio/Feather/code-single-displayio-feather.py

https://youtu.be/alqqO_ah1MM

## How It Works

First the code imports all the libraries needed for the example. All are included inside CircuitPython. Using `displayio`, the CircuitPython display library, the screen is defined (the parameters are in the Feather definition file so they don't need to be looked up, things like the screen width: 240 px and height 135 px).

The file **sample.gif** is opened via `gifio`. You may get an error that **sample.gif** is not found, please copy one of the example GIF files to **sample.gif**.

The first frame 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 `displayio` `TileGrid` is made consisting of the first frame and the entire display.

Finally, there is a loop which 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.

If the BOOT button is pressed, the memory is cleaned up and the program ends. This is just a convenience and a user's program need not use a button. It is suggested cleaning up the memory after using `gifio`.

# Playing Animated GIF Files in CircuitPython

## Feather Multiple GIFs

https://youtu.be/Te-IWadQoSs

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&nbsp; **Download Project Bundle** &nbsp;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**.&nbsp;

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/CircuitPython_gifio/Feather/code-multi-feather-direct.py

## 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](https://learn.adafruit.com/adafruit-esp32-s2-tft-feather/digital-input).

The display is addressed directly through `display.bus`.&nbsp;

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:

```auto
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`.&nbsp;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")`.


## Featured Products

### Adafruit PyPortal - CircuitPython Powered Internet Display

[Adafruit PyPortal - CircuitPython Powered Internet Display](https://www.adafruit.com/product/4116)
 **PyPortal** , our easy-to-use IoT device that allows you to create all the things for the “Internet of Things” in minutes. Make custom touch screen interface GUIs, all open-source, and Python-powered using&nbsp;tinyJSON / APIs to get news, stock, weather, cat photos,...

In Stock
[Buy Now](https://www.adafruit.com/product/4116)
[Related Guides to the Product](https://learn.adafruit.com/products/4116/guides)
### Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT

[Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT](https://www.adafruit.com/product/5300)
We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want unlimited mozzarella sticks? OK well, that's not something we can provide. But we can provide your...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5300)
[Related Guides to the Product](https://learn.adafruit.com/products/5300/guides)
### USB 3-in-1 Sync and Charge Cable - Micro B / Type-C / Lightning

[USB 3-in-1 Sync and Charge Cable - Micro B / Type-C / Lightning](https://www.adafruit.com/product/3679)
As USB technology evolves you'll want the **One Cable To Sync/Charge All Things** (or, at least, portable devices with Micro-B, Type C, or Lightning ports) and this cable will do the job nicely

This very nice **USB 3-in-1&nbsp;Charging Cable** looks like...

No Longer Stocked
[Buy Now](https://www.adafruit.com/product/3679)
[Related Guides to the Product](https://learn.adafruit.com/products/3679/guides)

## Related Guides

- [Adafruit PyPortal - IoT for CircuitPython](https://learn.adafruit.com/adafruit-pyportal.md)
- [Adafruit ESP32-S2 TFT Feather](https://learn.adafruit.com/adafruit-esp32-s2-tft-feather.md)
- [League of Legends Level Trophy for PyPortal](https://learn.adafruit.com/league-of-legends-level-trophy-for-pyportal.md)
- [PyPortal Twitter Follows Trophy](https://learn.adafruit.com/pyportal-twitter-follows-trophy.md)
- [Getting Started with Braille Output for CircuitPython REPL](https://learn.adafruit.com/getting-started-braille-output-circuitpython-repl.md)
- [Using LittlevGL with Adafruit Displays](https://learn.adafruit.com/using-littlevgl-with-adafruit-displays.md)
- [PyPortal Google Calendar Event Display](https://learn.adafruit.com/pyportal-google-calendar-event-display.md)
- [CircuitPython Neko Kitty with Displayio](https://learn.adafruit.com/circuitpython-neko-kitty-with-displayio.md)
- [PyPortal Oblique Strategies](https://learn.adafruit.com/pyportal-oblique-strategies.md)
- [Custom Fonts for CircuitPython Displays](https://learn.adafruit.com/custom-fonts-for-pyportal-circuitpython-display.md)
- [Data Logging IoT Weight Scale](https://learn.adafruit.com/data-logging-iot-weight-scale.md)
- [PyPortal LIFX Lighting Controller ](https://learn.adafruit.com/pyportal-lifx-lighting-controller.md)
- [Forecast the Weather at Home with a No-Code Barometer ](https://learn.adafruit.com/dps310-analog-barometer.md)
- [PyPortal Air Quality Display](https://learn.adafruit.com/pyportal-air-quality-display.md)
- [Adafruit IO Basics: Schedule Actions](https://learn.adafruit.com/adafruit-io-basics-scheduled-triggers.md)
- [PyPortal Wake-Up Light Alarm Clock](https://learn.adafruit.com/pyportal-wake-up-light.md)
- [Arcada Animated GIF Display](https://learn.adafruit.com/pyportal-animated-gif-display.md)
