mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-20 13:56:30 +02:00
* photocraft-plugins: sandboxed WebAssembly filter plug-ins (wasmi host, ABI v1) A new L4 crate runs plug-ins in wasmi (pure Rust, MIT/Apache) with no host imports, a fuel budget metered in slices with a wall-clock deadline, a memory cap, a recursion cap and wasmi's strict module limits. Every band gets a fresh instance; traps, budgets, bad manifests and bad pointers are all Errors. Pixels go over as interleaved normalised f32 in tile-aligned bands, in parallel on native, blended by the selection. Includes the example Invert plug-in (no_std Rust, examples/plugins/invert-rs) built into a test fixture, hostile-module tests, and docs/plugins.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Engine: plugin.* commands (install, list, run, remove, reload) plugin.run filters the active pixel layer, a targeted channel or a smart object (recorded as a smart filter) as one undo step; Preferences > Plug-ins gains Use Additional Plug-ins Folder, loaded when prefs apply. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * UI: Filter > Plug-ins lists installed plug-ins with generated dialogs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Plug-ins: bands never outgrow the memory cap; regenerate parity Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Bench: example plug-in Invert vs built-in Invert on 24 MP Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
31 lines
1.0 KiB
Rust
31 lines
1.0 KiB
Rust
//! Compiles a WebAssembly text plug-in to a `.wasm` module and checks that it loads:
|
|
//! `cargo run -p photocraft-plugins --example wat2wasm -- plugin.wat plugin.wasm`
|
|
|
|
use photocraft_plugins::{Limits, Plugin};
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().skip(1).collect();
|
|
let (Some(input), Some(output)) = (args.first(), args.get(1)) else {
|
|
eprintln!("usage: wat2wasm <in.wat> <out.wasm>");
|
|
std::process::exit(2);
|
|
};
|
|
let bytes = match wat::parse_file(input) {
|
|
Ok(b) => b,
|
|
Err(e) => {
|
|
eprintln!("{e}");
|
|
std::process::exit(1);
|
|
}
|
|
};
|
|
match Plugin::load(&bytes, Limits::default()) {
|
|
Ok(p) => println!("{} ({}): {} bytes, params {}", p.manifest().name, p.id(), bytes.len(), p.manifest().params_notation()),
|
|
Err(e) => {
|
|
eprintln!("not a valid plug-in: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
if let Err(e) = std::fs::write(output, &bytes) {
|
|
eprintln!("{output}: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|