Commit Graph

508 Commits

Author SHA1 Message Date
shmuelbiller1 7d75280ab4 fix(package): preserve FONTS report header and document warning output 2026-10-09 14:35:42 -04:00
shmuelbiller1 c8642eeddb test(package): retain unreadable children and break circular dependencies without aborting 2026-10-09 14:34:21 -04:00
shmuelbiller1 0b326c48bc fix(package): keep copying linked documents on parse failures, cycles and depth limits 2026-10-09 14:33:39 -04:00
shmuelbiller1 f9384dfed7 test(package): nested native files retain PDF compatibility preview and compression 2026-10-09 11:55:49 -04:00
shmuelbiller1 71484fd013 fix(package): preserve nested previews, PDF content, compression and embedded assets 2026-10-09 11:54:37 -04:00
shmuelbiller1 7c3687af29 test(package): distinct nested assets sharing a stale source path remain separate 2026-10-09 11:52:37 -04:00
shmuelbiller1 ba1b7a834f fix(package): deduplicate by resolved source and rebase links per containing document 2026-10-09 11:51:54 -04:00
shmuelbiller1 f549f6ad4d style: keep new package traversal within rustfmt width 2026-10-09 11:37:28 -04:00
shmuelbiller1 a4a040653d test(package): resolve nested links from their actual source after moving files 2026-10-09 11:35:51 -04:00
shmuelbiller1 deff7bb757 fix(package): resolve transitive links against the moved file's actual location 2026-10-09 11:34:02 -04:00
shmuelbiller1 022069d5a5 fix(links): retain resolved source paths when packaging moved nested documents 2026-10-09 11:33:42 -04:00
shmuelbiller1 1f668dfaad fix(package): retain nested documents' embedded ICC profile bytes 2026-10-09 11:32:32 -04:00
shmuelbiller1 816a0fe762 test(package): reopen nested linked documents from portable folder and ZIP deliveries 2026-10-09 11:31:30 -04:00
shmuelbiller1 4fe06391d4 fix(package): retain existing top-level missing-link reporting API 2026-10-09 11:30:54 -04:00
shmuelbiller1 ae68704dfc fix(package): preserve rebased portable paths for relative output folders 2026-10-09 11:29:53 -04:00
shmuelbiller1 eacef005b0 fix(package): recursively collect and rebase placed documents and their assets 2026-10-09 11:29:01 -04:00
BFlat 9ff0277306
Merge pull request #763 from callmeBalloch/feat/affinity-af-validation
AF.4: harden current .af artboards, text and images with a pinned corpus
2026-10-09 22:21:20 +07:00
Riccardo Balloch 79c5d673ff AF.4: validate and harden Affinity 3 artboards, text and images 2026-10-09 13:45:55 +00:00
bflatastic 7255ac394d Fix #745: a working Libraries panel of graphics, colours and text styles
The Libraries panel was a placeholder: it invited dragging art onto it,
but nothing happened. It now keeps local libraries (no account, no
cloud), as Illustrator's Libraries panel does:

- drag art off the canvas (or a swatch) onto the panel to add it, or use
  + to add the selection's graphic, fill or stroke colour, character
  style or paragraph style;
- drag a graphic onto the canvas (or double-click it) to place a copy,
  click a colour to paint the selection through the active Fill/Stroke
  proxy, click a style to apply it to the selected type;
- the library picker and the panel menu create, rename and delete
  libraries; each is a .vclibrary file in a Libraries folder next to the
  preferences (session-only in the web app, headless sessions and runs
  without preferences).

Engine: library.list/get/setCurrent/create/rename/delete/add/use/
removeItem. A graphic is stored as a native document with a thumbnail:
adding copies as Copy does and placing pastes as Paste does, resources
and swatch-name conflicts included. Using a style adds it to the
document and applies it in one undo step.

Clipboard::to_document gave its layer the id u64::MAX, which made a
saved copy overflow Document::fix_next_id when read back; the layer now
takes an id above the objects', and fix_next_id saturates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 20:12:59 +07:00
BFlat a01b0dfc7a
Merge pull request #739 from AutoHenry/feat/602-scale-art-with-artboard
Fix #602: Scale Artwork with Artboard
2026-10-09 18:29:28 +07:00
bflatastic 00344f9b68 Fix #733: PDF export keeps type as text in embedded subset fonts
The PDF writer defaulted to Convert Text to Outlines, so every glyph of
every page became a path: a text-heavy PDF grew several times larger on
export (a 7-page document went from 27 KB to 226 KB) and its text could
no longer be selected or searched. Illustrator's PDF presets embed font
subsets and keep live text; that is now the default too
(advanced.outlineText: false). Outlining stays available as an option,
fonts that can't be embedded still become outlines with a warning, and
printer's marks (page information) are drawn as shapes as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 18:06:38 +07:00
HT f2b35fc039 Fix #602: Scale Artwork with Artboard scales the art with a resized artboard
`artboard.setProps {scaleArt: true}` maps the art fully inside a resized
artboard (as Move Artwork with Artboard gathers it) and its artboard guides
from the old rectangle onto the new one, each side by its own ratio, in one
undo step, and returns the ids scaled. Strokes, effects and corners follow
Scale Strokes & Effects and Scale Corners (`strokes`, `corners`), pattern tiles
Transform Pattern Tiles (`patterns`); locked and hidden art follows
`lockedAndHidden` (default: prefs moveLockedWithArtboard). The resolved choices
are journaled, so a replay scales the same objects the same way. A move that
keeps the size scales nothing.

The Artboard tool's `scaleArt` option (saved with `moveArt`) makes handle
drags proportional, as the public help describes, keeps them proportional at
the 1 pt minimum, and leaves the scaled art out of the Smart Guide targets.
Move and Scale Artwork with Artboard are check boxes in the Control bar and
Properties' Edit Artboards; the artboard size fields there and in the
Transform panel pass the option. Translated in the eight catalogs that have
Move Artwork with Artboard. docs/mcp.md and the ROADMAP updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:50:35 +01:00
bflatastic f8a7695c3a Fix #712: the bounding box hides while a drag moves, scales or rotates
During a Selection-tool drag the bounding box and its handles stayed on
screen while the art moved, so the content looked as if it slid inside
a box of its own. The box now hides once a drag moves, scales or
rotates the selection, as in Illustrator, and comes back on release. A
press that hasn't moved, and a marquee, keep it. Tools gain
`transforming()` (Session::tool_transforming) for this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:39:12 +07:00
bflatastic 4b9f9b9bc2 Part of #637: .ai files saved without PDF compatibility open from their editing data
Such a file's PDF part is a placeholder page, which was refused. When
the file carries editing data, it now opens from that alone: its
structure as a PDF-compatible file's, its point type made from the text
document, and type it can't make (area type, type on a path) left out
with a note that marks the import as lossy. Without editing data, or
with pages picked or layers off, the placeholder is refused as before;
damaged editing data says so.

The page-order note is no longer given when the page has no type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:35:22 +07:00
bflatastic 0be7640088 Part of #637: the editing data's structure read whole, colours, gradients, transparency, names, images and artboards included
The layers reader of the editing copy (operators translated into
PostScript for the interpreter, any file with RGB colours, gradients,
transparency or images falling back to its page) is replaced by a reader
of the whole structure (import/ai): layers and sublayers with their
options, groups, compound paths, clipping groups and layer clipping,
names, hidden and locked objects, RGB, CMYK, grey, named and spot
colours, gradients, transparency, fill rule, overprint, embedded images
with their alpha channel, guides and every artboard, and objects drawn
as their look when they have several fills or strokes, effects or a
brush. Containers: Zstandard, zlib or plain data in EPS and .ai.

The text placement, the comparison with the page and the overwrite guard
stay around it. The page's type takes its text object's place without a
group; the comparison is by lightness, on nothing, without layers that
don't print. Symbols, pattern fills, placed files and unknown operators
make the file come in as its page where they show, and are left out of
layers that don't.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:02:36 +07:00
BFlat 9f7526aee6
Merge pull request #721 from imachus/pr/ja-kinsoku-set
Type: Kinsoku Set — Hard (today's set), Soft and None (#633)
2026-10-09 15:51:18 +07:00
bflatastic 5db4d9b78b Merge remote-tracking branch 'origin/main' into land/719 2026-10-09 15:32:23 +07:00
imachus 806e543fd1 Type: Kinsoku Set — Hard (today's set), Soft and None (#633)
Paragraph panel › Kinsoku Set (with the East Asian options) and `text.setFormat {kinsoku}`, as
decided in #633:

- Hard: today's set, so existing documents don't change; the default, and not saved.
- Soft: as Hard, except that 々, the prolonged sound mark ー (JLREQ cl-10) and small kana (cl-11)
  may start a line: JLREQ's level 3 line-breaking rules (Appendix C.3). Half-width forms aren't in
  those classes and stay off the line start.
- None: no kinsoku.

The setting reaches every break the composers consider (greedy, every-line and hyphenation
points). Reset Panel returns to Hard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:26:37 +09:00
bflatastic 58b95b51ef Merge branch 'pr719' into land/719 2026-10-09 15:19:04 +07:00
bflatastic 0559aac53e Save and Export ask before replacing a file whose import left things out
The engine refuses to write over the file a document was read from when
reading it left something out, unless acknowledgeLoss is passed. In the
app that surfaced as an error naming a parameter. File > Save, Save As,
Save a Copy, Save as Template and Export As now ask instead ("Replace
'a.eps', the file this document was opened from?", with what would be
lost), and OK repeats the command with acknowledgeLoss. Closing a
document whose save asks keeps it open, and so does Package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 15:05:52 +07:00
bflatastic 53c4c6eb02 Merge branch 'pr715' into land/715 2026-10-09 14:57:46 +07:00
Matthew Farrow 8fe0fd8394 EPS import: bound what hostile editing data can cost, and say when it can't be read
- a story is read once however many text objects name it; the text objects, their pairs with the
  page's type, the pieces of a line and a story's size are capped, and over a cap the layers aren't used
- the ASCII85 of the text document is bounded before it is decoded
- joining the pieces of lines that interleave no longer removes the wrong pieces
- a run length too large for the text saturates instead of overflowing
- a dictionary left open at the end of a layer, and layers nested deeper than are read, make the
  file one that comes in as its page (they were silently dropped)
- a file whose editing data can't be decoded says so, and the notes about art that was too much or
  too far away count as losses, so writing over the source asks first
- the private data of a .ai is inflated under a cap of its own (the PDF reader's decoder has none)
- the other writers (PDF, selection, office, print) ask before replacing a source that lost things,
  and a recovered copy remembers that

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 03:49:49 -04:00
Matthew Farrow ec43ac5a1e Read Illustrator EPS and .ai layers from their editing data
An Illustrator EPS is a flattened page plus, after %%EOF, an editing copy of
the document; a PDF-compatible .ai carries the same in its private data.
Importing only the page lost layer names, order, visibility, hidden layers
and hidden objects and hidden text.

- eps: read the editing copy (Zstandard %AI24_DataStream, older zlib
  %AI9_DataStream) into layers, sublayers, groups, compound paths, clip
  groups and hidden objects, run by the existing PostScript interpreter.
  Falls back to the page, with a warning, when a shown layer uses an
  operator that isn't read or the art differs from the page by over 5%.
- eps: read the text document (ate.rs) to place type on hidden layers and
  objects; the page's type is matched to the file's text objects by
  position (pieces of a line included) and kept with the nearest one when
  none claims it. Area type and type on a path are left out with a note.
- pdf/engine: .ai files go through the same reader.
- engine/cli: a file whose import left things out isn't overwritten unless
  asked (acknowledgeLoss, --replace-lossy).
- eps: font names re-encoded with a *<n> suffix resolve to their family.
- i18n: es/it/ru for the new import messages; ROADMAP updated.

Container and text-document formats were inferred from user-owned files; the
Adobe file format specification was not read.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 03:49:49 -04:00
bflatastic f8138e14ba Fix #546: DXF export writes each fill's outlines before its hatch
Laser and cutter software skips HATCH entities, so shapes that were only
filled (type, traced art) reached it as nothing. Each filled area is now
written as its outlines (polylines and splines, in the fill's colour)
followed by the solid hatch; R12 keeps writing the outlines alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:49:42 +07:00
bflatastic a52ad5cac8 Fix #703: the Templates folder is in the desktop's documents folder
New from Template... and Save as Template opened their dialog in
~/Documents/VectorCraft Templates. On desktops whose documents folder has
another name (Italian ~/Documenti) or where the folder was never made, the
dialog started in a folder that doesn't exist and showed an error.

- The default Templates folder is now in the user's documents folder: on Linux
  and the BSDs the one XDG_DOCUMENTS_DIR names in user-dirs.dirs, elsewhere
  ~/Documents.
- The folder a dialog starts in is made when missing; where it can't be, the
  dialog starts in the nearest folder above it that exists, else home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:22:32 +07:00
Jax Spenser 29310175af Image Trace: Flat Logo mode (sub-pixel edges, restored corners, true lines and circles)
A fourth Image Trace mode for flat-colour logos. The existing tracer follows hard pixel
edges, so an outline can only be as good as the pixel grid; here each pixel is read as a
blend of the logo's flat colours, the blend is interpolated smoothly (cubic B-spline), and
every outline is placed where two colours are equally present, to a fraction of a pixel.

Outlines are then cleaned the way a person would:
- corners the blur rounded are put back (line fits either side of a bend, intersected);
- near-straight runs and near-circular arcs become exact lines and arcs (Snap Curves To Lines);
- the rest is fitted with as few cubic Beziers as the tolerance allows (Schneider);
- touching colours overlap by 0.06 px so no hairline gap opens between independent fits;
- shapes are painted biggest first; transparent areas fully enclosed by artwork (letters
  knocked out of a badge, the counters of an "o") are painted white so the logo reads the
  same on any background, or become real holes with Ignore White (each hole belongs to the
  smallest outline containing it);
- an outline whose fit strays more than 1.4 px from the raw contour is fitted plainly.

Colours are found automatically (and completed from pixels no blend of the known colours
explains, so a small accent is not lost) or named with `logoColors: ["#rrggbb", ...]` (white is
always its own class; colours closer than 12 count as one; at most ten). Gradients and photos
are refused with advice to use Color (a flat-colour score of the solid areas, 0.93). A
hard-edged source with no anti-aliasing is softened by under a pixel and fitted with looser
snap tolerances. Images over 1024 px on the long side are averaged down first (further, if
they are busy enough to make the unmixing expensive) and the result is mapped back exactly.
More real outlines than we will fit are refused, not silently truncated.

Also: a "Flat Logo" preset, the mode in the Image Trace panel (Method hidden: it always
stacks), the command docs and MCP prompt, es/fr/it/ru translations for the two new messages
and the mode name, and the ROADMAP.

Never-crash: no unwrap/expect/panic, every size and float is bounded and checked, with
tests for degenerate and extreme input (NaN/infinite parameters, 0x0 and 1x1 images, sparse
outlines, an anchor budget, a 200,000-entry palette) and a 250-run randomised no-panic
property test. The B-spline interpolation follows Unser et al. and Thevenaz et al., and the
curve fitter follows Schneider (Graphics Gems); both are written from the papers.

Measured (local experiment, not in CI): a flat-colour logo's vector original rendered down
to a soft 199x100 px PNG and traced. Mean edge error vs the original at 1600 px wide:
built-in colour presets 2.5 to 3.4 px, Flat Logo 0.78 px (0.48 px from a crisp source);
region overlap 0.88-0.91 vs 0.966. About 0.1 s for a 200 px logo.

Tests: 60 new in the trace crate (unmix, field, contours, geometry, Beziers, corners,
outline fitting, palette, end-to-end on synthetic shapes made in code) and 3 in the engine.
cargo xtask ci passes (fmt, clippy, test, assets, brands, layers, wasm): 4,290 tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 17:57:04 +11:00
bflatastic 5acc269a41 Merge #694: Radial Blur, Smart Blur and Unsharp Mask
# Conflicts:
#	ROADMAP.md
2026-10-09 13:36:38 +07:00
bflatastic e9bbf43d15 Fix #693: a click activates its artboard; in-place pastes go onto it
- A press with a selection tool inside an artboard makes it the active one, as
  the Artboard tool's does; before, only the navigator and the Artboards panel
  changed it.
- Paste in Place, in Front and in Back take `artboard` (the UI passes the active
  one): the objects go where they were on the artboard they were copied from,
  on that artboard. Without it, they paste where they were, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:32:44 +07:00
bflatastic 1e7f5084d8 Part of ROADMAP gap 2: Radial Blur, Smart Blur and Unsharp Mask on a pixel-filter pipeline
Effect › Blur › Radial Blur (spin/zoom, draft/good/best) and Smart Blur
(Normal mode), Effect › Sharpen › Unsharp Mask: Photoshop-style filters in
vectorcraft_effects::pixel, run by the renderer on the object's pixels in
stack order with Gaussian Blur and Feather, cached while panning; lengths in
points, bounded work per pixel. PDF, Expand Appearance and SVG export write
the effected objects as images. Dialogs with preview (method/quality
dropdowns, fields in documented order), menu entries, translations, tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:30:31 +07:00
bflatastic 2de7257736 Merge #667: native Affinity import with artboards, vectors, text and images 2026-10-09 12:48:31 +07:00
bflatastic 4ab13dabfb Part of #663: User Interface > Show Tool Group Labels
The toolbar names its tool groups (Select, Shapes, Draw, Modify...). A new
preference, on by default, turns the names off for a cleaner toolbar: a faint
dash then separates the groups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:38:28 +07:00
bflatastic 55cc14e4a8 Merge #687: Rearrange All Artboards layouts, order and one click
# Conflicts:
#	ROADMAP.md
2026-10-09 12:28:10 +07:00
bflatastic 01df2c730b Fix #681: Rearrange All Artboards layouts, order and one-click access
- artboard.rearrange takes layout (gridByRow, gridByColumn, row, column;
  byColumn stays as an alias of gridByColumn) and order (leftToRight,
  rightToLeft); Columns is the row count of a grid by column and is
  ignored by row and column. It returns {artboards, rows, columns}.
- A Rearrange All Artboards dialog: Layout and Layout Order toggles drawn
  in code (widgets::layout_button, previewing the order), Columns/Rows,
  Spacing, Move Artwork with Artboard and the artboard count.
- One click: Rearrange All in the Properties panel (Document section with
  several artboards, Edit Artboards' Quick Actions); the Artboards panel's
  Rearrange button and menu item now open the dialog too.
- Tests for every layout x order (artboards, art riding along, one undo
  step), the dialog, the Properties button; the command sweep covers the
  new params. Translations for ja, es, it, ru, fr, zh-hans, zh-hant and
  pt-br; ROADMAP updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:22:48 +07:00
callmeBalloch 5d41601da1
Merge storytold/main into AF.3 native Affinity import
Conflicts: ROADMAP (main's guides and file-format rows, with the Affinity
items kept); fileio/load.rs (main's physical-size raster documents, kept
visible to the Affinity preview fallback).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GQPh8UDgMyARR5Hat9UchC
2026-10-09 05:20:33 +00:00
bflatastic 0924bc16ae Part of #663: Canvas Color offers light, medium and dark grey
Preferences > User Interface > Canvas Color offered Match User Interface
Brightness and White only: with a dark interface the first is a high-contrast
dark canvas around the white page, and White hides where the page ends. Light
Gray, Medium Gray and Dark Gray keep the page's edge in view at a gentler
contrast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:14:33 +07:00
bflatastic e92bbdbdac Fix #683: Preferences > Type > Additional Fonts Folder
VectorCraft found fonts only in the system's font folders (and, on Windows,
those font services activate). A new preference names one more folder, read
with its subfolders after the platform's: its fonts are listed in the font
menus and used as if installed, without installing them.

- vectorcraft_text::set_user_font_dirs / user_font_dirs: folders
  system_font_dirs adds to every scan (none on wasm).
- prefs fontsFolder (Type > Options > Additional Fonts Folder), trimmed; when
  it changes after the first scan, the fonts are scanned again at once, so the
  folder's fonts appear (or go) and type in them lays out again.
- The label is translated where Additional Plug-ins Folder is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 12:05:16 +07:00
bflatastic 7bd496b1e2 Images: the web app keeps the decoder's 512 MB limit
#677 lets one image decode take up to 2 GB, so large print sheets open on the
desktop. wasm32 can address only 4 GB and aborts when an allocation fails, so
the web app keeps the decoder's default 512 MB and reports larger images as an
error instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:43:59 +07:00
bflatastic ee7be83ee0 Merge #677 2026-10-09 11:43:41 +07:00
bflatastic 50bb3b2693 Merge #676 2026-10-09 11:43:41 +07:00
bflatastic 2f81b4437b Merge #674 2026-10-09 11:43:40 +07:00