5.5 KiB
CRT Photobooth
A fullscreen photobooth for a Linux laptop mirrored to a 4:3 CRT. Guests press the button (any mouse button) to take a 3-photo shoot with countdowns and flashes. After 4 shoots, all 12 photos are printed on one contact sheet. When idle for 5 minutes, a fish-tank screensaver protects the CRT from burn-in.
Setup on a new laptop
-
Install Python 3.11 or newer (check with
python3 --version). -
Install the dependencies:
pip install pygame-ce opencv-python pillowNote: it's
pygame-ce, notpygame— the community edition has wheels for newer Python versions. If pip refuses because the system Python is "externally managed", either usepip install --user ...or create a virtual environment:python3 -m venv ~/photobooth-venv ~/photobooth-venv/bin/pip install pygame-ce opencv-python pillow # then run with: ~/photobooth-venv/bin/python photobooth.py -
Plug in the Macally webcam and confirm Linux sees it:
ls /dev/v4l/by-id/You should see something like
usb-SolidYear_Macally_USB2.0Camera-video-index0. The default config finds it automatically by name. -
Set up the printer. The booth prints via CUPS with the
lpcommand. Check what's configured and set a default:lpstat -p # list printers lpoptions -d NAME # set the default printer lpstat -p -d # verify: should show a default destinationPrint a test page from the printer settings GUI to make sure it works before an event.
-
Copy this whole folder to the laptop and run it:
python3 photobooth.pyAdd
--windowedto test in a window instead of fullscreen. Press Esc or Q to quit.
Running headless (lid closed)
While it is running, the booth holds systemd keep-awake locks
(systemd-inhibit, block mode: sleep, idle, and handle-lid-switch
when no desktop environment already holds it). The laptop will not suspend
or idle-sleep, and — on machines where logind manages the lid — closing
the lid does nothing, so the laptop can run tucked away behind the CRT.
The locks are released as soon as the program exits.
If the machine still suspends when the lid closes (some desktop
environments keep the lid lock for themselves), disable lid suspend on
that machine: put HandleLidSwitch=ignore in
/etc/systemd/logind.conf.d/photobooth.conf (needs root, applies even
when the booth is not running) or use the desktop's own power settings.
Customizing
- All settings live in
config.toml— camera choice, screen text, countdown lengths, screensaver timeout, printer options. Comments in the file explain each one. - Idle screen background: replace
assets/background.png(any size, it gets scaled to the screen — 4:3 looks best, e.g. 800×600). - Fish: drop your fish drawings into the
fish/folder as PNGs with transparent backgrounds. Draw them facing right — the program flips them automatically when they swim left. Bubbles come out of the front (mouth) end. Deleteplaceholder_fish.pngonce you have real fish.
Switching cameras
In config.toml, device = "auto-macally" finds the Macally cam by name.
To use a different camera:
device = "auto-integrated"— match another camera by (partial) name fromls /dev/v4l/by-id/, case-insensitivedevice = "/dev/video2"— an exact device pathdevice = "0"— a plain index
Where things go
photos/— individual shots for the current print cycle. Deleted automatically after a successful print. (If the program is restarted mid-cycle, photos here are counted so no progress is lost.)contact_sheets/— every printed sheet, kept as a backup in case of printer trouble. Sheets are full US-letter pages at 300 DPI, so they also print at the right size from any other app. Delete them manually now and then, or setdelete_contact_sheets = truein the config to remove each one right after it prints.
If printing fails
The booth doesn't lose anything: the contact sheet is saved in
contact_sheets/, an error shows on the idle screen, and you can print the
sheet by hand with:
lp -o media=letter -o fit-to-page contact_sheets/sheet_XXXX.jpg
Common causes: printer off or unplugged (lpstat -p says "disabled" —
re-enable with cupsenable PRINTER_NAME), or no default printer set.
Troubleshooting the camera
Test the camera on its own (uses the device from config.toml):
python3 camera.py
It first prints a pre-flight dump of every camera the system sees
(/dev/v4l/by-id/ names, device nodes, and what each node identifies as),
then reports which device was matched, resolved, and opened, plus the OpenCV
version. If the booth ever uses the wrong camera, run this and read the
output — it shows exactly where the selection went sideways.
If it reports black frames (or the live preview shows a warning): the Macally cam's chipset sometimes wedges and streams pure black until it is power-cycled. Unplug the camera, plug it back in, and restart the program. Worth doing a quick test shoot at the start of an event.
Heads-up
- The Brother HL-5470DW is a monochrome laser — contact sheets print in black & white.
- The live preview is mirrored (like a mirror) so posing feels natural, but
saved photos are not mirrored. Set
mirror_preview = falseto change that. - CRT overscan may crop the very edges of the screen; once the CRT is connected, adjust text positions/sizes in code or the CRT's own controls.