Commit Graph
125 Commits
Author SHA1 Message Date
aiongg fa6f5b285b Integration: one LOOK_VERSION (12) and RENDER_CACHE_VERSION (69) bump for the merged camera-look changes 2026-10-22 02:42:38 +00:00
aiongg 70e9338085 Merge PR #1040: LR-IMP-FORMATS: decode Minolta MRW
docs/parity-checklist.md: header keeps the newer date; LR-IMP-FORMATS row keeps both sides' changes.
docs/raw-parity.md: header change note names both sides' changes.
docs/raw/coverage.tsv: merged cleanly; same rows as both sides, no duplicates (regenerated on the combined branch).
2026-10-22 02:42:05 +00:00
aiongg 04b099a4f5 Merge PR #1901: LR-EDIT-OPTICS-PROFILE: apply A7CR embedded distortion for corrected full-frame raws
crates/engine/src/camera_preview.rs: LOOK_VERSION keeps both history lines and the higher value.
crates/engine/src/media.rs: RENDER_CACHE_VERSION keeps the higher value.
docs/whats-new.md: both 2026-10-14 entries under one heading.
2026-10-22 02:40:09 +00:00
aiongg bb930900af Merge PR #1545: LR-RAW-DNG: preserve lens corrections in the existing DNG tone-fit proxy
crates/engine/src/camera_preview.rs: LOOK_VERSION keeps both history lines and the higher value.
crates/engine/src/media.rs: RENDER_CACHE_VERSION keeps the higher value.
2026-10-22 02:38:07 +00:00
aiongg 53ce89fc11 Integration: #1616 move the overcast-scene doc comment back to its test 2026-10-22 02:37:51 +00:00
aiongg 8bd9a3af1e Merge PR #1616: LR-PROF-CAMERACOLOR: near-black frames get a tone curve when no colour look fits (#1587)
crates/engine/src/camera_preview.rs: LOOK_VERSION keeps the higher value; fit_tone_only_pairs (from #1616) takes the HighlightCheck of #699 from fit_tone_only_on, and fit_dark_tone passes its frame's (empty, as no JPEG pixel reaches 0.85) check.
crates/engine/src/media.rs: RENDER_CACHE_VERSION keeps the higher value.
docs/parity-checklist.md: LR-PROF-CAMERACOLOR row keeps both sides' changes.
2026-10-22 02:37:46 +00:00
aiongg cf804ee9f6 Merge PR #699: LR-PROF-CAMERACOLOR: fit the tone curve of low-contrast scenes (range limit 1.5 to 1.2)
crates/engine/src/camera_preview.rs: LOOK_VERSION keeps both history lines and the higher value.
crates/engine/src/media.rs: RENDER_CACHE_VERSION keeps the higher value.
2026-10-22 02:37:09 +00:00
Andrew FrahnandClaude Sonnet 5.5 5e1bac1264 Merge upstream/main into pr/longtail-raws
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 09:58:17 +11: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
radialmonster cc75f0b765 LR-RAW-DNG: preserve lens corrections in the existing DNG tone-fit proxy 2026-10-15 09:03:26 -04:00
Alex ChambersandClaude Opus 5.5 aecdb99a7a LR-PROF-CAMERACOLOR: fit tone for near-black NEFs (#1587)
Use luminance pairs after the existing camera looks fail their colour-pair
minimum. Keep the source colour, exclude clipped pixels from training, and
check held-out luminance and each clipped pixel before accepting the curve.

The darkest supplied D610 sample changes from +2.81 to -0.09 stops at the
median. The other 15 renders are byte-identical. Add synthetic coverage for
source-colour precedence, independent holdout and invalid or clipped input.
Bump LOOK_VERSION to 10 and RENDER_CACHE_VERSION to 67 after checking open PRs.

Engine tests pass. Workspace tests pass with only the known #1457 overlay
test excluded. Formatting, Clippy, HEIC, parity, layers, assets and WASM pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:27:28 +02:00
Alex ChambersandClaude Opus 5.5 1be3b3d743 LR-EDIT-OPTICS-PROFILE: apply A7CR embedded distortion for corrected full-frame raws
Use the corrected-radius table convention for full-frame Bayer ILCE-7CR files with distortion Auto or forced Auto. Preserve Off files, unvalidated modes and the existing ILCE-7RM4A conversion.

Add mapping, setting, scope, padding, orientation, resizing and DNG checks. Record camera-JPEG geometry and color measurements, including the remaining wide-end edge residual. Refresh stored lens data with LOOK_VERSION 11 and rendered results with RENDER_CACHE_VERSION 68.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 10:21:19 +02:00
Alex ChambersandClaude Opus 5.5 d5a6d6c509 LR-PROF-CAMERACOLOR: fit the tone curve of low-contrast scenes (range limit 1.5 to 1.2)
Both tone fits refused a curve when the brightest 1/32 of the training
pairs was less than 1.5x the darkest 1/32, a hard cliff before any
acceptance gate: a hazy ILCE-7RM4 burst (issue #631) opened with the
neutral fallback on frames just under it (DSC01630: range 1.489, dE76 vs
the camera JPEG 23.8) and with a camera look on the frame just over it.
MIN_TONE_RANGE = 1.2 still refuses nearly uniform pairs.

A curve under the old 1.5 must also keep the bright areas (camera JPEG
luminance 0.85 and up), which the fit and the held-out gates leave out, no
further from the camera JPEG than the neutral fallback (highlights_hold,
full and partial looks): fitted to a narrow range it extrapolates them, and
reviews found synthetic frames whose accepted curve rendered a 0.93 sky at
0.28 to 0.61. The bright pixels come from the proxies before any training
filter, and for DRO photos the curve is checked lowered as it will be
used, inside the search. The tone curve of a black-and-white camera JPEG
(#577) comes from the same fit, so it gets the same check, by luminance as
its own gates compare: a synthetic frame's 0.93 sky rendered at 0.28
without it. DSC01630 (DRO Auto): look accepted, dE76 1.94. Every other
file of a 309-file sweep (135 public Sony) renders pixel-identical, also
with the camera JPEGs made grey. RENDER_CACHE_VERSION 63, LOOK_VERSION 6
(smart previews refit).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 10:21:18 +02:00
Brandon ThomasandClaude Opus 5.5 e44e7157fc Batch 38: rustfmt and parity summary after the merges
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:58:56 -04:00
Brandon Thomas d5b2cd1474 Merge PR #1595 (rebased)
# Conflicts:
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-15 01:48:05 -04:00
Brandon Thomas 97959610be Merge PR #1592 (rebased)
# Conflicts:
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-15 01:47:46 -04:00
Brandon Thomas 99eba2e069 Merge PR #1586 (rebased)
# Conflicts:
#	crates/engine/src/camera_preview.rs
#	crates/engine/src/files.rs
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-15 01:45:53 -04:00
Brandon ThomasandClaude Opus 5.5 26e43cd691 Merge PR #1595
Stacked on rb/1592: LOOK_VERSION 8 -> 9; the PR's corpus-profile helper is the base's corpus_uses_the_bundled_profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:42:11 -04:00
Brandon ThomasandClaude Opus 5.5 480e96c030 Merge PR #1592
Stacked on rb/1586: LOOK_VERSION 7 -> 8; README lists the base's ILCA-99M2 profile too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:42:11 -04:00
Brandon ThomasandClaude Opus 5.5 2756414f46 Merge PR #1586
Resolved against rb-base-36: LOOK_VERSION 6 -> 7; starting_colour_tags passes no lens (merge frames arrive without it).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:42:11 -04:00
Brandon Thomas 51a784cd95 Merge PR #1475 (rebased)
# Conflicts:
#	crates/raw/examples/rawinfo.rs
#	crates/raw/src/lib.rs
#	crates/raw/src/vendor/arw.rs
#	crates/raw/src/vendor/erf.rs
#	crates/raw/src/vendor/mef.rs
#	crates/raw/src/vendor/nef.rs
#	crates/raw/tests/lossy_dng.rs
#	crates/raw/tests/robust.rs
2026-10-15 01:13:36 -04:00
Brandon Thomas cf0002b484 Merge PR #1471 (rebased)
# Conflicts:
#	docs/parity-checklist.md
2026-10-15 01:10:17 -04:00
Brandon Thomas 66a0cd826c Merge PR #1475
# Conflicts:
#	crates/merge/src/output.rs
#	crates/raw/src/vendor/nef.rs
2026-10-15 01:05:31 -04:00
Brandon Thomas 7f7401713a Merge PR #1471
# Conflicts:
#	crates/engine/src/camera_preview.rs
#	crates/engine/src/merge.rs
#	crates/merge/src/frame.rs
#	crates/merge/src/hdr.rs
#	docs/parity-checklist.md
2026-10-15 00:56:52 -04:00
Brandon Thomas 9ca113defa Merge PR #1135 (rebased)
# Conflicts:
#	xtask/src/main.rs
2026-10-15 00:53:45 -04:00
Brandon Thomas 0af2d36442 Merge PR #1320 (rebased) 2026-10-15 00:52:32 -04:00
Brandon Thomas cab59313fd Merge PR #1316 (rebased) 2026-10-15 00:52:32 -04:00
Brandon Thomas 372f39f8f7 Merge PR #1320
# Conflicts:
#	crates/engine/src/files.rs
#	crates/raw/src/demosaic/ahd.rs
2026-10-15 00:38:16 -04:00
Brandon Thomas af8843bf01 Merge PR #1316
# Conflicts:
#	crates/engine/src/camera_preview.rs
#	crates/engine/src/media.rs
2026-10-15 00:33:33 -04:00
Brandon Thomas f613aeba59 Merge PR #1176
# Conflicts:
#	crates/raw/src/vendor/arw.rs
#	docs/parity-checklist.md
#	docs/sony-lens-corrections.md
2026-10-14 23:54:06 -04:00
Brandon Thomas 9ca3cd0926 Merge PR #1135
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	README.md
#	crates/raw/Cargo.toml
#	crates/ui-egui/src/theme.rs
#	xtask/src/main.rs
2026-10-14 23:23:18 -04:00
Brandon Thomas 5b3856ba2b Merge PR #1613
# Conflicts:
#	docs/parity-checklist.md
2026-10-14 22:33:13 -04:00
Brandon Thomas 75e0a6dd2a Merge PR #1835 2026-10-14 22:32:07 -04:00
Brandon Thomas e2f6555220 Merge PR #1750 2026-10-14 22:29:42 -04:00
Brandon Thomas aba04aaf5c Merge PR #1087
# Conflicts:
#	ROADMAP.md
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/raw-parity.md
#	docs/raw/coverage.tsv
#	docs/raw/evidence.tsv
#	xtask/src/main.rs
2026-10-14 21:59:31 -04:00
Brandon Thomas 260a460c11 Merge PR #1019
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-14 21:57:59 -04:00
MyrarcandOpenAI Codex cebaade144 CI-RUST195: keep strict Clippy clean on Rust 1.95
Move nested conditions into match guards and simplify equivalent Boolean
expressions without changing validation or short-circuit behavior. Keep
the explicit permitted Testkit dev-dependency arm in the layer checker.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
2026-10-15 08:50:22 +07:00
Claude 05352e18dd Merge storytold/lightcraft main into LR-MERGE-HDR (white balance)
Brings in batch 35 / v0.8.0. Code merged cleanly; conflicts only in docs: the LR-MERGE-HDR row keeps main's
lens-correction text plus this branch's white-balance item, and this branch's What's New entry moves to the
2026-10-14 section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gRtdWF1E9358FfzhzYqCS
2026-10-14 16:22:53 +00:00
Marco Arnulfo 17e05759b4 DNG export and Convert / Copy as DNG write the colour a raw without matrices opens with (fixes #1745) 2026-10-14 18:08:53 +02:00
Michael Anderson 975b08c334 LR-PROF-CAMERACOLOR: Add a bundled Nikon Z 6II camera profile
Fitted with lightcraft-cli calibrate to 296 of my own Z 6II photos.
2026-10-14 07:32:56 -05:00
Michael Anderson 2bc2f60277 LR-PROF-CAMERACOLOR: Add a bundled Nikon Z 8 camera profile
Fitted with lightcraft-cli calibrate to 261 of my own Z 8 photos.
2026-10-14 07:32:56 -05:00
Michael Anderson c854e172e4 LR-PROF-CAMERACOLOR: Match the camera look against lens-corrected JPEGs
The fit compared the uncorrected raw with the corrected JPEG. It now warps the raw with the file's own lens correction when that lines up better.
2026-10-14 07:32:47 -05:00
Andrew FrahnandClaude Opus 5.5 b45ac5e659 Merge upstream/main into pr/longtail-raws
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 19:22:33 +11:00
Andrew FrahnandClaude Opus 5.5 50cb797872 Merge upstream/main into pr/raw-erf
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 18:48:38 +11:00
Alex ChambersandClaude Opus 5.5 ac677a2624 LR-EDIT-OPTICS-PROFILE: decode Sony shading, CA and distortion tables with settings and provenance; apply nothing new
Sony ARWs record shading, lateral chromatic aberration and distortion as a camera setting plus a radial
table in the raw image IFD (0x7031-0x7037), with copies in the encrypted SR2SubIFD (0x797c-0x7982).
They are now decoded for every body that records them and carried through RawInfo and RawImage as
`lens_metadata.sony` (types in crates/raw/src/lens_metadata.rs, decoder in
crates/raw/src/vendor/arw_lens.rs):

- Raw-IFD fields are the ones the TIFF reader parsed, which is what the image itself uses. A scan of
  the directory adds diagnostics only: repeated tags, and why an entry the reader skipped was dropped
  (values outside the file, an unknown type, past the reader's limits). SR2SubIFD fields are read
  from their first entry. Only the exact layouts are accepted: SHORT[1] or non-negative SSHORT[1]
  settings, SSHORT[17] headed by 16 for shading and distortion, SSHORT[33] headed by 32 for CA.
  Nothing is allocated from a count in the file.
- The raw IFD's copy wins. The SR2SubIFD copy fills in only for a tag the raw IFD lacks, never for a
  malformed one, and the two copies' agreement is recorded.
- Settings keep their number and their documented meaning, Unknown(value) otherwise (never Off).
- Framing evidence (stored frame, Sony and default crops, reference rectangle, coding, 3:2) and a
  per-component status. Only Applied components become opcodes.

Applied corrections are unchanged: the ILCE-7RM4A distortion conversion receives exactly the table it
received before, and no other body or component gains a correction. The ILCE-7CR distortion misses its
camera JPEG at 24 mm, and shading and CA semantics are not validated on any body; see
docs/sony-lens-corrections.md.

Locating the SR2SubIFD, now done for every ARW that has one, selects the SR2Private offset, length and
key with the TIFF reader's own rules, which lightcraft-tiff now exposes and builds its reader on
(directory_entries, entry_span, ParseOptions::budget_for, decode_value). Only each field's first value
is decoded, so the directory's other entries cost no memory sized by the file: a 16 MiB file whose
SR2Private holds eight fields aliasing it peaks at 37 kB. DirectoryEntries keeps its layout private,
and its positions() iterator uses checked arithmetic.

Tests: synthetic decoder tests; a differential test of the SR2Private selection against the TIFF
reader's in both byte orders (0 to 8,193 filler entries, unreadable and unusual first occurrences of
each field, a used-up value budget); a dhat peak-heap test; public-corpus checks against the values
ExifTool prints, with pinned and anchored SHA-256s (LIGHTCRAFT_CORPUS_REQUIRED=1 makes absent files
fail); and an opt-in local inventory check (crates/raw/tests/sony_lens_inventory.rs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:19:21 +02:00
Andrew FrahnandClaude Opus 5.5 6696a92005 Merge upstream/main into pr/longtail-raws
Docs conflicts resolved on upstream's text; MRW edits reapplied with
coverage re-measured by docs/raw/coverage.py (243 verified, 946
unverified, 221 preview). Drops stale duplicate rows upstream's docs
carried in raw-parity.md and gaps.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 08:07:58 +11:00
Andrew FrahnandClaude Opus 5.5 a3071fe0f3 Merge upstream/main into pr/raw-erf
Docs conflicts resolved on upstream's newer state (Leica Q3, Hasselblad Lunar);
ERF counts recomputed with docs/raw/coverage.py: 240 verified, 229 preview.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 07:55:22 +11:00
PiMinusMax d64a1ecc93 LR-PROF-CAMERACOLOR: bundled Sony ILCA-99M2 camera profile
Fitted with `lightcraft-cli calibrate` to 144 usable ILCA-99M2 ARWs (of
150, seven shooting days, Standard creative style, DRO Auto) and their
in-camera JPEGs; aggregate colour statistics only.

On 30 withheld photos (profile fitted to the other 120) mean dE76 against
the camera JPEG goes 5.11 -> 4.87; 25 of 30 improve, the worst
regression is 0.24. All 150 photos stay accepted. The public raw.pixls.us
ILCA-99M2 file, not used for fitting, stays accepted (5.57 -> 5.73).

A corpus test checks that this public sample's fit keeps exactly the
built-in profile's matrix and table; the ILCE-7CR test now shares its
body. LOOK_VERSION 5 -> 6, as the profile changes the fit of this model.
2026-10-13 17:33:23 +02:00
dev-null-undefinedandClaude 14e0d12813 LR-IMP-PREVIEW-READ: stand-ins and raw thumbnails decode the smallest embedded JPEG that covers them
`embedded_preview_srgb` (the loupe stand-in and the grid thumbnail of an unedited raw) decoded the
largest embedded JPEG whatever the size asked for: a 512 px thumbnail of a Sony A7R VI ARW decoded
its 9984 x 6656 JPEG (5.6 MB) although the file holds a 1616 x 1080 one (0.3 MB).

`lightcraft_raw::embedded_preview_covering(bytes, min_edge)` returns the smallest of a TIFF-based
raw's JPEGs whose long edge is at least `min_edge` and that is a copy of the largest one: aspect
ratio within 1 % (not a letterboxed thumbnail of another shape) and the same number of components
(not the grey semantic masks of an iPhone ProRAW DNG); else the largest, as `embedded_preview`.
The colour-space handling stays in `decode_raw_preview` (a `covering` argument); an unsupported
raw's editing source and the camera-look fit keep the largest JPEG, so a source never depends on
its size level.

On 120 raws of every make in the corpus at 256 / 512 / 1600 px: wherever the largest JPEG is still
chosen the output is identical byte for byte; where a smaller one is (Sony, Nikon, Panasonic,
Adobe DNG) orientation matches, the size is equal or 1-2 px off, mean difference <= 4.7 / 255.

- Rebased onto #1020: its plan route (`preview_window` -> `planned_preview`) now takes the box size and picks
  with `embedded_preview_covering` too, so a TIFF raw read through the sparse plan gets the whole file's JPEG.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-13 14:33:52 +02:00
dev-null-undefinedandClaude Opus 5.5 6467d54325 Perf: camera-look colour step 1.5-1.9x faster on full-size raws, same pixels
The hue/saturation table of a fitted camera look (ILCE-7RM4A, APS-C ILCE-7RM6, ...) ran
HsvTable::apply pixel by pixel: branches on the data (largest channel, hue sector),
saturating float-to-usize casts and bounds-checked table reads, ~550 instructions and 1.2
branch misses per pixel. CameraColourModel::apply now runs it 16 pixels at a time
(HueSat::apply_lanes -> HsvTable::apply_lanes, structure of arrays): per pixel the same IEEE
operations in the same order, with the branches turned into selects and the table indices
computed as exact f32 integers, so the compiler vectorises everything but the table reads,
powf and the rare rem_euclid, which run lane by lane. DNG profile tables and the other colour
models keep the per-pixel path.

Measured on a Core Ultra 9 185H P-core (busy machine, min of N):
- HsvTable alone, 72x5x5 fitted-look-shaped table, random colours, one thread:
  243 -> 106 cycles (57 -> 26 ns) per pixel.
- Colour stage of a full-size load, one thread: 60 MP ILCE-7RM4A 3.80 -> 1.99 s,
  26 MP APS-C ILCE-7RM6 HQ 1.88 -> 0.98 s; 4 CPUs: 1.02 -> 0.67 s, 0.56 -> 0.30 s.

Exactness: new tests compare the lanes with the one-by-one path bit for bit (to_bits) on tens
of thousands of colours (every combination of zero, -0, tiny, negative, around 1, huge, NaN and
+-inf components; grey; hues at the 0/360 degree wrap; near-black noise in the restore's blend)
for fitted, value-scaled, 2D, many-turn and degenerate tables, 16 and 5 lanes, and on an image
whose rows aren't a whole number of lanes. Stage fingerprints (decode, AHD, 2560 px and
full-size loads) of 7 Sony raws are identical to origin/main.

Sources: own design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 12:03:21 +02:00