Commit Graph
524 Commits
Author SHA1 Message Date
Brandon Thomas 8329b7be0a Merge PR #608 2026-10-09 20:36:11 -04:00
Brandon Thomas 9a694a4d41 Merge PR #572 2026-10-09 20:36:10 -04:00
Brandon Thomas 40e9c56119 Merge PR #509 2026-10-09 20:36:10 -04:00
Brandon Thomas e282505af2 Merge PR #505 2026-10-09 20:36:09 -04:00
Brandon Thomas 98b83a9a2a Merge PR #504 2026-10-09 20:36:09 -04:00
Brandon Thomas e87863d48d Merge PR #549 2026-10-09 20:36:08 -04:00
sanyamsingh001andCodex f78b60b84a LR-IMP-ADD-DIALOG: initialize UI before measuring import frames
Co-authored-by: Codex <codex@openai.com>
2026-10-10 08:43:15 +10:00
midasdf c0ff290e7e M1: retain selection after permanent photo deletion
Reuse the landed current-view deletion selection logic for photo.deletePermanently, retaining survivors or choosing the next neighbour and the previous at the end. Preserve catalog-only deletion and existing undo/persistence behavior.

Refs #441, #451, #545.
2026-10-10 03:24:49 +09:00
hxwandClaude Opus 5.5 46c7660e5c #538: breadcrumbs open their folder as spelled; fix browse test on Windows
browse_a_local_folder compared the browsed folder with backslashes replaced
by slashes, but library.browse keeps the platform's separators; compare
paths instead. A breadcrumb now opens the path cut from the original string,
so a UNC share keeps its leading \ and a bare drive opens its root (C:\)
rather than the current folder on that drive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:04:41 -05:00
Brandon Thomas 53711eb1ef Merge PR #273
# Conflicts:
#	docs/parity.md
2026-10-09 12:04:03 -04:00
Brandon ThomasandClaude Opus 5.5 95d8aed986 Merge origin/main into profile-gain-table-map (RENDER_CACHE_VERSION: main's 21 + 1 = 22)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:52:23 -04:00
Brandon Thomas 5328100722 Merge PR #451 2026-10-09 11:36:31 -04:00
Brandon Thomas 967b858129 Merge PR #449 2026-10-09 09:26:00 -04:00
Brandon Thomas d31f805945 Merge PR #460 2026-10-09 09:25:59 -04:00
Brandon Thomas 12a2a99f2a Merge PR #368 2026-10-09 09:25:58 -04:00
Brandon Thomas 0b6cfd89ec Merge remote-tracking branch 'origin/main' into fix-449 2026-10-09 08:57:20 -04:00
sanyamsingh001andCodex 265e7e4d50 LR-LIB-RATING: fix relative ratings and grid bracket shortcuts
Co-authored-by: Codex <codex@openai.com>
2026-10-09 22:48:00 +10:00
Elliot Graham 03cb96f86a LR-LIB-FOLDER: delete populated album folders with undo (#501) 2026-10-09 13:33:22 +01:00
hxwandClaude Opus 5.5 5630734832 LR-BEHAV-BG-TASKS: render export batches side by side (issue #496)
A batch ran its photos strictly one after another: each render is
row-parallel inside, but a photo's decode, its PNG/TIFF/WebP encode and
the wait on a GPU render are mostly serial, so a 32-core machine averaged
~9.5 busy cores on the CPU path and 1-2 with the GPU.

run_batch now keeps export_parallelism() photos in flight (cores / 4,
1..=4; one on wasm32) on scoped lane threads plus the calling thread.
Each holds an estimate of its working memory from a new export_gate
(twice the memory budget, separate from the decode gate it nests over),
so full-size 24 MP exports (~1.2 GB each) run two at a time by default.
Lanes run at most `lanes` photos past the last one placed, which also
bounds the finished files waiting for their turn. Paths, conflict
handling, original protection, writes, results and progress stay in
batch order (Placer), so the files are the same as one at a time; a
panic in a lane becomes that photo's error.

render_bench's batch scenario now goes through export_batch. 8 x 24 MP
JPEGs, 32 cores + RTX 4080 Laptop: CPU 3.87 s -> 2.35 s, GPU 4.21 s ->
1.82 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 07:00:59 -05:00
Elliot GrahamandCodex b9f951998f #491: Keep Local import headers within the centre pane
Co-Authored-By: Codex <noreply@openai.com>
2026-10-09 12:08:11 +01:00
MarekSpodBiedry 44735cd5e7 Issue #272: Show in Explorer selects photos whose path has a space
Explorer only selects a file when the path after /select, is quoted. Rust's argument quoting wraps the whole "/select,C:\My Photos\a.jpg" switch in quotes as soon as the path has a space, so Explorer opened Documents. Build the switch as /select,"<path>" (backslashes, verbatim \\?\ and \\?\UNC\ prefixes stripped) and pass it with raw_arg on Windows. The library folder tree's context menu now shows the platform's reveal label too, and the Russian catalog gains "Show in Explorer" and "Show in File Manager".
2026-10-09 12:19:27 +02:00
BuonBredaandClaude Opus 5.5 fa1565d855 LR-PROF-CAMERACOLOR: camera local tone mapping (ProfileGainTableMap) as a per-photo opt-in
Renders a raw's DNG ProfileGainTableMap (Apple ProRAW's local tone mapping)
when the photo's Profile option "Camera local tone mapping" is on
(`profile.camera_local_tone`, off by default: Lightroom Classic renders
ProRAW without it). Built on #427's parser; supersedes the decode-time
applier of the first version of #273.

- raw/gaintable: GainTableMap::gain / evaluator (GainEval) per DNG 1.7.1:
  bilinear between tables with edges replicated, input clamp(weights .
  (R,G,B,min,max))^gamma in linear ProPhoto after the baseline exposure,
  index input x MapPointsN clamped to the last point. Saturating cell
  math; maps whose sizes don't match their gains aren't evaluated.
  SourcePlacement: where a developed source sits in the active area.
- pipeline/local_tone: the gain per output pixel in the scene-linear
  stage, before the white balance, mapped back through the frame (crop,
  user orientation, warp) and the EXIF orientation. lin_needs_cpu routes
  the stage to the CPU when it's on (CPU and GPU match); lin_key includes
  it. SourceInfo::local_tone carries the map from the decoder.
- develop: Profile::camera_local_tone (omitted from JSON when off, so
  existing settings and their hashes are unchanged); Profile row checkbox
  when the source has a map; translations.
- RENDER_CACHE_VERSION 17. Docs: parity row and What's New as an opt-in.

Off renders pixel-identical to main on two iPhone 15 Pro ProRAWs (12 and
48 MP). On adds ~60-75 ms to the scene-linear stage at 1536x2048 on a
2-core VM, the same for both files (cost follows output pixels).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFqow2P1EtDxt6nRjjQoTA
2026-10-09 11:11:52 +02:00
supper_yijie bf35a3c6c5 fix #425: Restore Simplified Chinese font rendering
1.Added Simplified Chinese font support for web and desktop builds.
2.Kept Inter as the default font, with Chinese used only as a fallback.
3.Verified Chinese glyph tests and a macOS universal build.

Signed-off-by: supper_yijie <syj794844854@163.com>
2026-10-09 15:12:33 +08:00
midasdf 35718bc92c M1: keep deletion selection near the current photo 2026-10-09 15:04:40 +09:00
Hanmo 40652fc5f9 M6: move radial masks by dragging inside their ellipses 2026-10-09 13:35:02 +08:00
Brandon ThomasandClaude Opus 5.5 7dcfbed05c LR-EDIT-DETAIL-DENOISE: list settings tabs from TABS; fix the SAM 3 worker's wasm check
The unknown-tab error now names every Settings tab (it missed AI Denoise after the
faces merge). lightcraft-sam3-worker (#359) only builds its server off wasm32, so
`cargo xtask wasm` passes again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:07:43 -04:00
Brandon ThomasandClaude Opus 5.5 1e1eb5fe16 Merge origin/main (batches 14 and 15) into AI RAW denoise (#384)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:30:17 -04:00
Brandon ThomasandClaude Opus 5.5 c65065de2f Merge the faces stack (#172/#173/#174, integrate-batch-14) into AI RAW denoise (#384)
One config-dir helper (engine::config::config_dir; camera_profiles re-exports it) with both
the face-models and denoise-models defaults; hosts set up both model folders; Settings has
Faces and AI Denoise tabs; both command sets registered; both model dialogs; locale entries
from both; one [features] table per app manifest; Cargo.lock regenerated by cargo; the
DecodedSource cache cost counts both segmentation mattes and the denoised twin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:29:59 -04:00
Brandon Thomas 7365d06c13 Merge PR #359 2026-10-09 00:17:59 -04:00
Brandon Thomas ab73d3d2e0 Merge PR #423 2026-10-09 00:17:58 -04:00
Brandon Thomas cae7bea08e Merge remote-tracking branch 'origin/main' into fix-359
# Conflicts:
#	crates/engine/src/segment/worker.rs
2026-10-08 23:57:36 -04:00
Brandon Thomas ca97329ae1 Merge PR #174 2026-10-08 23:45:49 -04:00
Brandon Thomas 3368eb49ee Merge PR #173 2026-10-08 23:45:49 -04:00
Brandon Thomas cbf9935b6e Merge PR #172
# Conflicts:
#	docs/parity.md
2026-10-08 23:45:49 -04:00
Brandon Thomas 91d317900f Merge PR #395 2026-10-08 23:22:56 -04:00
sanyamsingh001andCodex 56754e5703 LR-BEHAV-HEADLESS: keep CPU snapshots isolated from saved preferences
Co-authored-by: Codex <codex@openai.com>
2026-10-09 13:19:47 +10:00
Brandon Thomas 1a2d2ab975 Merge PR #422 2026-10-08 22:43:10 -04:00
Daniel Voshart 111cc893ec LR-LIB-PEOPLE: preserve later person navigation on current main
Port the original Escape return and last-person shortcut behavior, keeping current translations and a no-wrap chip. The existing headless regressions and all seven quality gates pass with the hosted fonts on the refreshed recognition dependency chain.

Generated with Codex.
2026-10-08 22:29:31 -04:00
Daniel Voshart 24f87a91a0 LR-PREF-PEOPLE: update pure-Rust recognition and preserve valid model replacements
Keep current upstream UI behavior and the later detector contract checks. Validate candidate models before replacing working weights and records, with a synthetic regression that failed before the fix. Remove the unrelated GPU equivalence-test relaxation. All seven quality gates pass with the pinned hosted fonts.

Generated with Codex.
2026-10-08 22:29:31 -04:00
Daniel VoshartandClaude Opus 5.5 20a801d6d2 Faces: YuNet face detection and one-click model downloads, with nothing bundled
Photo > Detect Faces runs the YuNet detector (a small pure-Rust interpreter over the ONNX graph, no
runtime dependency) and adds the faces it finds as unnamed face regions in one undo step. The detector
and the recognition models are opt-in downloads: Settings > Faces shows each model's licence and
training-data note, Download stays disabled until the terms are accepted, and the file is fetched over
https with lightcraft-fetch from the model's own repository at a commit-pinned address, checked against
its recorded size and SHA-256 and then installed. Detect Faces offers the detector's download the first
time it is used. No model file is part of the repository (the real-model tests read LC_YUNET_MODEL; two
ignored tests download from the real hosts).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:29:30 -04:00
Daniel Voshart fd4019300a LR-EDIT-DETAIL-DENOISE: address installation and model-policy review
Generated with Codex.
2026-10-08 22:07:23 -04:00
7935999d94 LR-EDIT-DETAIL-DENOISE: non-destructive AI RAW denoise with pure-Rust CPU/GPU
Recover the unpublished denoise work against current upstream. Preserve later opt-in model setup, shared Rust HTTPS downloads, pending-photo resume and an Amount-independent switch. Keep original RAWs unchanged and share the current color finish between ordinary and denoised sources.

Bound public tiling inputs, refuse corrupt-cache exports, and retain synthetic/real-model coverage. Include two Windows path spelling fixes in existing tests. No model weights, face code, media or Tract runtime are included.

Validation: cargo xtask ci (all seven gates); installed RawNIND CPU/GPU agreement 1.38e-6; native CPU preview/export on a public 24 MP Sony RAW, unchanged original SHA-256.

Co-authored-by: Codex <noreply@openai.com>

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

Generated with Codex.
2026-10-08 22:07:20 -04:00
Daniel VoshartandClaude Sonnet 5.5 7845d515e8 Faces: nothing is bundled, so YuNet is not reported as installed
The model list marked the YuNet detector as bundled with LightCraft and installed, but no model ships
inside LightCraft (the weights are opt-in downloads or files the user adds). Drop the notion: a
model is installed when its folder is, it can be removed like any other, and the licence notice no
longer says it is bundled.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:59:02 -04:00
Daniel VoshartandClaude Sonnet 5.5 cb34bb4842 Faces: Settings > Faces tab and the add-a-model licence dialog
An off-by-default "Recognise faces" toggle and the face model list in Settings,
with a one-drop install: pick a .onnx (Add a model file…) or drop one on the
window. The engine inspects it (recognised by hash, or described from its
shape), a dialog shows its licence, whether commercial use is allowed, what it
was trained on and what LightCraft had to assume, and Install stays disabled
until "I accept" is ticked. "Get…" opens a model's own page in the browser:
LightCraft never fetches a model itself. A file it cannot use says why.

The models folder is shared by the app, the CLI and the MCP server
(`engine::config`, `$LIGHTCRAFT_FACE_MODELS` overrides `<config>/models`), so a
model installed from one is there for the others. A session has none until a host
asks (`with_default_face_models`), which keeps tests hermetic.

Nothing runs a model yet, and the tab says so. Headless tests cover the whole
flow (the dialog, refusing until accepted, installing, a file it cannot use).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:59:01 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 8ff45f5237 Sidebar: dragging albums or photos near its top or bottom edge scrolls it
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 24b80b4ee3 Albums: the Albums header is the way back to the top level
It replaces the strip under the tree, which could be scrolled out of view
and shifted the rows when it appeared; the header is always visible and
nothing moves.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 085c25b10b Albums: drop beside a row to place it by hand; Sort A–Z goes back to by name
Dropping on the edge of a row places the album there (album.reorder) with
a line showing where; a folder's middle still means inside. A closed folder
opens only when the drop would go inside it. Sort Contents A–Z and Sort
Albums A–Z (album.sort) appear once a folder is ordered by hand.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 67aed0b4f4 Albums: a drag ends with the main button, Esc cancels it, hidden rows are no targets
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 aaae39fae0 Albums: drag an album or folder onto a folder to move it
A folder under the pointer is outlined when the drop is allowed and opens
after resting there; a drop zone under the tree takes an album back to the
top level. The move is album.move, so it is one undo step.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:07 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 5443ae28f9 Albums: address review of folder creation
Show a dialog's error and keep it open instead of closing it, open the
folder menu from the triangle too, draw a triangle only on folders that
hold something, reveal even when the section is folded, reuse the
translated Create … labels, and fix a misplaced doc comment.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:02:06 -04:00