Display GIF on Inky Frame using micropython

Can I display a GIF on my Inky Frame?
I can’t work out how to convert a GIF to JPEG in MicroPython but maybe I have missed something obvious (like that I don’t need to convert the GIF).
The GIFs in question come from the BBC Weather RSS feed so they are static not animated.

Plan B is to convert the 32 BBC RSS Weather GIFs (1.gif - 32.gif) to JPEG in the Gimp and load from local resource. I would create a sprite sheet but I don’t think the “word” GIFs (like MIST) would work.

This is what I have so far:

# Display BBC Weather for Reading (2639577) on Pimoroni Inky Frame
# For the weather where you live goto https://www.bbc.co.uk/weather and find your number
# Just a modified news_headlines.py as pre-installed on Pimoroni Inky Frame
from picographics import PicoGraphics, DISPLAY_INKY_FRAME_4 as DISPLAY  # Inky Frame 4.0"
from network_manager import NetworkManager
import WIFI_CONFIG
import uasyncio
from urllib import urequest
import math, gc


weatherURL = "http://weather-broker-cdn.api.bbci.co.uk/en/forecast/rss/3day/2639577"


# Callback handler for Pioroni NetworkManager
# Lifted and shifted from Pimoroni news_headlines
def status_handler(mode, status, ip):
    print(mode, status, ip)

# Reads through stream appending to result until char is found
# Lifted and shifted from Pimoroni news_headlines
def read_until(stream, char):
    result = b""
    while True:
        c = stream.read(1)
        if c == char:
            return result
        result += c

# Reads through stream ignoring everything, stop when char is found
# Lifted and shifted from Pimoroni news_headlines
def discard_until(stream, char):
    while stream.read(1) != char:
        pass

# Parses an XML stream
# Lifted and shifted from Pimoroni news_headlines
def parse_xml_stream(stream, accept_tags, group_by, max_items=3):
    tag = []
    text = b""
    count = 0
    current = {}
    while True:
        char = stream.read(1)
        if len(char) == 0:
            break

        if char == b"<":
            next_char = stream.read(1)

            # Discard stuff like <?xml vers...
            if next_char == b"?":
                discard_until(stream, b">")
                continue

            # Detect <![CDATA
            elif next_char == b"!":
                stream.read(1)  # Discard [
                discard_until(stream, b"[")  # Discard CDATA[
                text = read_until(stream, b"]")
                discard_until(stream, b">")  # Discard ]>
                gc.collect()

            elif next_char == b"/":
                current_tag = read_until(stream, b">")
                top_tag = tag[-1]

                # Populate our result dict
                if top_tag in accept_tags:
                    current[top_tag.decode("utf-8")] = text.decode("utf-8")

                # If we've found a group of items, yield the dict
                elif top_tag == group_by:
                    yield current
                    current = {}
                    count += 1
                    if count == max_items:
                        return
                tag.pop()
                text = b""
                gc.collect()
                continue

            else:
                current_tag = read_until(stream, b">")
                tag += [next_char + current_tag.split(b" ")[0]]
                text = b""
                gc.collect()
        else:
            text += char


# Parse tthe RSS feed extracting specific values for items
# Lifted and shifted from Pimoroni news_headlines but removed error handling
def get_rss(url, items, values):
    stream = urequest.urlopen(url)
    output = list(parse_xml_stream(stream, values, items))
    return output

# Helper to abbreviate some common words
# Note this is totally hand cranked
def abbreviate(text):
    retVal = text
    retVal = retVal.replace("Temperature", "Temp")
    retVal = retVal.replace("temperature", "temp")
    retVal = retVal.replace("Minimum", "Min")
    retVal = retVal.replace("Maximum", "Max")
    retVal = retVal.replace("minimum", "min")
    retVal = retVal.replace("maximum", "max")
    return retVal


# Helper to calulate height of text (assuming bitmap8 font is 8 high)
def get_text_height(graphics, text, width, scale = 1, font_height = 8):
    return math.ceil(graphics.measure_text(text, scale) / width) * font_height * scale
    

# Connect to WiFi
# Lifted and shifted from Pimoroni news_headlines
network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=status_handler)
uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK))

# Gets the weather image which includes a meaningful title
image = get_rss(weatherURL, b"image", [b"title", b"url"])

# Gets the weather entries/items, we oonly want the titles
feed = get_rss(weatherURL, b"item", [b"title"])

heading = image[0]["title"]
weather1 = abbreviate(feed[0]["title"])
weather2 = abbreviate(feed[1]["title"])

del feed

# output some debug info
print(heading)
print(weather1)
print(weather2)

# Create a PicoGraphics object for the display
# Lifted and shifted from Pimoroni news_headlines
graphics = PicoGraphics(DISPLAY)
WIDTH, HEIGHT = graphics.get_bounds()

# Clear the display (1 = white)
graphics.set_pen(1)
graphics.clear()

# Use the bitmap8 font
graphics.set_font("bitmap8")

# Set a nice padding value
PADDING = 5
# All text will be the same width
TEXT_WIDTH = WIDTH - PADDING * 2
# Keep track of our Y position on the display
Y = PADDING

# Add a heading (3 = blue)
graphics.set_pen(3)
graphics.text(heading, PADDING, Y, TEXT_WIDTH, scale=3)
Y += get_text_height(graphics, heading, TEXT_WIDTH, scale=3) + PADDING

# Add today's weather (0 = black)
graphics.set_pen(0)
graphics.text(weather1, PADDING, Y, TEXT_WIDTH, scale=3)
Y += get_text_height(graphics, weather1, TEXT_WIDTH, scale=3) + PADDING

# Add tomorrow's weather (same pen, i.e. black)
graphics.text(weather2, PADDING, Y, TEXT_WIDTH, scale=3)
Y += get_text_height(graphics, weather1, TEXT_WIDTH, scale=3) + PADDING

# Update the display
graphics.update()

# Try to free some resources (does this even work?)
del graphics
gc.collect()