The PostScript interpreter that reads EPS and PostScript files turned
the samples of a CMYK image into display RGB and stored an RGBA PNG,
so the image lost its ink amounts. The DCTDecode filter decoded a CMYK
JPEG to RGB, so it lost its ink amounts too. The PDF importer keeps
the ink amounts of 8- and 16-bit CMYK images (in a CMYK TIFF, or the
CMYK JPEG itself).
A CMYK image (image or colorimage in DeviceCMYK, CIEBasedDEFG or a
four-component ICCBased space) now keeps its samples in a CMYK TIFF
(ImageBlob::cmyk_tiff), read through its Decode array, at every bit
depth the interpreter reads. A CMYK JPEG gives its samples as stored,
and the image's Decode array reads them: [1 0 1 0 1 0 1 0] undoes the
inverted samples of Adobe's CMYK JPEGs. The pixels that a MaskColor
or an ImageType 3 mask hides become a grayscale opacity mask over the
image, as in PDF import. A mask that hides nothing adds no mask. Gray,
RGB, indexed and spot color images and image masks stay RGBA PNGs.
Docs: docs/file-format-parity.md, docs/target-app-parity.md.
The editing data reader sized each row of a 1-bit image as width ×
channels bits, padded to a whole byte, but read one bit per pixel and
made the pixel gray from it. A 1-bit RGB or CMYK image came out as a
black and white image of the wrong bits. When that made the layers
differ from the page by more than 5%, the file opened from its PDF
part instead, with a warning.
The reader now takes channel c of pixel x from bit x × channels + c of
the row, a set bit being the channel at full strength, and converts
the samples as it converts 8-bit ones. 1-bit gray images read as
before.
When a graphics driver crashed the process while the window started,
as Intel's Direct3D 12 driver (igd12umd64.dll) did on an Intel UHD
Graphics 605 (#2243), the next start picked the same adapter again. The
restart without a failing adapter and the first-frame watch run inside
the process, so the crash ended them along with it.
Each start now writes graphics-start.json in the log folder before the
graphics start, adds the adapter once one is picked, and clears both
when the first frame reaches the screen or the app ends without
crashing. A start that finds an earlier start still recorded there
leaves that adapter out, as a restart does, logs it and shows a note in
the status bar. When the crash came while the adapters were being
listed (wgpu's Direct3D 12 backend creates a device on each GPU to list
it), the next starts list OpenGL's adapters alone, except on macOS. The
adapters stay left out until the app version or the Graphics Processor
preference changes, a start shows its first frame on one, or no adapter
is left. WGPU_BACKEND and WGPU_ADAPTER_NAME choose regardless of the
record.
Docs: docs/development.md, docs/target-app-parity.md.
A PDF, PDF-compatible .ai or .ait opened from its pages had an empty
File Info. Nothing read the file's document information
dictionary or its XMP packet, so file.info reported no author,
description or keywords, even for a PDF that VectorCraft exported.
vectorcraft_pdf::file_info reads both. The author, description,
keywords, copyright status, notice and URL and the created and modified
dates come from the XMP packet (dc:creator, dc:description, dc:subject
or pdf:Keywords, xmpRights:Marked, dc:rights, xmpRights:WebStatement,
xmp:CreateDate, xmp:ModifyDate), else from the dictionary's Author,
Subject, Keywords, CreationDate and ModDate. document.open,
file.newFromTemplate and file.revert put each value through file.info's
checks and leave out a value that file.info refuses. A packet that is
not well-formed XML leaves the dictionary's values. File Info does not
set the title, and a file restored from the document it carries keeps
that document's File Info. vectorcraft-pdf depends on roxmltree 0.21,
which usvg already brings into Cargo.lock.
Docs: docs/mcp.md (File Info), docs/file-format-parity.md,
docs/target-app-parity.md.
When type had used a font, removing the font while the app ran left
it in the font menus, and the type kept drawing in it until the app
restarted. The font list is the loaded faces plus the scanned catalog,
and a scan replaced the catalog but kept every loaded face.
A scan now drops each loaded face whose file it did not catalog, with
the face's cached outlines. A family with no face left leaves the font
lists, and type set in it lays out in the fallback font and is
reported missing, as when a document opens without the font. When the
font is installed again, the next scan lists it and the type draws in
it again. Bundled fonts and fonts added as bytes have no file and
stay.
Docs: docs/mcp.md, docs/target-app-parity.md.
Adds a Finnish (Suomi, `fi`) catalog with 4,770 entries, written in
sentence case from the English labels with ordinary Finnish
vector-illustration vocabulary. It covers menus, `tl!` literals and the
668 `@msg` status and error messages: `fi` is in KEEPS_MENU_NAMES and
COMPLETE_MESSAGES. Like the other complete catalogs, it leaves the
product, workspace and perspective preset names in English.
Plurals are one/other with the partitive singular after any number but
1 (1 taso, 2 tasoa). Any fi-* locale selects Finnish; sv-FI does not.
Tests: `cargo test -p vectorcraft-ui-egui --lib i18n` passes (47),
including the new finnish_reads_as_finnish and the bundled-font glyph
check.
Clean-room, AI-assisted (Claude Code) translation; a native speaker
checked it in the running app, but it has not been proofread line by
line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds Swedish (Svenska) as an interface language: 4770 strings, written from the English source.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Play an action on every file in a folder or every data set, with destination
and Override Open/Save/Export. Actions panel and File › Automate › Batch…
open the dialog; new strings in pt-br.
Co-authored-by: Cursor <cursoragent@cursor.com>
VariableKind::Graph binds a graph root; dataset rows supply CSV as graph.setData.
Make Graph Dynamic, Variables dialog, capture/apply, and pt-br for the new strings.
Co-authored-by: Cursor <cursoragent@cursor.com>
Load and save variable datasets as CSV for data-merge pipelines, and
translate the new Variables panel commands in Brazilian Portuguese.
Co-authored-by: Cursor <cursoragent@cursor.com>
# Conflicts:
# docs/target-app-parity.md
Store the registration point with the symbol and place instances so that point lands on (x, y). Symbol Options exposes the same 9-point control as Transform.
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose existing Warp styles, orientation and percentage controls through the shared live effect dialog while preserving preview history and effect targets. Keep ordinary Enter owned by focused non-searchable combo controls.
Co-authored-by: Codex <noreply@openai.com>
assets.export of abutting fills must leave no ghost edge (#983 / #1037); panel thumbnails use the same Art Optimized supersample. Progress docs mark the gap closed.
Keep surviving drawable runs separate when Delete or Backspace removes an open-path anchor. Preserve appearance, selection and one-step Undo.
Co-authored-by: Codex <noreply@openai.com>
Make and Edit choose the Intertwine tool: hovering highlights the overlap
area under the pointer, a click swaps which object is on top there, and a
path drawn around overlaps (Shift: a rectangle) arranges every overlap
inside it; Esc or Enter goes back to the tool chosen before. The overlap
faces move to vectorcraft-tools, shared by the tool and the command.
Clicks inside a raised area pick the member drawn on top there, the
Object menu gets the Intertwine submenu, and the new labels and the
predicate message are translated in the complete catalogs. docs/gaps.md
records what landed under G13.
An Intertwine group keeps its objects as they are, in their own stacking
order; each member can be drawn over the others in an area of its own.
The group draws, hits, saves and exports through its live expansion, so the
members stay editable and Release gives them back unchanged.
object.intertwine.arrange picks an overlap area by a click point or by a
closed path drawn around overlaps and toggles which member is on top
there, or brings a member to the front or sends it to the back where three
or more objects overlap.
A step whose id is draw_path or draw_shape runs that tool with its params,
checked as tools/call checks arguments; its result is the tool's, so later
steps can use "$N.id". The reply lists the ids the drawing steps made
under created. The unknown-argument check is shared with tools/call.
The drawing tools style the object they draw in the same call: dash, cap
and join go to the stroke.set that strokeWidth already sends, opacity and
name to object.setProps, and effects are applied in order as apply_effect
does. The options are checked (effect ids against effect.list) before
anything is drawn, so a bad one leaves no half-styled object behind.
A gradient given to several objects fits each one's own bounds. With
span: "selection", a linear or radial gradient without its own vector is
placed once on the union of the targets' bounds, at its angle and aspect,
and every target gets that vector in document coordinates, so the ramp
runs on across them. A solid colour, a swatch, a freeform gradient or an
explicit start/end with it is refused before anything changes; the next
object drawn still fits the gradient to itself.
object.group, ungroup, the clipping mask and compound path Make/Release,
the Arrange commands, lock, hide, edit.duplicate, object.move, rotate,
scale, reflect, shear and the Pathfinder commands acted only on the
selection, so a script had to send select.set first. Given ids, they now
select those objects (select.set, with its checks) and run as on the
selection, in the same undo step; without ids nothing changes.
The nine OFL faces in `assets/fonts` are compiled into every build of
vectorcraft-text: 3.4 MB of the binary, about 1.6 MB of a gzipped wasm.
An embedder that loads every font at run time with `FontDb::add_font`
(a web app serving its own font catalogue, say) ships them twice and
can't turn them off.
- vectorcraft-text: `bundled-fonts`, a default feature, holds the
`include_bytes!` list. Off, a database starts without them (craft-fonts
and system fonts are unaffected) and text has no glyphs until a font
is added, as when the bundled fonts fail to parse.
- vectorcraft-engine: a `bundled-fonts` default feature forwards to it,
so the apps and any embedder using the engine keep the fonts unless
they build it with `default-features = false`.
- The workspace declares vectorcraft-text without default features, so
no library crate turns the fonts back on. The tests of cad, metafile
and tools, which lay type out, ask for the feature in their
dev-dependencies; the other crates' tests get it through testkit.
`cargo test --workspace` builds with the fonts, as before. A new
integration test, `without_bundled_fonts`, covers the configuration
without them (`cargo test -p vectorcraft-text --no-default-features
--test without_bundled_fonts`): the database starts without them, text
in no font lays out with no glyphs, and a font added later is used and
is the fallback for families the database lacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>