Un diaporama pour l'ethos
  • Rust 98.3%
  • Shell 1.7%
Find a file
2026-10-07 16:59:25 +02:00
packaging Lightweight fullscreen slideshow with smooth transitions 2026-10-07 11:59:52 +02:00
src fix flitter attempt 2026-10-07 16:59:25 +02:00
.gitignore Lightweight fullscreen slideshow with smooth transitions 2026-10-07 11:59:52 +02:00
Cargo.lock Lightweight fullscreen slideshow with smooth transitions 2026-10-07 11:59:52 +02:00
Cargo.toml Lightweight fullscreen slideshow with smooth transitions 2026-10-07 11:59:52 +02:00
GUIDE.md Add step-by-step guide for Arch testing and Raspberry Pi deployment 2026-10-07 14:04:28 +02:00
LICENSE Lightweight fullscreen slideshow with smooth transitions 2026-10-07 11:59:52 +02:00
README.md fix flitter attempt 2026-10-07 16:59:25 +02:00

myslideshow

A small, fullscreen image slideshow for a Raspberry Pi driving a TV, for example in a waiting room. Point it at a directory of pictures and leave it running. Written in Rust on SDL2. Target: Debian / Raspberry Pi OS Bookworm.

Features

  • Smooth transitions: fade, fade through black, slide, zoom, or none.
  • Slow pan and zoom on every image (on by default; --pan 0 --zoom 0 turns it off). Images never expose their edges while moving.
  • With pan/zoom off, CPU use while an image is on screen is near zero. With it on, the screen is redrawn every frame; use --fps 30 on slower boards. Images are decoded and downscaled in a background thread, with one image prefetched, so transitions stay smooth.
  • Works with X11, Wayland, or straight on the display via KMSDRM (Pi OS Lite, no desktop needed). SDL picks the backend automatically.
  • The directory is rescanned at the end of each cycle, so you can add or remove pictures while it runs (Samba share, scp, USB copy...). If the directory is empty, it is rescanned every 5 seconds.
  • Unreadable or corrupt files are skipped. EXIF orientation is honoured. Hidden files are ignored.
  • Formats: jpg, jpeg, png, webp, bmp, gif (first frame only), tif, tiff.

Usage

myslideshow [OPTIONS] <DIR>
Option Default Description
<DIR> (required) Directory containing the images
-d, --duration <DURATION> 10 Seconds each image stays on screen (excluding the transition)
-t, --transition <TRANSITION> fade Transition effect: fade, fade-black, slide, zoom, none, random
-T, --transition-time <TRANSITION_TIME> 1.5 Transition length in seconds
-f, --fit <FIT> contain How images fit the screen: contain (whole image, black bars if needed) or cover (fill the screen, crop the edges)
-p, --pan <PERCENT> 8 Slow pan: the image is enlarged by this much and drifts across the extra area, from a random start towards the farthest corner (the longest straight path), at a speed matched to the display time. 0 disables
-z, --zoom <PERCENT> 6 Slow zoom: further scaling over the display time, in or out at random, combined with the pan. 0 disables
--fps <FPS> 60 Frame-rate cap while animating; lower it (e.g. 30) to save CPU on slow boards. Rounded to the refresh rate divided by a whole number (60 Hz: 60, 30, 20...) so motion stays even
-s, --shuffle off Random order, reshuffled every cycle
-r, --recursive off Include images from subdirectories
--windowed off Run in a window instead of fullscreen (for testing)
-h, --help / -V, --version Help / version

Transitions: fade is a smooth crossfade, fade-black fades out to black then in, slide pushes the new image in from the right, zoom is a crossfade with a gentle zoom, none is an instant cut, and random picks one of the effects each time.

Example:

myslideshow --shuffle --duration 15 --transition random ~/Pictures

Keyboard

Key Action
Right / Space / PageDown Next image
Left / PageUp Previous image
P Pause / resume
Esc / Q Quit

Building

On the Pi

sudo apt install build-essential libsdl2-dev curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release        # binary: target/release/myslideshow

Cross-compiling from x86

Use cross (needs Docker or Podman). The default cross image has no SDL2 for the target, so add a Cross.toml:

[target.aarch64-unknown-linux-gnu]
pre-build = [
    "dpkg --add-architecture $CROSS_DEB_ARCH",
    "apt-get update && apt-get install --assume-yes libsdl2-dev:$CROSS_DEB_ARCH",
]
cargo install cross
cross build --release --target aarch64-unknown-linux-gnu

For a 32-bit Raspberry Pi OS use armv7-unknown-linux-gnueabihf instead (and the same pre-build block under that target). Check which one you have with uname -m on the Pi: aarch64 means 64-bit, armv7l means 32-bit.

Installing the .deb

Build the package with cargo-deb:

cargo install cargo-deb
cargo deb                                         # native build
cargo deb --target aarch64-unknown-linux-gnu      # after a cross build (use --no-build to reuse it)

Copy target/debian/myslideshow_*.deb (or target/<target>/debian/) to the Pi and install it:

sudo apt install ./myslideshow_0.1.0-1_arm64.deb

The package installs:

  • /usr/bin/myslideshow
  • /lib/systemd/system/myslideshow.service (not enabled automatically)
  • /etc/default/myslideshow (config file, kept across upgrades)
  • this README in /usr/share/doc/myslideshow/

It also creates a slideshow system user (member of video, render, input) and the directory /srv/slideshow (group-writable, owned by slideshow).

Running as a kiosk

(a) Pi OS Lite, no desktop (systemd + KMSDRM)

  1. Install the .deb (above). Put images in /srv/slideshow, for instance over scp, or a Samba share pointing at that directory.

  2. Edit /etc/default/myslideshow to set SLIDESHOW_DIR and SLIDESHOW_ARGS (for example SLIDESHOW_ARGS="--shuffle --duration 15").

  3. Enable and start:

    sudo systemctl enable --now myslideshow
    journalctl -u myslideshow -f       # logs
    sudo systemctl restart myslideshow # after changing the config
    

The unit runs /usr/bin/myslideshow $SLIDESHOW_ARGS ${SLIDESHOW_DIR} as the slideshow user with SDL_VIDEODRIVER=kmsdrm, restarts it on failure, and adds the video, render and input groups. Do not run it on a system where a desktop already owns the screen; use (b) there.

Without the .deb: copy packaging/myslideshow.service to /etc/systemd/system/, packaging/default to /etc/default/myslideshow, create the user with sudo adduser --system --group --home /srv/slideshow slideshow (or change User= in the unit to an existing user such as pi), then run sudo systemctl daemon-reload and enable it as above.

(b) Pi OS with desktop (autostart)

On Bookworm the default compositor is labwc (Wayland). Add to ~/.config/labwc/autostart:

/usr/bin/myslideshow --shuffle /home/pi/Pictures &

On X11 sessions (or if you switched to X11 with raspi-config), create ~/.config/autostart/myslideshow.desktop:

[Desktop Entry]
Type=Application
Name=myslideshow
Exec=/usr/bin/myslideshow --shuffle /home/pi/Pictures

For a real kiosk also enable desktop auto-login (raspi-config > System Options > Boot / Auto Login > Desktop Autologin), and do not enable the systemd service from (a) on the same machine.

Tips (optional)

Keep the screen from blanking. On the desktop: sudo raspi-config > Display Options > Screen Blanking > No. On Lite, add consoleblank=0 to the single line in /boot/firmware/cmdline.txt and reboot. The slideshow itself also asks SDL not to start a screensaver.

Turn the TV off at night. Pick whichever your setup supports, and run it from cron (crontab -e), for example off at 19:00 and on at 07:30, Mon-Fri:

0  19 * * 1-5  vcgencmd display_power 0
30  7 * * 1-5  vcgencmd display_power 1
  • vcgencmd display_power 0|1 works on Lite with KMSDRM on some Pi models and setups; it may have no effect with the KMS driver, in which case use CEC.
  • Under labwc on the desktop use wlr-randr --output HDMI-A-1 --off / --on (list outputs with wlr-randr; cron needs WAYLAND_DISPLAY and XDG_RUNTIME_DIR set).
  • HDMI-CEC (TV is switched off or on properly, and works on Lite): install cec-utils and run echo 'standby 0' | cec-client -s -d 1 to turn the TV off, and echo 'on 0' | cec-client -s -d 1 to turn it on. The TV must have CEC enabled.

Troubleshooting

  • Black screen, or "Could not initialize EGL" / "kmsdrm not available" under systemd. Check the service user is in video, render and input (id slideshow; the unit adds them, a hand-run user needs them too). Check journalctl -u myslideshow for the real error. Try forcing a driver with SDL_VIDEODRIVER=kmsdrm, or x11 / wayland on a desktop. Make sure no other program (a desktop, another instance) holds the display.
  • Keyboard does not work under KMSDRM. Keys are read from /dev/input, so the user must be in the input group. Log out and in again (or restart the service) after changing groups.
  • Out of memory or very slow start with huge photos. Large images (for example 48 MP phone photos) are fully decoded in RAM before being scaled down, which can use hundreds of MB. On 1 GB Pis, resize such photos beforehand (e.g. to 1920x1080 or 3840x2160) or avoid the biggest ones.
  • A picture does not show up. It may be unreadable, hidden (name starts with .), in a subdirectory (use --recursive), or an unsupported format. New files are picked up at the end of the current cycle. Skipped files are logged to stderr.
  • Testing on a PC. Use --windowed.

License

MIT, see LICENSE.