Commit Graph
4080 Commits
Author SHA1 Message Date
bflatastic d807236bf2 i18n(zh-hant): the shared parameter-check errors, now that Traditional Chinese translates every message (#2930, #2784)
#2784 made zh-hant a language that translates every status and error message while #2930 added the shared parameter-check errors to the others; main's shared_param_check_errors_are_translated failed on zh-hant.
2026-10-19 00:15:35 +07:00
BFlat 9c1d1d56ed Merge pull request #2944 from dotCooCoo/fix/save-for-web-preview-folder-per-run
Save for Web: each browser preview is written to its own folder
2026-10-19 00:10:12 +07:00
BFlat 53bd154059 Merge pull request #2938 from dotCooCoo/fix/legacy-ai-names-windows-1252
Legacy .ai export: the title and spot color and gradient names are written in Windows-1252
2026-10-19 00:09:56 +07:00
BFlat 1f2e90a7b3 Merge pull request #2937 from dotCooCoo/fix/ai-image-left-out-warns
.ai import: the editing data reader warns about each image it can't read
2026-10-19 00:09:38 +07:00
BFlat c7f748c75c Merge pull request #2936 from dotCooCoo/fix/editing-data-hash-reads-utf16-desc
PDF and .ai import: editing data with a UTF-16 description is checked against its pages
2026-10-19 00:09:23 +07:00
BFlat 4de769175e Merge pull request #2935 from dotCooCoo/fix/issue-2830
Legacy .ai export: an F line follows each %AI5_EndRaster
2026-10-19 00:09:07 +07:00
BFlat 9a8e2ac6a0 Merge pull request #2930 from dotCooCoo/fix/number-param-error-translated
i18n: number, object id and date parameter errors are translated
2026-10-19 00:08:55 +07:00
BFlat 419ed87cff Merge pull request #2929 from dotCooCoo/fix/anchor-commands-refuse-a-bad-subpath
Paths: anchor commands refuse a subpath that is not a whole number
2026-10-19 00:08:43 +07:00
BFlat eeb9513bbb Merge pull request #2921 from dotCooCoo/fix/links-on-mapped-drives
Links: a document opened from a mapped drive finds links on its share
2026-10-19 00:08:31 +07:00
BFlat c092ca1a48 Merge pull request #2917 from dotCooCoo/fix/menu-commands-refuse-text-numbers
Transform Each, Rasterize, Mosaic, Trim Marks and Rearrange: a number given as text is refused
2026-10-19 00:08:16 +07:00
BFlat ba2a11a807 Merge pull request #2914 from dotCooCoo/fix/pdfinfo-reads-postscript
MCP: document.pdfInfo answers one page for an EPS, a .ps file or a PostScript .ai
2026-10-19 00:08:04 +07:00
BFlat f1757c7bda Merge pull request #2907 from dotCooCoo/fix/eps-tiff-predictor-all-depths
EPS and .ai import: images with TIFF predictor 2 draw their samples at every bit depth
2026-10-19 00:07:47 +07:00
BFlat e616f1fe5c Merge pull request #2784 from dotCooCoo/feat/zh-hant-messages
i18n: Traditional Chinese translates status-bar and error messages
2026-10-19 00:07:32 +07:00
BFlat 647d51eaf6 Merge pull request #2765 from dotCooCoo/feat/open-targa-files
File formats: Targa (.tga) files open and place
2026-10-19 00:07:17 +07:00
BFlat 0d34a58b7b Merge pull request #2943 from youngeuibae/page-api
web: window.vectorcraft, the control channel for the page
2026-10-19 00:07:07 +07:00
BFlat 3a685eae61 Merge pull request #2939 from MortenHusted/feat/select-by-color
Select: select.color picks objects by fill and stroke colour, no object needed
2026-10-19 00:06:55 +07:00
BFlat e4d94109a2 Merge pull request #2922 from dotCooCoo/fix/issue-2871
Type: a click away from the text being edited ends editing without making new text
2026-10-19 00:06:44 +07:00
BFlat 4a90d13fc0 Merge pull request #2916 from dotCooCoo/fix/issue-2881
Fields: arrow keys and the wheel step to the next whole unit, and Ctrl/Cmd steps to the next tenth
2026-10-19 00:06:26 +07:00
BFlat 8a2d0db225 Merge pull request #2915 from EricKuck/fix/ai-outer-glow-dilation
Effects: an Outer Glow grows its solid silhouette by a quarter raster pixel before the blur
2026-10-19 00:06:16 +07:00
BFlat e358bbfdfb Merge pull request #2928 from nrq6993-a11y/stream/vc-issue-2719-wysiwyg-zoom
Fix #2719: honor Display Print Size for status-bar 100% zoom
2026-10-19 00:06:00 +07:00
BFlat 7d7853d7fd Merge pull request #2931 from MortenHusted/fix/raster-scale-only
CLI, MCP: the raster scale no longer resizes DXF exports
2026-10-19 00:05:46 +07:00
BFlat 0a14001126 Merge pull request #2911 from nrq6993-a11y/stream/vc-issue-2646-floating-panel-opaque
Fix #2646: keep undocked shared-dock panels opaque
2026-10-19 00:05:29 +07:00
BFlat 910e33b796 Merge pull request #2927 from nrq6993-a11y/stream/vc-issue-2727-mask-editing-dim
Fix #2727: opacity-mask editing no longer dims the canvas
2026-10-19 00:04:45 +07:00
BFlat 9b64fce9ec Merge pull request #2913 from Higgs32584/fix/2707-cmyk-icc-output-tags
CMYK profiles carry every tag an ICC output profile requires (#2707)
2026-10-19 00:04:16 +07:00
BFlat cd35c27a53 Merge pull request #2941 from devius/ka-fixes
i18n(ka): Letter and Word Spacing as in the other Craft apps; "weren't read" in the catalog's usual form
2026-10-19 00:04:00 +07:00
dotCooCoo ab01a1a927 Save for Web: each browser preview is written to its own folder
Preview in Browser wrote every page to one folder,
VectorCraft Save for Web in the system's temporary folder. A second
preview of a document with the same title, from the same app or from
another one running, overwrote the first preview's page, and any image
file of the same name (PNG-8 and PNG-24 both write .png), before the
browser read them. The same overwrite made
dialogs::tests_save_for_web::preview_in_browser_opens_the_page fail now
and then, when another Save for Web test in the same binary, or a test
run in another checkout on the machine, previewed Untitled-1 at the
same time.

Each preview now goes to a new folder inside that one, named after the
process id and a count of the process's previews. A name that an
earlier process with the same id left there is skipped for the next
count. The page keeps its name and its images folder. A preview first
removes the entries of VectorCraft Save for Web that were last changed
an hour ago or earlier, which also clears the files the single folder
held before.

Docs: docs/target-app-parity.md.
2026-10-19 00:03:53 +07:00
dotCooCoo d054b5b4c7 Legacy .ai export: the title and spot color and gradient names are written in Windows-1252
Saving a version 7 .ai wrote the title, spot color names and gradient
names as the UTF-8 bytes of their characters: a spot color named Café
was written (Caf\303\251) in the header's custom colors and in each x.
Type and, since #2722, layer names are written in Windows-1252, the
encoding the file installs with TE.

These names now go through #2722's Windows-1252 path, so Café is
written (Caf\351). A character outside Windows-1252 is written as ?,
with one warning for all of these names. A spot color keeps one name
in the header, in each x and X and in gradient stops, and a gradient
keeps one name in its definition and in each Bg. Two spot colors or
two gradients whose names become the same that way are numbered (? 2).

Docs: docs/file-format-parity.md.
2026-10-19 00:03:52 +07:00
dotCooCoo ba32ef5b09 .ai import: the editing data reader warns about each image it can't read
An image in a .ai's editing data whose operands had no matrix, fewer
than 11 numbers, or a matrix of other than six numbers was left out
with no warning. So was one whose matrix maps it onto a line or a
point. The reader's warnings did not mention such an image, while the
reader warned "an image VectorCraft can't read was left out" for an
image whose size or bit depth it can't use.

Each of those exits now adds the same warning, as does the one where
the decoded pixels don't make an image.
2026-10-19 00:03:51 +07:00
dotCooCoo f0c2d8c890 PDF and .ai import: editing data with a UTF-16 description is checked against its pages
A PDF or PDF-compatible .ai saved with Preserve Editing carries the
native document as an embedded file, with a hash of its pages at the
end of the file's /Desc. The import read /Desc with from_utf8_lossy and
looked for "hash ". /Desc is a PDF text string, which may be written as
UTF-16BE with a byte order mark (ISO 32000-1 7.9.2.2). Written that
way it holds no UTF-8 "hash ", so the import found no hash, took the
editing data as intact and reopened the native document with no
warning, even after another app had changed the pages.

/Desc is now read with text_string, the importer's decoder for text
strings, so the hash is found in UTF-16BE, UTF-8 and PDFDocEncoding.
Changed pages open as artwork with the "changed in another app"
warning. The embedded file's /UF and /F names are decoded the same
way, so editing data named only in UTF-16BE is found.
A /Desc without a hash is still trusted, as before.
2026-10-19 00:03:51 +07:00
dotCooCoo e5c9054324 Legacy .ai export: an F line follows each %AI5_EndRaster
alongtheblue-sketch took 0.12.0's version 7 output of the SVGs in #2692
and #2830, edited it by hand and opened it in the reference app
(https://github.com/storytold/vectorcraft/pull/2801#issuecomment-6244853548).
Writing the image lines as #2801 does, with the bracketed matrix and
the 60-digit data lines, did not change the result there. With one
line, F, added after %AI5_EndRaster, the reference app opened the image
in its clipping group and the art after it in both files.

The writer now writes F after every %AI5_EndRaster: clipped, grouped
and loose images, flattened images and images in pattern tiles. No path
is open at that point, so the line paints nothing. VectorCraft's reader
opens the files with the same objects as before, and the file's
PostScript prolog draws the same page.
2026-10-19 00:03:50 +07:00
dotCooCoo 9fe0f03de2 i18n: number, object id and date parameter errors are translated
The errors of the parameter checks that many commands share had no
@msg row in any catalog: "`{key}` must be a number, not {v}" from
check_numbers (object.move, object.rotate, object.setBounds and the
other callers), "missing integer `{key}`" from index_param in
cmd/appearance.rs (appearance, effect and freeform gradient commands),
the three object id errors of checked_ids_param and checked_id, and
the Unix seconds error of date_param. A template
matches only the whole text, so the row for "`{key}` must be a
number" did not match the longer check_numbers message. These errors
showed in English in the status bar, and "no such object id {value}"
matched the general "no such object {0}" row and showed half in
English. The scan in complete_languages_translate_every_message does
not read messages built with bad(), so that test did not report them.

Each of the 6 messages now has a row in the 18 catalogs that translate
every status and error message and in Bulgarian, Danish, Indonesian and
Dutch, and "missing number `{key}`" has a row in Danish and Indonesian.
No English string changes.

Docs: docs/target-app-parity.md.
2026-10-19 00:03:48 +07:00
BFlat 429e147164 Merge pull request #2940 from ElPaule/i18n/de-missing-entries
i18n(de): add missing PSD error messages and effect Soft entry
2026-10-19 00:03:48 +07:00
dotCooCoo c0ec14b86d Paths: anchor commands refuse a subpath that is not a whole number
path.curvatureEdit, path.removeAnchor, path.convertAnchor,
path.reshapeSegment, path.split, path.setHandle and path.insertAnchor
read subpath as an unsigned integer and fell back to 0 for any other
value. A subpath of 1.5, -1 or "1" edited subpath 0 and the command
reported success. path.split read anchor and segment with as_u64 too
and treated any other value as absent, so a bad anchor beside a good
segment split at the segment.

These commands now refuse a subpath that is not a whole number of 0 or
more with "missing integer `subpath`", the error path.curvatureEdit,
path.removeAnchor, path.convertAnchor and path.reshapeSegment already
give for a bad anchor or segment, and path.split refuses such an anchor
or segment too. Without a subpath, or with null, they edit subpath 0 as
before. The document and the undo history stay as they were after each
error. The params text of the six commands that listed subpath as
required now marks it optional.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-19 00:03:47 +07:00
dotCooCoo 89a73abc38 Links: a document opened from a mapped drive finds links on its share
craft-docpath follows a network path only on the share the document is
on, and its caller contract asks for a document opened from a mapped
drive to be passed by its UNC path. fileio::document_path passed the
drive path as given, so a document opened as Z:\jobs\doc.vectorcraft
treated a link stored as \\server\share\img\logo.png, on the share
behind Z:, as on another computer: the image was missing, and
document.open, links.check and links.info gave refused: "the path is on
another computer".

On Windows, when a stored path is refused as on another computer and
the document is on a drive, document_path now reads the final path of
the document's folder (std::fs::canonicalize). When that names a share
(\\?\UNC\server\share\...), the path is checked again against the
document's path on that share. Links on other computers stay refused,
and paths that were followed resolve as before. Opening a document,
Link Info, links.check and the linked-file watch all use it. Other
systems are unchanged.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-19 00:03:47 +07:00
dotCooCoo cc8944ad2a Transform Each, Rasterize, Mosaic, Trim Marks and Rearrange: a number given as text is refused
Transform Each, Rasterize, Create Object Mosaic, Create Trim Marks and
Rearrange All Artboards read their optional numbers with f64_or, which
falls back to a default for a value that is not a JSON number.
object.transformEach {"scaleH": "50"} left the selected objects at
their size and reported success. Rasterize did the same with ppi,
Create Object Mosaic did the same with width, height, spacingX and
spacingY, Create Trim Marks did the same with offset, length, bleed and
weight, and Rearrange All Artboards did the same with spacing. Crop
Image cropped to the artboard when rect was a string or another value
that is not an array.

These commands now fail with "`<key>` must be a number, not <value>"
for a value that is not a number or null, as the transform commands
do, and change nothing. Transform Each checks scaleH, scaleV, moveH,
moveV and rotate. Crop Image refuses a rect that is not an array of
four numbers with "rect must be [x, y, width, height]", the message it
already gave for an array of the wrong length; a null rect crops to the
artboard, as a missing one does.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-19 00:03:46 +07:00
dotCooCoo 05264b2801 MCP: document.pdfInfo answers one page for an EPS, a .ps file or a PostScript .ai
document.pdfInfo refused PostScript (an EPS, a .ps file, or a .ai in
PostScript form), mostly with "this is a PostScript file ..., not a
PDF", although document.open and file.place read the same file
through the EPS reader as one page.

It now answers {pages: 1, needsPassword: false, pageInfo: [{width,
height, rotation: 0, boxes: {}}]}. The page is the file's bounding box
(%%HiResBoundingBox when it has one, a US Letter page without one),
read from its comments without running its program. thumbnail: 1 is a
PNG of what that page prints, read by the EPS reader without any
editing data the file carries. A program whose header is only %! is
read as PostScript, as clipboard.importEps reads it.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-19 00:03:45 +07:00
dotCooCoo 372887fc6c EPS and .ai import: images with TIFF predictor 2 draw their samples at every bit depth
The PostScript interpreter that reads EPS and PostScript .ai files
accepts a FlateDecode or LZWDecode filter with Predictor 2 at
BitsPerComponent 1, 2, 4, 8 and 16, but undid the horizontal
differencing only at 8 bits. At the other depths the filter gave back
the stored differences, and the image drew them instead of its
samples.

The predictor is now undone at every depth it accepts, as ISO 32000-1
§7.4.4.4 describes: each component adds the same component of the
pixel to its left, within its bit width, and each row starts again.
16-bit components add as big-endian 16-bit numbers. The padding bits
at the end of a row stay as they are, and 8-bit data takes the same
path as before. The PNG predictors are unchanged.

Docs: docs/target-app-parity.md.
2026-10-19 00:03:43 +07:00
dotCooCoo 841fc0cd51 i18n: Traditional Chinese translates status-bar and error messages
Squashed from #2784 (its merge of main dropped).
2026-10-18 23:50:58 +07:00
dotCooCoo d7e7066251 File formats: Targa (.tga) files open and place
Squashed from #2765 (its merge of main dropped).
2026-10-18 23:50:58 +07:00
focuerandClaude Opus 5.5 dc7216f0e4 web: rustfmt window.vectorcraft
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:50:58 +07:00
MortenHusted 36aecff81d Select: select.color reads compound paths and empty type as document.inspect does
A compound path holds its members, so select.color passed over it and
looked at the members instead, whose paint inspect doesn't report: a
black compound path (art with holes, as PDFs bring in) never matched
"#000000". It now matches by its own fill and stroke, and its members
never do. Type without characters reads as the default character fill,
as inspect reports it (CodeRabbit on #2939).
2026-10-18 23:50:58 +07:00
focuerandClaude Opus 5.5 9dbab52168 web: window.vectorcraft, the control channel for the page
The same JSON methods as the desktop control server (engine.execute, ui.inspect, ui.screenshot, …),
as promises on window.vectorcraft, like FilmCraft's window.filmcraft: an agent driving the editor in a
browser tab or an <iframe> uses the same commands as the CLI and the MCP server. openFile opens
bytes the way a dropped file opens; captureDownloads keeps saves in the page for readFile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:50:58 +07:00
dotCooCoo 09a6fbe470 Type: a click away from the text being edited ends editing without making new text
While a Type tool edited text, a click on blank canvas ended the
editing and also placed new point type at the click. Area Type and
Type on a Path did the same with a click on a path.

Such a click now only ends the editing. The typing session is
committed, empty point type that a click placed is discarded as before,
and the Type tool in use stays active; the next click makes new type.
The same applies when the editing began with a double-click from a
selection tool. A click on other type still edits it at once, and a
drag that draws an area-type frame still makes the frame.
2026-10-18 23:50:57 +07:00
dotCooCoo b30d80e056 Fields: arrow keys and the wheel step to the next whole unit, and Ctrl/Cmd steps to the next tenth
In number fields, Up/Down and a wheel notch added a whole step and kept
the fraction, so 5.1 mm stepped up to 6.1 mm. A plain step now goes to
the next whole unit in its direction (5.1 goes up to 6 and down to 5; 5
goes up to 6 and down to 4), and a Ctrl/Cmd step goes to the next tenth,
in the field's own unit. Repeated presses or notches of one size add or
take one step each, and presses and notches are applied in the order
they came. A Shift step still adds or takes ten and keeps the fraction.

The number fields that widgets.rs draws for the panels, the Control bar
and the dialogs (unit, percent, degree and count fields) all use this
step (widgets::step_value).
2026-10-18 23:50:57 +07:00
EricKuckandClaude Fable 5.1 1b8e3d9ae1 Outer Glow grows its solid silhouette by a quarter raster pixel before the blur, as the glows AI files export measure
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-18 23:50:57 +07:00
bflatastic 12d107cc56 fmt (#2928) 2026-10-18 23:50:57 +07:00
MortenHusted eba9abc21e CLI, MCP: the raster scale no longer resizes DXF exports
`vectorcraft-cli run/convert --scale` and the MCP export tool's `scale`
are raster pixels per point, but they were passed to every export, and
DXF reads `scale` as drawing units per unit: a 2x PNG next to a DXF
doubled the drawing and left it unitless ($INSUNITS 0). They now go
only to raster formats. DXF's own scale stays reachable through the
format options.
2026-10-18 23:50:57 +07:00
bflatastic 88494319da fmt (#2911) 2026-10-18 23:50:57 +07:00
MortenHusted d25289a3be Select: select.color picks objects by fill and stroke colour, no object needed
Scripts had to know an object id before they could select art by colour
(select.same.* and select.magicWand start from one). select.color
{fill?, stroke?} takes colours as paint.setFill does and selects the
objects whose fill and stroke read as them in #rrggbb, as
document.inspect reports colours, with Select > Same's selection rules.

The label is translated in each of the 23 catalogs, which
complete_languages_translate_every_menu_string requires.
2026-10-18 23:50:57 +07:00
nrq6993-a11yandCursor 2025c357d9 Fix #2719: honor Display Print Size for status-bar 100% zoom
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 23:50:57 +07:00