Commit Graph
1026 Commits
Author SHA1 Message Date
dotCooCoo 09eab2c93c Merge main into fix/blend-reversed-key-stroke-direction 2026-11-14 07:14:47 -08:00
dotCooCoo 9977ef2e01 Merge main into fix/graph-series-group-opacity 2026-11-14 07:11:27 -08:00
BFlat edefbd0e7d Merge pull request #7449 from dotCooCoo/fix/links-stored-brush-art
Links: placed images in stored brush art get Links rows
2026-11-14 21:55:20 +07:00
BFlat b541d97a06 Merge pull request #7586 from dotCooCoo/fix/blend-spot-stop-plates
Blend: steps between gradients linked to the same spot swatch keep its process plates
2026-11-14 21:54:47 +07:00
BFlat 35ac921b86 Merge pull request #7589 from dotCooCoo/chore/guides-shared-one-pass-helpers
Guides: document and layer guide edits share one set of one-pass helpers
2026-11-14 21:53:41 +07:00
BFlat 8863c41560 Merge pull request #7581 from dotCooCoo/fix/pdf-cmyk-image-keeps-icc
PDF export: CMYK images that keep their numbers carry their ICC profile
2026-11-14 21:53:33 +07:00
BFlat 5762ec729b Merge pull request #7598 from dotCooCoo/fix/symbol-art-bounds-nested
Symbols: a symbol nested in symbol art is measured by its own art
2026-11-14 21:53:07 +07:00
BFlat 64dd5eb174 Merge pull request #7418 from dotCooCoo/fix/reflected-dimension-line
Dimension tool: a reflected aligned dimension has its line on the reflected side
2026-11-14 21:52:10 +07:00
BFlat 508a0b0180 Merge pull request #7597 from dotCooCoo/fix/separations-spot-stop-plates
Print: a spot gradient stop prints its process plates on the separations
2026-11-14 21:51:47 +07:00
dotCooCoo 20529f1ffb Merge main into fix/graph-wedge-legend-black-kept 2026-11-14 06:08:51 -08:00
dotCooCoo 80854eb4b8 Merge main into fix/export-bakes-symbol-art-effects 2026-11-14 06:00:09 -08:00
dotCooCoo d233cd8291 Merge main into fix/graph-series-group-opacity 2026-11-14 05:57:05 -08:00
BFlat 3c15649730 Merge pull request #7427 from dotCooCoo/fix/live-paint-expand-drawn-stroke
Live Paint: Expand keeps the faces and edges that draw
2026-11-14 20:37:59 +07:00
BFlat 9800d48e58 Merge pull request #7571 from dotCooCoo/fix/cmyk-tiff-alpha-16-bit
TIFF: a 16-bit CMYK or gray TIFF with alpha converts at 16 bits
2026-11-14 20:37:26 +07:00
dotCooCoo b3c2fdab21 Merge main into fix/svg-raster-keeps-resolution 2026-11-14 05:11:34 -08:00
dotCooCoo bc24ad5352 Symbols: a symbol nested in symbol art is measured by its own art
Document::symbol_art_bounds measured a symbol's art without the
document, so an instance of another symbol in that art counted as the
20 x 20 square. It now measures the art through SymbolBoxes, so a nested
instance takes its own symbol's art, and an inline graphic of the outer
symbol is sized by it and follows it when that symbol changes.

- The inline resolve order also follows the instances that size a
  symbol's art, so a symbol is measured after the type in the art of
  the symbols it holds is laid out again.
- A symbol whose art reaches itself through an instance and an inline
  graphic is an empty slot. Only instances that the measurement uses
  count, so one a clipping path hides adds no dependency.
- A missing symbol, a symbol without art, a symbol that holds an
  instance of itself, and nesting 32 deep still measure as the square.
- SymbolBoxes finds symbols through a name index built once, and the
  inline resolve pass and inline_art_bounds share one index, instead
  of scanning the symbol list for each lookup.
2026-11-14 05:10:41 -08:00
dotCooCoo 786dcc5581 Images: scaled-down images keep their color beside clear pixels
The image crate's filtered resize filters each channel on its own, which
is correct only for premultiplied pixels, and its thumbnail averages each
channel on its own too. Placed images, linked-image previews, MCP
captures and previews, metafile bitmaps, PDF downsampling and library
thumbnails passed straight RGBA to them, so the color under clear pixels
(usually black) bled into the opaque pixels beside them and darkened
cut-out edges.

vectorcraft_doc::resample scales such images with each pixel's color
weighted by its alpha: filtered resampling premultiplies the pixels in
place and divides them back after, and averaging takes the area-weighted
mean of the pixels each new one covers. Opaque and alpha-free images are
scaled as before. PDF export also multiplies the inks of a CMYK image
with alpha by that alpha before resampling them, and divides them by the
resampled alpha after.
2026-11-14 05:07:39 -08:00
dotCooCoo 98bf61bb53 Merge main into fix/objects-on-path-widgets-flatten-once 2026-11-14 05:00:14 -08:00
dotCooCoo 0c892b5500 Merge main into fix/blend-reversed-key-stroke-direction 2026-11-14 04:51:02 -08:00
dotCooCoo 3597752c63 Merge main into fix/graph-wedge-legend-black-kept 2026-11-14 04:50:46 -08:00
dotCooCoo add6938441 Merge main into fix/links-stored-brush-art 2026-11-14 04:49:13 -08:00
dotCooCoo 1fe52fc5b6 Merge main into fix/separations-spot-stop-plates 2026-11-14 04:47:00 -08:00
dotCooCoo 6ab46b5fd8 Print: a spot gradient stop prints its process plates on the separations
A gradient stop linked to a spot ink that also carries process plates
(a DeviceN stop opened from a PDF) printed only its spot tint: print
separations and Separations Preview left its Cyan, Magenta, Yellow and
Black plates blank. They now print the stop's plates beside the tint.
With spots printed as process, each process plate prints the stop's
plate layered with the spot tint's process equivalent, as a separated
image's spot plates layer. Plates beside no spot link, or beside
Registration, still print nothing of their own.

The color visitor also skipped a freeform gradient's points, so print
plates kept their display colors and Document Color Mode left them
unconverted. The points are now visited as unlinked colors.
2026-11-14 04:46:10 -08:00
dotCooCoo 173a057beb Merge main into fix/reverse-path-profiles 2026-11-14 04:39:50 -08:00
dotCooCoo 7f17649731 Guides: document and layer guide edits share one set of one-pass helpers
Document::guides_to_saved, remove_edit_layer, retain_guides and the
artboard guide moves now call the layer helpers in node/ops.rs
(held_guides, strip_held, map_held), which Node::strip_ruler_guides and
Node::map_ruler_guide_positions already use. The copies in
document_guides.rs (picked_in_layers, drop_picked, edit_picked) are
removed. Picked stays for the walks through objects and opacity-mask art.

Results, guide order, copies kept for undo and the number of nodes each
walk looks at are unchanged.
2026-11-14 04:34:05 -08:00
dotCooCoo 3a6b016253 Blend: steps between gradients linked to the same spot swatch keep its process plates
A blend between two gradients whose matching stops are tints of one spot
swatch kept the link and interpolated the tint, but every step's stop lost
the process inks (C, M, Y, K) printed with the spot ink, so PDF export wrote
the steps as the spot ink alone.

- Matching stops linked to one swatch interpolate each process ink with the
  tint; a stop without process inks counts as none of each, and the ends
  keep their own.
- Gradients with different stop counts keep the inks at every resampled
  stop, interpolated with the midpoint-adjusted fraction between two stops
  of one swatch.
- A solid blended with a gradient brings no process inks of its own: its
  stand-in gradient no longer copies the other gradient's.

Stops of different swatches, or linked and unlinked stops, still blend into
unlinked process colors without plates.
2026-11-14 04:25:55 -08:00
dotCooCoo 8fa551e173 Selection: clicks in a clip group follow the region its clipping path's effects give it
The canvas clips a clip group by its clipping path with the path's live
geometry effects applied, but clicks, hovers and marquees still tested
the plain clipping path. A click where a Transform effect had moved the
clip selected nothing, and a click on the clipping path's own place
selected art that was not drawn there.

- The engine registers the effect-shaped region with the doc crate
  (`hit::set_clip_region`), as it does for image paint and live art. It
  gives a region only when the clipping path holds a visible geometry
  effect; otherwise clicks keep the plain shapes, and type keeps
  counting by its frame.
- Clicks, `objects_at`, the hidden art of a selected object, the Unlock
  submenu's list and marquees inside a clip group or a clipping layer
  use that region. Outline view and layers with Preview off draw no
  effects and keep the plain shapes; the Selection, Direct Selection
  and Enclosing Lasso marquees pass the view's outline state
  (`hit::marquee_in_view`). Each container around a selected object
  tests its clipping path in the outline state a click has there.
- A marquee touches the clipping path itself by its own geometry, as a
  click on its outline finds it, and also on the edge of the region, so
  a marquee around a clipping path that an effect moved into large art
  still selects it. `hit::marquee_in` keeps the plain shapes for the
  Color Theme Picker, which clips by them.
- The region is kept per thread until the clipping path or the live
  inputs change. A clip group's reach takes in the region's box, so
  culling does not skip art the region moved past the plain clipping
  path. Up to 4096 boxes are kept; when they are full, a new box
  replaces only as many others as it needs room for.

Docs: docs/target-app-parity.md.
2026-11-14 04:08:03 -08:00
dotCooCoo b3fd92ccdc PDF export: CMYK images that keep their numbers carry their ICC profile
A CMYK TIFF written again, a CMYK JPEG that the Compression settings
resample or compress again, and a CMYK image written with its mask as
its soft mask lost the CMYK profile the image embeds. Such an image is
now written in an ICCBased space holding that profile, byte for byte,
when output.profiles is all or taggedSource, and in PDF/A-2b, PDF/X-3
and PDF/X-4 unless profiles is destination. Pixels the Output settings
convert are never tagged with it.

A CMYK JPEG embedded as it is now follows the same rule instead of
always carrying its own ICC_PROFILE segments: with profiles none it is
DeviceCMYK, and PDF/X-1a export no longer refuses a CMYK JPEG that
carries a profile.

A profile tags an image only when it is at most 16 MiB and its declared
size, acsp signature, device class, CMYK color space and tag table are
well formed. Tagged CMYK documents blend transparency in the document's
CMYK profile space, not in an image's own; without that space they
blend in DeviceCMYK, or keep their RGB space in PDF/A.
2026-11-14 03:59:32 -08:00
dotCooCoo fe82f68d6f TIFF: a 16-bit CMYK or gray TIFF with alpha converts at 16 bits
Place, Open and relink read a CMYK or grayscale TIFF with an alpha
channel through extra_samples_tiff_rgba, which cut every 16-bit sample
to its high byte before converting it. A faint ink or a low alpha was
lost: cyan 129 at full alpha showed as white, and an alpha of 129
became fully transparent.

The samples are now normalized at the depth the file stores them, and
only the resulting color and alpha are rounded to 8 bits (a 16-bit
alpha to the nearest 8-bit value). Associated alpha is divided out at
16 bits. A pixel whose associated alpha is zero now has no color,
instead of keeping its stored color. TIFF 6.0's Associated Alpha
Handling section states this arithmetic and the zero-alpha rule for
RGB data; applying them to CMYK and gray samples is VectorCraft's own
rule.
2026-11-14 03:44:41 -08:00
dotCooCoo cde9a27b4f Objects on Path: the widgets flatten the group's path once per lookup
Finding where the Rotate All, Space, Move All and Select/Move widgets
go and testing whether the pointer is over one flattened the group's
path two to three times per widget. Starting a Space, Move All or
Select/Move drag flattened it five times, and one pointer move over the
group could flatten it eleven times. Each lookup now flattens the path
once and shares that measurement across the widgets:

- vectorcraft-doc makes `Measured` public with `stop` and `stops`, and
  adds `attachable`, which returns the path with its measurement.
- `Widgets::of` gives all four widgets for the canvas, `widget_at` gives
  the widget under the pointer, and `WidgetDrag::hit` gives the drag a
  press starts, each from one flattening. The Selection and Objects on
  Path tools and the canvas use them.
- A Space, Move All or Select/Move drag keeps its measurement and
  measures again only when the group's path changes.

Widget places, hits, cursors and drag results are unchanged. The new
`spine-count` feature of vectorcraft-doc exposes the flattening counter
to vectorcraft-tools' tests; it is enabled only as a dev-dependency and
leaves Cargo.lock unchanged.
2026-11-14 03:01:29 -08:00
dotCooCoo 083180075c Graphs: a black fill set on wedge legend labels stays black on dark wedges
On a pie with Legends in Wedges, the graph draws legend labels white on
dark wedges unless they keep a fill of their own, and it read a kept black
fill as no fill of its own. A label recolored from white to black on a dark
wedge went back to white the next time the graph was drawn.

The graph now marks the legend labels' fill as set when a command sets it
(legendFillSet in the graph's label styles, kept through save and open), and
draws a marked fill on every wedge, black included. Undo clears the mark. A
size, font or stroke change does not set it, and neither does a whole-pie
recolor that gives the legend labels different fills; one that gives them
all the same fill sets it. A swatch edit or color conversion leaves the
default black legend fill as it is, and keeps a non-black legend fill from a
file saved without the mark as the labels' own when it turns black.
2026-11-14 02:54:22 -08:00
dotCooCoo 5afedf5804 Merge main into fix/blend-reversed-key-stroke-direction 2026-11-14 02:46:52 -08:00
dotCooCoo e7feeb311d SVG import: a raster stored again as PNG keeps its resolution
A raster that SVG import decodes and stores again (a TIFF, a BMP or any
other format that is not PNG, JPEG, GIF or WebP, or an image whose EXIF
or TIFF orientation turns or flips it) was written as a PNG with no pHYs
chunk, and a turned or planar CMYK TIFF was written without resolution
tags, so the image lost the resolution its file declares.

The converted PNG now carries the source's resolution in a pHYs chunk,
and the CMYK TIFF in its resolution tags, as Open and Place store them.
A quarter turn (orientations 5 to 8) swaps the horizontal and vertical
values. An image that declares no resolution is stored without one, and
an image stored unchanged keeps its own bytes.

The PNG, JPEG, TIFF, WebP and BMP resolution readers and the pHYs writer
move from the engine to vectorcraft-doc, so the SVG importer can use
them; the engine and renderer entry points forward to them unchanged.
2026-11-14 02:40:45 -08:00
dotCooCoo 9834c58b66 Merge main into fix/links-stored-brush-art 2026-11-14 02:26:44 -08:00
dotCooCoo ad31fe9527 Merge main into fix/reverse-path-profiles 2026-11-14 02:21:25 -08:00
dotCooCoo ded56d3d70 Merge main into fix/graph-series-group-opacity 2026-11-14 02:15:46 -08:00
dotCooCoo cee68c525a Merge main into fix/reflected-dimension-line 2026-11-14 02:15:24 -08:00
dotCooCoo 997aaa61b9 Merge main into fix/live-paint-expand-drawn-stroke 2026-11-14 02:08:40 -08:00
dotCooCoo df3d012e1f Merge main into fix/export-bakes-symbol-art-effects 2026-11-14 02:07:20 -08:00
dotCooCoo fb13d2045d Merge main into feat/cjk-tsume 2026-11-14 01:56:33 -08:00
BFlat 3c7d72f8bc Merge pull request #7333 from dotCooCoo/fix/graph-series-gradient-per-mark
Graphs: a kept gradient takes the same place on every mark of its series
2026-11-14 16:54:26 +07:00
dotCooCoo 5fbb4f2c64 Merge main into fix/links-stored-brush-art 2026-11-13 23:11:59 -08:00
dotCooCoo 6bcc48690d Merge main into fix/reverse-path-profiles 2026-11-13 23:08:45 -08:00
dotCooCoo 897b4f0ecf Export: placed symbol art counts its baked objects and drawn depth
PDF, print, EPS and DXF exports now check the art of each placed symbol
instance after its effects are baked. The objects it holds, including
the copies a Transform effect makes, opacity mask art and the art of
instances placed inside it (counted once), count against the export's
16,000,000-object budget. An instance whose baked art passes the budget,
or would draw deeper than the 128 levels a document may draw, stays an
instance.

- doc: DrawnHeights measures how deep an object outside the layers
  draws, symbols and patterns it uses included.
- effects: the bake tracks how deep each baked object sits, and a
  rejected candidate releases what it and the instances in it charged.
2026-11-13 23:02:02 -08:00
dotCooCoo ae05540f70 Merge main into feat/cjk-tsume 2026-11-13 22:46:57 -08:00
dotCooCoo cbdd3b4706 Merge main into fix/reflected-dimension-line 2026-11-13 22:46:36 -08:00
BFlat 0ca2952093 Merge pull request #7363 from dotCooCoo/fix/stained-instance-export
Symbols: a stained instance keeps its stain in SVG, PDF and the other exports
2026-11-14 13:42:39 +07:00
BFlat be93e4b3f2 Merge pull request #7377 from dotCooCoo/fix/symbol-expand-reset-bbox
Symbols: Break Link and Expand keep an instance's bounding box
2026-11-14 13:42:23 +07:00
dotCooCoo 2a4185d6ca Merge main into fix/graph-series-gradient-per-mark 2026-11-13 22:15:43 -08:00
dotCooCoo 1494e2c230 Type: Tsume narrows the space around each character's ink
Character panel > Tsume, shown with Show East Asian Options, takes away a
percentage of the blank space on each side of a character's ink, inside
its own width, in horizontal type. The value is from 0 to 100, 0 by
default. 50 halves that space and 100 sets the ink against the
characters before and after it; the glyph keeps its shape. A character
without ink, such as a space, keeps its width, and a ligature or a
letter with its marks takes the value of its first character. The
font's pair kerning, tracking, manual kerning and Insert Aki are added
after it, and justification keeps it. Vertical type keeps its spacing.

- text.setFormat and text.setRangeStyle take `tsume`; a value that is
  not a number or is outside 0 to 100 is refused, naming the key.
  Character styles carry it, and a file holding a value outside the
  range opens with the nearer end.
- The Character panel's Tsume field has 0, 25, 50, 75 and 100 in its
  menu, and Reset Panel sets it to 0. Character Style Options shows it
  in Advanced Character Formats.
- Live SVG text places each character Tsume moves, and type on a path
  with Tsume is written as outlines.

Docs: docs/mcp.md (Tsume, Character Style Options fields),
docs/target-app-parity.md.
2026-11-13 21:50:05 -08:00