Commit Graph
5 Commits
Author SHA1 Message Date
45bedb0962 Monitor profile auto follows each window's display; what is applied is visible (#569) (#591)
* Monitor profile: say which profile is in use and why; apply a late display reading (#569)

Color Settings › Monitor Profile used to fall back to sRGB without a
word when the display's profile was missing, unreadable, not RGB or
unusable as a destination, and dropped a macOS reading that took longer
than 2 s. `ColorState::monitor_status` now reports the profile actually
applied, its fingerprint, the source (auto / manual / fallback) and the
reason for a fallback. `edit.colorSettings` (`monitorStatus`),
Help › System Info and the Color Settings dialog show it, and a fallback
in auto posts a notice.

The macOS reader also names the display it read. On a dual-display Mac
it reports the menu-bar display ("Built-in Retina Display") while the
canvas is on the external monitor, which is the display-selection bug
in #569; following the window's display is the next step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Monitor profile auto: each window uses the profile of the display it is on (#569)

The macOS reader now lists every display (id, name, frame, ICC profile
and its System Settings name) instead of asking for the "main screen",
which from a windowless helper is the menu-bar display. Each window
picks the display it overlaps most, as NSWindow.screen does, and its
canvas is shown in that display's profile: moving a window to another
display switches the profile without a restart, and two windows of one
document on different displays each keep their own. The GPU canvas
shares the document texture and keeps a display LUT per (document,
display); CPU textures are per (document, display).

Displays are read again when PhotoCraft comes back to the front (a
profile changed in System Settings or by a calibration tool), and when
a window is on an unknown display or one whose size changed (connected,
removed, rearranged), at most every 5 s. A failed re-read keeps the
previous reading. Help › System Info lists each display's profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Monitor profile auto: act on the r1 review; no periodic re-read (#569)

Following the owner's decision on echo round r1:

- No periodic discovery: a read costs about 0.2 s of CPU, and a profile
  reassigned while PhotoCraft stays in front with no window moving
  practically doesn't happen. It is picked up at the next return to the
  front, or when Edit › Color Settings opens, which now reads at once.
- Every document window, not only the main one, asks for a reading when
  it is on an unknown display or one whose size changed.
- The focus re-read is throttled to one per 30 s; a trigger inside that
  window is deferred, not dropped.
- Starting a reading schedules the frame that applies its result, so an
  idle window doesn't wait for unrelated input.
- The osascript helper is stopped after 10 s (killed and reaped, both
  pipes drained meanwhile), so a hung reading can't block later ones.
- The Color Settings dialog recomputes "Monitor profile in use" as it
  draws, and the status says when an earlier reading is kept after a
  failed re-read (detection `retained`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Monitor profile auto: document windows count for focus and wake the main window (#569)

Echo round r2 on #591:

- Coming back to PhotoCraft through a document window (macOS reports
  focus per window, so the main window stays unfocused) now counts as a
  return to the front and reads the displays again, within the 30 s
  throttle.
- A document window that is on an unknown or resized display, or that
  brings PhotoCraft back to the front, asks the main window for a frame:
  the reading starts there, so it no longer waits for unrelated input.
  One frame per trigger, no continuous repaints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Monitor profile: pass the notice dismiss preference added on main

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-07 09:02:58 -04:00
d8d648cb72 GPU canvas: Rgba16Float display texture for 16/32-bit documents (#46) (#84)
* engine: display LUT without the 32-bit preview for the GPU canvas shader; keep values above 1.0 in texture_buffer

ColorState::gpu_canvas_lut leaves View > 32-bit Preview Options out of the display LUT
(the canvas shader applies exposure/gamma before it, on unclipped float texels), and
ColorState::hdr_preview returns the active preview. CanvasDisplay::texture_buffer no
longer clamps linear values to 1.0 before sRGB-encoding them (the 8-bit path clamps
afterwards with the same result).

Refs #46

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* GPU canvas: Rgba16Float display texture for 16/32-bit documents (#46)

16- and 32-bit documents get an Rgba16Float canvas texture when the adapter can
sample, filter, render to and copy it (Rgba8Unorm stays for 8-bit documents, as the
fallback, and for high-bit documents over 100 MP, about 1.07 GB with mips), so smooth
gradients no longer band through 8 bits. Both the wgpu compositor path (encode pass
with 16F pipelines; no upper clamp) and the CPU band/rect upload path (f32 -> half
conversion, reused band buffer) write it. The 32-bit preview (exposure/gamma) moves
into the canvas shader, before the colour-management/proof LUT, so values above 1.0
are exposed into range instead of clipped. GpuCanvas::read_texels / texture_info for
tests and benchmarks; PHOTOCRAFT_CANVAS_F16=0/1 disables the float canvas / ignores
the budget. large_image_bench gains --depth 16|32.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 23:30:53 -04:00
d5eb44e9fd Colour-managed canvas: document profile -> monitor (P3/Adobe RGB/ProPhoto/Gray/CMYK), linear EXR, embedded CMYK (#66)
* CMYK documents display and export through their embedded CMYK profile

A thread-local CmykSpace (photocraft_color::convert::with_cmyk_space) replaces the built-in
coated CMYK while the CPU compositor, the GPU compositor's uploads and the PSD merged
composite convert a document's CMYK pixels; GPU residents track the profile they were
converted with.

Refs #46

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* EXR/HDR are linear: tag imports linear sRGB, linearise exports

Refs #46

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Colour-managed canvas: document profile -> monitor profile on GPU and CPU paths

* engine display_color: CanvasDisplay per (document profile, mode, monitor), identity fast
  path when they match (sRGB on sRGB costs nothing); linear composites are stored
  sRGB-encoded in the 8-bit texture. canvas_lut now always carries the CM transform, with
  Proof Colors / Gamut Warning / 32-bit preview on top.
* GPU canvas applies the display LUT whenever the transform isn't the identity (also for
  filter/proxy previews); the CPU canvas and Navigator transform the 8-bit composite.
* Edit > Color Settings > Monitor Profile (auto|built-in|.icc). macOS 'auto' reads the main
  display's ICC profile at launch via osascript/AppKit (no unsafe); elsewhere sRGB.
* Tests: P3 (hand-computed), Adobe RGB, ProPhoto, Gray Gamma 2.2, synthetic CMYK, linear,
  monitor setting; GPU+CPU canvas test via kittest (skips without Rgba32Float).

Fixes #46

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* io: tag EXR/HDR linear in import_flat (adapt to the shared image_to_document)

#65 moved flat decoding into image_to_document(name, img) so camera raws can reuse it; the
linear-EXR tagging needs the file bytes for format detection, so it now runs in import_flat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 15:44:13 -04:00
Brandon ThomasandClaude Opus 5.5 f7eb6ea9e7 Format: adopt the craft-family rustfmt.toml and format the workspace
CI's `cargo fmt --all -- --check` has failed on every run because the
repo had no rustfmt config and was never formatted. Use the same settings
as EffectCraft/FilmCraft (max_width 160, use_small_heuristics Max), which
also keeps the churn small. Formatting only; no code changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 11:31:17 -04:00
Brandon ThomasandClaude Opus 5.5 aa87012aab Analysis, notes, proof views, workspaces (+ in-progress work of other agents)
Image > Analysis (ruler, count, measurement scale/log/record, scale
marker), notes (PSD Anno round trip, Notes panel, import), Modifier Keys
panel, Proof Setup plates / Legacy Mac RGB / colour blindness (Vienot),
32-bit preview options, custom pixel aspect, extras options, New/Delete/
Lock Workspace. Parity 600/625, FLOOR 595.

Checkpoint: also contains compiling in-progress work from the parallel
panels, type styles, File menu, photo, filters, UI-parity and fidelity
agents, plus photocraft-cli serve.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 22:49:07 -04:00