Commit Graph
20 Commits
Author SHA1 Message Date
1df68e9a5d CLI batch: recorded-action steps, --format .ext, strict --quality, refuse --out = --in (#489, #490, #491, #492) (#545)
* CLI --quality refuses every value outside 1-100 (#491)

--quality was parsed as a u8 and clamped, so 0 and 101-255 were silently
accepted while 256 and above were rejected. Every value outside 1-100 is now
a bad --quality error, checked before any file is read or written.

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

* CLI batch: --format with a leading dot names outputs <stem>.<ext> (#490)

batch built output names from the raw --format value, so --format .jpg wrote
a..jpg. One leading dot is now dropped, as the save path and
file.automate.batch already do.

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

* CLI batch --actions takes recorded-action and droplet steps (#489)

batch read only {"command", "params"} objects, so the [id, params] pairs a
recorded action or droplet stores failed with 'missing "command"'. It now
uses the engine's action parser (automate_cmds::parse_action, split out of
parse_script), which takes [id, params], objects and bare ids, bare or
wrapped in {"steps": ...} or a droplet; {"actions": ...} still works.

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

* CLI batch refuses an --out folder that is the --in folder (#492)

Results are saved as <out>/<stem>.<ext>, so --out naming the input folder
silently replaced the originals. batch now compares the canonical folders
(relative spellings, trailing separators, symbolic links) and fails before
writing anything, naming the folder; the new --in-place flag opts in.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:21:07 +07:00
Carter SmithandGitHub f373fdb52f Raise rust-version to 1.95, the minimum egui 0.36 needs (#471) 2026-10-07 11:32:23 +07:00
floflo777andGitHub 9ae984c0ae Use the real Gaussian Blur id in the docs and MCP schema (#390)
filter.blur.gaussian isn't registered, so the documented CLI run and the
agent loop failed with "unknown command". Pin the schema examples with a test.
2026-10-07 10:34:03 +07:00
Brandon ThomasandGitHub c161eaec73 Fonts: use craft-fonts as an optional build input; move the Japanese fonts out (#353) (#353) 2026-10-06 18:21:46 -04:00
Brandon ThomasandGitHub 968baf639e Photoshop oracles via storytold/photocraft-corpus: pinned corpora, corpus feature, test-corpus, CI job (#190) (#190) 2026-10-05 17:47:33 -04:00
Brandon ThomasandGitHub 7c6a78b05a GPU: crash-safe startup and device-loss fallback (#243, #4) (#252) (#252) 2026-10-05 12:05:22 -04:00
Brandon ThomasandGitHub 0f955e6c82 Scorecard: cargo xtask perf + scorecard, budgets, checklists, nightly perf (#221) (#239) (#239) 2026-10-05 10:53:02 -04:00
Brandon ThomasandGitHub 7f3d9ea68a Packaging: Linux runtime deps + start-up library check (#201); wasm 26.3 -> 18.8 MiB (#198) (#237) (#237) 2026-10-05 10:52:20 -04:00
Brandon ThomasandGitHub 574d0d3d53 PSD corpus: psd-tools set (pinned, verified), an oracle for every file, and the fixes it found (#195) (#195) 2026-10-05 08:01:39 -04:00
d3b540234c Large images: adapter texture limits, banded compositing/export, proxy thumbnails, history byte budget (#71)
* Compose: render in place and in bands; area-reduced and proxy thumbnails

render_tiled wrote every tile into a Vec and then copied them into the output:
two full-size float copies (6.3 GB for a 14000² document). Tiles are now
written straight into the output band by band.

New streaming APIs so large documents never need a full-size float
composite: render_bands (sink per band of ~8 MP), render_reduced (banded
area average, bit-identical to the old flatten-then-average thumbnail) and
flatten_to_surface (Flatten Image, Merge Visible, Copy Merged and the other
flattened-surface users).

thumbnail() reduces a downsampled proxy (moved from ui-egui to
compose::proxy, now also scaling spot channels) for documents over 16 MP
when that is faithful (no layer effects or vector masks), so navigator,
channel and histogram thumbnails of a 196 MP document cost milliseconds.

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

* GPU canvas: request the adapter's real limits; banded CPU fallback; navigator thumbnail

egui-wgpu asks for an 8192 px texture limit, so the wgpu compositor rejected
every document wider or taller than 8192 px and each refresh fell back to a
full CPU flatten. The desktop and web apps now request the adapter's own
max_texture_dimension_2d and max_buffer_size (gpu_canvas::use_adapter_limits);
the benches use the same limits.

The CPU fallback (documents beyond the GPU limit, or features it lacks) is
GpuCanvas::refresh: it renders and uploads the composite band by band
instead of a full float composite plus a full RGBA8 copy. The CPU canvas
texture is reduced in bands too, and the Navigator on the GPU canvas uses a
cached thumbnail instead of a full-resolution CPU composite per revision.

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

* IO: banded export and import; no full-size copies in encoders; larger decode limits

- Flat export renders the composite in bands and quantises each band; alpha
  is dropped in place when every pixel is opaque. The single-layer native
  path copies surface rows a band at a time (no f32 read_region and no
  per-pixel Vec). Buffers come from try_reserve: Err, not an abort.
- PSD export encodes the merged image band by band into its planes (no
  flatten, no second plane copy); near-opaque documents are re-encoded
  without the white matte so the output is unchanged. Layer interleaved
  bytes are freed before their planes are compressed.
- Flat import converts in ~32 MB bands (and not at all when already RGBA);
  the PSD merged-image un-matte works per tile row.
- Encoders borrow the image when no conversion is needed (Image::converted)
  instead of cloning it; PNG only copies 16-bit data for the byte swap.
- Decode limits: 2^30 pixels and 8 GiB on 64-bit targets (a 20000² JPEG
  was refused at 2^28).

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

* Filters: write tile results in memory-bounded groups

apply_tiled collected every tile's float result before writing any (3.1 GB
for a 14000² layer). Results are now produced and written in groups of about
256 MB (at least one tile per core).

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

* History: bound pixel memory by Preferences > Performance > Memory Usage

History::max_bytes caps the current document's tiles plus the tiles only
history holds (layers, masks, alpha channels); History::trim drops the
oldest states beyond it after every recorded step and when preferences
change, always keeping the last step undoable. The engine sets it from
memory_usage_mb, which was unused.

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

* Large-image benchmark (14k / 20k): open, refresh, thumbnails, filter, stroke, saves

One operation per run on a cached synthetic photo, with the GPU device created
the way the app creates it, so /usr/bin/time -l reports that operation's peak
memory. Documented in docs/development.md.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 16:45:17 -04:00
5716c2f6f1 security: constrain automation filesystem access (#72)
Rebased onto main (#58/#61/#63/#66/#70/#74) by the maintainers: automation
open/save return and surface import/export warnings (app.open/app.save
reply with `warnings`), automation opens route .abr/.grd to the preset
libraries with script events suppressed, interactive opens keep open_file's
path/recent/notice handling.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 16:35:06 -04:00
Gh0stlyandGitHub 8b1cbb741b security: authenticate control channels and bound transport resources (#61)
* security: authenticate and bound control transports

* fix: keep connection limiter compatible with current stable
2026-10-04 13:58:59 -04:00
Brandon ThomasandClaude Opus 5.5 42266291d5 Fidelity, GPU fallbacks, interactive performance; print spool-file fix
PSD oracle 111 -> 113 (tent effect blurs, bevel height/shading, glow
range, spread rounding, text gamma, gradient span, Lab blending, colour
burn/dodge edges), channel restrictions (brst), bevel contour/texture,
chisel techniques. Vector masks, pass-through clips, artboards, pattern
fills and bevel textures render on the GPU (parity <=1/255). PNG export
7x, PSD save 4x, .pcraft save 3.6x faster; CPU effects refresh 11x;
deadlock in the effect-map blur fixed. interactive_bench example.

Print: unique spool file per call (concurrent prints of same-named
documents overwrote each other).

Workspace: 2,040 tests pass, clippy clean, layers + wasm OK, parity 600/625.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:26:34 -04:00
Brandon ThomasandClaude Opus 5.5 cfecebbcfb Headless JSON-lines server and MCP command_batch
crates/automation/src/rpc.rs: a headless session behind the control
protocol's envelope (engine.execute, doc.*, session.list, batch), on
stdio or loopback TCP. MCP gains command_batch (headless and bridge).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 21:40:12 -04:00
Brandon Thomas d98bee4c94 progress, release workflows 2026-10-01 10:49:51 -04:00
Brandon Thomas aad724f28e work in progress 2026-10-01 10:07:04 -04:00
Brandon Thomas 536a7346fb more algorithms, progress 2026-10-01 08:25:06 -04:00
Brandon Thomas a517477da8 readme, more impl 2026-09-30 11:15:03 -04:00
Brandon Thomas ae92ac20bf continued wip 2026-09-30 09:37:18 -04:00
Brandon Thomas 16941f7198 one-shot 2026-09-30 05:02:08 -04:00