Re: STICKY: TUTORIAL: Build the #1 Image Viewer – Automatically in 3 Minutes!
Posted: Tue May 21, 2019 12:57 pm
NOTE TO OTHER READERS: This person is using a script to export the contents of a FileMaker database to a JPG image. The image file is continuously overwritten at regular intervals and displayed on a large screen to show employees the live status of items at a warehouse. The image display is controlled by my fehshow command. To understand the full context, please start here.
Let me start by saying that no image viewer in the world can fully display an image that does not fully exist!
In the "few times" you saw an incomplete image, feh was almost certainly catching the image "in the act" of being written to the storage device by your script!
For example, if feh happens to reload the image at the exact moment only 70% of the JPG file has been written, then the top 70% of the image would appear normal and the bottom 30% would be gray (indicating "no data").
Feh is doing its job perfectly — it's showing you EXACTLY what the contents of the image file look like at that exact moment!
I of course have no clue what kind of "export script" you're using to generate the JPG file, but it could easily take a good chunk of a full second to complete the write. So if feh is reloading the same image every 10 seconds, for example, you might expect to see some amount of gray about 1% to 10% of the time.
Writing a file can take a surprisingly long time — especially when you consider that writing a file isn't necessarily just "writing" a file. Depending on what the software is doing and how it behaves, it could actually be a matter of "process 10%, write 10%; process the next 10%, write the next 10%".
As an extreme example, it could take 40 days to write a single JPG file if the processing component involved ray tracing a complex 3D model with photorealistic lighting. The "actual time spent writing" might only amount to 1/10 of a second, but the "total time to complete the write" would still be 40 days. If you opened the JPG file after a full 20 days, half the image would still be gray! That's not the fault of the image viewer — that's just the nature of the situation.
Fortunately, I have a solution for all of this.
One method would be to "auto detect" when 100% of the image file has been written — and only then trigger feh to display the completed image. That way, only completed images would ever be displayed. But the code to do that would first have to kill the current instance of feh before re-launching a fresh instance of feh to display the newly-updated image. Not only is "auto-detect / kill / re-launch" somewhat complicated, but it would introduce an annoying screen flicker every single time the entire feh application had to be closed and re-launched from scratch.
A better method is to DRAMATICALLY REDUCE the chance of feh catching an image file "in the act" of being written.
You should still use feh's INTERNAL "--reload" feature to refresh the image every 10 seconds or 5 seconds or whatever you want (as I explained in my previous post). This will not cause any screen flicker because it's NOT reloading feh itself — it's simply reloading the image within feh!
[Side Note: The longer the time between "reloads", the less likely that feh will ever catch the image "in the act" of being written. For example, if you set feh to reload the image every 600 seconds — and you didn't do anything else — that alone would make it VERY RARE to catch an incomplete image. But I realize you probably want a fairly rapid reload rate, such as 5 or 10 seconds, which is why I'm taking a much deeper dive on this subject.]
So we need to conceal the processing component of "writing" an image AND greatly minimize the actual time it takes to write the data itself. In other words, we need to "hide" as much file-writing activity from feh as we possibly can — so that feh rarely ever sees it!
We can accomplish both of these goals by creating 2 high-speed RAM disks — which I will refer to as "RAM folders". I call them folders because they "look and feel" just like regular folders on the Raspberry's internal SD card. But unlike regular folders, these are high-speed folders for temporary data — where all the data is kept inside the much faster RAM memory chip, instead of a slower storage device like the flash-based SD card.
In effect, we can use the 2 RAM folders to create a 2-stage concealment of the writing activity. The 1st folder will hide 100% of the "processing" part of writing the file — and the 2nd folder will hide about 90% of the "writing" part of writing the file!
However, be aware that since these special folders use "volatile" RAM, any reboot or loss of power will cause everything inside them to disappear forever. But that should not be a problem for your particular application. It's pure upside with no downside!
Beyond its faster speed, a RAM folder has the added benefit of reducing wear and tear on your storage device. The cells in flash storage, for example, can eventually break if repeatedly written to over and over again. RAM memory does not have that problem.
I'll explain how to create the RAM folders in just a moment — but here's the overall strategy:
First, modify your export script to write the JPG file to RAM_Folder_1.
Then, in the next line of your export script, make your code "sleep" for about 2 seconds. The idea is to make sure everything related to "processing + writing" the JPG file has fully settled down and finished before anything else is done. If you're using Bash, use "sleep 2" — or whatever time interval you believe to be sufficient to completely finish the JPG export/writing process.
Then, in your next line of code, simply copy the completed JPG file from RAM_Folder_1 to RAM_Folder_2. Assuming it's Bash, use the cp command.
Finally, simply point my fehshow command to RAM_Folder_2 in the "auto start" .desktop file you previously created — as described in my prior post. And then reboot your system.
With this strategy, the only opportunity feh will ever have to catch the JPG file "in the act" of being created is the TINY amount of time it takes to copy a single small file from one RAM folder to another RAM folder! This should make the display of incomplete images go from "a few times" to VERY RARELY!
Now that I've explained the concept, we can create the two RAM folders. I've assigned each of them a maximum capacity of 10 MiB — by setting "size=10m" in Step 3 below. That's plenty of room to handle a single 1080p JPG file. And thanks to the tmpfs facility, each folder will NOT gobble up 10 MiB of RAM. Instead, it will only use what it needs — up to the maximum limit of 10 MiB. So if your JPG file is only 1 MiB, it will only use 1 MiB of RAM!
Note: 10 MiB (mebibytes / binary) is almost 10.5 MB (megabytes / decimal).
STEP 1: CREATE THESE 2 FOLDERS:
STEP 2: OPEN THE FSTAB FILE IN LEAFPAD:
sudo leafpad /etc/fstab
STEP 3: CAREFULLY ADD THESE 2 LINES AND SAVE THE FILE:
tmpfs /home/pi/RAM_Folder_1 tmpfs rw,noatime,size=10m,mode=755,uid=pi,gid=pi
tmpfs /home/pi/RAM_Folder_2 tmpfs rw,noatime,size=10m,mode=755,uid=pi,gid=pi
STEP 4: REBOOT!
From now on, those 2 regular-looking folders will be high-speed RAM folders! Change your "export script" to make use of them as I described — and, of course, point my fehshow command to RAM_Folder_2 in the "auto start" .desktop file.
Let me know how this technique works for you!
PS: You seem to prefer my fehshow command — perhaps because it lets you point to an entire folder without having to worry about the exact file name of the single JPG image inside it. But if you do know the exact file name and it doesn't change, it would be more optimal to use my fehview command instead. In theory, by pointing to a specific file, fehview won't waste time assessing what's in the folder. I have not done a performance comparison, but it's certainly possible that it might shave several milliseconds off the reload. Shrinking the "time window" for the image reload would make it even more rare for it to overlap the "time window" for the file writing. For your single-image scenario, the outward behavior of both commands would be the same — both provide full-screen display, etc. If you do switch to my fehview command, be sure to update the auto-start .desktop file by changing the command to fehview while including the full path to the file — and be sure to add "--reload 10" (or whatever time interval) to the feh command line inside "Image Viewing Settings". My advice on using the high-speed RAM folders still applies, no matter what command you use.