Files
nissaphotobooth/README.md
2026-07-22 15:57:26 -04:00

251 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
1. **Install Python 3.11 or newer** (check with `python3 --version`).
2. **Install the dependencies:**
```bash
pip install pygame-ce opencv-python pillow
```
Note: it's `pygame-ce`, not `pygame` — the community edition has wheels
for newer Python versions. If pip refuses because the system Python is
"externally managed", either use `pip install --user ...` or create a
virtual environment:
```bash
python3 -m venv ~/photobooth-venv
~/photobooth-venv/bin/pip install pygame-ce opencv-python pillow
# then run with: ~/photobooth-venv/bin/python photobooth.py
```
3. **Plug in the Macally webcam** and confirm Linux sees it:
```bash
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.
4. **Set up the printer.** The booth prints via CUPS with the `lp` command.
Check what's configured and set a default:
```bash
lpstat -p # list printers
lpoptions -d NAME # set the default printer
lpstat -p -d # verify: should show a default destination
```
Print a test page from the printer settings GUI to make sure it works
before an event.
5. **Copy this whole folder** to the laptop and run it:
```bash
python3 photobooth.py
```
Add `--windowed` to 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.
## Running on a Raspberry Pi (no desktop)
The booth needs no desktop environment. On a console-only machine (no X
or Wayland session) it automatically tells SDL to draw straight to the
screen via the KMS/DRM driver, so it runs fine on Raspberry Pi OS Lite.
1. **Install Raspberry Pi OS Lite (64-bit)** and boot with the screen,
camera, and mouse plugged in.
2. **Install the system packages:**
```bash
sudo apt install python3-venv cups fonts-dejavu-core
```
(`fonts-dejavu-core` is for the contact-sheet footer text — Lite
doesn't ship it and the fallback font is tiny.)
3. **Create a virtual environment and install the dependencies:**
```bash
python3 -m venv ~/photobooth-venv
~/photobooth-venv/bin/pip install pygame-ce opencv-python-headless pillow
```
Note the **headless** OpenCV build: the regular `opencv-python` wheel
needs X libraries that Lite doesn't have, and the booth uses no GUI
features. If the pygame-ce wheel's SDL lacks the KMS/DRM driver
(`pygame.error: kmsdrm not available`), use the distro build instead
(`sudo apt install python3-pygame`) — the booth uses nothing
pygame-ce-specific.
4. **Give your user access to the screen and input devices:**
```bash
sudo usermod -aG video,render,input $USER # then log out and back in
```
5. **Check which screen modes are available.** The Pi can only use modes
the display (or HDMI adapter) advertises:
```bash
cat /sys/class/drm/card*-HDMI-A-*/modes
```
If 800x600 isn't listed, set `[display]` width/height in `config.toml`
to one of the listed modes. For a 4:3 CRT behind an HDMI-to-coax
adapter, 720x480 fills the screen correctly (same trick as DVDs).
Everything scales to `[display]` automatically — no code changes
needed.
6. **Set up the printer** with CUPS from the command line:
```bash
lpinfo -v # find the printer's URI (USB printers: usb://...)
lpinfo -m # list available drivers
sudo lpadmin -p PRINTER -E -v <uri> -m <driver>
lpoptions -d PRINTER
lpstat -p -d # verify
```
Then set `printer = "PRINTER"` in `config.toml` to match.
7. **Run it** from the console:
```bash
~/photobooth-venv/bin/python photobooth.py
```
### Starting automatically at boot
Create `/etc/systemd/system/photobooth.service` (adjust the user and
paths to match your setup):
```ini
[Unit]
Description=CRT Photobooth
[Service]
User=pi
SupplementaryGroups=video render input
WorkingDirectory=/home/pi/nissaphotobooth
ExecStart=/home/pi/photobooth-venv/bin/python photobooth.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
Then:
```bash
sudo systemctl enable --now photobooth
```
Quit with Esc/Q on a keyboard, or `sudo systemctl stop photobooth` over
SSH. The keep-awake locks work the same as on a laptop (a Pi rarely
sleeps anyway). The `auto-macally` camera lookup already waits ~15
seconds for USB devices to enumerate, so no boot-order tweaks are needed.
## 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. Delete `placeholder_fish.png` once 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
from `ls /dev/v4l/by-id/`, case-insensitive
- `device = "/dev/video2"` — an exact device path
- `device = "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. Each sheet has two files: a `.jpg` (handy for viewing)
and a `.pdf` twin — the PDF is a full US-letter page at exactly 300 DPI
and is what actually gets sent to the printer. Delete them manually now
and then, or set `delete_contact_sheets = true` in 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:
```bash
lp -o media=letter -o fit-to-page contact_sheets/sheet_XXXX.pdf
```
(Print the `.pdf`, not the `.jpg` — the PDF's page size is exact, so the
printer can't stretch the photos.)
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`):
```bash
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 = false` to 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.