Commit Graph
14 Commits
Author SHA1 Message Date
Brandon Thomas 28a6d97434 Merge PR #1062
# Conflicts:
#	docs/parity-checklist.md
2026-10-14 21:58:37 -04:00
OneSlipsandClaude Opus 5.5 0f40a2d2f5 LR-MASK-EFFECTS: manage, group and fully import local adjustment presets (engine)
Mask effects gain groups, stars, partial presets (only some sliders, with or
without Amount), optional brush settings and the settings an imported preset
carries that we can't apply (kept for export). New commands: mask.updateEffect,
renameEffect, duplicateEffect, favoriteEffect, setEffectGroup,
renameEffectGroup, toolEffect; applyEffect takes several masks, all masks, or
the same-named masks on the selected photos in one undo step. A new mask starts
with the effect last applied to a mask of its kind (kept with the library).

Import (mask.importEffects and preset.import): Lightroom Classic local
.lrtemplate, Camera Raw local-correction .xmp, .lceffect and zips of these;
folders and LrC divider presets ("10 ----- DETAIL ----- 10") become groups;
grain / Point Color / toningLuminance reported and kept. Malformed files are
errors, never panics.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:33:25 +10:00
OneSlipsandClaude Opus 5.5 b7222213c9 PERF-PRESETS: thousands of presets no longer stall every command and frame
A Lightroom collection imported whole (11 113 presets, a 42 MB presets.json)
made every interaction take seconds:

- Session::persist ran after every command and serialized the whole preset
  list to compare it with the last write: 609 ms per slider tick (release,
  the real collection). Session::presets is now a PresetList whose generation
  changes on mutable access; persist serializes only when it (or the profile
  lists) changed, and skips the write when the bytes hash the same.
  develop.set: 609 ms -> 2.3 ms; preset.apply: 598 ms -> 3.1 ms.
- The Presets panel deep-cloned every preset into a BTreeMap, built a row,
  widget id and (with thumbnails) a variant render job for each of them every
  frame. Grouping is cached per generation and only rows in view are laid
  out: 5041 -> ~20 rows a frame, 2.3 ms with 5000 presets.
- The preset pickers (Import dialog, Settings > Import) build only the rows
  in view.
- add_presets and opening a library compared every preset with every other
  (quadratic); both use hash indexes now. Opening no longer serializes the
  list once just to remember it.

Tests: develop commands don't re-serialize unchanged presets (and a change
is still saved), generation semantics, a 20 000-preset import, and the
panel building only visible rows (fails on the old code: 5041 rows).
An ignored bench (presets_scale_bench, LIGHTCRAFT_BENCH_PRESETS) times a
real presets.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 02:32:29 +10:00
Claude 790a341776 Part of #374: launch imports run off the UI thread; folder walks are bounded and never take a drive root or home implicitly
Root cause (in 0.2.1 and still on main): files and folders named on the
command line were imported from the eframe app-creator closure with
`app.run("library.import", …)`, which runs the engine command synchronously:
`import::expand` walked the folder recursively (one `is_dir()` open per entry,
no depth or count bound, following links) and probed every file before the
first frame could be drawn. An argument that resolves to a drive root (`.` or
`..` with a launcher's working folder at `C:\`, `/` or `\` on Windows) or to
the home folder therefore walked the whole drive with the window stuck as a
black "not responding" box. The library-problem banner's pending import had
the same synchronous call. Every other recursive walk (Local's Include
Subfolders, Find Missing Photos, preset and LUT folders, MCP) was also
unbounded, which is the "Local folders with subfolders: not responding"
pattern of filmcraft#23, and a link loop recursed until the stack overflowed.

- engine `walk::files_in`: one bounded, iterative walker (32 folder levels,
  1,000,000 entries; `Walked::truncated` says it stopped), folder or file
  taken from the directory listing (no open per entry), links and junctions
  to a folder followed once. `import::expand` (+ `expand_within`), preset and
  LUT folder expansion and MCP `expand_paths` use it.
- engine `import::launch_path`: an empty launch argument is ignored; a
  relative one is resolved against the working folder; a drive or file-system
  root becomes its memory card's DCIM folder or is refused, and so is the home
  folder (a notice says why and to use File > Import Photos).
- desktop: launch arguments go through it and are imported with
  `import::start_paths` (the import worker), like dropped files; so does the
  library-problem banner's pending import.

Not verified on Windows (no machine here). The report says PhotoCraft 0.5.0
and `--memory` hang the same way with no arguments; nothing in LightCraft
walks the disk at startup without arguments (strace of a headless demo run
with HOME=/ and cwd /: no recursive listing), so that part may be outside
this code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 21:19:42 +00:00
Claude 7f386aa258 Merge fixes: close the test functions the #307/#325 and #325/#346 merges ran together
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:58:41 +00:00
peiyan0 493600743d engine, ui: support imported LUT profiles in profile dropdown and browser (#328) 2026-10-09 00:43:19 +08:00
Brandon ThomasandClaude Opus 5.5 6c3c155c99 LR-PRE-IMPORT: import Luminar looks (.lmp, .mplumpack)
An .lmp look is an XML property list of adjustment layers with named
sliders (newer looks: a Name.lmp/Contents/preset.lmp bundle); an
.mplumpack is a zip of looks plus PresetsInfo.plist (GroupName).
preset.import, the file dialog and drag & drop now accept both. Sliders
with a clear counterpart (exposure, contrast, highlights/shadows,
whites/blacks, WB shift, saturation/vibrance, clarity/structure,
dehaze, HSL, point curves, vignette, grain) map onto develop settings;
the rest is reported in `unmapped`. Looks are named after the look and
grouped by the pack. Tests use synthetic looks and packs only.

Fixes #9

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 02:59:25 -04:00
Brandon ThomasandClaude Opus 5.5 4a490db261 LR-PROF-IMPORT: .cube 3D LUTs as creative profiles
lightcraft-pipeline gains lut.rs: a .cube parser (LUT_3D_SIZE, DOMAIN_MIN/MAX, TITLE), a
trilinear lookup and an in-process registry; the finishing stage applies a `lut:` profile to
the display-encoded colour, blended by the profile amount (0–200 %); LUT profiles render on the
CPU. profile.import {paths} reads files, folders and zips, copies each LUT into the library's
Profiles/ folder, lists them in prefs and registers them when the library opens; the profile
browser shows them under their folder / zip name; profile.deleteImported. File ▸ Import
Profiles & Presets…, the file picker and drag & drop take .cube files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:20:39 -04:00
Brandon ThomasandClaude Opus 5.5 a98ea7858b LR-PRE-PREMIUM + KEYC-CATALOG: 41 built-in presets, F2 renames
- 23 more own-authored presets: Portrait (Moody Portrait, Golden Glow, Clean Studio),
  Landscape (Crisp Vista, Deep Sky, Lush Greens, Desert Warmth, Misty Morning), Urban,
  Food, Seasons, Vintage (Instant '70s, Cross Process, Bleach Bypass), Sepia B&W.
- F2 opens Rename Photos…; ⌘' / ⌘R / ⇧⌘E Classic keys verified.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:09:09 -04:00
Brandon ThomasandClaude Opus 5.5 1dc501bc3a LR-IMP-PROFILES: import presets from .lrtemplate, DNG presets, zip bundles and folders
preset.import (File ▸ Import Presets…, Presets panel ⋯, drag & drop, CLI, MCP) now reads
everything people actually download or carry over from other editors:
- classic .lrtemplate files (Lua table literal parser; value.settings uses crs: field names),
  including old process-version fields (Exposure, Contrast, FillLight, HighlightRecovery,
  Shadows, Brightness, Clarity, ToneCurve) approximated with today's sliders;
- photos carrying their edits in XMP ("DNG presets" from mobile apps, edited JPEG/TIFF): the
  look only, without the photo's crop, geometry or custom white balance;
- .zip bundles (stored + deflate) of any of these, skipping __MACOSX / hidden files;
- folders: the pack's folder name becomes the group, skipping app/format container folders
  ("Lightroom Classic", "XMP", "Mobile (DNG)"…).
Each imported preset reports the settings that had no counterpart (`unmapped`: profiles,
looks, local masks); the app's toast names them. dryRun previews, group overrides.
Dropped .lcpreset/.lrtemplate/.xmp/.zip files import as presets instead of photos.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 20:14:51 -04:00
Brandon ThomasandClaude Opus 5.5 5720cf333d LR-PROF-DROPDOWN: profile favourites and recent (persisted with the library), grouped profile menu, amount slider
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:23:26 -04:00
Brandon ThomasandClaude Opus 5.5 9c4526129e LR-PROF-CREATIVE: 16 own creative profiles (Film, Cinematic, Muted, B&W) as amount-scaled settings deltas
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:16:19 -04:00
Brandon ThomasandClaude Opus 5.5 3ef4eb0687 M9.2: preset files — .lcpreset import/export (groups preserved), XMP presets via crs: mapping
- engine presets.rs: .lcpreset JSON format {format: "lightcraft.preset", version, presets[]},
  parse_preset_file (.lcpreset file / bare preset / array, or XMP), folder expansion,
  Session::add_presets (identical presets skipped, id clashes get fresh user.* ids, built-ins
  never replaced).
- crs::preset_from_xmp: crs: fields → partial settings, crs:Name/crs:Group (fallback: file name /
  "Imported Presets").
- Commands preset.import {paths} and preset.export {path, ids?, group?}; UI commands
  file.importPresets / file.exportPresets (File menu, with native open/save dialogs on desktop),
  Presets panel "⋯" menu (Import Presets…, Export User Presets…) and group context menu
  (Export Group…).
- Tests: export → import round trip keeps groups/settings, duplicates skipped, clashing ids,
  malformed files reported, hand-written XMP preset imports and applies.
- docs/xmp-interop.md: preset file section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:05:26 -04:00
Brandon ThomasandClaude Opus 5.5 69e8aa6e18 M0.6: engine (Session, ~75 commands: library/photo/album/develop/crop/masks/spots/presets/versions/history/queries; undo via inverse ops; interactions; render jobs; demo library)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:33:29 -04:00