From c96e670356c1da43b02b8b1bf02ee98215927735 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 20 Sep 2026 20:15:51 +0200 Subject: [PATCH] Re-record the panorama for the trained filler; the scene waits for the preview and for the DNG instead of guessing --- docs/manual/media/panorama-filled.png | 4 +- docs/manual/media/panorama.gif | 4 +- tools/manual/record.sh | 1 + tools/manual/scenes.py | 68 +++++++++++++++++++++++++-- 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/docs/manual/media/panorama-filled.png b/docs/manual/media/panorama-filled.png index df3faec..7974967 100644 --- a/docs/manual/media/panorama-filled.png +++ b/docs/manual/media/panorama-filled.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:89031d39f081b3612c32cd00289ed512be9f4a5c133c53cfaee451ee897e7249 -size 1016389 +oid sha256:65c97e0424fa36f32a77dcc789108d92f1e42526e8d887b4864ff0a219299d18 +size 1046096 diff --git a/docs/manual/media/panorama.gif b/docs/manual/media/panorama.gif index a180f75..b68b49a 100644 --- a/docs/manual/media/panorama.gif +++ b/docs/manual/media/panorama.gif @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d307423e5e63f300649920f3ddcd08eb91ad4cf74962cb3293c04dce6bbff1f3 -size 426043 +oid sha256:5867f182c9cd8156328710ab21e0ad6b549c1fa7839d472922dba427b6f95b38 +size 902017 diff --git a/tools/manual/record.sh b/tools/manual/record.sh index 5634d6a..d1cd52f 100755 --- a/tools/manual/record.sh +++ b/tools/manual/record.sh @@ -21,6 +21,7 @@ shift || true export DR_HOME="${DR_HOME:-/var/tmp/dr-manual}" export DR_DISPLAY="${DR_DISPLAY:-:7}" export DR_BIN="${DR_BIN:-$repo/target/release/darkroom-desktop}" +export DR_LIBRARY="$library" media="$repo/docs/manual/media" mkdir -p "$media" "$DR_HOME/xdg/config/darkroom" "$DR_HOME/xdg/data/darkroom" diff --git a/tools/manual/scenes.py b/tools/manual/scenes.py index 97b0fa5..17efd4e 100755 --- a/tools/manual/scenes.py +++ b/tools/manual/scenes.py @@ -11,6 +11,8 @@ scene, so a different library needs the numbers looked at again. Panel coordinates hold for any library. """ import os +import re +import subprocess import sys import time @@ -18,6 +20,7 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import drive as dr # noqa: E402 OUT = sys.argv[1] if len(sys.argv) > 1 else '.' +DEMO_LIBRARY = os.environ.get('DR_LIBRARY', '') # the folder the merge writes its DNG into def shot(name): @@ -130,6 +133,9 @@ def library_thumbsize(): def library_selection(): + # The grid remembers its scroll between launches; the cells below are + # the grid at its top. + wheel(-40, 900, 500); pause(0.6) dr.click(*SELECT); pause(0.5) dr.click(*CELL_PANO_FIRST); pause(0.3) dr.x('keydown', 'shift'); dr.click(*CELL_NY_LAST); dr.x('keyup', 'shift'); pause(0.8) @@ -322,14 +328,70 @@ def develop_export(): # --- panorama --------------------------------------------------------------- +def wait_for_new(folder, suffix, since, timeout): + """Until a file ending in `suffix` newer than `since` appears in + `folder`'s tree — the merge's DNG — or `timeout` seconds pass.""" + t0 = time.time() + while time.time() - t0 < timeout: + for root, _, files in os.walk(folder): + for f in files: + if f.lower().endswith(suffix) and os.path.getmtime(os.path.join(root, f)) > since: + return True + time.sleep(2) + return False + + +def wait_until_lit(px, py, timeout): + """Until the window pixel at (px, py) is no longer black — the fill + preview has reached the corner of the border — or `timeout` passes.""" + t0 = time.time() + while time.time() - t0 < timeout: + out = subprocess.run( + ['import', '-window', dr.win(), '-crop', f'1x1+{px}+{py}', '-depth', '8', 'txt:-'], + capture_output=True, text=True).stdout + m = re.search(r'\((\d+),(\d+),(\d+)', out) + if m and max(int(v) for v in m.groups()) > 24: + return True + time.sleep(3) + return False + + +def join(name, parts): + """Concatenate recorded clips into `name`.mp4 and drop the parts.""" + lst = f'{OUT}/{name}.txt' + with open(lst, 'w') as f: + for p in parts: + f.write(f"file '{OUT}/{p}.mp4'\n") + subprocess.run(['ffmpeg', '-hide_banner', '-loglevel', 'error', '-y', '-f', 'concat', '-safe', '0', + '-i', lst, '-c', 'copy', f'{OUT}/{name}.mp4'], check=True) + os.remove(lst) + for p in parts: + os.remove(f'{OUT}/{p}.mp4') + + def panorama(): to_library() library_selection() - rec('panorama') + rec('panorama-a') dr.click(1325, 1079); pause(40) # Merge to panorama - dr.click(184, 637); pause(45) # Fill the border - dr.click(1543, 22); pause(60) # Merge + shot('panorama-aligned') + dr.click(184, 637); pause(6) # Fill the border cut() + # The preview fills at the working scale — minutes on the CPU rung — + # so the film pauses until the border's corner has been painted. + wait_until_lit(60, 110, 400) + pause(3) + shot('panorama-filled') + rec('panorama-b') + pause(2) + started = time.time() + dr.click(1543, 22); pause(8) # Merge + cut() + join('panorama', ['panorama-a', 'panorama-b']) + # The merge itself takes minutes too; the last picture is the + # composite in the grid. + wait_for_new(DEMO_LIBRARY, '.dng', started, 600) if DEMO_LIBRARY else pause(60) + pause(5) shot('panorama-done') dr.click(*BACK); pause(2)