With only ruler guides selected, X is the position of the vertical ones and Y
that of the horizontal ones; typing a value moves them (guide.move), together
when several are selected.
A point placed by the Pen, the shape tools and the other drawing tools, and a
dragged anchor, lands where two paths cross, where a path crosses a ruler guide
and where two ruler guides cross, with the Smart Guides label "intersect".
VectorCraft does not run scripts written for the reference app, and
File › Scripts held only the disabled Other Script…. File › Scripts ›
Check Script… picks a .jsx, .jsxinc or .jsxbin file, reads it without
running any of it, and shows a report: what the script needs (the
script language's own objects, the document model, files, menu
commands, dialogs, or features only the reference app has), what it
would do outside the document, the menu-command strings it passes, the
document-model member chains and type names it uses, its directives,
the files it includes, and the problems that would stop it loading.
Copy Report copies the report as JSON. File › Open and drag-and-drop
show the report for those files too.
- vectorcraft-scriptcheck, a new Standalone crate with no
dependencies, holds the checker: a lexer for ECMAScript 3 with E4X
literals and the #name and //@name directive lines, and an analysis
of the tokens that follows variables, function scopes and the files
a script includes. It never recurses: open brackets, the levels of
an XML literal and the function bodies being read are kept on stacks
capped at 4,096. It reads at most 8 MiB of a file and 32 MiB with the
included files, follows 64 included files 16 deep, looks up at most
1,024 paths for them, keeps 1,000 entries in a list, tracks 1,000
variables holding member chains and 1,000 holding File objects, and
cuts echoed text to 120 characters. A compiled script is reported as
compiled and isn't read.
- script.check (engine, a query) takes path, data or dataBase64. With a
path and includes: true, it reads the files the #include lines name
from inside the script's folder, through the automation read root,
and when the script or one of those files assigns a member chain or a
File object to a variable, the check treats the variable as holding
it in every file. It doesn't follow absolute names, names, folders or
links that lead out of the folder, names or folders longer than 4,096
bytes, or JSINCLUDE, and it reads only regular files.
- ui.checkScript shows the report (dialog scriptCheck). File › Open
lists Scripts (.jsx, .jsxinc, .jsxbin) and sends a script's path to
script.check, which reads at most 8 MiB of it.
The language rules come from ECMA-262 3rd edition and ECMA-357 2nd
edition. The directive, platform and document-model root names come
from the public JavaScript Tools Guide and scripting guide pages that
catalog.rs cites by URL, and executeMenuCommand, doScript, loadAction,
unloadAction and selectTool come from the public forum posts cited
there; only names are used. Every script in the tests is written from
scratch with invented names.
Docs: docs/mcp.md, docs/target-app-parity.md.
Inkscape 1.2+ saves a multi-page document as <inkscape:page> elements
in its <sodipodi:namedview>; VectorCraft opened it with one artboard
the size of the root, leaving the other pages' art outside any. Each
page with a size now becomes an artboard at its place (through the
viewBox, as the art is), named by its inkscape:label or "Artboard N".
Files without pages keep their one artboard.
Fixes#1601
A filter that can't become a live effect warned "filter on a group
ignored", even on a plain <rect>: usvg wraps every filtered element in
a group of its own, which the message named. The warning now names the
filter and its primitives and the element (by id, or "an object"), and
says it is drawn without it: "filter 'f' (feColorMatrix) on an object
isn't supported; drawn without it".
Fixes#1598
document.open (and file.newFromTemplate) with a path relative to the
working directory took the SVG's folder from Path::parent(), which is
"" for a bare file name and was then dropped, so relatively linked
images were "not found" (and, linked by their bare name, not listed in
missingLinks either). A relative path is now made absolute first: its
folder is the working directory, as for the absolute path.
vectorcraft-cli convert printed only the export's warnings; what reading
the input left out now comes as importWarnings.
Fixes#1604
A character style's OpenType features took nine tags. OtFeatures now
also keeps ss01-ss20, salt, titl, pnum, lnum, sups and subs (off by
default, one bit each in `extra`): they are accepted by the type
commands, stored with the style and passed to the shaper, so a font
that has them uses them.
The Affinity import test used ss01 as its example of a feature kept but
not rendered; it now uses cv01 for that (character variants still
aren't rendered) and keeps ss01 as one that is.
Fixes#1607
A scan's paper is a tenth darker in one corner than in another. Flat Logo found
each tone of it as a colour of its own and traced the bands and the specks
between them: on the scanned inputs 470 paths, 21 px from the art on average.
Two palette colours are now one when the pixels between them are no fewer than
a third of those at the lesser of the two: flat colours leave only their shared
edge between them, tones of one colour fill the gap. Whether the image is flat
art at all is still asked of the tones as found.
Flat Logo on its inputs, all sizes and variants: 3.106 -> 0.090 px off on
average, 88.5 -> 0.82 px at most, 69.9 -> 3.9 paths; clean, aliased, blurred
and noisy art as before.
A flyout's rows were 250 pt wide whatever they held, so in Spanish (and
other languages with long tool names) a name ran into its shortcut. The
rows are now as wide as the longest name and shortcut need, and never
narrower than before.
A save writes a temporary file beside the document and renames it over
it. Some network shares refuse one of those steps although the document
itself can be written. The save now falls back, without giving up what
the rename is for:
- the temporary file can't be created beside the document: it is made
in the system's temporary folder (for its owner only);
- the rename is refused: the content, whole and flushed in the
temporary file, is copied into the document itself;
- when that copy fails, the temporary file stays and the error names
it; when the document can't be opened for writing, it is untouched
and the first error is returned;
- permissions that can't be copied to the temporary file (SMB, FAT) no
longer fail the save.
A folder that isn't there and a full volume fail as before.
Lock › All Artwork Above and Hide › All Artwork Above went through the
objects above each selected object in its top-level layer, one selected
object at a time. For each object they looked up in a list whether it
was selected or already found, and they computed its bounds again for
each selected object below it until one overlapped it. With 100 tiles
selected under 25,000 rectangles, a release build of vectorcraft-cli
took 6.4 s for Lock, and with all of 5,001 objects selected it took
8.8 s and locked nothing.
The commands now go through each top-level layer that holds a selected
object once, and check each object that is not selected against the
bounds of the selected objects below it. The selected objects and the
objects found are kept in sets, and each object's bounds are computed
once. The objects they lock or hide, the count, the selection and the
undo step are the same as before. On the same documents Lock now takes
under 0.1 s.
Docs: docs/target-app-parity.md.
The renderer kept one tile per pattern name and ink plane, and used it
only at the raster scale it was made at: the device scale rounded up to
a power of two and capped. Two objects that paint one pattern at scales
for which the raster scale differs, such as a pattern scaled to 25%
with Transform Pattern Tiles next to the same pattern at 100%, replaced
each other's tile, and every frame rasterized both tiles again.
Tiles are now kept per pattern name and raster scale, within the tile
cache's budget of 128 MiB per thread and ink plane. When the budget
fills, the cache drops the least recently used tiles first. A tile is
still used only while the pattern's art, tile, tile type and overlap
are the ones it was made from. At 760%, with a pattern of 576 stars in
a 288 pt tile on a rectangle that fills the view, and the same pattern
at 25% on a square, release builds of vectorcraft-cli bench at
2880x1800 took a median of 26.0 ms a frame on main and 8.8 ms with this
change, with 8 threads.
Docs: docs/target-app-parity.md.
Reviewed the rows added after the Polish catalog was written (graph
legend and position options, Transform Objects, Load EPS into
Clipboard, the unknown-parameter and image-size messages, …): the
translations are correct and read naturally, so no wording changes;
drop the "not reviewed by a native speaker" marker above them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DukHNvUY45rjRnvtz91x33
Snap Curves To Lines made every straight piece within 2.5 degrees of level or
upright exactly so, whatever its length: a 200 px line 2 degrees off had each end
moved 3.5 px. Now a piece is levelled only when neither end moves more than
1.6 px; a longer line that far off is left as the image has it.
Technical Drawing (the preset with the option on) on its inputs: largest
distance from the art 4.21 -> 1.46 px (1.43 before levelling existed), mean
0.178 -> 0.126 px; on the askew inputs 98% -> 70% of the outline comes out level
or upright.
Gradients (params `gradients`, a checkbox in the panel for Grayscale and Color;
off unless asked for): an area whose colour changes evenly along one direction
is traced as one path filled with a linear gradient, not as bands of flat colour.
Gradients are found before the palette is made, so no colour is spent on their
bands: a connected run of smoothly changing pixels is a gradient when a plane
fits each colour channel with all three sloping the same way, the colours along
that way are at most six stops with ramps between them, and painting them back
gives the area's own pixels. Flat colour, soft edges between flat colours and
shading that goes two ways are left as they were.
The harness gains two linear-gradient inputs with known lines and stops, and
measures whether each is found, the angle of its line and the colours of its ramp.
Straight type takes the tracking that keeps its length as the file set
it; type on a path took none, so letter-spaced type on a curve came back
closed up to the font's advances (an "OFFICIAL ISSUED" badge sat to one
side of its band, a condensed title ran off the end of its path). Type on
a path now takes the same tracking, its length measured along the path
from the first glyph to the end of the last.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Type on a path is written glyph by glyph, and a stroke added to it as each
glyph's outline stroked right after the glyph. The path in between ended the
line, so each glyph came in as its own text object. Such a stroke, in the
glyph's own paint, is now held with the line and written after it, where it
becomes the type's stroke as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
# crates/pdf/src/tests_import_lines.rs