slide
Simple, lightweight slideshow selecting random images from specified directory. This slideshow is designed to compile and run also on a Raspberry Pi, for example to turn it into a digital picture frame.
Tested versions:
- Raspberry Pi 3 running Raspbian Stretch.
- Raspberry Pi 3 running Raspbian Buster.
- Raspberry Pi Zero running Raspbian Buster.
- Raspberry Pi 4B running Raspbian Buster.
Screen background is filled with a scaled version of the image to prevent pure black background.
This project is maintained by myself during my spare time. If you like and use it, consider buying me a coffee.
Usage
slide [-t rotation_seconds] [-T transition_seconds] [-h/--overlay-color overlay_color(#rrggbb)] [-a aspect] [-o background_opacity(0..255)] [-b blur_radius] [-p image_folder|-i imageFile,...] [-r] [-O overlay_string] [-v] [--verbose] [--stretch] [-c path_to_config_json]
image_folder: where to search for images (.jpg files)-i imageFile,...: comma delimited list of full paths to image files to display-c path_to_config_json: path to a JSON config file, or a directory containingslide.options.json-thow many seconds to display each picture for-rfor recursive traversal ofimage_folder-sfor shuffle instead of random image rotation-Sfor sorted rotation (files ordered by name, first images then subfolders)rotation_seconds(default=30): time until next random image is chosen from the given folderaspect(default=a): the required aspect ratio of the picture to display. Valid values are 'a' (all), 'l' (landscape), 'p' (portrait) and 'm' (monitor). Monitor will match the aspect ratio of the display we are running on.transition_seconds(default=1): time of image transition animation. Default is 1 second, and transition animation will be disabled if the value is set to 0aspect(default=a): the required aspect ratio of the picture to display. Valid values are 'a' (all), 'l' (landscape) and 'p' (portrait)background_opacity(default=150): opacity of the background filling image between 0 (black background) and 255blur_radius(default=20): blur radius of the background filling image-vor--verbose: Verbose debug output when running--stretch: When in aspect mode 'l','p' or 'm' crop the image rather than leaving a blurred background. For example, in landscape mode this will make images as wide as the screen and crop the top and bottom to fit.-hor--overlay-colorthe color of the overlay text, in the form of 3 or 6 digits hex rgb string prefixed by#, for example#00FF00or#0F0for color 🟢-Ois used to create a overlay string.- It defines overlays for all four edges in the order
top-left;top-right;bottom-left;bottom-right - All edges overlays are separated by
; - Each edge can either be just a test or contain formatting in the form
margin|fontsize|text - the text can contain special strings which are replaced during rendering:
<time>current time<date>current date<datetime>current time and date<exifdatetime>time stamp from the EXIF data of the image<filename>filename of the current image<basename>basename of the current image (without suffix)<filepath>filename including the path of the current image<dir>directory of the current image<path>path to the current image without filename
- Example:
slide -p ./images -O "20|60|Time: <time>;;;Picture taken at <exifdatetime>"To exit the application, press escape. If you're using a touch display, touch all 4 corners at the same time.
- It defines overlays for all four edges in the order
Configuration file
Slide supports loading configuration from a JSON formatted file called slide.options.json. This file can be specified by the -c command line option (file path or directory), and we will also attempt to read ~/.config/slide/slide.options.json and /etc/slide/slide.options.json in that order. The first file to load is used and its options will override command line parameters.
The file format is:
{
"path" : "/path/to/pictures",
"aspect" : "m",
"overlay" : "20|20|<filename>",
"shuffle" : true,
"recursive" : true,
"sorted" : false,
"stretch": false,
"rotationSeconds" : 300,
"opacity" : 200,
"debug" : false,
"debugThumbnail" : false,
"scheduler" : [
{
"exclusive" : true,
"path" : "/path/to/pictures/reddit_sync"
"stretch" : true,
"times": [
{
"start": "14:00",
"end": "16:00"
}
]
},
{
"exclusive" : true,
"stretch" : false,
"times": [
{
"start": "08:00",
"end": "10:00"
},
{
"start": "16:00",
"end": "19:00"
}
],
"path" : "/path/to/pictures/show_peak_times/"
},
{
"path" : "/path/to/pictures/always_show_1"
},
{
"path" : "/path/to/pictures/always_show_2"
}
}
Supported keys and values in the JSON configuration are:
path: where to search for images (.jpg files). This path is ignored if theschedulerfeature is used.aspect: the same as the command line argumentoverlay: the same as the overlay command line argumentshuffle: set to true to enable shuffle mode for file displayrecursive: set to true to enable recursive mode for file displaysorted: set to true to enable sorted mode for file displaystretch: set to true to enable, the same as the--stretchcommand line argumentrotationSeconds: the same as the-tcommand line argumentopacity: the same as the command line-oargumentblur: the same as the command line-bargumentdebug: set to true to enable verbose output from the programdebugThumbnail: set to true to draw a small thumbnail of the source image in the bottom leftmqtt: MQTT playback control (see below)immich: connect to an Immich server instead of a local path (see below)scheduler: this entry is an array of possible path values and associated settings. This key lets you manage display times/settings for a collection of paths. In the example above the top entry shows ONLY files from a Redit feed between 2 and 4pm, ONLY files from theshow_peak_timesfolder from 8am to 10am and then 4pm to 7pm. At all other times it alternates displaying files in thealways_show_1andalways_show_2folder.exclusive: When set totrueonly this entry will be used when it is in its valid time window.times: times is a JSON array of start and end times in which it is valid to display this image. The time is in the format HH:MM:SS and is based on the systems local time. Ifstartisn't defined then it defaults to the start of the day, ifendisn't defined it defaults to the end of the day.path: the path to image filesstretch: as above
MQTT control
Add an mqtt block to control playback remotely. Publish one of the commands below to the configured topic.
Example:
{
"mqtt": {
"host": "mqtt.local",
"port": 1883,
"topic": "slide/control",
"immichTopic": "slide/immich",
"clientId": "slide-frame",
"username": "slide",
"password": "secret",
"keepAlive": 30,
"qos": 0
}
}
Commands:
play/resume— resume slideshowpause— pause slideshownext/next-image— advance to next imagenext-folder— jump to next configured path (if multiple paths are configured)restart/reset— recreate the selector and restart playback IfimmichTopicis not set, it defaults to<topic>/immich.
Immich control topic (immichTopic):
album:<id>oralbumIds:id1,id2— filter to one or more album IDsperson:<id>orpersonIds:id1,id2— filter to one or more person IDsuser:<id>/userId:<id>/ownerId:<id>— show all assets owned by a user (clears album/person filters)extensions:jpg,jpeg,png— filter by file extension (useful for RAW exclusion)reset/clear— clear album/person/user filters- JSON payloads are also accepted, for example:
{"albumIds":["..."],"personIds":["..."],"order":"desc","size":"fullsize","userId":"...","extensions":["jpg","jpeg"]}
Immich configuration (lightweight + low power)
Immich uses an API key and a /api base path. This integration requests the asset search endpoint and downloads the configured image size into a local cache before displaying them. That keeps bandwidth and power usage low while still letting slide do its normal scaling and transitions. If you have RAW/HEIC images, set size to preview/thumbnail or use extensions to limit results to JPEG/PNG; slide will also fall back to preview if a fullsize download isn't readable. Immich metadata (EXIF original time / created time) is stored alongside cached assets so <exifdatetime> continues to work even if the cached image doesn't contain EXIF data.
Getting an Immich API key
In the Immich web UI, go to Settings and find API Keys (menu labels can vary by version), then create a new key and copy it.
Required API key permissions
slide uses Immich search plus the asset view/download endpoints, so the API key should include:
asset.read— required by Immich search endpoints (used to retrieve asset metadata).asset.view— required for the viewAsset endpoint (thumbnail/preview/fullsize).asset.download— required if you setsizetooriginal(download endpoint).
Finding an Immich user ID
You can use a user ID to show all assets owned by that user.
Common ways to find it:
- Admin UI: In Immich, open the Admin/Users page, click the user, and copy the UUID shown in the user details or URL.
- API (non-admin): Call the
users/meendpoint with the API key and read theidfield:
curl -H "x-api-key: IMMICH_API_KEY" http://immich.local:2283/api/users/me
Example (single source):
{
"immich": {
"url": "http://immich.local:2283",
"apiKey": "IMMICH_API_KEY",
"albumId": "b7f3c8b2-2e3f-4b32-9dc9-8c3f8b0a3ef7",
"size": "fullsize",
"order": "desc",
"pageSize": 200,
"maxAssets": 1000,
"refreshSeconds": 300,
"skipRetrySeconds": 3600,
"skipTags": ["frame-ignore"],
"cachePath": "~/.cache/slide/immich",
"cacheMaxMB": 512,
"includeArchived": false
}
}
Example (scheduler entry):
{
"scheduler": [
{
"exclusive": true,
"immich": {
"url": "http://immich.local:2283",
"apiKey": "IMMICH_API_KEY",
"albumIds": ["b7f3c8b2-2e3f-4b32-9dc9-8c3f8b0a3ef7"],
"size": "fullsize"
}
}
]
}
Immich settings:
url: base Immich server URL (the integration appends/apiautomatically if missing).apiKey: Immich API key (needsasset.view, andasset.downloadifsizeisoriginal).userId: optional user id to retrieve all assets owned by that user via the assets endpoint (see “Finding an Immich user ID” above).albumIdoralbumIds: optional album filters.personIdorpersonIds: optional person filters.extensions/allowedExtensions: optional list of file extensions to include (for example["jpg","jpeg","png"]).skipTags: optional list of tag names to exclude (case-insensitive).skipTagIds: optional list of tag IDs to exclude (case-insensitive).size:"fullsize","preview","thumbnail", or"original"(original uses the download endpoint).order:"asc"or"desc"ordering for asset search.
Note: tag filtering requires Immich to include tag data in search results. If your server doesn’t return tags on /search/metadata, skipTags/skipTagIds won’t apply.
pageSize: assets fetched per page.maxAssets: cap on total assets fetched (0 means no cap).refreshSeconds: refresh interval for reloading Immich assets (0 disables).skipRetrySeconds: retry interval for assets marked unsupported (0 disables retry).cachePath: local cache directory for downloaded images.cacheMaxMB: maximum cache size in MB (0 disables cleanup).includeArchived: include archived assets in search results. If you omitalbumId/albumIds/personIds, Immich returns all assets visible to the API key’s user. IfuserIdis set, album/person filters are ignored and all assets for that user are fetched. Whenimmichis set on an entry,pathandimageListare ignored.
Folder Options file
When using the default or recursive folder mode we support having per folder display options. The options are stored in a file called "options.json" in the images folder and support a subset of the applications configuration settings:
{
"stretch": false,
"aspect" : "m",
"opacity" : 200,
"blur" : 20,
"times": [
{
"start": "08:00",
"end": "10:00"
},
{
"start": "17:00",
"end": "19:00"
}
]
}
See the Configuration File section for details of each setting.
Dependencies
- qt5-qmake
- qt5
- qt5-image-formats-plugins
- libexif
- libmosquitto-dev
Home Assistant
See doc/homeassistant.md for a ready-to-use MQTT dashboard and scripts.
Ubuntu/Raspbian:
sudo make install-deps-deb
Build
Install dependencies
make install-deps-deb
Build project
make
Install binaries
sudo make install
macOS
Prerequisite: brew
brew install qt5
brew install libexif
brew install libexif
make
Article on using slides
This article has more helpful ways that you could use this repo as a picture frame
https://opensource.com/article/19/2/wifi-picture-frame-raspberry-pi
Removing black border (Raspberry Pi)
if you find that you have a black border around your screen you can remove it by disabling overscan. This is done by editing /boot/config.txt and uncommenting disable_overscan=1
