mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
Plug-ins: filters at API level 2 read type, images and symbol instances
A filter manifest at `api` 2 may list `inputs` (`type`, `image`,
`symbolInstance`). Such a filter is also given the selected objects of
those kinds, read only: type with its runs and paragraph attributes,
images with their pixel size, color mode and, when embedded and small
enough, their RGBA pixels in base64 (never a linked file's pixels or
path), and symbol instances with their symbol and transform.
The output must return each read-only object as {"id": ...} alone or
exactly as given. A change, an omission or a duplicate is refused
before the edit, so the document and undo history stay as they were,
including for output handed in from a heavy run. A filter without
`inputs` gets the same input bytes as before.
A manifest that lists `inputs` below `api` 2, outside a filter, with an
unknown or repeated kind, or with a permission list that lacks
`doc.read` does not install.
Part of #4333
This commit is contained in:
+57
-5
@@ -145,7 +145,10 @@ capability model proposed for PhotoCraft plug-ins
|
||||
`documentData` is `null` and an output that sets it is refused; without `doc.write` an output that changes the
|
||||
document is refused. A refused output leaves the document as it was.
|
||||
- `api` is the plug-in API level the manifest is written for: `1` (the default) or `2`, which adds the [host
|
||||
imports](#host-imports-api-level-2). A higher one is refused. `plugin.list` and `plugin.info` give it as `api`.
|
||||
imports](#host-imports-api-level-2) and a filter's `inputs` ([reading type, images and
|
||||
symbols](#reading-type-images-and-symbols)). A higher one is refused. `plugin.list` and `plugin.info` give it as
|
||||
`api`. `inputs` is not a permission: the objects it asks for are read under `doc.read`, which a filter that lists
|
||||
`permissions` and `inputs` must list.
|
||||
- Parameter declarations are unchanged by permissions (`params`, below).
|
||||
|
||||
Every run gets a **fresh instance**, so no state survives between calls. Traps, exhausted budgets, malformed
|
||||
@@ -237,6 +240,11 @@ still returns `1`.
|
||||
filters](#heavy-filters)). Hosts from before it ignore the key, so there the filter gets a light run's budget.
|
||||
- `api`: the plug-in API level, `1` when left out. `permissions`: what the plug-in may do, a list of names
|
||||
([permissions](#permissions)); without it, what its kind implies.
|
||||
- `inputs` (filters at `api` 2 only): the kinds of object besides paths and compound paths the filter reads, any of
|
||||
`"type"`, `"image"` and `"symbolInstance"`, each at most once (`"inputs": ["type", "image"]`). Left out or `[]`, the
|
||||
filter gets paths and compound paths alone, as before. An unknown, repeated or wrongly typed entry, `inputs` on
|
||||
another kind, below `api` 2, or with `permissions` that leave out `doc.read`, is refused when the plug-in is
|
||||
installed, and so is `api` 2 on hosts from before it.
|
||||
- `extensions` (exporters only, and required): 1–8 file extensions, lower-case letters and digits without the dot
|
||||
(`["plt"]`); the first is the one Export As gives the file. A built-in format keeps an extension both list (`svg`):
|
||||
`document.export` then writes the exporter's format only when asked for by its format id.
|
||||
@@ -276,8 +284,9 @@ parameters uses `label`, `unit`, `help` and `visibleWhen`, and lists the paramet
|
||||
|
||||
`input` is UTF-8 JSON: `{"objects": [...]}`. An object filter gets the selected paths and compound paths in paint
|
||||
order (bottom first): the selected ones and those inside selected groups and layers; hidden, locked, guide (compound
|
||||
guides too) and clipping paths are left out, and so are other kinds of object (type, images, symbols, live blends…), which a filter never
|
||||
touches. With nothing selected the list is empty (a generator then adds its own objects). A live effect gets one
|
||||
guides too) and clipping paths are left out, and so are other kinds of object (type, images, symbols, live blends…),
|
||||
which a filter never touches unless its manifest lists them in `inputs` ([reading type, images and
|
||||
symbols](#reading-type-images-and-symbols)). With nothing selected the list is empty (a generator then adds its own objects). A live effect gets one
|
||||
object: its geometry (`type`, `path`, `fillRule`, `bounds`) and its `fills` and `strokes`, as a filter gets them (hosts
|
||||
from before these give geometry only). The paints are read only: an effect may draw as wide as a stroke or use a
|
||||
fill's colour to decide its shape, but it changes only the geometry.
|
||||
@@ -323,6 +332,49 @@ type and `blob` but without their data, which follows the JSON in a saved file;
|
||||
`plugin.<id>` for a live-effect plug-in), `params` and `visible`. Its fills' and strokes' own effects aren't listed.
|
||||
- `bounds`: `[x0, y0, x1, y1]`, the geometric bounds (read only).
|
||||
|
||||
### Reading type, images and symbols
|
||||
|
||||
A filter whose manifest lists `inputs` also gets the selected objects of those kinds, in paint order among the paths
|
||||
and under the same rules (hidden and locked ones, type that clips a clip group and anything inside a symbol, a placed
|
||||
document or a live object are left out). They are never turned into outlines, rectangles or the symbol's art. Each
|
||||
has `id`, `type`, `name` (when it has one), `bounds` (`null` until the object has been laid out or drawn) and
|
||||
`transform`, `[a, b, c, d, e, f]` mapping its own space (text space, pixel space, the symbol's art) into the document.
|
||||
In this example the character and paragraph styles are cut short; a filter gets every attribute:
|
||||
|
||||
```json
|
||||
{"objects": [
|
||||
{"id": 17, "type": "type", "bounds": [10, 38, 52, 52], "transform": [1, 0, 0, 1, 10, 50],
|
||||
"text": {"kind": "point", "vertical": false,
|
||||
"runs": [{"text": "Hello\nthere", "style": {"font_family": "Source Sans 3", "size": 12}}],
|
||||
"paragraphs": [{"justify": "Left"}, {"justify": "Center"}]},
|
||||
"truncated": false},
|
||||
{"id": 18, "type": "image", "bounds": [0, 0, 4, 2], "transform": [2, 0, 0, 2, 0, 0], "pixelSize": [2, 1],
|
||||
"colorMode": "rgb", "linked": false, "pixelsOmitted": false, "pixelsBase64": "AAAegGQAHoA="},
|
||||
{"id": 19, "type": "symbolInstance", "bounds": [100, 0, 110, 10], "transform": [1, 0, 0, 1, 100, 0],
|
||||
"symbolId": "Star", "overrides": {}}
|
||||
]}
|
||||
```
|
||||
|
||||
- Type (`"type"`): `text.kind` is `"point"`, `"area"` or `"path"`; `runs` are its text runs with their character
|
||||
attributes as the native file stores them (`inline` when a run is an inline graphic), and `paragraphs` holds one
|
||||
paragraph style per paragraph (the paragraphs are split at `\n`). No font data or glyph outlines are given. Type
|
||||
whose runs hold more than 256 KiB of UTF-8 text, or more than 4,096 runs or paragraphs, comes with `truncated:
|
||||
true` and empty `runs` and `paragraphs`.
|
||||
- An image (`"image"`): `pixelSize` is its width and height in pixels; `colorMode` is `"rgb"`, `"cmyk"`, `"gray"` or
|
||||
`"unknown"`, read from the image itself. An embedded image whose pixels take at most 1 MiB in base64 (443 × 443
|
||||
pixels fit) has them in `pixelsBase64`: straight RGBA, 8 bits a channel, row by row from the top, and
|
||||
`pixelsOmitted: false`. A larger one, and a linked image (`linked: true`), has `pixelsOmitted: true` and no pixels.
|
||||
The host never reads a linked image's file for a filter and never gives its path.
|
||||
- A symbol instance (`"symbolInstance"`): `symbolId` is the name of the symbol it shows, with `missing: true` when the
|
||||
document has no symbol of that name. `overrides` is `{}`.
|
||||
|
||||
These objects are read only. The output must list each of them exactly once, as `{"id": 17}` alone or exactly as it
|
||||
was given (numbers compare by value, so `1` and `1.0` are the same). A changed or added field, one left out, an object
|
||||
listed twice or left out, and a new object with one of these types are refused, and the document and undo history
|
||||
stay as they were: `objects[1] (id 17): read-only field 'text.runs[0].text' changed`, `objects (id 17): a read-only
|
||||
object was left out`. New objects listed after one of them go just above it. Their text and pixels count towards the
|
||||
input's half of the memory cap, and an echo of them towards the 64 MiB output cap.
|
||||
|
||||
### Parameters
|
||||
|
||||
`params` points at `params_len` bytes of UTF-8 JSON: the validated parameters, plus `_context`:
|
||||
@@ -420,6 +472,6 @@ per change of their input, parameters or paints (results are cached), not per fr
|
||||
|
||||
- Tool plug-ins (pointer events on the canvas, a guide line or rectangle, geometry back), panel plug-ins, importers
|
||||
(plug-in formats that open files).
|
||||
- Live effects that change paint (they reshape geometry; an object filter recolours), and filters on type, images or
|
||||
symbols.
|
||||
- Live effects that change paint (they reshape geometry; an object filter recolours), and filters that change type,
|
||||
images or symbol instances (a filter at `api` 2 reads them, see [`inputs`](#reading-type-images-and-symbols)).
|
||||
- Apply Last Effect and Last Effect work for plug-in effects; there is no "last filter" for object filters yet.
|
||||
|
||||
Reference in New Issue
Block a user