[{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/000/338/original/BomberFlag.gif?1700100819","metadata":{"caption":"An animated GIF playing on two RGB matrices "}},{"element_type":"text","content":"\n  \n  \n        \u003cp\u003ePlaying 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.\u003c/p\u003e\n\u003cp\u003eTime for an update and to take the code from \u003ca href=\"https://learn.adafruit.com/using-animated-gif-files-in-circuitpython\" target=\"_blank\"\u003eUsing Animated GIF Files in CircuitPython\u003c/a\u003e and \u003ca href=\"https://learn.adafruit.com/creating-projects-with-the-circuitpython-matrixportal-library\" target=\"_blank\"\u003eCreating Projects with-the CircuitPython MatrixPortal Library\u003c/a\u003e 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.\u003c/p\u003e\n\u003cp\u003eThe first half of the code sets up the matrix on \u003ccode\u003eDisplayIO\u003c/code\u003e and the second half uses \u003ccode\u003eOnDiskGif\u003c/code\u003e from the \u003ccode\u003egifio\u003c/code\u003e module to display the animated GIF.\u003c/p\u003e\n\u003cp\u003eThe code displays all GIFs found in the \u003cem\u003e/gifs/\u003c/em\u003e directory on the MatrixPortal. Each animated GIF will display for 30 seconds before moving to the next animation.\u003c/p\u003e\n      \n\n","metadata":{}},{"element_type":"alert","content":"Remember to (re)size your GIFs for the size of your matrix display.","metadata":{"class":"element row-fluid alert-element build-alert alert-info","alert_type":"info"}},{"element_type":"text","content":"\n  \n  \n  \n  \n        \u003cp\u003e\u003cstrong\u003eOne major difference from the Animated GIF guide\u003c/strong\u003e: 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 \u003ccode\u003eDisplayIO\u003c/code\u003e. This is because the matrices have fewer pixels then most screens and the speed of the \u003ccode\u003eprotomatter\u003c/code\u003e library that powers the matrix display.\u003c/p\u003e\n      \n\n\n\n","metadata":{}},{"element_type":"code","content":"import displayio\nimport board\nimport rgbmatrix\nimport framebufferio\nimport time\nimport gifio\nimport os\n\n# Get a dictionary of GIF filenames at the passed base directory\ndef get_files(base):\n    allfiles = os.listdir(base)\n    file_names = []\n    for _, filetext in enumerate(allfiles):\n        if not filetext.startswith(\".\"):\n            if filetext not in ('boot_out.txt', 'System Volume Information'):\n                if filetext.endswith(\".gif\"):\n                    file_names.append(filetext)\n    return file_names\n\n# Set for 2 matrix\nbit_depth = 6\nbase_width = 64\nbase_height = 32\nchain_across = 1\ntile_down = 2\nserpentine = True\n\nwidth = base_width * chain_across\nheight = base_height * tile_down\n\naddr_pins = [board.MTX_ADDRA, board.MTX_ADDRB, board.MTX_ADDRC, board.MTX_ADDRD]\nrgb_pins = [\n    board.MTX_R1,\n    board.MTX_G1,\n    board.MTX_B1,\n    board.MTX_R2,\n    board.MTX_G2,\n    board.MTX_B2,\n]\nclock_pin = board.MTX_CLK\nlatch_pin = board.MTX_LAT\noe_pin = board.MTX_OE\n\ndisplayio.release_displays()\nmatrix = rgbmatrix.RGBMatrix(\n                width=width,\n                height=height,\n                bit_depth=bit_depth,\n                rgb_pins=rgb_pins,\n                addr_pins=addr_pins,\n                clock_pin=clock_pin,\n                latch_pin=latch_pin,\n                output_enable_pin=oe_pin,\n                tile=tile_down,\n                serpentine=serpentine,\n            )\ndisplay = framebufferio.FramebufferDisplay(matrix)\nsplash = displayio.Group()\ndisplay.root_group = splash\n\nDIRECTORY = \"/gifs/\"\n\nfiles = get_files(DIRECTORY)\nwhile True:\n    for i in range(len(files)):\n        odg = gifio.OnDiskGif(DIRECTORY+files[i])\n        # Load the first frame\n        start = time.monotonic()\n        next_delay = odg.next_frame()\n        end = time.monotonic()\n        overhead = end - start # how long did loading a frame take\n\n        gif_tile = displayio.TileGrid(\n            odg.bitmap,\n            pixel_shader=displayio.ColorConverter(\n                input_colorspace=displayio.Colorspace.RGB565_SWAPPED\n            ),\n        )\n        splash.append(gif_tile)\n        \n        start = time.monotonic()\n        # Display the GIF for 30 seconds\n        while time.monotonic() \u003c start + 30:\n            frame_shown = time.monotonic()\n            display.refresh()\n            next_delay = odg.next_frame()\n            time.sleep(max(0, next_delay - overhead))\n\n        splash.remove(gif_tile)","metadata":{"language":"auto","linenums":false}},{"element_type":"product","content":"https://www.adafruit.com/product/4745","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5778","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/420","metadata":{}}]