How I added smooth crossfading image transitions to my Raspberry Pi digital picture frame (OS Buster Edition)

Building a great digital picture frame is not just about putting together a minicomputer, a display, and a frame. The crucial part is the software, especially the image viewer.

Important note: This tutorial has been updated to the latest Raspberry Pi operating system, Bookworm. You will find a completely rewritten set of instructions here. I will leave this article online because there is a lot of useful information on this page that helps you understand the possibilities of Pi3D.

The image viewer software controls the type of transitions between your pictures. And the kind of transition makes the difference between a good and a bad digital picture frame.

I have tried many transitions until I finally found the one I wholeheartedly recommend. It is based on software called Pi3D, and in this article, I will describe how you can install PictureFrame to build a wonderful digital picture frame.

Tested with: Raspberry Pi OS Buster Desktop 2021 version, Raspberry 3 and 4, Pi3D 2.49, PictureFrame 2022.12.15, 1080p, and 4K displays.

A world of difference

The standard image viewer on Linux is a package called feh. It is a lightweight image viewer that many tutorials on self-made digital picture frames suggest to use. I do not recommend this approach.

When I built my first digital picture frame, I initially used feh because I could not find something better. But the problem with feh is that it offers no transitions between images. It can only do a hard cut between images.

This may be fine for outdoor advertising, but it is unsuited for any social setting.

The hard cuts between photos cause quite a disturbance, especially with a larger screen. There may be a sudden change in brightness, which is uncomfortable, something that distracts and doesn’t feel right. And it gets boring quickly.

I have tested many types of transition effects for over 12 years now. Crossfading transition effects with the right duration are the key to digital picture frame heaven.

You may say a standard image hard-cut image viewer is good enough. But then you would be missing out on something magical. A lack of transitions means that there is no emotion, nothing that touches you.

Here is an example of a 10 seconds crossfade transition effect (comes with soft piano music):

Click here to display content from YouTube.
Learn more in YouTube’s privacy policy.

I will explain this more in my article “5 essential tips I learned from building digital picture frames“.

This is where PictureFrame comes to the rescue.

Taking the Raspberry Pi’s graphical capabilities up a few notches

Back in 2014, I posted in the English Raspberry Pi forum that I was looking for image transition software.

One guy suggested I look at 2D/3D rendering software that came with many demo applications. There was one demo that got my attention in particular: SlideTransition. It built a slideshow of all files in a directory with four transition options.

Among them was crossfading. The one I was looking for.

The “guy” from the forum was Paddy Gaunt, who, together with Tim Skillman and Tom Ritchford, had written Pi3D, a Python Open GL ES 2.0 library for the Raspberry Pi.

The software dramatically simplifies writing 3D in Python while giving access to the power of the Raspberry Pi GPU. In layman’s terms, this software fully exploits the graphical capabilities of the small Raspberry Pi.

Paddy showed interest in my digital picture frame project and offered to write a Python script that would produce beautiful and customizable image transitions for my exact purpose: PictureFrame.py was born.

Over the years, users worldwide discovered the beauty of “PictureFrame powered by Pi3D”.

In 2021, Helge Erbe, wanting to do something useful during the Corona lockdown, built a PictureFrame integration for Home Assistant, the incredibly versatile home automation system. With this, he could control everything remotely and even see the currently displayed image in Home Assistant.

During his work, he cut through the Gordian knot that PictureFrame had become over the years because we constantly thought of new features that Paddy was kind enough to implement. Now, the software has a clean architecture, making adding features and integrations much easier.

The new, lighter structure, in turn, inspired Paddy to add a database that would subsequently make everything faster, especially if you had many thousand images. I have received emails from users with over 30,000 images on their picture frame, and the start-up took quite a bit of time because of the need for initial Exif data indexing. Paddy also included a lightweight web server, improved on the reverse geo search, and made many small improvements.

At the same time, Jeff Godfrey experimented with intelligent mat features using Pi3D, adding a floating mat to images where the image size ratio differed from the screen’s aspect ratio. The “intelligent” part of the mat function was that the mat’s color uses the image’s dominant color so that it blends in nicely. He didn’t stop there and added other types of mates you can configure to your liking.

The result of the collaboration of Paddy, Helge, and Jeff was a completely new version of PictureFrame. Still based on the graphic engine Pi3D but with many new features. I will break down these features into separate articles and describe the basic image viewer functionality here.

The software is still called “PictureFrame”, but now the development team adds the date behind the name. So the current version is something like “PictureFrame 2023.7.26” which means that it’s the release from July 26, 2023.

Let’s install it first and then go into the details of the script.

Installing PictureFrame on your Raspberry Pi

The following instructions assume that you have prepared your Raspberry Pi along with the instructions in the article “How to set up your Raspberry Pi for your digital picture frame up until chapter 2.8 “Disable Overscan”. The image viewer part will no be different.
If you haven’t done yet, please read that article first.

Make sure you have downloaded the “Raspberry Pi OS with Desktop” Image. “Raspberry Pi OS Lite” does not include some software packages that you will need.

For Raspberry Pi 4 Users

Open the Terminal and connect to your Raspberry Pi via SSH. The following settings refer to the graphics engine and change the raspi-config settings via the command line.

Copy and paste this in the Terminal:

sudo raspi-config nonint do_boot_behaviour B2 && sudo raspi-config nonint do_memory_split 512 && sudo raspi-config

In the raspi-config module, go to 6 Advanced Options > A2 GL Driver > Choose G2 GL Fake KMS.

Exit the configuration settings and enter line-by-line (hit Enter after every line)

sudo python3 -m pip install -U pip
sudo python3 -m pip install pi-heif
sudo pip3 install picframe
mkdir DeletedPictures
sudo reboot
picframe -i .

Don’t forget to include the dot at the end of the command.

You will be asked three questions for the basic configuration settings. Just hit Enter to keep the default for now. You can always change these settings later.

This will configure  /home/pi/picframe_data/config/configuration.yaml
To keep default, just hit enter
Enter picture directory [~/Pictures]: 
Enter picture directory [~/DeletedPictures]: 
Enter locale [en_GB.UTF-8]: 
created /home/pi/picframe_data

You can test the program by entering (make sure you have a monitor connected to your Raspberry Pi):

sudo xinit /usr/bin/python3 /home/pi/picframe_data/run_start.py /home/pi/picframe_data/config/configuration.yaml

With no images yet in ~/Pictures, the “No Pictures Selected” placeholder image is shown. It is a good sign if you can see this!

You can stop the slideshow by hitting “CTRL+C”.

For Raspberry Pi 3 Users

sudo raspi-config nonint do_boot_behaviour B4 && sudo raspi-config nonint do_memory_split 256 && sudo raspi-config 

In the raspi-config module, go to 6 Advanced Options > A2 GL Driver > Choose G1 (Legacy)

You will get a message “The GL driver is disabled”. Click “OK”.

Exit the configuration settings and enter

sudo python3 -m pip install -U pip
sudo python3 -m pip install pi-heif
pip3 install picframe
mkdir DeletedPictures
sudo reboot
picframe -i .

Don’t forget to include the dot at the end of the command.

You will be asked three questions for the basic configuration settings. Just hit Enter to keep the default for now. You can always change these settings later.

This will configure  /home/pi/picframe_data/config/configuration.yaml
To keep default, just hit enter
Enter picture directory [~/Pictures]: 
Enter picture directory [~/DeletedPictures]: 
Enter locale [en_GB.UTF-8]: 
created /home/pi/picframe_data

You can test the program by entering (make sure you have a monitor connected to your Raspberry Pi):

picframe ~/picframe_data/config/configuration.yaml

Don’t worry about any Error messages in the terminal.

With no images yet in ~/Pictures, the “No Pictures Selected” placeholder image is shown. It is a good sign if you can see this!

You can stop the slideshow by hitting “CTRL+C”.

Configuration Settings

Before you proceed, add a few photos to your /Pictures folder.

PictureFrame can be controlled via a configuration file, MQTT commands, and a light web server.

However, you want to need your basic default setting in the configuration file first. You will find it in the “picframe_data” directory and then in the subdirectory “config”. The file is configuration.yaml.

The other file in this directory “configuration_example.yaml” is the default. So should you ever mess up your “configuration.yaml” file, just delete it, make a copy of “configuration_example.yaml” and rename it to “configuration.yaml”.

Open “configuration.yaml” in an editor (e.g., Sublime Text) or with

sudo nano /home/pi/picframe_data/config/configuration.yaml

There are four sections: viewer, model, MQTT, and HTTP. You may be overwhelmed by the number of configuration options, but I will lead you through the most important ones and cover the rest in separate articles.

For a full directory of all Pi3D parameters, look here.

Pictures directory (model)

This line defines the directory where you put your images. Note that it is recursive, so all subdirectories are included. In your case, it will probably be “/home/pi/Pictures”. If you change it, don’t forget to include “/home/pi/”.

  pic_dir: "/home/pi/Pictures" # default="/home/pi/Pictures", root folder for images

PictureFrame works with JPG, JPEG, PNG, HEIC, and HEIF images.

Shuffle mode (model)

This line activates the shuffle mode for your image playlist. Set it to “True”.

  shuffle: True # default=True, shuffle on reloading image files

Delay between images (model)

This line specifies the time between two images in seconds. I have found a value of 200 ideal for a living room setting. Don’t make it too short, as you need to include the time for the transitions.

  time_delay: 200.0 # default=200.0, time between consecutive slide starts

Transition time (model)

This line defines the length of the transitions in seconds. I have found a value of 10 ideal. If you have a 4K display connected, five is ideal.

  fade_time: 10.0 # default=10.0, change time during which slides overlap

Times before reshuffling (model)

When PictureFrame starts, it creates a shuffled playlist of all the images. This ensures that every picture is shown exactly once before the playlist restarts. If you set “default=1”, it will reshuffle the playlist every time it finishes. “default=5” will show the same shuffled list five times. I recommend setting it to “1”.

  reshuffle_num: 1 # default=1, times through before reshuffling

Fit to screen (viewer)

Often, the aspect ratio of an image does not correspond to the aspect ratio of the screen. “default=True” means that the entire image is shown, which can lead to black bars left/right or top/bottom (pillar or letterboxing). “default=False” means that the image is stretched until it fills the entire screen. I only upload landscape-formatted images on my frame, so I choose “False.”

  fit: False # default=False, True => scale image so all visible and leave 'gaps'. False => crop image so no 'gaps'

Show file names (viewer)

You can show the metadata with your image. If you don’t want that, set it to = “”.

  show_text: "title caption name date folder location"  # default="title caption name date folder location", show text, include combination of words: title, caption name, date, location, folder

Use matting (viewer)

PictureFrame now offers the option to create a color-adjusted matte around images that do not fit your screen’s aspect ratio. There are many parameters to set here, which will be the subject of a separate article.

For the time being, you have to decide if you want matting or not. If you don’t want it, just set it to “False”.

  mat_images: True # default=0.01, True, automatically mat all images. False, don't automatically mat any images. Real value, auto-mat all images with aspect ratio difference > than value

Show the latest images first after adding new ones (model)

Whenever you add new images to your pictures folder, PictureFrame will reshuffle the playlist. “recent_n” will play the newest ones first (based on the Exif date), which is nice. You can set this number to “default=10” if you want to show the ten newest images or “0” if you want to turn this functionality off.

  recent_n: 7  # default=7 (days), when shuffling file change date more recent than this number of days play before the rest

Activate and configure MQTT (mqtt)

This is a very important setting if you later want to remote control your picture frame either through voice with Alexa, Home Assistant, iPhone, or Internet of Things devices. Set it to “default=True” if you want to use it.

And if you do, don’t forget to add your MQTT broker server address. If you are using a locally installed broker, add the IP address or the Bonjour counterpart (“pictureframe.local”). If you don’t have a username and password, just leave the value empty.

For information on installing a local Mosquitto MQTT broker, see here.

These are my default settings:

mqtt:
  use_mqtt: True             # default=False. Set True true, to enable mqtt
  server: 192.268.178.136    # No defaults for server
  port: 1883                  # default=8883 for tls, 1883 else
  login: ""               # your mqtt user
  password: ""   # password for mqtt user
  tls: "" # filename including path to your ca.crt.
  device_id: 'picframe'       # default='picframe' unique id of device. change if there is more than one picture frame

Automatically start the Pi3D slideshow at boot

We will use the systemd services to manage the PictureFrame at boot. Again, there is a slight variation for the Raspberry models.

If your user name is not “pi”, you must change “pi” in the instructions below to your user name.

For the Raspberry Pi 4

Create a new service file

sudo nano /etc/systemd/system/picframe.service

and paste the following text into the file:

[Unit]
Description=PictureFrame on Pi4
After=multi-user.target

[Service]
Type=idle

User=root
ExecStart=xinit /usr/bin/python3 /home/pi/picframe_data/run_start.py /home/pi/picframe_data/config/configuration.yaml

#Restart=always

[Install]
WantedBy=multi-user.target

Save with CTRL+O and close with CTRL+X.

Now, we need to change the file permissions to make it readable by all by typing

sudo chmod 644 /etc/systemd/system/picframe.service

As the last step, you need to tell the system that you have added this file and want to enable this service so that it starts at boot.

sudo systemctl daemon-reload
sudo systemctl enable picframe.service

Reboot your Pi, and you are all set!

For the Raspberry Pi 3

Create a new service file

mkdir ~/.config/systemd/user/ -p && nano ~/.config/systemd/user/picframe.service

and paste the following text into the file

[Unit]
Description=PictureFrame on Pi3

[Service]
ExecStart=/home/pi/.local/bin/picframe ~/picframe_data/config/configuration.yaml
#Restart=always

[Install]
WantedBy=default.target

Save with CTRL+O and close with CTRL+X.

Now, we need to change the file permissions to make it readable by all by typing

sudo chmod 644 ~/.config/systemd/user/picframe.service

As the last step, you need to tell the system that you have added this file and want to enable this service so that it starts at boot.

systemctl --user daemon-reload
systemctl --user enable picframe.service

Reboot your Pi, and you are all set!

Useful systemd commands

If you are not yet familiar with systemd, you can find a full introduction here.

But, to quickly recap, if you are making changes to the service files, you may find these commands useful to stop, start, or restart PictureFrame:

For the Raspberry Pi 4

sudo systemctl stop picframe.service
sudo systemctl start picframe.service
sudo systemctl restart picframe.service

For the Raspberry Pi 3

systemctl --user stop picframe.service
systemctl --user start picframe.service
systemctl --user restart picframe.service

Conclusion

If everything works as expected, you can now upload your full photo collection to your photo folder. Congratulations!

Thanks again to Paddy and his colleagues for their original work on Pi3D and Helge and Jeff for their outstanding contribution and for taking the PictureFrame to a new level. There is no other program that makes such beautiful transitions on the Raspberry Pi.

You can read more about PictureFrame here.

Was this article helpful?


Thank you for your support and motivation.


Scroll to Top