When CircuitPython starts up, the internal flash filesystem is read only. If you want to save bitmaps or screenshots to it, you must remount it as writable by creating a boot.py file with the following in it:
import storage
storage.remount("/", False)
This code goes in the boot.py file. You must press the reset button on your board after saving the boot.py file, or power cycle the device.
The catch is that it can only be writable by the MCU or USB. The common solution to this is to check an input to see which should be able to write it. Something like:
import board
import digitalio
import storage
switch = digitalio.DigitalInOut(board.D0)
switch.direction = digitalio.Direction.INPUT
switch.pull = digitalio.Pull.UP
# If the D0 is connected to ground with a wire
# CircuitPython can write to the drive
storage.remount("/", switch.value)
SD Card Support
Setting up the SD card for use is shown below. From then on files can be saved to files in the /sd directory.
import board
import busio
import storage
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
try:
import sdcardio
sdcard = sdcardio.SDCard(spi, board.SD_CS)
except ImportError:
import adafruit_sdcard
import digitalio
cs = digitalio.DigitalInOut(board.SD_CS)
sd_card = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
The following code is for the code.py file.
Taking a Screenshot
This can be as simple as importing the library and calling the save_pixels() function with an argument of either a file object or an absolute filename. The example below configures the SD card support and saves a screenshot onto the card.
If a file object is passed, it is written to. If a filename is passed, the named file is opened for writing and written to. In either case, the file is closed once the screenshot has been written.
# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries
# SPDX-License-Identifier: MIT
"""Example of taking a screenshot."""
# pylint:disable=invalid-name
import adafruit_sdcard
import board
import busio
import digitalio
import storage
from adafruit_bitmapsaver import save_pixels
TAKE_SCREENSHOT = False # Set to True to take a screenshot
if TAKE_SCREENSHOT:
# Initialize SD Card & Mount Virtual File System
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.SD_CS)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd") # /sd is root dir of SD Card
print("Taking Screenshot... ")
save_pixels("/sd/screenshot.bmp")
print("Screenshot Saved")
storage.umount(vfs)
print("SD Card Unmounted") # Do not remove SD card until unmounted
Handling rotation
A wrinkle with taking screenshots is that some boards use a rotated buffer and some don't. The library takes this into account. On some boards, e.g. the PyPortal, the screenshot will be oriented as expected (shown at the top of this page).
However, on some otherboards, e.g. the PyGamer, it will be rotated 90 degrees. This can be correctly with any image editing software.
Saving a Bitmap
Saving a bitmap is only slightly more involved than saving a screenshot.
A file or filename is passed and used in the same way.
Since this saves the contents of a Bitmap object and not the contents of the screen, that Bitmap must be passed as well. Furthermore, Bitmaps don't contain the actual 24-bit color that ends up on the screen. Instead, they contain indices into a Palette. The result of this is a dramatic memory savings, but at the cost of an additional step between the bitmap and the screen. The practical result of this is that the associated displayio.Palette object must be passed along with the bitmap.
# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries
# SPDX-License-Identifier: MIT
"""Example of using save_bitmap"""
# pylint:disable=invalid-name
import adafruit_sdcard
import board
import busio
import digitalio
import storage
from displayio import Bitmap, Palette
from adafruit_bitmapsaver import save_pixels
TAKE_SCREENSHOT = False # Set True to take a screenshot
WHITE = 0xFFFFFF
BLACK = 0x000000
RED = 0xFF0000
ORANGE = 0xFFA500
YELLOW = 0xFFFF00
GREEN = 0x00FF00
BLUE = 0x0000FF
PURPLE = 0x800080
PINK = 0xFFC0CB
colors = (BLACK, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, WHITE)
print("Building sample bitmap and palette")
bitmap = Bitmap(16, 16, 9)
palette = Palette(len(colors))
for i, c in enumerate(colors):
palette[i] = c
for x in range(16):
for y in range(16):
if x in {0, 15} or y in {0, 15}:
bitmap[x, y] = 1
elif x == y:
bitmap[x, y] = 4
elif x == 15 - y:
bitmap[x, y] = 5
else:
bitmap[x, y] = 0
if TAKE_SCREENSHOT:
# Initialize SD Card & Mount Virtual File System
print("Setting up SD card")
spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=board.MISO)
cs = digitalio.DigitalInOut(board.SD_CS)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd") # /sd is root dir of SD Card
print("Taking Screenshot... ")
save_pixels("/sd/screenshot.bmp", bitmap, palette)
print("Screenshot Saved")
storage.umount(vfs)
print("SD Card Unmounted") # Do not remove SD card until unmounted
Consider the PyPaint project found in this guide. The ability to save the painting can be added with a few lines, essentially:
from adafruit_bitmapsaver import save_pixels
.
.
.
save_pixels('/sd/pypaint.bmp', self._fg_bitmap, self._fg_palette)
Display Object Saving
Here is an example of using a display object rather than an in memory bitmap and palette:
# SPDX-FileCopyrightText: 2023 DJDevon3
# SPDX-License-Identifier: MIT
"""Screenshot on a 3.5" TFT Featherwing (integrated SD Card)"""
# pylint:disable=invalid-name
import adafruit_sdcard
import board
import digitalio
import displayio
import fourwire
import storage
from adafruit_hx8357 import HX8357
from adafruit_bitmapsaver import save_pixels
displayio.release_displays()
# 3.5" TFT Featherwing is 480x320 pixels
DISPLAY_WIDTH = 480
DISPLAY_HEIGHT = 320
TAKE_SCREENSHOT = False # Set to True to take a screenshot
# Initialize SPI Bus
spi = board.SPI()
# Initialize TFT Featherwing Display
tft_cs = board.D9
tft_dc = board.D10
display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs)
display = HX8357(display_bus, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT)
if TAKE_SCREENSHOT:
# Initialize SD Card & Mount Virtual File System
cs = digitalio.DigitalInOut(board.D5)
sdcard = adafruit_sdcard.SDCard(spi, cs)
vfs = storage.VfsFat(sdcard)
virtual_root = "/sd" # /sd is root dir of SD Card
storage.mount(vfs, virtual_root)
print("Taking Screenshot... ")
save_pixels("/sd/screenshot.bmp", display)
print("Screenshot Saved")
storage.umount(vfs)
print("SD Card Unmounted") # Do not remove SD card until unmounted
Because saving a PyPortal sized bitmap blocks other code from running and takes a noticeable amount of time, it can be useful to display a message to the user while the saving is taking place.
This results in a BMP file as shown below:
Page last edited November 04, 2025
Text editor powered by tinymce.