Commit Graph
1149 Commits
Author SHA1 Message Date
aiongg a1455fa7cd Merge PR #1988: #1507: web start-up treats only NotFoundError as a missing file
apps/lightcraft-web/src/files.rs: keeps #1987's and #1988's tests
docs/whats-new.md: keeps both 2026-10-15 entries
2026-10-21 14:56:12 +00:00
aiongg 047e9bb962 Integration: #1924 a fresh re-import keeps its own stem sidecar 2026-10-21 14:55:45 +00:00
aiongg 4e581739bd Merge PR #1924: Do not read a sibling's shared stem sidecar on import (#1905)
docs/parity-checklist.md: header keeps the newer 2026-10-18 change
2026-10-21 14:54:19 +00:00
aiongg 523894b00b Merge PR #1998: LR-BEHAV-BG-TASKS: Reload from Disk reads its files in the background
docs/parity-checklist.md: header names #1998's change
2026-10-21 14:54:08 +00:00
aiongg c1c9f94094 Merge PR #842: Read large Lightroom catalogs by page
crates/engine/src/lightroom_catalog.rs: test helpers chained; native_catalog_rows takes #842's last_page argument, native_catalog_with_last_table_page builds on it
docs/parity-checklist.md: LRC-LIB-CATALOG-IMPORT keeps both texts
2026-10-21 14:53:52 +00:00
aiongg 80a7b8bba8 Merge PR #2230: Lightroom import: skip images whose file record is missing instead of failing 2026-10-21 14:53:06 +00:00
Claude d4627e9c26 #1507: dropping a Session no longer panics on the web
`face_download::Downloads::drop` gave a running download a second to stop,
with `Instant::now()` and `thread::sleep`, which panic on wasm32 ("time not
implemented on this platform"). The web host replaces its Session when the
library can't be opened, so with this branch an unreadable `catalog.log`
killed the page with the generic panic screen instead of showing the
library-problem window (found in a real-browser check of PR #1988). The wait
is skipped on wasm32, where there are no download threads; the cancel flags
are still set. Native test: an idle Downloads drops at once.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-19 09:01:22 +00:00
Matthew James SivakandClaude Opus 5.5 0360f940e3 Merge main into lightroom-jxl-dng
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 08:33:20 +02:00
Carlos VillanuevaandClaude Opus 5.5 16417e2eca Lightroom import: document the functions this change touches
CodeRabbit's docstring check counted the touched functions without doc
comments (read_with_progress, apply_prepared, inspect_report, result_dialog
and a test helper). Comments only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhZLBHaSnSko1eMByPibfh
2026-10-18 18:04:34 +00:00
Carlos VillanuevaandClaude Opus 5.5 9eec26804d Lightroom import: report skipped images as data and say so in the UI language
Review of #2230: the skipped-image warnings were English text shown as is
in the result window. Skipped images are now data in the import and inspect
reports (`skipped`: image id and reason: missingFile, missingFolder,
missingRoot, incompletePath, masterSkipped) instead of warnings, and the
result window adds one line counting them through tr_format!, translated in
every UI language; the eight-warning cap is unchanged.

Reader-level tests now cover a missing folder and root record and a virtual
copy of a skipped master read from a catalog file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhZLBHaSnSko1eMByPibfh
2026-10-18 17:21:36 +00:00
Matthew James SivakandClaude Opus 5.5 7b2d7b25ea LR-BEHAV-BG-TASKS: an older Reload can't overwrite a newer one; background Reload auto-writes sidecars
Review of #1998. Each reload plan takes a ticket; apply skips a photo a
later-started reload has already been applied to, so an older read that
finishes last no longer restores the previous dimensions and content hash.
The app's background completion now commits through Session::execute_fn,
so the XMP sidecar auto-write (and the save) happen as for the command.
Regression tests: an_older_reload_does_not_replace_a_newer_one,
a_background_reload_writes_the_sidecar_with_auto_write_on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:07:40 +02:00
Carlos VillanuevaandClaude Opus 5.5 bb9fe91bf2 Merge storytold/lightcraft main into lightroom-import-skip-orphan-images
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhZLBHaSnSko1eMByPibfh
2026-10-18 17:07:17 +00:00
Matthew James Sivak bf6e10fb06 Merge origin/main into reload-from-disk-background 2026-10-18 18:07:13 +02:00
Carlos VillanuevaandClaude Opus 5.5 1de6401aeb Lightroom import: one warning per skipped image, as the other import warnings
Go back to one "image N: not imported; …" warning per image, the format the
import's other skip warnings use; the result window already caps the list
(first eight, then "N more warnings"). Note the behaviour in the
LRC-LIB-CATALOG-IMPORT tracker row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhZLBHaSnSko1eMByPibfh
2026-10-18 13:25:44 +00:00
Brandon Thomas 56c9b49634 Merge PR #1919: Hasselblad FFF: colour matrix from the embedded 3FR header
# Conflicts:
#	docs/parity-checklist.md
#	docs/raw-parity.md
2026-10-18 09:22:57 -04:00
Brandon Thomas 4b6db59ade Merge PR #1903: LRC-PRINT-PAGE: Page Options print page numbers, page info and crop marks (gap 15)
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-18 09:22:40 -04:00
Brandon ThomasandClaude Opus 5.5 cbdbd50f84 Merge main into #1919 (main already dropped the drop(write) line)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 09:21:51 -04:00
Brandon Thomas 5b66a4825e Merge PR #2150: Keep face index records aligned after a torn or failed append 2026-10-18 09:20:42 -04:00
Brandon Thomas 7134099101 Merge PR #1691: LR-EXP-TYPE: omit redundant alpha from opaque 8-bit exports (#1670) 2026-10-18 09:20:34 -04:00
Brandon Thomas ad22d059db Merge PR #1844: fix(import): keep Lightroom luminance ranges open at white, report unmapped local sliders
# Conflicts:
#	contributors/people.toml
2026-10-18 09:20:33 -04:00
Brandon Thomas 29384a0404 Merge PR #1898: LR-MERGE-HEADLESS: merge dialogs remember the last settings per kind 2026-10-18 09:20:21 -04:00
Brandon Thomas 11308a5c8a Merge PR #2035: Reject out-of-range start in photo.rename and photo.renamePreview 2026-10-18 09:18:17 -04:00
Brandon Thomas 9bf08f6ce6 Merge PR #2083: Reject signed hex digits in #rrggbb colour parsing 2026-10-18 09:18:16 -04:00
Carlos VillanuevaandClaude Opus 5.5 ad43a976f3 Lightroom import: one warning per skip reason; skip incomplete original paths too
A catalog with many orphaned images produced one warning line each (82 in
the reported catalog). Skipped images are now listed in one warning per
reason, showing the first ten ids. An image whose original path is empty is
skipped the same way instead of failing the whole import.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhZLBHaSnSko1eMByPibfh
2026-10-18 12:33:18 +00:00
Carlos VillanuevaandClaude Opus 5.5 9c812b88a9 Lightroom import: skip images whose file record is missing instead of failing
A catalog can keep Adobe_images rows whose AgLibraryFile, AgLibraryFolder
or AgLibraryRootFolder record is gone; Lightroom ignores them, but the import
stopped at the first one with "image N: missing file record". Such images,
and their virtual copies, are now skipped with a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RhZLBHaSnSko1eMByPibfh
2026-10-18 12:19:10 +00:00
NetterSilverandClaude Haiku 5.5 0d2c77c258 Fix Assisted Culling bursts that cross midnight at month end (#2095)
Found while testing crates/engine/src/cmd/cull.rs:17-20 (secs, used by the burst grouping at cull.rs:45)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-17 18:38:33 -06:00
skylar taylor-barrick 2218d97e89 Merge pull request #2199 from skylartaylor/open-original-media-gate
Open Original: only file types LightCraft reads reach the system opener
2026-10-17 17:07:18 -06:00
FredApps d515f9affe Merge main into file-backed Lightroom catalog import (#798)
Preserve the file-backed reader and current upstream safeguards.
Resolve documentation conflicts without integrating unmerged work.
2026-10-18 00:49:15 +02:00
skylar taylor-barrickandClaude e6587c3f82 chore: clear the rustc 1.96 clippy lints that fail cargo xtask ci
Unrelated to the #2135 security fix in the commit before this one: both lines
predate this branch and are rustc/clippy 1.96 lint churn. `cargo clippy
--workspace --all-targets` only warns about them, but `cargo xtask ci` runs it
with `-D warnings` (xtask/src/main.rs), so the gate fails before any test runs.

- `clippy::nonminimal_bool` in `slide_overlay::shadow` (reported twice, two
  overlapping suggestions on the one expression): `!(A && B) || !C || !D` is
  `!(A && B && C && D)` by De Morgan, which is what the line now says. The
  operands are pure float comparisons and `is_finite` guards with no side
  effects, so this is an exact rewrite — a NaN or infinite `mx0`/`my0` still
  makes `shadow` return without drawing, as before. (Clippy's second suggestion
  drops the `my0.is_finite()` term and is *not* equivalent; it is not used.)
- `clippy::drop_non_drop` on `drop(write)` in
  `same_folder_as_original_refuses_photos_without_a_folder`. The line is not
  dead: `write` is a closure holding a mutable borrow of `written`, and the
  `drop` ended that borrow so the next assertion could read it. The closure now
  lives in a block of its own instead, which ends the borrow at the brace
  rather than relying on `drop` of a non-`Drop` type. Every assertion of the
  test is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-17 10:33:47 -06:00
skylar taylor-barrickandClaude d54673bb95 #2135: only file types LightCraft reads reach the system opener
Photo ▸ Edit In ▸ Open Original in Other Editor handed a photo's stored path
straight to `open` / `xdg-open` / `explorer.exe`, with `Path::is_file()` as the
only check, and Lightroom catalog import kept original paths exactly as the
catalog had them. A crafted `.lrcat` could therefore put `payload.exe`,
`start.lnk`, `run.bat`, `page.hta`, `Evil.app` or `go.command` into the library
and have it run on one user click.

- `lightcraft_engine::open_path`: one gate for every path that leaves
  LightCraft for the OS. The extension must be one LightCraft reads
  (`import::EXTENSIONS`, which already covers the Edit In copy formats
  `tif`/`tiff`/`psd`), it must be a regular file (so a `.app` bundle and any
  other folder are out), what a link resolves to must be a read type too, and
  what is handed over is the absolute path. A refusal is the sentence shown to
  the user.
- Open Original and Edit In go through it; a refused photo is listed in
  `skipped` with the reason, and the menu item is greyed out for a record that
  can never be opened (extension only, so no disk or share is touched while a
  menu is drawn).
- `lightroom_catalog::refuse_non_media` drops such images where the catalog is
  read and again where its photos become records, with a warning each, so a
  refused entry never becomes an openable library record. A virtual copy of a
  refused original goes with it.

Tests: a catalog naming a program (and a virtual copy of it) imports neither
while the catalog's real photos do; a library record naming a program is never
handed to the stub launcher, which records no invocation, and a program
selected beside a photo leaves only the photo, by absolute path. Both fail
before this change.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-17 10:18:47 -06:00
NetterSilverandClaude Haiku 5.5 fafa70724b Keep face index records aligned after a torn or failed append
Fixes #2129

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:33:33 +02:00
NetterSilverandClaude Haiku 5.5 80e439f6dc Reject signed hex digits in #rrggbb colour parsing
Found while testing crates/slideshow/src/settings.rs:296-300 (parse_color); same pattern in crates/engine/src/slideshow.rs:117-122 (fadeColor)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-17 00:45:25 +00:00
aiongg 7b934ca2b2 Sidecars: write XMP only beside an existing local original 2026-10-16 17:57:30 +00:00
aiongg 346681561a Lightroom import: follow catalog paths only on this computer or the catalog's share 2026-10-16 17:44:52 +00:00
NetterSilverandClaude Haiku 5.5 312dd04830 Reject out-of-range start in photo.rename and photo.renamePreview
Found while testing crates/engine/src/rename.rs:919 (start parsed at crates/engine/src/cmd/manage.rs:12)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-16 16:21:24 +02:00
Matthew James SivakandClaude Opus 5.5 62e82479d2 LR-PROF-CAMERACOLOR: fit a DNG's tone with a look table and a 1024 px preview
A DNG whose profile has a LookTable but no ProfileToneCurve (Adobe Standard in
Lightroom-written DNGs) was not tone-fitted and rendered with the near-linear
default tone: flat and ~0.8 EV darker than Lightroom. A look table defines colour,
not tone, and the fit already applies the tables to its proxy. The preview may now
be 10% of the raw's long edge (and 384 px), so Lightroom's 1024 px previews
qualify. Two lossy ILCE-7CM2 DNGs now match Lightroom's mean linear RGB within 3%.
Render cache 65, look version 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 10:46:01 +02:00
FredApps 08e3893731 LR-798: refresh file-backed catalog against main 2026-10-15 22:44:43 +02:00
FredApps 9bec9db541 LR-1670: refresh opaque RGB export against main 2026-10-15 22:24:56 +02:00
Claude 6938be39e4 Engine tests: drop the drop() of a closure (clippy drop_non_drop)
Clippy 1.97 rejects `drop(write)` in the same-folder export test: the
closure has no Drop, so its borrow of `written` already ends at its last
use and the call did nothing. Removed, with a note on why the following
read of `written` compiles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J2NDVXA8jQQWeJb4YVTb6b
2026-10-15 19:17:57 +00:00
Claude b5dc500c54 Hasselblad 3FR / FFF: uncompressed RGB embedded previews
These files carry no JPEG: their preview is an uncompressed 8-bit RGB
IFD (1217 x 913 in the H4D-40 FFF, 218 x 218 in the CFV 3FR). The
largest such image is handed on by embedded_preview as a small baseline
TIFF, which lightcraft_codecs::decode reads, so 3FR / FFF show a preview
in the grid and loupe before they are developed. No Orientation tag is
written: the raw file's applies, as for JPEG previews without one. The
FFF's 16-bit copy (with a TransferFunction of unknown meaning) is not
used.

decode_raw_preview applied a container-declared colour space by forcing
the JPEG decoder on any owned preview; it now checks for JPEG bytes, so
a wrapped TIFF (or a JPEG XL preview) goes to its own decoder.

Checked on the CC0 H4D-40 FFF and CFV 3FR through
embedded_preview_srgb: right colours, the 3FR upright through its
Rotate90. Tests cover the wrap, the choice among RGB images, a short
strip and truncated files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J2NDVXA8jQQWeJb4YVTb6b
2026-10-15 18:58:05 +00:00
fanyzp 5bf0d45ba8 Do not read a sibling's shared stem sidecar on import (#1905)
With stem naming, `IMG_0001.xmp` is the sidecar of every file of that stem and, in a
folder Lightroom has worked on, it is the raw's. On import the packet was looked up
with the library naming alone, so a TIFF or JPEG arriving beside a raw of the same
name read the raw's packet and took its rating, label, keywords and `crs:` develop
settings (the case radialmonster reported in #92; the read side of a catalogued photo
is #1523).

`ImportStems` ranks the files an import is adding as if they were catalogued already,
in the order `StemOwners` uses for writing: the library's files and the arriving ones
together, a raw first, then the file name in lower case. A file that does not own the
stem sidecar reads only its own `<file>.xmp`, never the sibling's packet. A file that
is not catalogued yet has no id, and the id it draws when the import commits is above
every id in the library, so it loses a tie against a catalogued file; between
arriving files the order they arrive in stands for it.

Folder synchronize and the Lightroom catalog import go through the same function, so
a file arriving there is ranked the same way.
2026-10-16 02:20:40 +08:00
Marco Arnulfo 79d726f856 LRC-PRINT-PAGE: Page Options print page numbers, page info and crop marks (gap 15)
The Print dialog's Page section gets Lightroom's Page Options for Single Image
and Contact Sheet: the page number at the bottom right, the print settings line
(sharpening, profile, resolution) at the bottom left, and crop marks at the
corners of each photo. They are `print.set {page: {pageNumbers, pageInfo,
cropMarks}}`, saved with templates, drawn in the preview and composed into the
PDF; marks and text turn white on a dark page.
2026-10-15 15:38:03 +02:00
Matthew James SivakandClaude Opus 5.5 b9b80aee8a LR-BEHAV-BG-TASKS: Reload from Disk reads its files in the background
photo.reload decoded every targeted file on the UI thread, so a selection
of raws froze the window until all were read. The command is now split into
plan / probe / apply (engine `cmd::reload`); the app intercepts photo.reload
and probes the files on a worker thread with a cancellable activity row
(kind `reload`, counted progress), applying the result as one undo step.
`wait: true` keeps the old in-place behaviour for agents; CLI/MCP unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:35:11 +02:00
Matthew James SivakandClaude Opus 5.5 a43cb68593 LR-MERGE-HEADLESS: merge dialogs remember the last settings per kind
The HDR / Panorama / HDR Panorama dialogs now open with the options of the
last merge of that kind instead of the defaults, and those options are kept
in the library's prefs.json (Session::last_merge) so they survive a restart.
"With Last Settings" and HDR for Each Bracket Set read the same store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:04:14 +02:00
Brandon Thomas 5e9f7f1a65 Merge PR #1027 (rebased)
# Conflicts:
#	ROADMAP.md
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/target-app-parity.md
2026-10-15 03:40:37 -04:00
Brandon Thomas 9ddb8d1824 Merge PR #1663 (rebased)
# Conflicts:
#	crates/ui-egui/locales/de.json
#	crates/ui-egui/locales/es.json
#	crates/ui-egui/locales/fr.json
#	crates/ui-egui/locales/ja.json
#	crates/ui-egui/locales/pt-br.json
#	crates/ui-egui/locales/ru.json
#	crates/ui-egui/locales/uk.json
#	crates/ui-egui/locales/zh-hans.json
#	crates/ui-egui/locales/zh-hant.json
2026-10-15 03:40:17 -04:00
Brandon Thomas 8291f08ab7 Merge PR #1602 (rebased) 2026-10-15 03:40:15 -04:00
Brandon ThomasandClaude Opus 5.5 1d7699056e Merge PR #1027
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:36:18 -04:00
Brandon ThomasandClaude Opus 5.5 2179473536 Merge PR #1663
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:24:51 -04:00
Brandon ThomasandClaude Opus 5.5 00dced3dae Batch 39: #1829's straight brush lines carry pen pressure as the author merged them with #1033 (the whole masks.rs from the PR head)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:07:35 -04:00