Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 94 additions & 19 deletions examples/image_gallery.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@
# NAME Photo Frame
# DESC A touch enabled image gallery

"""
'''
An image gallery demo to turn your Pimoroni Presto into a desktop photo frame!

- Create a folder called 'gallery' on the root of your SD card and fill it with JPEGs.
- The image will change automatically every 5 minutes
- You can also tap the right side of the screen to skip next image and left side to go to the previous :)

"""
'''
import os
import time

import jpegdec
import machine
import plasma
import sdcard
import uos
from presto import Presto
Expand Down Expand Up @@ -45,7 +46,7 @@
j = jpegdec.JPEG(display)

# Where our images are located
directory = "gallery"
directory = 'gallery'

# Stores the total number of images in the user gallery
total_image_count = 0
Expand All @@ -71,18 +72,26 @@ def display_error(text):


try:
print('Setting up SD card')
# Setup for SD Card
sd_spi = machine.SPI(0, sck=machine.Pin(34, machine.Pin.OUT), mosi=machine.Pin(35, machine.Pin.OUT), miso=machine.Pin(36, machine.Pin.OUT))
sd = sdcard.SDCard(sd_spi, machine.Pin(39))

print('Mounting SD Card')
# Mount the SD to the directory 'sd'
uos.mount(sd, "/sd")

# if the gallery folder exists on the SD card we want to use the images in there!
if os.stat("sd/gallery"):
directory = "sd/gallery"
# ADD THIS - Give the SD card time to settle
time.sleep(1)

except OSError:
# if the gallery folder exists on the SD card we want to use the images in there!
if os.stat('sd/gallery'):
print('Found SD Gallery')
directory = 'sd/gallery'
else:
print('Did not find SD Card Gallery')
except OSError as error:
print(f'Error setting up SD Card - {repr(error)}')
pass


Expand All @@ -95,12 +104,12 @@ def numberedfiles(k):


try:
files = [file for file in sorted(os.listdir(directory), key=numberedfiles) if file.endswith(".jpg")]
files = list(file for file in sorted(os.listdir(directory), key=numberedfiles) if file.endswith('.jpg') or file.endswith('.jpeg'))
except OSError:
display_error("Problem loading images.\n\nEnsure that your Presto or SD card contains a 'gallery' folder in the root")

total_image_count = len(files) - 1

print(f'Found {total_image_count} files')

def return_point():
global lfsr
Expand All @@ -126,7 +135,7 @@ def fizzlefade():

while True:

for _ in range(2000):
for i in range(2000):
x, y = return_point()
if x > -1 and y > -1:
display.pixel(x, y)
Expand All @@ -137,13 +146,29 @@ def fizzlefade():
if lfsr == 1:
break

def reinit_sd():
"""Reinitialize SD card to recover from SPI errors"""
global sd_spi, sd
try:
# Give the SD card a moment to reset
time.sleep(0.1)
# Reinitialize the SPI and SD card
sd_spi = machine.SPI(0, sck=machine.Pin(34, machine.Pin.OUT), mosi=machine.Pin(35, machine.Pin.OUT), miso=machine.Pin(36, machine.Pin.OUT))
sd = sdcard.SDCard(sd_spi, machine.Pin(39))
time.sleep(0.1)
return True
except:
return False


def show_image(show_next=False, show_previous=False):

print(f'show_image called')

global current_image
global total_image_count

# Get the next image in the gallery
# If we're at the end of the gallery, loop back and start from 1.
if show_next:
if current_image < total_image_count:
current_image += 1
Expand All @@ -155,40 +180,53 @@ def show_image(show_next=False, show_previous=False):
else:
current_image = total_image_count

# Open the index file and read lines until we're at the correct position
print(f'image index {str(current_image)}/{str(total_image_count)}')

try:
img = f"{directory}/{files[current_image]}"

j.open_file(img)

print(f'reading {img} into memory')

# Read the entire JPEG file into memory first
with open(img, 'rb') as f:
jpeg_data = f.read()

print(f'read {len(jpeg_data)} bytes, opening with jpegdec')

# Now open from RAM instead of file
j.open_RAM(jpeg_data)

print(f'opened {img}')

img_height, img_width = j.get_height(), j.get_width()

img_x = 0
img_y = 0

# if the image isn't exactly 240x240 then we'll try to centre the image
if img_width < WIDTH:
img_x = (WIDTH // 2) - (img_width // 2)

if img_height < HEIGHT:
img_y = (HEIGHT // 2) - (img_height // 2)

print(f'img_x: {img_x}')
print(f'img_y: {img_y}')

display.set_layer(0)
display.set_pen(BACKGROUND)
display.clear()
j.decode(img_x, img_y, jpegdec.JPEG_SCALE_FULL, dither=True)

fizzlefade()

# Now draw the current image to Layer 1
display.set_layer(1)
# Decode the JPEG
j.decode(img_x, img_y, jpegdec.JPEG_SCALE_FULL, dither=True)

except OSError:
except OSError as e:
print(f"OSError details: {e}")
display_error("Unable to find/read file.\n\nCheck that the 'gallery' folder in the root of your SD card contains JPEG images!")
except IndexError:
display_error("Unable to read images in the 'gallery' folder.\n\nCheck the files are present and are in JPEG format.")
display_error(f"Unable to read images in the '{directory}' folder.\n\nCheck the files are present and are in JPEG format.")


def clear():
Expand All @@ -198,6 +236,42 @@ def clear():
display.set_layer(1)
display.clear()

# Test SD card access before showing images
print("\n=== SD Card Diagnostic Test ===")
try:
test_files = os.listdir('sd/gallery')
print(f"✓ Can list directory: {len(test_files)} files")

test_file = f'sd/gallery/{test_files[0]}'
print(f"Testing file: {test_file}")

# Try opening with standard Python file operations
with open(test_file, 'rb') as f:
test_data = f.read(1000)
print(f"✓ Can read with open(): {len(test_data)} bytes")

# Now try with jpegdec
print(f"Testing jpegdec.open_file()...")
j.open_file(test_file)
print(f"✓ jpegdec opened successfully!")
print(f" Image size: {j.get_width()}x{j.get_height()}")

except Exception as e:
print(f"✗ Test failed: {type(e).__name__}: {e}")
# The jpegdec test failed and corrupted SPI - reinitialize!
print("Reinitializing SD card after failed jpegdec test...")
reinit_sd()
time.sleep(0.5)

print("=== End Diagnostic ===\n")

# Store the last time the screen was updated
last_updated = time.time()

# Show the first image on the screen so it's not just noise :)
clear()
show_image()
presto.update()

# Store the last time the screen was updated
last_updated = time.time()
Expand Down Expand Up @@ -249,3 +323,4 @@ def clear():
while touch.state:
touch.poll()
time.sleep(0.02)