mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Part of #868: vectorcraft-cli convert writes legacy .ai (--ai-version 7, --hidden-objects, --transparent-images)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
//! vectorcraft-cli mcp [--connect 127.0.0.1:7979 | --headless] [--automation-read-root DIR] [--automation-write-root DIR]
|
||||
//! vectorcraft-cli run [--in FILE] [--cmd id [--params '{json}']]... [--export out.svg]... [--scale 2]
|
||||
//! vectorcraft-cli commands
|
||||
//! vectorcraft-cli convert IN OUT [--scale 2] [--artboard 0 | --range 1-3,5] [--outline-text] [--decimals N] [--replace-lossy] [--editing-data]
|
||||
//! vectorcraft-cli convert IN OUT [--scale 2] [--artboard 0 | --range 1-3,5] [--outline-text] [--decimals N] [--replace-lossy] [--editing-data] [--ai-version 7|pdf] [--hidden-objects layer|omit|visible] [--transparent-images flatten|omit]
|
||||
//! vectorcraft-cli info FILE
|
||||
//! vectorcraft-cli bench FILE [--size 2880x1800] [--iters 5]
|
||||
//! vectorcraft-cli perf [--paths 50000] [--deep]
|
||||
@@ -84,7 +84,7 @@ USAGE:
|
||||
vectorcraft-cli commands
|
||||
Print the command catalogue as JSON.
|
||||
|
||||
vectorcraft-cli convert IN OUT [--scale N] [--artboard I | --range R] [--outline-text] [--decimals N] [--replace-lossy] [--editing-data]
|
||||
vectorcraft-cli convert IN OUT [--scale N] [--artboard I | --range R] [--outline-text] [--decimals N] [--replace-lossy] [--editing-data] [--ai-version 7|pdf] [--hidden-objects layer|omit|visible] [--transparent-images flatten|omit]
|
||||
Open IN (any readable format) and export OUT in the format its extension picks (see Writable
|
||||
formats). --artboard is 0-based, --range 1-based (\"1-3,5\"); a PDF gets every artboard
|
||||
unless one of them is given, EPS the bounds of the art, the other formats the first artboard.
|
||||
@@ -95,6 +95,11 @@ USAGE:
|
||||
--replace-lossy is given. --editing-data opens a .ai from its editing copy even where that
|
||||
draws differently from its PDF part (which can be older), as long as it can be read. The
|
||||
result has the export's warnings, and importWarnings for what reading IN left out.
|
||||
--ai-version 7 writes a .ai as the legacy version 7 (layers, groups and type kept; one file
|
||||
per artboard, OUT-<artboard>.ai when there are several; default pdf, PDF-compatible), with
|
||||
--hidden-objects (default layer: a hidden layer above each layer's hidden objects; omit;
|
||||
visible), --transparent-images (default flatten, with the art under them; omit) and
|
||||
--outline-text (type as outlines instead of text).
|
||||
|
||||
vectorcraft-cli info FILE
|
||||
Print a JSON summary: the import warnings (what didn't come in as it was, such as an EPS
|
||||
@@ -223,6 +228,9 @@ fn convert(args: &[String]) -> Result<(), String> {
|
||||
let (mut scale, mut artboard, mut range, mut outline_text, mut replace_lossy, mut editing_data) =
|
||||
(1.0f64, None::<u64>, None::<String>, false, false, false);
|
||||
let mut decimals = None::<u64>;
|
||||
// Legacy `.ai` options, passed on as the export's own (`aiVersion`, `hiddenObjects`,
|
||||
// `transparentImages`); the engine checks their values.
|
||||
let mut legacy: Vec<(&str, String)> = vec![];
|
||||
let mut it = args.iter();
|
||||
while let Some(a) = it.next() {
|
||||
match a.as_str() {
|
||||
@@ -233,6 +241,9 @@ fn convert(args: &[String]) -> Result<(), String> {
|
||||
"--decimals" => decimals = Some(it.next().and_then(|v| v.parse::<u64>().ok()).ok_or("--decimals needs a number")?),
|
||||
"--replace-lossy" => replace_lossy = true,
|
||||
"--editing-data" => editing_data = true,
|
||||
"--ai-version" => legacy.push(("aiVersion", it.next().cloned().ok_or("--ai-version needs 7 or pdf")?)),
|
||||
"--hidden-objects" => legacy.push(("hiddenObjects", it.next().cloned().ok_or("--hidden-objects needs layer, omit or visible")?)),
|
||||
"--transparent-images" => legacy.push(("transparentImages", it.next().cloned().ok_or("--transparent-images needs flatten or omit")?)),
|
||||
f => files.push(f.to_string()),
|
||||
}
|
||||
}
|
||||
@@ -250,6 +261,9 @@ fn convert(args: &[String]) -> Result<(), String> {
|
||||
if let Some(decimals) = decimals {
|
||||
params["decimals"] = json!(decimals);
|
||||
}
|
||||
for (key, value) in legacy {
|
||||
params[key] = json!(value);
|
||||
}
|
||||
let mut r = h.call("engine.execute", json!({"command": "document.export", "params": params})).map_err(|e| format!("export {output}: {e}"))?;
|
||||
// What reading the input left out (a missing linked file, an unsupported filter…) matters as
|
||||
// much as what writing the output did.
|
||||
|
||||
@@ -115,3 +115,57 @@ fn convert_reports_import_warnings() {
|
||||
let w = out["importWarnings"].as_array().unwrap_or_else(|| panic!("{out}"));
|
||||
assert!(w.iter().any(|w| w.as_str().unwrap().contains("nowhere-to-be-found.png")), "{out}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_writes_legacy_ai_with_its_options() {
|
||||
// Two artboards, a shown rectangle and a hidden one.
|
||||
let src = tmp("legacy.vectorcraft");
|
||||
ok(&[
|
||||
"run",
|
||||
"--cmd",
|
||||
"file.new",
|
||||
"--params",
|
||||
r#"{"width":120,"height":80,"artboards":2}"#,
|
||||
"--cmd",
|
||||
"shape.rectangle",
|
||||
"--params",
|
||||
r#"{"x":10,"y":10,"width":20,"height":10}"#,
|
||||
"--cmd",
|
||||
"shape.rectangle",
|
||||
"--params",
|
||||
r#"{"x":40,"y":10,"width":20,"height":10}"#,
|
||||
"--cmd",
|
||||
"object.hide",
|
||||
"--export",
|
||||
&src,
|
||||
]);
|
||||
// One file per artboard, named after it; hidden objects in a hidden layer by default.
|
||||
let out = tmp("legacy.ai");
|
||||
let r: Value = serde_json::from_str(&ok(&["convert", &src, &out, "--ai-version", "7"])).unwrap();
|
||||
let files: Vec<&str> = r["files"].as_array().unwrap().iter().filter_map(Value::as_str).collect();
|
||||
assert_eq!(files.len(), 2, "{r}");
|
||||
assert!(files.iter().all(|f| std::fs::read(f).unwrap().starts_with(b"%!PS-Adobe-3.0")), "{r}");
|
||||
assert!(r["warnings"].to_string().contains("hidden layer"), "{r}");
|
||||
// One artboard is the file itself; the hidden rectangle left out.
|
||||
let one = tmp("legacy-one.ai");
|
||||
let r: Value = serde_json::from_str(&ok(&[
|
||||
"convert",
|
||||
&src,
|
||||
&one,
|
||||
"--ai-version",
|
||||
"7",
|
||||
"--range",
|
||||
"1",
|
||||
"--hidden-objects",
|
||||
"omit",
|
||||
"--transparent-images",
|
||||
"omit",
|
||||
]))
|
||||
.unwrap();
|
||||
assert!(r["warnings"].to_string().contains("hidden objects are left out"), "{r}");
|
||||
assert!(std::fs::read(&one).unwrap().starts_with(b"%!PS-Adobe-3.0"));
|
||||
// A value the engine doesn't take is an error.
|
||||
let bad = Command::new(BIN).args(["convert", &src, &tmp("bad.ai"), "--ai-version", "7", "--hidden-objects", "behind"]).output().unwrap();
|
||||
assert!(!bad.status.success());
|
||||
assert!(String::from_utf8_lossy(&bad.stderr).contains("hiddenObjects"), "{}", String::from_utf8_lossy(&bad.stderr));
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ the app's own editing copy of a file (an EPS after its `%%EOF`, a `.ai`'s `AIPri
|
||||
| 2026-10-13 | minor | PDF.W1: PDF export and print composition use the shared guarded writer; drawing, colour policy and editable import stay app-owned. Metadata regression coverage and immutable dependency checks added; scores and hours unchanged. |
|
||||
| 2026-10-13 | minor | Native documents with a lot of path data (traced or generated art, in layers, symbols or patterns) are saved as compact JSON, about a fifth of the size; small documents stay pretty-printed (#1492); Paste takes a PDF or EPS another app copied as editable vector art: from the macOS pasteboard (with SVG), EPS on Windows beside PDF, and `.eps` files copied in a file manager, with the new command `clipboard.importEps` (#1538, fixes #1499); Opening or placing a file with an image too large to decode says so, and the Links panel shows it on the row (#1540, part of #1479); a multi-artboard `.ai` with notes beside its artboards opens from its editing data, a page's art past its artboard no longer lying over the page before it (#1528); a `.ai` gradient whose stops are listed upwards keeps each midpoint on the stop that starts its part of the ramp (#1530); SVG text on a path follows basic shapes (circle, ellipse, rect, line, polyline, polygon) as their SVG 2 equivalent paths (#1531, fixes #1527); PDFs whose alpha soft masks are drawn as images import with the mask instead of empty art (#1551); EPS and PostScript type set in Type 42 (TrueType) fonts imports at its size instead of 1000 times too large (#1553); PDF and EPS import keep a clipping path whose bounding box covers the page but whose shape doesn't (#1544, fixes #1542) (the `.ai` row for #1528 was written by that PR); scores unchanged (estimated) |
|
||||
| 2026-10-13 | minor | `.ai` read as its PDF part: a page whose art reaches past its artboard to the left (notes beside a design) moves right in the row until that art clears the page before it, so it is no longer taken for that page's art; a multi-artboard `.ai` with such notes opened as its PDF part ("the art on them differs from the page's"), without the art outside its artboards, and now opens from its editing data |
|
||||
| 2026-10-12 | minor | Legacy `.ai` of version 7 (Save As › `ai` › Version: Legacy (version 7), #868): written from the published specification, keeping layers, groups, compound paths, clipping groups, gradients and images, one artboard per file chosen in an artboard picker; type as editable text objects (point, area and on a path, fonts by PostScript name, Windows-1252), or outlines (Text: Outlines); hidden objects, which the format can't hide, in a hidden layer of their own, omitted or made visible (Hidden Objects); images with see-through pixels flattened with the art under them or omitted (Transparent Images). The `.ai` reader reads legacy type (`To` … `TO`) and `Ar`; scores unchanged (estimated) |
|
||||
| 2026-10-12 | minor | Legacy `.ai` of version 7 (Save As › `ai` › Version: Legacy (version 7), #868): written from the published specification, keeping layers, groups, compound paths, clipping groups, gradients and images, one artboard per file chosen in an artboard picker; type as editable text objects (point, area and on a path, fonts by PostScript name, Windows-1252), or outlines (Text: Outlines); hidden objects, which the format can't hide, in a hidden layer of their own, omitted or made visible (Hidden Objects); images with see-through pixels flattened with the art under them or omitted (Transparent Images). The `.ai` reader reads legacy type (`To` … `TO`) and `Ar`. `vectorcraft-cli convert` takes `--ai-version 7`, `--hidden-objects` and `--transparent-images`; scores unchanged (estimated) |
|
||||
| 2026-10-13 | minor | TIFF: grayscale files with an alpha channel or other extra channels place, relink and open, read as CMYK files with alpha already were (8 and 16 bits, either polarity; #1489, part of #1466); the rows for #1434 (strokes kept apart from a faded or masked fill, a `.ai`'s RGB numbers) and #1435 (SVG knockout groups without masks, `--decimals`) were written by those PRs; scores unchanged (estimated) |
|
||||
| 2026-10-12 | minor | TIFF is available in Export for Screens and Asset Export with shared format settings; scores and hours unchanged |
|
||||
| 2026-10-12 | minor | Affinity import: a text frame too short for its first line (a 64 pt title in a 54 pt frame) is made taller from its top, with a warning in the open result, instead of showing nothing (#1423), as `.ai` area type is (#1392); the spacing Affinity itself fits the line with isn't read; scores unchanged |
|
||||
|
||||
+3
-1
@@ -599,7 +599,9 @@ PostScript form, which keeps layers, groups, compound paths and clipping groups
|
||||
of `range` (default all; `{name}-{artboard}.ai` when several, listed in the result's `files`), with
|
||||
`transparentImages: "flatten"` (default) or `"omit"` for images with see-through pixels, opacity or a blending mode,
|
||||
`hiddenObjects: "layer"` (default: a hidden layer of each layer's hidden objects), `"omit"` or `"visible"`, and
|
||||
`outlineText: true` to write type as outlines instead of text objects.
|
||||
`outlineText: true` to write type as outlines instead of text objects. From the CLI: `vectorcraft-cli convert in.svg
|
||||
out.ai --ai-version 7 [--hidden-objects layer|omit|visible] [--transparent-images flatten|omit] [--outline-text]
|
||||
[--range R]`.
|
||||
|
||||
Drive a tool like a mouse:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user