scenes.py aimed every press at window pixels, and the develop column had already moved under it: Compose now sits above Adjust, so the old exposure coordinate lands on a straighten slider. Every scene now names what it presses by its accessible label through the automation hook, places points on the photograph relative to the canvas, and opens its photographs by file name. Each starts from a known place and undoes what it did, so one can be recorded alone; the few that continue another's state name it, and running one runs that first into a scratch folder. Each scene also declares the pictures it makes and the sources they depend on. `record.sh --check` fails when the manual shows a picture no scene makes, or a scene makes one it does not show; it reads two files. `record.sh --changed` re-records the scenes whose sources, or own code, changed since the commit that last touched their pictures. record.sh builds with the automation feature, restores the library from DR_LIBRARY_SNAPSHOT, starts from a fresh profile and pins inference to the CPU; the launch screen is recorded from an empty profile of its own. Re-recorded with the ported scenes, and looked at frame by frame. What differs from the pictures they replace: - develop, presets, settings, local, compose, film, wb, light: the current develop column (Compose with Vertical and Horizontal above Adjust, the Label button), otherwise the same moments. - library pictures: the filter bar's colour-label chips; no collection left over from an earlier run in the sidebar; library-selection is the twelve alpine frames rather than eight of them and four New York ones. - library-rating rates two frames nobody had rated, so the stars are set and not cleared. - develop-zoom goes on past 1:1 with the wheel and ends on the file's pixels as hard-edged blocks. - repair covers a real mark on the road, with a size that fits it; film is shown on the Chinatown frame instead of the road. - panorama tries Perspective, Spherical and Cylindrical before filling. - launch, launch-folder and panorama-aligned came out byte-identical.
151 lines
5.7 KiB
Bash
Executable File
151 lines
5.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Re-record the manual: docs/manual/README.md's pictures, from the app itself.
|
|
#
|
|
# tools/manual/record.sh LIBRARY [SCENE...] every scene, or those named
|
|
# tools/manual/record.sh --changed LIBRARY the scenes whose sources
|
|
# changed since their pictures
|
|
# tools/manual/record.sh --check the manual and the scenes
|
|
# agree (no app, no display)
|
|
# tools/manual/record.sh --list the scenes and their pictures
|
|
#
|
|
# Needs Xvfb, xdotool, ImageMagick's `import`, ffmpeg and optipng. Builds the
|
|
# desktop binary with the `automation` feature — the hook scenes.py finds
|
|
# controls by name through — unless DR_BIN names one. Starts a private X
|
|
# server, opens LIBRARY in a fresh throwaway profile under DR_HOME, runs the
|
|
# scenes and writes PNGs and GIFs into docs/manual/media/.
|
|
#
|
|
# LIBRARY is the author's demo set — seventy face-free frames, the
|
|
# twelve-frame panorama from fixtures/pano among them — and the scenes open
|
|
# its photographs by file name. Recording changes it (ratings, collections,
|
|
# the merged DNG), so DR_LIBRARY_SNAPSHOT, if set, is copied over it first.
|
|
#
|
|
# Environment: DR_HOME (/var/tmp/dr-manual), DR_DISPLAY (:7), DR_BIN,
|
|
# DR_LIBRARY_SNAPSHOT, DR_EXPORT_DIR (LIBRARY/../export), DR_INFERENCE
|
|
# (`cpu`, the default, pins inference to the CPU so a recording does not
|
|
# fight a training run for the GPU; `probe` lets the app choose), CARGO
|
|
# (cargo; a wrapper taking cargo's arguments works too).
|
|
set -euo pipefail
|
|
|
|
here="$(cd "$(dirname "$0")" && pwd)"
|
|
repo="$(cd "$here/../.." && pwd)"
|
|
scenes="$here/scenes.py"
|
|
|
|
mode=record
|
|
case "${1:-}" in
|
|
--check) exec python3 "$scenes" check ;;
|
|
--list) exec python3 "$scenes" list ;;
|
|
--changed) mode=changed; shift ;;
|
|
""|-h|--help) sed -n '2,/^set -e/p' "$0" | sed '$d; s/^# \{0,1\}//'; exit 0 ;;
|
|
esac
|
|
|
|
library="$(cd "${1:?library folder}" && pwd)"
|
|
shift
|
|
|
|
if [ "$mode" = changed ]; then
|
|
python3 "$scenes" changed | tee /dev/stderr > /dev/null
|
|
mapfile -t chosen < <(python3 "$scenes" changed | cut -f1)
|
|
if [ ${#chosen[@]} -eq 0 ]; then
|
|
echo "nothing to re-record: every picture is newer than what it depends on"
|
|
exit 0
|
|
fi
|
|
set -- "${chosen[@]}"
|
|
fi
|
|
|
|
export DR_HOME="${DR_HOME:-/var/tmp/dr-manual}"
|
|
export DR_DISPLAY="${DR_DISPLAY:-:7}"
|
|
export DR_LIBRARY="$library"
|
|
export DR_AUTOMATION="$DR_HOME/automation.sock"
|
|
media="$repo/docs/manual/media"
|
|
|
|
if [ -z "${DR_BIN:-}" ]; then
|
|
(cd "$repo" && ${CARGO:-cargo} build --release -p darkroom-desktop --features automation)
|
|
DR_BIN="$repo/target/release/darkroom-desktop"
|
|
fi
|
|
export DR_BIN
|
|
|
|
if [ -n "${DR_LIBRARY_SNAPSHOT:-}" ]; then
|
|
rsync -a --delete "$DR_LIBRARY_SNAPSHOT/" "$library/"
|
|
fi
|
|
|
|
# A fresh profile every time, so a scene sees the library and not whatever
|
|
# the last run left in the catalog. The inference cache is kept — it is
|
|
# minutes of compiling — and so are the links to the models. The marker is
|
|
# what makes the wipe safe: nothing without it is deleted.
|
|
profile="$DR_HOME/xdg"
|
|
if [ -d "$profile" ] && [ ! -e "$DR_HOME/.manual-profile" ]; then
|
|
echo "$profile exists and was not made by record.sh; set DR_HOME elsewhere" >&2
|
|
exit 1
|
|
fi
|
|
mkdir -p "$DR_HOME" && touch "$DR_HOME/.manual-profile"
|
|
rm -rf "$profile/config" "$profile/state"
|
|
if [ -d "$profile/data/darkroom" ]; then
|
|
find "$profile/data/darkroom" -mindepth 1 -maxdepth 1 \
|
|
! -name inference ! -name models ! -name runtime -exec rm -rf {} +
|
|
fi
|
|
mkdir -p "$profile/config/darkroom" "$profile/data/darkroom"
|
|
|
|
# The models and the runtime are shared with the real profile: a segmenter
|
|
# that is not there makes "Find subjects" a picture of nothing.
|
|
for d in models runtime; do
|
|
src="${XDG_DATA_HOME:-$HOME/.local/share}/darkroom/$d"
|
|
[ -e "$src" ] && ln -sfn "$src" "$profile/data/darkroom/$d"
|
|
done
|
|
|
|
# Keep the inference choice the app last made, but on the CPU unless asked.
|
|
backend="$profile/data/darkroom/inference/backend.json"
|
|
if [ "${DR_INFERENCE:-cpu}" = cpu ] && [ -e "$backend" ]; then
|
|
python3 - "$backend" <<'PY'
|
|
import json, sys
|
|
p = sys.argv[1]
|
|
d = json.load(open(p))
|
|
d['rung'], d['reason'] = 'Cpu', 'forced for the demo'
|
|
json.dump(d, open(p, 'w'), indent=2)
|
|
PY
|
|
fi
|
|
|
|
# A folder library, chosen: no launch screen on the way in.
|
|
cat > "$profile/config/darkroom/sessions.json" <<JSON
|
|
{ "version": 0, "sessions": [ { "backend": "folder", "server": "$library",
|
|
"login": "", "user_id": "", "root": "", "root_chosen": true,
|
|
"formats": [], "last_scan": null } ] }
|
|
JSON
|
|
export_dir="${DR_EXPORT_DIR:-$(dirname "$library")/export}"
|
|
cat > "$profile/config/darkroom/settings.json" <<JSON
|
|
{ "export": { "destination": "$export_dir" } }
|
|
JSON
|
|
|
|
started_x=""
|
|
if ! DISPLAY="$DR_DISPLAY" xdpyinfo >/dev/null 2>&1; then
|
|
Xvfb "$DR_DISPLAY" -screen 0 1920x1200x24 +extension GLX +render -noreset \
|
|
> "$DR_HOME/xvfb.log" 2>&1 &
|
|
echo $! > "$DR_HOME/xvfb.pid"
|
|
started_x=1
|
|
sleep 2
|
|
fi
|
|
cleanup() {
|
|
python3 "$here/drive.py" stop || true
|
|
if [ -n "$started_x" ]; then kill "$(cat "$DR_HOME/xvfb.pid")" || true; fi
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
stamp="$DR_HOME/.recording-started"
|
|
touch "$stamp"
|
|
python3 "$here/drive.py" launch
|
|
DR_TOOLS="$here" python3 -c '
|
|
import os, sys, time
|
|
sys.path.insert(0, os.environ["DR_TOOLS"])
|
|
import drive as dr
|
|
dr.wait_ready()
|
|
dr.wait_for("id:grid-scroll", 120)
|
|
time.sleep(10) # the first thumbnails, and the scan settling
|
|
'
|
|
python3 "$scenes" record "$media" "${@:-all}"
|
|
|
|
# GIFs for the page; the MP4s are working files and are not kept.
|
|
for mp4 in "$media"/*.mp4; do
|
|
[ -e "$mp4" ] || continue
|
|
"$here/gif.sh" "$mp4" "${mp4%.mp4}.gif" 960 10
|
|
rm "$mp4"
|
|
done
|
|
find "$media" -name '*.png' -newer "$stamp" -exec optipng -quiet -o2 {} + || true
|