Show the composite in the grid in the manual, and say how it gets there

The panorama scene now ends in the grid, on the composite in its wide
cell beside the twelve frames it was made from, with the thumbnail the
merge made: the picture is taken straight after the merge, before any
rescan could have found the file. The manual's library section says how
a panorama's cell is sized and packed, and its panorama section that the
composite is in the grid the moment it is written. panorama.md §9 records
the race that kept it out, the catalogue-then-register path that
replaced it, how the thumbnail is developed, and the layout's classes.
This commit is contained in:
2026-09-28 19:57:37 -04:00
parent 34630ff752
commit 8d66fa9be5
8 changed files with 225 additions and 138 deletions
+47
View File
@@ -294,6 +294,53 @@ carrying the first source's EXIF in a sub-IFD as `dr-export` already does.
file is written and catalogued, beside its sources, with the merge as the
first entry in its history.
**How it gets there (FR-MRG-6, 2026-09-28).** A rescan fired as the merge
finished raced the upload it followed — the 800 MB copy into a folder library
was still running when the folder was listed, and a Nextcloud upload takes
minutes — so the listing lacked the composite, recorded the folder's
validator, and the grid did not show it until the next sync pass. Now:
- *Catalogued by the merge.* `MergeEvent::Done` carries a `Composite` — the
name it will have, the size of the picture it opens on (the crop, or the
whole when filled), the capture time written into the DNG (the mean of the
frames'; the sources' earliest where none has one), the body, and its
thumbnails. `library::catalogue_composite` writes the row in one
transaction, keyed on `(root_id, source_ref)` exactly as the scan will list
the file, at `metadata_state = 2`, and the grid reloads. The name is chosen
against the catalog's names in that folder (`names_in_folder`), since the
upload replaces whatever is at its name.
- *The server's half after the upload.* Once a file the catalog already has
a row for is sent, the drain lists its folder once, records the file id the
server assigned (`record_uploaded`) and puts the merge's thumbnails in the
store under it; then the grid rescans. A scan that ran before the upload
leaves the row alone, and the one after it updates it in place.
- *Thumbnails from the merge.* The bands are box-reduced as they are written,
after the fill, to a copy 4096 pixels long (`merge_thumbs::Reduced`). That
copy is written as a linear DNG in memory with the composite's own profile,
header and crop and opened through `open_session` — develop's first open:
the D19 pipeline, the default view transform and tone mapping, the as-shot
balance and the working-space-to-display conversion. The grid, large and
wide classes are rendered from that session, staged in the outbox as
`x.dng.thumbs` before the rename releases the payload, and drawn from
memory until the upload has a file id to store them under. A test develops
a synthetic composite both ways and holds the mean, 95th and 99.5th luma
percentiles within 3–4 levels; the naive balanced-and-gamma picture misses
by 13. Older composites, which have no staged thumbnails, are thumbnailed
the ordinary way.
- *A wide cell.* `library_ui::layout` places the grid as a lattice of slots.
`natural_span` maps aspect to 2, 3 or 4 columns (from 1.9, 2.45 and 3.46 —
√(s(s+1)) is where two neighbouring classes leave the same share of their
cell empty), capped at the columns there are and the whole row on the
tablet, and the same number names the thumbnail class (`Wide2`–`Wide4`, 512
pixels of long edge per column). A wide cell that does not fit in the rest
of a row starts the next; nothing later moves into the gap, so ordinals —
the arrows, a shift-click's run, the timeline, burst folding — are
untouched, and up/down step by rows through the layout. The window's own
read carries `w` and `h`; where the wide ones sit in the whole list is one
query, run when the list changes, and a library with no panorama answers it
from the partial index `images_wide`, created on first use rather than by a
schema bump.
## 10. Order of work
1. **S15**, all four, before anything else. (1) and (2) are a day each and
File diff suppressed because one or more lines are too long