mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
M4.12: one loader and encoder for every frontend — engine fileio (load/encode/export/save, append-only FORMATS table, OPEN_EXTS, document.formats query, typed per-format options, parse_range); document.open reads native/legacy, SVG/SVGZ, PDF/.ai, .ait (opens untitled like native templates) and PNG/JPEG/GIF/WebP/TIFF/BMP; desktop, web, control channel, headless MCP and the CLI open and encode through it; open dialogs list "All readable files" plus one filter per format
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
d99853ed2a
commit
4d503c0327
25 files changed
+1293
-559
No files matched your search
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! ```text
|
||||
//! vectorcraft-cli mcp [--connect 127.0.0.1:7979 | --headless]
|
||||
//! vectorcraft-cli run [--in file.vectorcraft|file.svg] [--cmd id [--params '{json}']]... [--export out.svg|.png|.pdf|.jpg|.webp|.vectorcraft]... [--scale 2]
|
||||
//! vectorcraft-cli run [--in FILE] [--cmd id [--params '{json}']]... [--export out.svg|.png|.pdf|.jpg|.webp|.vectorcraft]... [--scale 2]
|
||||
//! vectorcraft-cli commands
|
||||
//! vectorcraft-cli convert IN OUT [--scale 2] [--artboard 0] [--outline-text]
|
||||
//! vectorcraft-cli info FILE
|
||||
@@ -28,21 +28,21 @@ USAGE:
|
||||
(vectorcraft --control 7979), falling back to a headless in-process session.
|
||||
|
||||
vectorcraft-cli run [--in FILE] [--cmd ID [--params JSON]]... [--export FILE]... [--scale N]
|
||||
Headless batch: open FILE (.vectorcraft/.svg) or start a new document, run commands in
|
||||
Headless batch: open FILE (any readable format) or start a new document, run commands in
|
||||
order, export (.svg, .png, .pdf, .jpg, .webp, .vectorcraft by extension). Prints one JSON result per step.
|
||||
|
||||
vectorcraft-cli commands
|
||||
Print the command catalogue as JSON.
|
||||
|
||||
vectorcraft-cli convert IN OUT [--scale N] [--artboard I] [--outline-text]
|
||||
Open IN (.vectorcraft, .svg, .pdf/.ai, images) and export OUT by extension (.svg, .pdf, .png,
|
||||
.jpg, .webp, .vectorcraft). Live effects are kept; --outline-text writes SVG text as paths.
|
||||
Open IN (any readable format) and export OUT by extension (.svg, .pdf, .png, .jpg, .webp,
|
||||
.vectorcraft). Live effects are kept; --outline-text writes SVG text as paths.
|
||||
|
||||
vectorcraft-cli info FILE
|
||||
Print a JSON summary: title, colour mode, units, artboards, object counts by kind, fonts.
|
||||
|
||||
vectorcraft-cli bench FILE [--size WxH] [--iters N]
|
||||
Render FILE (.vectorcraft/.svg) fitted to WxH (default 2880x1800) and print ms per frame
|
||||
Render FILE (any readable format) fitted to WxH (default 2880x1800) and print ms per frame
|
||||
(warm), multithreaded and single-threaded.
|
||||
|
||||
vectorcraft-cli perf [--paths N]
|
||||
@@ -50,6 +50,11 @@ USAGE:
|
||||
synthetic N-path document (default 50000). Exits non-zero if a budget is exceeded.
|
||||
";
|
||||
|
||||
/// The usage text plus the formats `document.open` reads.
|
||||
fn usage() -> String {
|
||||
format!("{USAGE}\nReadable formats: .{}\n", vectorcraft_engine::cmd::fileio::OPEN_EXTS.join(", ."))
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
let r = match args.first().map(String::as_str) {
|
||||
@@ -61,14 +66,14 @@ fn main() -> ExitCode {
|
||||
Some("bench") => bench(&args[1..]),
|
||||
Some("perf") => perf::run(&args[1..]),
|
||||
Some("-h" | "--help" | "help") | None => {
|
||||
print!("{USAGE}");
|
||||
print!("{}", usage());
|
||||
Ok(())
|
||||
}
|
||||
Some("-V" | "--version") => {
|
||||
println!("vectorcraft-cli {}", env!("CARGO_PKG_VERSION"));
|
||||
Ok(())
|
||||
}
|
||||
Some(other) => Err(format!("unknown subcommand `{other}`\n\n{USAGE}")),
|
||||
Some(other) => Err(format!("unknown subcommand `{other}`\n\n{}", usage())),
|
||||
};
|
||||
match r {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
//! The CLI opens every readable format (PDF, .ai, images) through the engine's `document.open`.
|
||||
|
||||
use std::process::Command;
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
const BIN: &str = env!("CARGO_BIN_EXE_vectorcraft-cli");
|
||||
|
||||
fn tmp(name: &str) -> String {
|
||||
let dir = std::env::temp_dir().join(format!("vectorcraft-cli-fileio-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
dir.join(name).to_string_lossy().to_string()
|
||||
}
|
||||
|
||||
fn ok(args: &[&str]) -> String {
|
||||
let out = Command::new(BIN).args(args).output().unwrap();
|
||||
assert!(out.status.success(), "{args:?}: {}", String::from_utf8_lossy(&out.stderr));
|
||||
String::from_utf8(out.stdout).unwrap()
|
||||
}
|
||||
|
||||
/// `run` a new `width`×`height` document with a rectangle and export it to `out`.
|
||||
fn make(out: &str, width: u32, height: u32) {
|
||||
ok(&[
|
||||
"run",
|
||||
"--cmd",
|
||||
"file.new",
|
||||
"--params",
|
||||
&format!(r#"{{"width":{width},"height":{height},"artboards":2}}"#),
|
||||
"--cmd",
|
||||
"shape.rectangle",
|
||||
"--params",
|
||||
r#"{"x":1,"y":1,"width":2,"height":1}"#,
|
||||
"--export",
|
||||
out,
|
||||
]);
|
||||
}
|
||||
|
||||
fn info(file: &str) -> Value {
|
||||
serde_json::from_str(&ok(&["info", file])).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_pdf_to_svg_and_info_on_ai() {
|
||||
let pdf = tmp("in.pdf");
|
||||
make(&pdf, 120, 80);
|
||||
let svg = tmp("out.svg");
|
||||
ok(&["convert", &pdf, &svg]);
|
||||
assert!(std::fs::read_to_string(&svg).unwrap().contains("<svg"));
|
||||
|
||||
let ai = tmp("in.ai");
|
||||
std::fs::copy(&pdf, &ai).unwrap();
|
||||
let v = info(&ai);
|
||||
assert_eq!(v["artboards"].as_array().unwrap().len(), 2, "{v}");
|
||||
assert_eq!(v["artboards"][0]["rect"][2], 120.0);
|
||||
// `run --in` takes it too.
|
||||
ok(&["run", "--in", &ai, "--cmd", "document.inspect"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn images_open_at_their_pixel_size() {
|
||||
let webp = tmp("tiny.webp");
|
||||
make(&webp, 3, 2);
|
||||
let v = info(&webp);
|
||||
assert_eq!(v["artboards"][0]["rect"], serde_json::json!([0.0, 0.0, 3.0, 2.0]), "{v}");
|
||||
assert_eq!(v["kinds"]["Image"], 1, "{v}");
|
||||
let png = tmp("tiny.png");
|
||||
ok(&["convert", &webp, &png, "--scale", "2"]);
|
||||
assert_eq!(&std::fs::read(&png).unwrap()[16..24], [0, 0, 0, 6, 0, 0, 0, 4], "IHDR 6×4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn help_lists_readable_formats() {
|
||||
let out = ok(&["--help"]);
|
||||
assert!(out.contains("Readable formats: .vectorcraft") && out.contains(".ait") && out.contains(".webp"), "{out}");
|
||||
}
|
||||
Reference in new issue
Block a user