The editor

Show an image on a MicroPython display

Turn a PNG or JPG into the Python module that a display driver's bitmap() draws.

Why a plain image file will not do

Russ Hughes' display drivers (gc9a01py, st7789py and the ILI9342C one) draw a picture with tft.bitmap(module, x, y). The module has to hold WIDTH, HEIGHT, BPP, a PALETTE and a BITMAP, which is what his imgtobitmap.py writes. A file with only WIDTH, HEIGHT and a block of data stops with "module has nothing called BITMAP", on Mokxi and on a real board alike. Mokxi makes the right file for you.

Make the module

  1. Open a MicroPython project (a board with a main.py). A CircuitPython project's + asks for a file name only.
  2. Click + in the file tabs and choose Add image as bitmap.
  3. Pick a PNG or JPG.
  4. Set the Width and Height. Changing one changes the other so the picture keeps its shape. They start at the biggest size that fits 240 x 240, or the display in your circuit when it has one.
  5. Choose the Colors: 2, 4, 16 or 256. More colors look better and take more room: a 70 x 70 picture is 613 bytes at 1 bit a pixel in 2 colors, and 4,900 bytes at 8 bits a pixel in 256 colors.
  6. Check the preview, change the file name if you like, and press Add to project.

The new <name>.py opens in its own tab. Nothing is uploaded: the picture is read and shrunk in your browser.

Draw it

Copy the driver into the project the way you do for any library, then import the new module next to it. For a round GC9A01 display:

from machine import Pin, SPI
import gc9a01py
import happy

spi = SPI(2, baudrate=40000000, sck=Pin(8), mosi=Pin(11))
tft = gc9a01py.GC9A01(spi, dc=Pin(19, Pin.OUT), cs=Pin(3, Pin.OUT), reset=Pin(37, Pin.OUT))
tft.fill(0)
tft.bitmap(happy, 70, 70)

The picture has to fit on the display from the x, y you give: a driver draws nothing, or too much, when it does not.

If the colors look wrong

The palette is stored as the C drivers read it, with the two bytes of each color swapped. st7789py reads it that way when its needs_swap is on, and shows the bytes the other way around when it is off. If red and blue trade places on your display, that is the swap. The same driver and file behave the same on a real board.

The published gc9a01py computes the two bytes of each pixel in bitmap() with a mistake in one line (color & 0xff00 >> 8 groups as color & 0xff), so its low byte is the palette index rather than part of the color. That shows as slightly wrong shades. Changing those two lines to buffer[i] = color & 0xff and buffer[i + 1] = color >> 8 fixes it.