Commit Graph

1166 Commits

Author SHA1 Message Date
Brandon Thomas 3a06aab5bc Merge PR #584 2026-10-09 20:36:11 -04:00
Brandon Thomas 6168511f66 Merge PR #574 2026-10-09 20:36:11 -04:00
Brandon Thomas 8329b7be0a Merge PR #608 2026-10-09 20:36:11 -04:00
Brandon Thomas 21b58f4653 Merge PR #562 2026-10-09 20:36:11 -04:00
Brandon Thomas 9a694a4d41 Merge PR #572 2026-10-09 20:36:10 -04:00
Brandon Thomas 6203fa36a1 Merge PR #557 2026-10-09 20:36:10 -04:00
Brandon Thomas 514e828508 Merge PR #540 2026-10-09 20:36:10 -04:00
Brandon Thomas bde7ff911e Merge PR #530 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 d23ff731ee Merge PR #502 2026-10-09 20:36:09 -04:00
Brandon Thomas 8a06fa0e5a Merge PR #500 2026-10-09 20:36:09 -04:00
Brandon Thomas e87863d48d Merge PR #549 2026-10-09 20:36:08 -04:00
Brandon Thomas 3726520504 Merge PR #526
# Conflicts:
#	ROADMAP.md
2026-10-09 20:36:08 -04:00
Brandon Thomas bd32d82a1f Merge PR #524
# Conflicts:
#	docs/parity.md
2026-10-09 20:36:07 -04:00
Brandon Thomas f41a6357eb Merge PR #600
# Conflicts:
#	crates/engine/src/media.rs
2026-10-09 20:36:07 -04:00
Brandon Thomas a1993c7093 Merge PR #615
# Conflicts:
#	docs/parity.md
2026-10-09 20:35:30 -04:00
Brandon Thomas edb3f29351 Merge PR #603
# Conflicts:
#	docs/parity.md
2026-10-09 20:35:29 -04:00
Brandon Thomas 414332a74d Merge PR #531 2026-10-09 20:34:54 -04:00
Brandon Thomas 1d3b69fe63 Merge PR #513 2026-10-09 20:34:54 -04:00
Brandon Thomas 89dc78b3bf Merge PR #508 2026-10-09 20:34:54 -04:00
Exalted5373 b5440f167f LR-IMP-CAMERA-COVERAGE: CR2 black level from the masked columns only
Canon's SensorInfo left border is not where light starts: on every corpus
body 10-36 columns left of it already hold image (EOS 6D: masked columns
0-70, border 84), and the black level was averaged over all of them. The
6D read 2591 instead of 2047 (4 % of the range), so CR2s rendered dark with
crushed shadows; 40D +141, 5DS R +131, 5D Mark II +73. The masked run is
now measured from the data: columns whose mean stays within 1/256 of the
range of the leftmost columns', minus a two-column margin.

Against Lightroom Classic (EOS 6D still life, 2000 px, ΔE00): base 7.63 ->
5.23 (p95 24.7 -> 11.3); mean over 86 edit variants abs 9.13 -> 6.19,
effect 3.09 -> 2.75.
RENDER_CACHE_VERSION 23.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:04:31 -07:00
sanyamsingh001 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
Claude cf9d8f7ebb
M11: name Nikon High Efficiency NEFs instead of blaming a missing table (#193)
High Efficiency NEFs (HE / HE★, Z 8, Z 9, Z 6III, Z f) keep compression
34713 but carry a JPEG XS-based codestream (SOC + CAP, FF10 FF50) and no
maker-note 0x0096 table. They fell through to "Nikon compressed NEF
without a linearization table", so the Preview only notice gave Z f users
no hint why their raw wasn't decoded or that Lossless compressed NEFs work.

Detect the codestream before asking for the table and report "Nikon High
Efficiency NEF" with the workaround. Add a synthetic regression test, CC0
Z f HE + Lossless samples to the corpus (raw.pixls.us) with a corpus test,
and list HE NEF among the format gaps in parity.md and ROADMAP.md.

No decoder: the format has no public specification and the existing
decoders (LibRaw, rawler) are LGPL and derived from Nikon's binaries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011bbmJTxYJyYqKfNH8uXRC6
2026-10-09 16:21:11 -06:00
radialmonster 37d3621505 LR-IMP-FORMATS: read the two-field 12-bit ORF layout of old Olympus compacts
C5060WZ, C7070WZ, SP-510UZ, SP-550UZ, SP-565UZ and SP-570UZ files say
uncompressed 12-bit with many strips whose byte counts sum to exactly
width x height x 1.5. main refused them because the 12-bit branch wanted a
single strip, so they fell to "Olympus compressed ORF" and opened
preview-only. The samples are packed MSB-first, the strips hold two fields
(even output rows, then odd ones) with one gap at the seam, and the last row
of the second field sits right after the last strip. Accepted only when all of
that holds exactly. CFA comes from the Exif tag, white balance from maker-note
entries 0x1017/0x1018, black 0. RENDER_CACHE_VERSION 27 (adjust at merge).
2026-10-09 17:23:50 -04:00
Garrett Gonzalez-Rivas 4470d87dcb Nix: bump craft-fonts to 8dcdacd (the sane revision the release workflow uses) 2026-10-09 15:37:15 -04:00
Alex Chambers dc37496da4 LR-PROF-CAMERACOLOR: bundled Sony ILCE-7CR camera profile
Fitted with `lightcraft-cli calibrate` to 125 usable ILCE-7CR ARWs (of 131,
September 2025 to September 2026, Standard creative style) and their
in-camera JPEGs; aggregate colour statistics only.

Without it, 8 of the 131 photos fail the fit gates and open with the
neutral matrix (dE76 6-26 against the camera JPEG). On 26 withheld photos
(profile fitted to the other 105) mean dE76 goes 4.07 -> 3.29 and both
withheld rejections are accepted (26.0 -> 6.1, 6.2 -> 5.5); the 24
withheld photos whose own fit was accepted are about unchanged (12
improve, mean 3.06 -> 3.08, worst regression 1.8). With the final profile
all 131 are accepted. The nine public raw.pixls.us ILCE-7CR codings stay
accepted (mean 1.59 -> 1.99).

A corpus test checks the public lossless-L sample's fit keeps exactly the
built-in profile's matrix and table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:52:47 +02:00
Alex Chambers f48122992b LR-IMP-CAMERA-COVERAGE: ILCE-7CR test pins the black level of Bayer codings only
The YCbCr M coding's pedestal is corrected separately (#535, item 3), so
this test no longer depends on which change lands first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:50:32 +02:00
Alex Chambers ea080e58bd LR-IMP-CAMERA-COVERAGE: Sony ILCE-7CR samples in the corpus
Three CC0 raw.pixls.us files of one ILCE-7CR (61 MP) scene: lossless
compressed L and M (subsampled YCbCr) and compressed ARW2. A raw corpus
test pins model, colour-filter layout, black level, white level, as-shot
gains and default crop, and checks that the lossless and compressed
mosaics agree inside the crop (green block correlation 0.9976). An engine
corpus test checks each gets a fitted camera look, not the neutral
fallback. All nine public codings decode and fit (mean dE76 1.59 against
their camera JPEGs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:50:32 +02:00
Hendrik 6831983a4e DOCS-CODEX: document Codex MCP setup and external libraries 2026-10-09 20:48:26 +02: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
MarekSpodBiedry e529e6f8f4 Use the system clock in the CLI and headless MCP sessions (#554) 2026-10-09 19:29:39 +02:00
Alex Chambers 5bbb5214f4 LR-BEHAV-BG-TASKS: demo scenes: a rayon worker renders a scene alone, never in parallel (deadlock)
Demo scene pixels were generated inside `OnceLock::get_or_init` on the
caller's thread, and the render runs on rayon. A rayon worker that waits
for rows another worker took runs queued jobs on top of itself; when one
of those asked for the same scene, it waited in `get_or_init` on the
generation further down its own stack, and every other request for that
scene waited behind it, forever. The faces scan's pool threads hit it (two
tests_face_recognize tests sat in `Once::wait` for 30 minutes); any rayon
worker loading demo photos could.

Each (scene, size) slot now has one generation at a time: the first caller
renders, with no lock held, and later callers wait on a condvar for that
generation's outcome. The render never needs a thread that waits:
- a rayon worker (the faces scan, merges) renders on its own thread alone,
  without rayon (`Scene::render_fit_serial`, the same pixels), so it never
  runs other jobs mid-render, and the work stays within its pool and that
  pool's limits (scan pace, LIGHTCRAFT_FACE_THREADS);
- other callers (the render workers, plain threads) render in parallel on a
  pool of rayon's default size (RAYON_NUM_THREADS, else the available
  parallelism), whose threads only render; where it can't start, they
  render alone too (no rayon, so no deadlock). Generating a scene never
  touches the global rayon pool (asking its size would start it, which
  panics where its threads can't start).
The scan's first render of a demo scene now takes 1 to 2.3 s on one
thread instead of 0.5 to 1.3 s on its light pace's two (M3 Max, 2560 px
preview source); interactive loads are unchanged.
A generation number gives each waiter the outcome of the generation it
waited for, even when a retry starts first. A render that panics is an
error for its callers (`scene_pixels` returns a Result) and the next
request tries again. No duplicates, no unbounded threads.

Tests (each waits with a timeout, so a deadlock fails instead of hanging):
rayon workers keep asking a 4-thread pool for a scene while it is generated
(24 replies counted, at least 4 overlapping; times out at 120 s on the
OnceLock code); a scene is rendered once however many ask (the first
version of this fix rendered 5 copies at once); a rayon worker renders
alone on its own thread; callers wait for the generation running; a failed
generation is an error and the next request retries; a retry never changes
the outcome waited for (state-level, and a racing retrier: 60 of 60
waiters got the retry's pixels on the previous version); in a process
whose global pool failed to start, a scene is still generated; the serial
render is the parallel one, pixel for pixel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 18:52:10 +02:00
Brandon Thomas 968646c059 LR-IMP-FORMATS: render cache version 23 (interleaved DNG 1.7 rasters render differently)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:34:53 -04:00
Brandon Thomas af35fa1bd0 Merge origin/main into #513 (parity row keeps main's Hasselblad/SRW notes)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:34:53 -04:00
Brandon Thomas 88ea1a804b
Merge pull request #553 from storytold/claude/integrate-batch-20
Integrate #464, #273
2026-10-09 12:28:58 -04:00
Jason Baldwin 13e3406829 Merge origin/main into #540 (relative-WB format list: SRW from main joins the shared helper) 2026-10-09 18:12:44 +02:00
hxw 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 Thomas 1727477382 Merge PR #464 2026-10-09 12:03:42 -04:00
Brandon Thomas 03b3d606ce
Merge pull request #546 from storytold/claude/integrate-batch-19
Integrate #474, #448, #447, #499, #459
2026-10-09 12:02:17 -04:00
Brandon Thomas de087c0c6f Merge remote-tracking branch 'origin/main' into claude/integrate-batch-19 2026-10-09 12:02:10 -04:00
Brandon Thomas da6cbcf968
Merge pull request #545 from storytold/claude/integrate-batch-18
Integrate #478, #368, #460, #449, #451, #468
2026-10-09 11:56:38 -04:00
Brandon Thomas 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
Jason Baldwin 29b3f35136 LRC-LIB-CATALOG-IMPORT: read Lightroom's Custom white balance by its as-shot shift on relative-WB raws (#510)
A Custom white balance from a Lightroom catalog or XMP sidecar was taken as absolute Kelvin for every
raw. Raws LightCraft develops relative to their as-shot look (ARW, NEF, RW2, RAF, CR3, CR2, PEF; 6500 K
means as shot) then read a small tweak as a large blue shift: ΔE 22 against Lightroom's export on the
photos of issue #510.

The crs mapper now takes a `Target` (preset, rendered, raw with a measured illuminant, relative-WB raw)
instead of a bool. For relative-WB raws, and rendered files with only `Temperature`, a Kelvin value is
converted to the same mired shift from the packet's `AsShotTemperature` / `AsShotTint`. Without that
reference (Lightroom catalogs keep none for Custom photos) the photo stays As Shot and the import
report lists `Temperature, Tint` as not carried over. Import, sidecar read and catalog import decide
the target the same way through `lightcraft_catalog::relative_wb_format`.

Tests: shift from the issue's numbers (3650 → 3578 K lands at ~6275 K), the As Shot fallback with its
report entry, target selection per file, and the catalog mapper's Custom-WB case.
2026-10-09 17:48:05 +02:00
Brandon Thomas 38431cb4db Merge PR #459
# Conflicts:
#	crates/engine/src/import.rs
#	crates/mcp/src/headless.rs
#	crates/raw/src/lib.rs
#	docs/parity.md
#	xtask/src/main.rs
2026-10-09 11:38:44 -04:00
Brandon Thomas abe4c5fe1b Merge PR #499 2026-10-09 11:37:31 -04:00
Brandon Thomas c6745bc6f7 Merge PR #447
# Conflicts:
#	docs/parity.md
2026-10-09 11:37:19 -04:00
Brandon Thomas 093c948f8b Merge PR #448 2026-10-09 11:36:52 -04:00