Commit Graph

64 Commits

Author SHA1 Message Date
Brandon Thomas eca6c9e2e2 docs: README — RAW formats and XMP interop status
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:08:10 -04:00
Brandon Thomas 36e80900bb docs: AGENTS.md — merge agent branches one at a time with CI in between
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:08:02 -04:00
Brandon Thomas 7d421dc3d3 M3.8: fix merge — unsupported-raw preview probe carries embedded XMP; AGENTS.md per-agent ports/scratch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:07:51 -04:00
Brandon Thomas 4dd57efcac Merge branch 'worktree-agent-af78b5603e6882a3f' 2026-10-01 01:06:29 -04:00
Brandon Thomas 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 Thomas b6c9f66857 M10.8: keep lc:settings JSON readable in sidecars (escape only <, >, & in element content)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 01:04:00 -04:00
Brandon Thomas 07359a735e M3.8: embedded previews for every raw container + engine fallback; raw corpus
- embedded_preview: CR3 PRVW/THMB boxes (plus RAF, RW2, ORF, PEF from the
  format commits); stops at the first valid box of each kind
- engine: raw variants that report Unsupported are probed and shown from
  their embedded JPEG (orientation from the JPEG or the raw), not an error
- crates/raw/tests/corpus.rs: every corpus/raw file is recognised, has a
  JPEG preview (DNG optional) and decodes or is a known-unsupported
  variant; prints decode timings
- xtask corpus --download: 37 CC0 raw.pixls.us samples (matched by SHA-256)
- ROADMAP/crate docs: format coverage, NEF Huffman / RW2 format 4 /
  compressed ORF+RAF gaps, neutral colour-matrix fallback

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:40:09 -04:00
Brandon Thomas 8af27c11b1 M10.8: XMP sidecars — save/read metadata + develop settings, auto-write, crs: interchange
- crates/engine/src/sidecar.rs: <stem>.xmp (default) or <file>.xmp next to originals with rating,
  label, title, caption, copyright, creator, keywords, capture time/GPS, pick flag + full develop
  settings in lc:settings; atomic writes; read on import (sidecar wins for metadata, edits restored)
  and via photo.readMetadataFromFile (one undo step); raw/DNG embedded XMP used without a sidecar.
- Commands: photo.saveMetadataToFile (Cmd+S), photo.readMetadataFromFile, library.xmpPreferences
  {autoWrite, naming}, library.toggleAutoWriteXmp; prefs persisted in the library's prefs.json.
  Auto-write rewrites sidecars after each committed change (not mid-drag; undo/redo too).
- crates/engine/src/crs.rs: crs: develop fields (PV2012 light, WB abs/incremental, presence, HSL,
  B&W mix, parametric + point curves, colour grading, sharpening, NR, vignette, grain, optics,
  geometry, crop) → partial settings; documented in docs/xmp-interop.md.
- meta: write_xmp_lc for extra lc: properties; crs namespace canonicalised on read (never written).
- Tests: packet round trip, crs mapping with hand-written snippets, save → delete library →
  re-import restores edits, auto-write + prefs persistence, foreign sidecar, DNG-embedded XMP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:36:19 -04:00
Brandon Thomas daa32c3e4a Merge main into raw formats branch (nrw/raf/orf/rw2/pef/cr3 in the open dialog, nrw import)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:31:23 -04:00
Brandon Thomas f5b28bfca9 M11.3: Olympus ORF decoding (uncompressed)
16-bit LE words (12-bit-in-top-bits detected and shifted), 12-bit rows
of LE 32-bit words read MSB-first (black-box), maker-note
ImageProcessing crop, BlackLevel2, WB_RBLevels for old- and new-style
notes, CFA phase from the data (GRBG/RGGB), CameraSettings preview.
Compressed ORF reports Unsupported (documented gap).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:26:58 -04:00
Brandon Thomas 008e8d0f8c docs: README feature status (persistence, MCP libraries, export metadata/watermark)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:19:08 -04:00
Brandon Thomas 3f86346c5d M11.3: Pentax PEF decoding (uncompressed and Huffman)
Huffman table from maker note 0x0220 (codes/lengths, black-box layout),
T.81 difference categories, same-colour horizontal prediction with
per-row-parity vertical seeds; BlackPoint, WB levels, maker-note image
area or dark-column trimming. Unit round-trip test with our own table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:17:42 -04:00
Brandon Thomas 55c5c6f0c6 M1.4: persistent libraries for headless MCP (lightcraft-cli mcp --library DIR); bump render cache version
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:17:38 -04:00
Brandon Thomas fa77faeb6b Merge branch 'worktree-agent-a51e3311b37df5c4e' 2026-10-01 00:13:33 -04:00
Brandon Thomas 424e23e6e8 M10.6: text watermark on export (Inter, size relative to image, 9 anchors, opacity, shadow)
ab_glyph (Apache-2.0, pure Rust) rasterizes the already-attributed Inter font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:13:33 -04:00
Brandon Thomas d752f0e8db M11.3: Panasonic RW2 decoding (packed 12/14-bit)
Black-box derived layout: 0x4000-byte chunks stored rotated by 0x1ff8,
16-byte LE blocks read LSB-first (10x12-bit or 9x14-bit samples).
Sensor borders, CFA code, per-channel black, linearity limit, WB levels,
ISO; JpgFromRaw preview via a generic undefined-tag JPEG candidate.
The quantised raw format 4 reports Unsupported (documented gap).
Adds a rawdump debug example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:11:34 -04:00
Brandon Thomas bdf479baf6 M0.4: demo scenes — remove vertical banding in terrain shading (wide slope stencil, smooth light direction, depth warp, aerial perspective)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:09:30 -04:00
Brandon Thomas 1da0263d56 Merge main into persistence branch (keep JobPool renderer; wasm inline job timing via now_ms)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:09:07 -04:00
Brandon Thomas 759d3c7f8a M1.3: import (recursive folders, content-hash duplicates, add vs copy)
- engine::import: expand files/folders recursively (sorted; hidden entries
  and the library folder skipped), skip known paths, probe + hash in
  parallel (std:🧵:scope), skip duplicates by content hash (against
  the library and within the batch), add in place or copy into
  <library>/Originals/YYYY/YYYY-MM-DD/ with unique names; one undoable op.
- library.import {paths, mode: add|copy, album?} returns
  {imported, duplicates[{path, existing, reason}], failed, scanned}.
- probe_bytes records the content hash (SipHash-1-3 128) on every photo.
- system clock for import/edit times on native (Session::with_system_clock).
- app: command-line folders are expanded by the engine (re-importing the
  same folder is a no-op); example gen_photos writes procedural test JPEGs
  (never committed).
- Measured (200 procedural 2000 px JPEGs, M-series): import 2.25 s; reopen:
  library load 1.7 ms, control ready 0.12 s, first thumbnail 0.17 s,
  visible grid drawn 0.48 s (thumbnails from the disk cache).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:04:07 -04:00
Brandon Thomas 77ff166841 Merge branch 'worktree-agent-ac4c81fc23fc995ec' 2026-10-01 00:03:41 -04:00
Brandon Thomas c6954d5bd9 M10.5: export metadata policy (all / all except camera / copyright / none, remove location) with EXIF + XMP embedding
New lightcraft_meta::write_exif (IFD0 + Exif + GPS IFDs; round-trip tested).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:03:38 -04:00
Brandon Thomas 2d2bc2ad8f M0.11: web build (WASM)
apps/lightcraft-web runs the egui UI in the browser (eframe web, glow/WebGL2):
procedural demo library on load; in-memory imports via file picker
(Cmd+Shift+I) and drag-and-drop (MemStore + bytes-based engine hooks);
export goes through app.export and downloads in the browser; `?bench` logs
first-frame and slider latency. `cargo xtask web [--serve [port]] [--dev]`
builds with the matching wasm-bindgen CLI into <target>/web/; the web app is
part of the CI wasm check. Wasm fixes: lazy profiling Instant in pipeline,
web-time clocks in ui-egui (render timings were 0 on wasm). Docs: docs/web.md.
No persistence on web yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 00:01:18 -04:00
Brandon Thomas 3cc97c58d1 M5.1: cache-friendly Gaussian blur (no transposes; in-row horizontal passes, banded running-sum vertical passes) + per-stage pipeline profiling
3–10x faster blurs on a 3000x2400 plane (min-of-9; machine under load, see blur_bench example).
LIGHTCRAFT_PROFILE=1 now also times log-lum, base, clarity, texture, dehaze, masks and NR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:59:10 -04:00
Brandon Thomas 17057f7bbc docs: README (MCP, CLI, export, status, contributing), AGENTS.md (asset enforcement, crash recovery, testing/perf), screenshots re-captured with Inter
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:52:34 -04:00
Brandon Thomas f0ffa11333 M0.1: enforce the asset rule in CI (cargo xtask assets); replace Adobe-published Source Sans 3 with Inter
Every image/icon/font/media/profile file must match an assets/ATTRIBUTION.md path pattern;
Adobe profile/template formats and Adobe-named assets are rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:52:33 -04:00
Brandon Thomas bcecab7d84 M1.5: thumbnail/preview cache (disk + memory LRU, prioritized job pool)
- new crate lightcraft-preview (L3): 128-bit content hashing (SipHash-1-3),
  cost-bounded Lru, DiskCache (JPEG q90 files keyed by content hash +
  settings hash + size + RENDER_CACHE_VERSION; temp+rename writes; LRU prune
  by mtime to 80% of budget; corrupt files dropped), PreviewCache (memory
  LRU over disk), JobPool (per-slot dedupe, priorities, reprioritize/drop,
  inline mode for wasm).
- engine: Session::thumb_job buckets thumbnails to 128/256/384/512 and serves
  them from the cache without decoding the source; decoded thumbnail
  sources now in a 384 MB LRU (was unbounded); library attaches
  <library>/thumbs; library.info cache stats; library.clearPreviews.
- ui-egui: Renderer runs on JobPool; thumbnails scrolled out of the
  prefetch area are dropped from the queue; on-screen thumbnails get
  re-prioritized; ui.inspect reports in-flight renders + thumb textures.
- Demo library (24 photos): grid fully drawn 4.4 s cold -> 0.21 s warm
  (24/24 disk hits, no source decoded).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:51:47 -04:00
Brandon Thomas c7be09429d M10.4: multithreaded AVIF encoding (ravif threading, speed 8): ~4x faster export
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:45:06 -04:00
Brandon Thomas f7b502309c M11.2: Fujifilm RAF decoding (uncompressed Bayer and X-Trans)
RAF header/record parsing, raw IFD (0xf000) with 16-bit, 12-bit LSB and
32-bit-word MSB packings found by black-box analysis of CC0 samples,
X-Trans layout (reversed record, anchored at 0,0), crop, black levels,
WB_GRB levels, metadata and preview from the embedded JPEG. Compressed
RAF reports Unsupported. Colour uses the documented neutral fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:44:09 -04:00
Brandon Thomas e7b3724b5f M1.4: crash-safe catalog persistence (op log + snapshot)
- catalog: Store trait (FsStore: temp+fsync+rename+dir fsync; MemStore),
  Journal: CRC-checked JSON-lines op log with sequence numbers + atomic
  snapshots; torn final record dropped and truncated, stale records after a
  snapshot skipped, mid-log damage preserved as catalog.log.damaged-N.
- PushHistory op so each edit logs one history step (not the full history).
- engine: Session::open_library/persist/close_library; every top-level
  command is fsynced before returning; presets.json + view.json;
  library.info / library.compact commands.
- app: default library ~/Pictures/LightCraft Library (LIGHTCRAFT_LIBRARY or
  --library DIR override), --memory for throwaway sessions, snapshot on quit.
- tests: proptest replay(log)==state with random snapshots/reopens, every
  truncation of the last record, stale log, mid-log damage, FsStore, engine
  restart without close.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:40:40 -04:00
Brandon Thomas 08617b02d9 fmt: rustfmt crates/pipeline/src/finish.rs (main was not fmt-clean; needed for cargo xtask ci)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:40:40 -04:00
Brandon Thomas 908713c39b M10.2: MCP/CLI export shares the engine encoder (all formats, batch, size limit, sharpening)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:39:08 -04:00
Brandon Thomas 75dacbb49a Merge branch 'worktree-agent-a4280cb55a450d08a' 2026-09-30 23:37:39 -04:00
Brandon Thomas 72ba795439 M10.2: export dialog + batch export (JPEG/PNG/TIFF/WebP/AVIF, size, file-size limit, output sharpening, naming, folder)
Export encoding lives in lightcraft-engine::export (pure bytes, shared by app/CLI/MCP/web).
Embeds our own sRGB ICC; writer creates the output folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:37:24 -04:00
Brandon Thomas 50307e59db M0.9: MCP server + lightcraft-cli
crates/mcp (lightcraft-mcp, L5): hand-written MCP over stdio (JSON-RPC 2.0,
protocol 2025-06-18 with 2025-03-26/2024-11-05 negotiation): initialize,
ping, tools/list, tools/call, resources/list/read. Two backends behind one
trait: Headless (in-process engine Session; answers engine.execute,
engine.commands, ui.render, app.export) and Remote (the desktop app's
loopback JSON-lines control channel; lazy connect + reconnect).

Tools: helpers (list_commands, run_command, import, query_photos,
select_photos, list_controls, get/set_develop, apply_preset, crop,
render_photo -> image content, export), UI tools when connected
(screenshot -> image content, inspect_ui, set_ui, list_widgets, click,
press_key, type_text, pointer_gesture), plus one cmd_<id> tool generated
per command in the registry (--compact omits them).

apps/lightcraft-cli: `mcp [--connect [ADDR]] [--demo] [--compact] [FILES]`,
`render <in> -o <out> [--set control=value]... [--settings] [--preset]
[--size] [--quality]`, `commands`, `controls`.

Acceptance e2e: crates/mcp/tests/e2e.rs sets exposure over MCP and renders
(headless and through the TCP transport); apps/lightcraft-cli/tests/cli.rs
does the same through the real binary's stdio. Docs: docs/mcp.md,
docs/control-protocol.md. Also rustfmt of one line in pipeline/finish.rs
(main was not fmt-clean).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:37:08 -04:00
Brandon Thomas 59585102b1 M7.2: luminance + colour noise reduction (guided filter on log-luminance, chroma blur)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:29:07 -04:00
Brandon Thomas c0655d6fe6 M8.3: render heal/clone/remove spots (frequency-separation heal, auto source search)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:28:58 -04:00
Brandon Thomas ca35e7f888 M2.2: base profiles (Color/Neutral/Vivid/Landscape/Portrait/Monochrome) with amount
Profiles are our own looks applied underneath the user's sliders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:28:51 -04:00
Brandon Thomas 41c80a027d fmt: rustfmt crates/pipeline/src/finish.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:26:44 -04:00
Brandon Thomas 5560415d56 M3.7: Nikon NEF uncompressed decoding
16-bit word and 12-bit MSB-packed uncompressed NEF, maker-note black
levels and WB_RBLevels, masked trailing column trim, robust white
estimate ignoring 0xFFFF padding. Huffman-compressed NEF is reported as
unsupported (no clean-room description available).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:58:34 -04:00
Brandon Thomas ac14995c75 ROADMAP: status update
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:58:07 -04:00
Brandon Thomas 7029602b1e Merge branch 'worktree-agent-af7fd3f101800f8dc' 2026-09-30 22:56:47 -04:00
Brandon Thomas 440cedfa9c README: product-style showcase with screenshots of public-domain photos developed in LightCraft; reproducible showcase scripts; display-referred tone map for JPEGs (exact pass-through); fixes (crop panel wrap, overlay clipping, greyscale histogram, painted chevrons)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:56:38 -04:00
Brandon Thomas a7ea39573b M0.7/M0.8: Lightroom-style egui UI (top bar, My Photos, photo/square grid, loupe + filmstrip, Edit panel with histogram/curves/mixer/grading, crop/masking/remove/presets/info/keywords/versions/history, dialogs, shortcuts) + control channel + desktop app; engine file loading via codecs/raw
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 22:34:03 -04:00
Brandon Thomas b0d435f223 continued work 2026-09-30 22:21:57 -04:00
Brandon Thomas 955ae1f976 Merge branch 'agent-codecs' 2026-09-30 12:28:19 -04:00
Brandon Thomas 52e4809995 M1.1: codecs MPF preview thumbnail test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:27:09 -04:00
Brandon Thomas fa59a060dc M1.1: codecs fuzz/corpus/bench tests, thumbnail options, README
Property tests (random bytes behind every magic, mutated/truncated files),
corpus tests (corpus/images, pngsuite, raw routing, system ICC profiles),
ignored 24 MP JPEG benchmark, decode_thumbnail_with(min_embedded_edge),
fast deflate levels for PNG/TIFF, README with formats, licences, gaps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:26:05 -04:00
Brandon Thomas 345f0454f2 M3.7: Sony ARW decoding (ARW2 cRAW, uncompressed, LJ92 tiles)
ARW2 implemented from Dietz, EI 2016 (128-bit blocks, interleaved 16-pixel
sets, 7-bit scaled deltas, 5-segment tone curve from 0x7010); black/white/
WB/CFA/crop from the raw IFD's documented Sony tags. Verified visually on
A7 III / A7 IV samples; ~500-850 MP/s row-parallel decode.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:59:49 -04:00
Brandon Thomas 7cb30e5edd Untrack agent worktrees; ignore .claude/
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:46:03 -04:00
Brandon Thomas 1c073db30f Merge agent-codecs: lightcraft-codecs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:46:03 -04:00