Commit Graph
3164 Commits
Author SHA1 Message Date
Andrew FrahnandClaude Opus 5.5 ab240d6ece Perf: hue/saturation tables skip the sRGB round trip and fmodf in their per-pixel path
HsvTable::apply took the value through linear -> sRGB -> linear even when the table's value
scale is 1 (every hue/saturation-only table, as fitted camera looks are), and wrapped hues with
rem_euclid (an fmodf call) three times per pixel. The value is now kept as it is for a unit
scale and the sRGB-encoded value is reused otherwise; hues are wrapped by a helper that equals
rem_euclid bit for bit (tested) without the call for values within one period.

2048 px render of a 24 MP ARW, single thread: 16.4 -> 15.1 G instructions, 4.94 -> 4.76 G cycles.

Sources: own design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:29 +11:00
Andrew FrahnandClaude Opus 5.5 07ae88e923 Perf: preview builds render photos side by side and make the thumbnail from the view's source
library.buildPreviews rendered one photo at a time, and each photo's thumbnail job decoded the
file again at thumbnail level after (before, in fact) the view job had decoded it at preview
level. Now the view renders first and its decoded source serves the thumbnail, and photos
render in as many lanes as an export batch (two for 1:1 previews, a full-size source each);
a panic in one photo counts as that photo's failure.

100 24 MP ARWs, standard previews, loaded machine: 49.4 s -> 38.4 s (CPU 3m28 -> 2m49).

Sources: own design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:29 +11:00
Andrew FrahnandClaude Opus 5.5 6873aab6eb Drafts keep the wide planes across a noise-reduction change (CPU NR drag)
A noise-reduction change invalidated the scene-linear stage and with it every spatial
plane (base, clarity, dehaze, chromaticity), so each tick of an NR drag on the CPU rebuilt
all of them. The plan now also carries the linear key without the NR settings; a draft
render whose image differs from the cached one only in NR keeps those wide blurs and redoes
only log luminance and the fine texture band. Full-quality renders never take them.

Draft NR drag, single thread: prepare 18.7 -> 7 ms (render ~135 -> ~125 ms CPU).

Sources: own design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:28 +11:00
Andrew FrahnandClaude Opus 5.5 db7e37843e Export: Remove location info also covers Original and DNG formats
No location in the XMP sidecar or the DNG's packet; exporting an original
that embeds GPS with the option on is refused instead of leaking it.

Sources: own design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:23 +11:00
Andrew FrahnandClaude Opus 5.5 80e58ed55b engine: lens profile corrections from a lensfun-format database
Raws without an embedded lens correction look their EXIF lens up in the
user-supplied database; the profile goes through the existing Enable Profile
Corrections path (amount sliders, CPU/GPU geometry stage, DNG export).
Synthetic-grid test renders a distorted chart through the pipeline.

Sources: own design (see lightcraft-lensdb for the model sources).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:18 +11:00
Andrew FrahnandClaude Opus 5.5 00ea386f7f lensdb: lens distortion (poly3/poly5/PTLens), TCA (linear/poly3) and vignetting (pa) profiles, lensfun-format loader
Profiles are interpolated in focal length (vignetting also in aperture and
focus distance), scaled by crop factor, and converted by least squares to the
DNG WarpRectilinear / FixVignetteRadial polynomials the pipeline already
applies. The lensfun database (CC-BY-SA) is only read from a directory the
user supplies; nothing is bundled.

Sources: lensfun's published database format and lens calibration
documentation (no lensfun code read), PanoTools wiki (a, b, c distortion
model), DNG specification 1.6 (WarpRectilinear, FixVignetteRadial);
interpolation and fitting: own design.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 19:30:18 +11:00
PiMinusMaxandClaude Opus 5.5 385348b258 LR-PROF-CAMERACOLOR: the camera-look guard blends in smoothly instead of switching (#820)
Between a kept luminance share of 0.15 and 0.25 the table colour is now blended in with a smoothstep,
so noisy shadows show no step between pixels that get the table colour and pixels that keep theirs.
At 0.25 and above pixels render exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:24:09 +02:00
树洋 陈 8e61ad6b13 Add Ctrl+O / Cmd+O to show every mask overlay at once
Previously the masking overlay showed only the selected mask's region
(toggled by O). This adds a new Overlay::AllMasks variant that paints
the evaluated alpha of every visible mask that has components in one
tint, wired to a new "Show All Mask Overlays" command (Ctrl+O on
Windows/Linux, Cmd+O on macOS) reachable from the View menu, the
masking panel header (stack icon), and the keyboard shortcut.

Both the CPU and GPU render paths evaluate all visible masks and hand
their alpha planes to visualize::apply, which layers each mask's
region so multiple masks are visible at once. The all-masks overlay
takes precedence over the single-mask overlay so the shortcut is not
shadowed by the always-on per-mask view.
2026-10-11 15:56:17 +08:00
Jason Baldwin 6bfe2235af LRC-SS-TEMPLATES: slideshow templates: built-ins of our own, user templates, browser with hover preview
A slideshow template is the Playback (not "prepare previews"), Layout /
Options / Backdrop, Overlays and Titles settings as one versioned JSON
document (format lightcraft.slideshowTemplate, version 1).

- Engine: slide_template (SlideLook, Template, built-ins, user template
  files in <settings>/slideshow-templates read through each section's own
  merged() validation; size and count caps; newer versions refused; bad
  files reported and skipped; file names sanitised so ids never leave the
  folder). Applying replaces the four settings in one step and keeps the
  replaced ones as "previous" for the session (prefs have no undo).
- Five built-ins of our own: Plain Black, Gallery Wall, Edge to Edge,
  Cinema Wide, Shooting Data (no Lightroom names or designs, no images).
- Commands slideshow.templates.list/apply/save/update/rename/delete/
  import/export; slideshow.preview {template} previews without applying.
- UI: Template Browser at the top of Settings > Slideshow (built-in, user,
  previous settings; click applies, hover previews on the selected photo,
  right-click update / rename / export / delete; save and import), file
  dialogs on the desktop; strings in the nine locales.
- Docs: parity row (partial), whats-new, control protocol and MCP.
2026-10-11 09:22:11 +02:00
ingolfteetzandClaude Opus 5.5 4700c8a74e LR-IMP-FORMATS: decode Canon EOS R5 Mark II C-RAW (CRX QP-map first literal and escape)
The CRX 0x200 QP map opens with its first symbol as a 32-bit literal; every
later symbol is Rice coded with a limited-length escape: 23 zeros, the
terminating 1 and the symbol in 8 bits (the ITU-T T.87 layout for a 32-bit
limit and 8-bit symbols, without its minus-one offset). The old rule (an
escape after 16 zeros with a 16-bit literal) matched only the first symbol,
which is all the R8 and R7 maps need. R5 Mark II maps (QP 150-162) jump by up
to 12 where the Rice parameter is 0, giving 18- to 22-zero prefixes that
misparsed ("Canon CRX adaptive QP value -21087"): 174 of 306 sampled files
from a private R5 Mark II library opened as previews. Every QP map of its
33,665 C-RAW files now decodes to the exact end of its entropy stream; the six
oracle fixtures are unchanged. Established by black-box analysis of the
bitstream; no third-party decoder source consulted.

Adds the four CC0 R5 Mark II samples (raw.pixls.us 7881-7884) to the corpus
with pinned sensor hashes (the crop-mode framing is left to #754), bumps
RENDER_CACHE_VERSION to 43, and updates cr3.md, raw-parity (235 verified
models), coverage, gaps, the checklist rows, ROADMAP, target-app-parity and
What's New.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:20:49 +02:00
Alex ChambersandClaude Opus 5.5 484c160c13 LR-EXP-PHOTOS: Apple Photos imports in the activity stack (#345)
Rebased onto the activity stack (#601). An export adding its files to
Photos keeps its row through that step, with "Adding to Apple Photos…" as
the detail. The worker turns the row's ✕ off (TaskHandle::set_cancellable)
before its last look at the cancel flag and reports what it saw, so a
cancel either stops the export before Photos is asked or is refused, never
both "cancelled" and imported. activity: a per-task gate orders a cancel's
decision against a step switching cancelling off, so a cancel can't be
accepted between the switch and the step's look at the flag and then be
ignored. An import of its own (export.addToPhotos, or
the Photos step left running after a foreground app.export) holds a row of
kind applePhotos while Photos works: no ✕, no count, the album as detail.
The desktop app refuses export.addToPhotos {wait: true}: its window's
thread never waits for Photos. The label is in every catalog; tests assert
the rows, the refused cancel and the refused wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:19:00 +02:00
Alex ChambersandClaude Opus 5.5 c722e6bb64 LR-EXP-PHOTOS: Apple Photos fixes from the live test and review
- Ten minutes plus five seconds a file per import (was one minute): the
  first live run timed out while macOS's permission prompt was still up,
  and Photos' duplicates question waits for a person too.
- Files go to osascript 200 at a time, all within the import's one time
  limit: one run with every path went over macOS's 1 MiB argument limit
  at about 10,000 files, and Photos got nothing. A failed later batch says
  how many files Photos had added.
- The progress line "Adding to Apple Photos…" is translated on the UI
  thread; on the export worker it was always English.
- docs/apple-photos.md: who can add what (the control port is reachable by
  any local program, other users' included), batching, the new limit, and
  tested end to end (macOS 26.6.2, Photos 11.0, packaged app). The parity
  row says so; What's New has an entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:19:00 +02:00
Alex ChambersandClaude Opus 5.5 a6431c152d LR-EXP-PHOTOS: add exported files to Apple Photos (macOS, #236)
The Export dialog gets "Add to Apple Photos" with an optional album (macOS
only). app.export takes addToPhotos / photosAlbum (dialog, Export with
Previous, presets, MCP, lightcraft-cli run and render --opt); the new
export.addToPhotos {paths, album?, wait?} adds files already on disk and
export.photosImports {job?} reports how imports went.

A constant AppleScript run by /usr/bin/osascript asks Photos' import
command (Apple Events, not synthetic input) to import the files into a
top-level album of exactly that name (made when missing; albums in folders
are never used; several of that name: refused), skip check duplicates
false, and returns the media item ids. Album names and paths are passed
only as separate arguments (on run argv), never spliced into the script.
The runner is injectable (Session::apple_photos): with_fs installs the real
one on macOS only, and tests use fakes, so no test starts osascript or
Photos.

Imports are jobs (Session::apple_photos_imports), one at a time. The
desktop app (Session::apple_photos_background, set in open_session) never
waits for Photos on its UI thread: the background export adds on its
worker, app.export without background and export.addToPhotos answer with
the running job, and the app announces the outcome. Without a window (MCP,
lightcraft-cli) imports wait by default, and both headless front ends (the
MCP/CLI backend and the snapshot UI) wait for a running one before the
process ends, on every exit path, through one engine helper
(Session::wait_for_photos_imports) whose deadline follows the job: a
writing allowance while an export still writes, then the import's own
time limit from when Photos was asked, under an overall cap. A runner that panics, waiting or on a
worker, ends its import as failed and frees the slot (panic guard plus a
completion guard). Session::after_export reserves
the import slot before an export writes anything and frees it on every
exit path (handed the files, cancelled, failed, dropped), so a competing
import is refused with the export's job number instead of the export
failing its Photos step after writing. Permission (-1743), missing Photos,
cancel, timeouts, ambiguous albums, busy imports, other osascript failures
and partial imports produce actionable messages; the export's files are
kept either way. Hidden on other platforms; the web build compiles it out.

Packaging: the hardened-runtime entitlements gain
com.apple.security.automation.apple-events (app and CLI) and Info.plist
gains NSAppleEventsUsageDescription, without which macOS refuses the
events without asking.

Not yet tested end to end against a real Photos library: manual steps,
with the packaged app, in docs/apple-photos.md. Parity row LR-EXP-PHOTOS is
now partial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:19:00 +02:00
Jason Baldwin 43f31532a7 LRC-LIB-CATALOG-IMPORT: Open Library recognises a Lightroom catalog and offers to import it (#891)
Open Library given a Lightroom Classic catalog folder, one of its .lrdata /
.lrcat-data folders, Backups/, the .lrcat or its -wal/-shm/.lock files used to
create an empty LightCraft library inside Lightroom's folder (or, for the
.lrcat file, close the current library and then fail). Now:

- engine: lightroom_folder::lightroom_catalog_at (names only, top-level scan
  bounded to 10 000 entries, never fails); Session::open_library refuses those
  places with EngineError::LightroomCatalog {path, catalog} before creating
  anything. A LightCraft library (catalog.snap / catalog.log) always wins.
- app: app.openLibrary checks before closing the current library, keeps it,
  returns {opened: false, lightroomCatalog, path} and shows a dialog with
  Import Lightroom Catalog… (file.importLightroom with the catalog found) and
  Cancel. The library problem window gets the error instead.
- Lightroom import status keeps the catalog path after the task ends.
- CLI --library explains how to import instead.
2026-10-11 08:40:18 +02:00
Jason Baldwin f98078415e LRC-SS-TITLES: slideshow intro and ending screens
Intro and ending title screens (Lightroom Classic's Titles panel): each on
or off, a background colour and, centred, the Overlays identity plate or a
line of text, in the plate's colour or an override colour, at a scale, for
its own duration (default: the slide duration).

- Playback timeline: titles are items (Item::Title) of Playback; the intro
  plays once before the first photo, the ending after the last photo when
  repeat is off; random order never moves them; arrows step across them;
  fades, pause and readiness work as for slides; n of N counts photos only.
- Engine: slide_title (TitleSettings in prefs.json, TitleCompose drawing
  through the slide composer and overlay text renderer), slideshow.titles
  get/set, slideshow.preview {title}.
- UI: titles composed on a render worker (Renderer::request_title), the
  control bar shows Intro / End, Settings > Slideshow > Titles section and
  a Photo / Intro / Ending preview choice; strings in the nine locales.
- Docs: parity row (partial), playback note, whats-new, control and MCP.
2026-10-11 08:24:54 +02:00
cookingwithsimonandClaude Opus 5.5 5bb43a51f7 LR-VIEW-ZOOM: sharp 1:1 in Compare and Reference (zoom windows per pane)
Compare and Reference drew each pane from a whole-frame render of at most
2560 px, so 1:1 was a magnified preview and focus could not be checked.
Each pane now also renders the window on screen from the photo's own
pixels (Slot::CompareRegion), as the loupe does (#323). The media cache
keeps up to two full-size originals while either view is open, so one
pane's window does not evict the other's source.

Docs: gaps.md entry 4 shrinks to overlays and soft proofing; checklist
LR-VIEW-ZOOM / LR-VIEW-COMPARE and ui-parity zoom row updated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UyHnpE9573a7nJFQqnGNex
2026-10-11 05:55:48 +00:00
JordyUSAandClaude Opus 5.5 15f6718a2e LR-HDR-EDIT: read crs:HDREditMode from XMP into hdr.enabled
Lightroom's Light panel "HDR" switch (`crs:HDREditMode`, `1`/`True` on,
`0`/`False` off) now sets `hdr.enabled` when importing XMP sidecars, presets,
DNG presets and Lightroom catalogs, instead of being reported as unmapped (an
off value was already silent). The rest of the HDR settings keep their
defaults. Follow-up to #646, ported from #466.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:47:04 +07:00
JordyUSAandClaude Opus 5.5 7154ee149b LR-EDIT-HDR-MODE: HDR button next to B&W, as Lightroom has it
HDR editing is switched with an HDR button in the Edit panel header, beside
Auto and B&W and drawn the same way (the shared text_button: highlighted
while on), instead of a checkbox at the top of the Light panel. While HDR is
on, the Light panel still shows Visualize HDR and the headroom slider above
the light sliders; with HDR off they're hidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:46:28 +07:00
JordyUSAandClaude Opus 5.5 fb678b9e35 LR-VIEW-HISTOGRAM: HDR histogram for HDR edits
An HDR edit's preview shows its SDR rendition, so its histogram said nothing
about the highlights above SDR white. Now it shows the HDR rendition:
`pipeline::hdr_histogram` renders the edit small (384 px, float HDR, same
framing) and bins it with SDR on the left half and the HDR range on the right
(`Histogram::of_hdr`, `HdrBins`), on a fixed scale of Hdr::MAX_EV_LIMIT (5)
stops above SDR white so it doesn't rescale when the headroom limit changes.
The engine's `develop()` (CPU and GPU renders) and the web worker swap it in
for HDR edits; high-bit-depth, windowed and proofed requests keep the image's
histogram, and a display profile's histogram doesn't replace it. Web workers
carry the HDR bins across their wire (`Histogram::to_words` / `from_words`).

The panel draws it in Lightroom's layout: a solid line at SDR white, dashed
lines between the stops, the headroom limit as an orange line with the range
past it dimmed, a bar under the plot (white; one band per stop in Visualize
HDR range's colours while that is on), SDR / HDR labels and an info tooltip.
Follow-up to #646, ported from #466.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:46:27 +07:00
JordyUSAandClaude Opus 5.5 c9c0268f8b LR-HDR-EXPORT: say how viewers without cICP show a PQ PNG
Readers that don't read the PNG cICP chunk show the PQ samples as if they
were sRGB (flat, washed out): expected for PQ PNG, but it surprises people.
Noted in What's new (with the gain map JPEG as the look-right-everywhere
choice), as the export dialog's HDR PNG hint, and in the option and encoder
docs. Review suggestion on #664.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:46:27 +07:00
JordyUSAandClaude Opus 5.5 cbc0e2d7db LR-HDR-EXPORT: HDR PNG export as 16-bit Rec. 2020 PQ (cICP, cLLI)
With HDR output on, a photo edited in HDR exports as a 16-bit PNG with the PQ
curve in Rec. 2020 (SDR white at HDR_REFERENCE_WHITE_NITS), described by a
`cICP` chunk (PNG third edition: BT.2020 primaries, PQ, RGB, full range) and
a `cLLI` content light level chunk (the levels the HDR AVIF records). EXIF,
XMP and print resolution are kept; no ICC profile next to cICP. Photos without
an HDR edit, and HDR edits with HDR output off, export as before.

`codecs::encode_png_pq` sits next to `encode_avif_pq` and takes the same
input. Follow-up to #646, ported from #466.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:46:27 +07:00
Chad ElliottandClaude Opus 5.5 8c84677079 docs(windows): #399 note the pre-0.6 install-folder upgrade fix
Add a What's New entry for keeping the install folder when upgrading from a
pre-0.6 Windows installer, and describe the new Windows MSI job in the
Packaging lint workflow header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:46:21 -05:00
Chad ElliottandClaude Opus 5.5 a82ecb3753 fix(windows): #399 ignore stale App Paths values in the install-folder fallback
The App Paths directory search doesn't check that lightcraft.exe exists, and
when the old installers' unquoted path is gone, Windows Installer falls back
to the text before the first space: a deleted
C:\Program Files\LightCraft\lightcraft.exe resolved to C:\, so an upgrade
would install into the drive root. Gate the fallback on a second search of
the same value with a FileSearch for lightcraft.exe.

The install-folder test gains legacy-folder-deleted (failed before this fix)
and legacy-exe-deleted cases, and removes its empty parent registry key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 00:18:22 -05:00
Vikram Bhaskaran c536986c48 README: point the font-standard note at craft-fonts (#826).
storytold/craftrules is not a public repository, so the standards link in the
Chinese/Japanese fonts note was a 404 for anyone outside the maintainers. The
rule the sentence states lives with the font repo it points at anyway.
2026-10-11 15:45:40 +11:00
Jason Baldwin 0a09450809 Merge slideshow-composer (with main) into slideshow-overlays 2026-10-11 06:42:02 +02:00
Jason Baldwin 1b8cb436a8 Merge slideshow-playback (with main) into slideshow-composer
# Conflicts:
#	crates/ui-egui/locales/fr.json
#	crates/ui-egui/locales/uk.json
2026-10-11 06:40:14 +02:00
Jason Baldwin 46e431a200 Merge origin/main into slideshow-playback (0.6.0 and shared docking) 2026-10-11 06:40:02 +02:00
Jason Baldwin c52ff0f014 Merge origin/main into albums-library-photos-only (0.6.0 and shared docking; locale catalogs: kept both sides' keys) 2026-10-11 06:40:00 +02:00
Claude 61fef5cfd5 Progress docs: gaps.md reviewed after 0.6.0 (R7 C-RAW, refused CRX variants, riscv64 build)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HXAV8vMWLidoocKuPEpUVk
2026-10-11 04:34:33 +00:00
Nigel Ihza Firdausy 38756b89d0 fix(query): saturate pagination values in 32-bit web builds 2026-10-11 11:04:36 +07:00
Nigel Ihza Firdausy 789019714a fix(sliders): support focused wheel and arrow nudges (#864) 2026-10-11 11:03:13 +07:00
Nigel Ihza Firdausy d9d1a5a730 fix(ui): show completion for library maintenance and Auto Sync (#875) 2026-10-11 10:59:36 +07:00
Wladmir Júnior 7707379812 pt-BR: translate face recognition and album sorting strings 2026-10-11 00:44:03 -03:00
THEtheChadandGPT-6 Astra 32a358180c fix(windows): #399 preserve legacy MSI install folders
Fall back to the parent directory of the App Paths executable when an
older installer did not write InstallFolder. Keep explicit destinations
and the newer stored folder ahead of the legacy fallback.

Exercise the real MSI searches and actions with isolated per-user probes
on x64 and x86, including legacy paths with spaces and Unicode.

Co-Authored-By: GPT-6 Astra <noreply@openai.com>
2026-10-11 03:42:56 +00:00
robmdunnandClaude 21d71feb04 LR-HDR-EXPORT: HDR renders keep the camera tone curve in the midtones
Raws with a fitted camera look (e.g. Nikon NEF) rendered HDR with the
generic tone curve instead, more than a stop darker through the midtones
than the SDR render: PQ JPEG XL / AVIF exports looked dark everywhere,
and gain map JPEGs carried negative gains, so they went dark on HDR
displays. ToneMap::camera_hdr keeps the camera curve up to 1.5 EV over
grey and lifts highlights as ToneMap::hdr does.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 22:15:17 -04:00
sanyamsingh001andCodex 0b61450c7b LR-BEHAV-UNDO: keep file history consistent after failed renames
Co-authored-by: Codex <codex@openai.com>
2026-10-11 12:05:37 +10:00
THEtheChadandGPT-6 Astra aec298c116 test(engine): LRC-LIB-LIBFOLDERS cover mixed Windows separators
Exercise both separator directions for folder and individual-file imports.
Verify duplicate detection, stable photo IDs, added/deleted file detection,
and reuse of a confirmed scan when the folder spelling changes.

Co-Authored-By: GPT-6 Astra <noreply@openai.com>
2026-10-11 01:59:03 +00:00
THEtheChadandGPT-6 Astra dac0d4c6e2 test(engine): LRC-LIB-LIBFOLDERS normalize sync fixture paths
Rebuild fixture path components with native separators so expected paths
match directory scans on Windows, including files that have been removed.
This is a prerequisite for Windows validation and overlaps the path-helper
fix in upstream PR #660; it can be dropped once that change lands.

Co-Authored-By: GPT-6 Astra <noreply@openai.com>
2026-10-11 01:59:03 +00:00
skylar taylor-barrick 0ba118de92 Merge pull request #869 from skylartaylor/codex/ui-suite-integration-20261010
Add shared docking while preserving photo tools and catalog drops
2026-10-10 19:57:59 -06:00
goujichengandDeepSeek V3.2 bc2cbf41db LR-IMP-PREVIEW-READ: an unedited raw's grid thumbnail is its embedded JPEG
The grid already showed the camera's embedded preview first, then queued a render of the whole raw
to replace it. For a 512 px thumbnail that render decodes 50 of a 56 MB Fuji RAF's bytes for a
picture the 4 416 × 2 944 embedded JPEG already covers — 45 s a photo on the 1.2 MB/s share this was
measured on, 8.3 GB of traffic for a 149-photo folder, and a queue that delayed the render the user
was actually waiting for (measured: the first loupe render of a cold photo finished 174 s after the
click, most of it spent behind thumbnails). Idle for a minute afterwards, the same folder read 12
previews (26.9 MB) and decoded zero raws for thumbnails, against 638 MB of whole-file reads before.

- `Session::embedded_thumb_is_final` answers whether a photo is an unedited raw whose camera JPEG the
  viewer is showing — the same `has_import_look` gate the preview path uses.
- `grid::skips_the_real_render` is the decision (unit-tested): a cached render as stand-in, an edited
  photo and a raw without an embedded JPEG all still render, because their thumbnail must show the
  pipeline's output rather than the camera's.
- `Renderer::remember_embedded_thumb` records the quick render's key and the bucket, and
  `thumb_quick_is_final` / `thumb_quick_pending` let the per-frame grid request stop at the embedded
  preview instead of rebuilding the render job (and its cache key) every frame.
- The thumbnail key still follows the settings hash, so editing a photo re-renders its thumbnail
  through the ordinary background path.

`docs/raw-preview-reads.md` and the `LR-IMP-PREVIEW-READ` parity row record the behaviour and the
numbers.

Co-Authored-By: DeepSeek V3.2 <noreply@deepseek.com>
2026-10-11 09:39:32 +08:00
robmdunnandClaude 77fcd81dde Merge main into jxl-export
ROADMAP.md: take main's restructured version; JPEG XL export is now
recorded in docs/file-format-parity.md and docs/gaps.md (gap 25).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-10 21:32:39 -04:00
skylar taylor-barrick a7e8f1cc26 UI.9: reconcile upstream before shared UI landing 2026-10-10 19:07:51 -06:00
PiMinusMaxandClaude Opus 5.5 d76a4121e6 LR-PROF-CAMERACOLOR: near-black pixels no longer turn white in the camera look (#820)
HueSat::apply restores luminance with before / after. Near black, where noise makes some channels
negative, the hue/saturation table can bring after close to 0, and the gain turned single pixels
white (isolated white dots in dark areas, most visible at fit). Luminance is now restored only if
the table kept at least 25 % of it; such colours keep their colour, like black and non-finite ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:32:34 +02:00
john01px2022andClaude Opus 5.5 32e78b352c LR-EXP-WATERMARK: the watermark preview fills the Export dialog's width
The preview was capped at 348 × 200 pt, so a portrait photo showed about
130 pt wide. It now spans the dialog for any photo shape. The cached 512 px
thumbnail still shows at once; a render at the preview's own pixel size
(in 128 px steps) then replaces it, so the wider preview stays sharp. The
web build, which has no worker thread, keeps the thumbnail only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:31:56 -07:00
john01px2022andClaude Opus 5.5 7d27cf8bfb LR-CROP-STRAIGHTEN: test the rotate pointer off all four crop corners
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:18:57 -07:00
john01px2022andClaude Opus 5.5 6807421f64 LR-CROP-STRAIGHTEN: the rotate pointer faces away from its side of the crop box
The crop tool's rotate pointer always bulged up, which only reads right
above the box. It now turns to bulge away from the nearest point of the box
outline: right beside the right edge, down below it, left beside the left
edge, diagonally off a corner, and following a box that is already rotated.
icons::paint_turned draws an icon turned about its centre; icons::paint is
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 17:09:44 -07:00
radialmonster f032d6e389 LR-PROF-CAMERACOLOR: read an untagged camera JPEG in the colour space the raw's EXIF states, for every make (#778)
A Sony body shot in Adobe RGB writes ColorSpace Uncalibrated with InteropIndex R03 in the raw's EXIF and leaves the
embedded JPEG untagged, so the look was fitted against the JPEG decoded as sRGB. The EXIF fallback now applies to
all makes (the Nikon maker note still wins); DNGs are skipped, since their previews come from the converter.
2026-10-10 20:06:50 -04:00
Brandon ThomasandClaude Opus 5.5 9e6c4c6fc9 Release prep: 0.6.0 and Linux riscv64 release build (#844)
- release.yml: new linux-riscv64 job (ported from GridCraft): cross-compiles on
  ubuntu-24.04 against ports.ubuntu.com riscv64 libs, packages a tar.gz with
  package.sh --formats tar, smoke-tests lightcraft-cli under QEMU. The release
  job needs it, so its tarball lands in the draft and SHA256SUMS.
- packaging/linux/package.sh: CROSS_ARCH/CROSS_TARGET/CROSS_COMPILE/EMULATOR
  support (target dir, cross strip, emulated --version).
- README Downloads and docs/releasing.md list the riscv64 tarball.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
v0.6.0
2026-10-10 19:38:10 -04:00
john01px2022andClaude Opus 5.5 6f44b33ca7 LR-EXP-WATERMARK: rotate the watermark in quarter turns (#827)
A watermark (text, horizontal or vertical, or a graphic) can be turned 0,
90, 180 or 270 degrees clockwise, like Lightroom Classic's rotate buttons.
It is sized before it is turned and placed and inset by the turned box; the
shadow still falls down and to the right. New watermark key `rotation`
(other values are errors); settings without it draw unturned. The Export
dialog gets a Rotate row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:18:57 -07:00
john01px2022andClaude Opus 5.5 ffd737ceab LR-EXP-WATERMARK: separate horizontal and vertical watermark insets (#827)
Watermark.inset becomes inset_x (from the left or right edge) and inset_y
(from the top or bottom edge), like Lightroom Classic's watermark editor.
The watermark keys are insetX and insetY; the old inset key still reads as
both, so saved presets and existing MCP calls keep working.

The Export dialog's Inset slider becomes Horizontal inset and Vertical
inset, each greyed out when the position is centred along its axis.
cargo fmt reflows WM_POSITIONS and its test from the previous commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:11:03 -07:00