diff --git a/examples/image_gallery.py b/examples/image_gallery.py index 55985ec..985adaf 100644 --- a/examples/image_gallery.py +++ b/examples/image_gallery.py @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -155,24 +180,38 @@ 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() @@ -180,15 +219,14 @@ def show_image(show_next=False, show_previous=False): 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(): @@ -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() @@ -249,3 +323,4 @@ def clear(): while touch.state: touch.poll() time.sleep(0.02) +