Commit Graph
13 Commits
Author SHA1 Message Date
Gert Pellin 9652d1d6b2 PDF/EPS import: a clip only counts as covering the page when it does
Both readers skipped a clip of at most six straight segments whose
bounding box contained the page. A diamond touching the page edges has
the page as its bounding box, so its clip was dropped and everything it
cuts away showed. geom::hit::polygon_covers_rect answers it properly
(one convex polygon containing the page's corners); any other path is
kept as a clip.

Fixes #1542
2026-10-13 08:51:40 +07:00
bflatastic 44d170f059 PDF import: pattern swatches read inside an alpha mask keep their images; a luminosity mask test 2026-10-13 08:11:27 +07:00
Gert Pellin fce90e3144 PDF import: images in an alpha soft mask count by their alpha
An alpha soft mask's vector art is whitened so its luminance is its
alpha, but images kept their colour: cairo (and so Inkscape) draws a
mask as an image whose alpha is in its own SMask, often black pixels,
so the mask came in empty. While reading an alpha mask's art the
importer now reads images white with their own alpha (under their own
cache key, without the JPEG and CMYK shortcuts), and stencil masks
white; a luminosity mask nested inside reads them as they are.

Fixes #1550
2026-10-13 08:11:27 +07:00
EricKuck 34b3c59a03 PDF import: an editor's .ai keeps its RGB numbers, and a fill faded or masked by its group keeps its stroke apart 2026-10-12 23:06:19 +07:00
Aaron GuoandClaude Opus 5.5 563ff62aa0 PDF import: gradient-filled shapes open as one path, not a clipped rectangle (#1304)
A PDF, and the PDF part of a PDF-compatible .ai, writes a shape filled
with a gradient as a clip followed by a shading fill: the shape, W n,
then sh, which fills the clip's bounds. The importer kept that as a
clip group of the shape (a clipping path) and a rectangle the size of
its bounds filled with the gradient. The Shape Builder skips clipping
paths, so it built its pieces from the rectangles: two overlapping
gradient-filled diamonds gave three rectangles. The Fill swatch showed
? for such a selection, since it held groups.

A clip whose only content is one rectangle covering the clip, filled
with a gradient placed on the page and nothing else, now comes in as
one path: the clip's outline, its subpaths closed, with the
rectangle's fill, opacity, blend mode and mask. It draws as before and
edits like a gradient-filled path drawn in the app. Clips holding
anything else (a flat colour, several objects, a gradient that doesn't
cover the clip, a shading that doesn't extend past its ends) stay clip
groups.

Tests: a diamond clipping a shading imports as one closed path of four
anchors with the linear gradient where it was, and a gradient covering
only part of the diamond or a flat colour stay clipped. Two overlapping
diamonds in a hand-written PDF, clicked on their overlap with the Shape
Builder, give what is left of each (9000 pt² each) and the overlap
diamond (3000 pt²), each with its gradient; main gave three rectangles
of 12000 pt².

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 14:49:59 +07:00
arhammusheer 5beac4f122 #1244: smaller objects: Node 352 -> 152 bytes, NodeKind 200 -> 80, and a cheaper undo estimate
Rarely set fields move into one optional boxed NodeExtras, and large NodeKind payloads (images,
live shapes, blends, envelopes) are boxed. Every object, and every undo step that copies it,
shrinks: a 50k-path move keeps ~24.5 MB per step instead of ~40 MB. Files stay byte-identical
(Node keeps its flat JSON through a borrowed Serialize and a from-wire Deserialize, no flatten),
and loading is slightly faster. Undo and redo reuse their step's size estimate instead of
walking the document again (8.3 -> 5.6 ms for a 50k-path move).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc

# Conflicts:
#	crates/engine/src/cmd/graph.rs
#	crates/svg/src/export.rs
2026-10-12 11:02:32 +07:00
Hiroshi InukaiandClaude Opus 5.5 aa9f0153a4 PDF/.ai import: glyphs spaced each their own way keep their place
Character tightening and optical kerning space each glyph differently, as
Japanese titles often are. The importer evened a line out with one
tracking value (type on a path took none), leaving glyphs up to an eighth
of an em out of place. When the file's font is installed and one value
can't place every glyph, each character now keeps its own tracking,
measured along the baseline (along the path for type on a path).

Glyphs closed up by up to half an em (the proportional widths of CJK
punctuation) also continue their line instead of starting another.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:46 +07:00
fastmikey99andClaude Opus 5.5 1d0305fc2a PDF import: clip art reaching past the page to the crop box
A clip to the page box is dropped as redundant (by hayro, and by
push_clip_path), so art a file hides outside the page - a mock-up backdrop
thousands of points across, say - came in unclipped: it showed, and it sized
Fit to Artwork Bounds and CropTo::Bounding to metres. Viewers show a page
through its crop box, so each object reaching past it now keeps its own clip
to it, with a warning. Art inside the page is unchanged (no clip groups).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 08:26:26 +07:00
bflatasticandClaude Opus 5.5 e63606826a Fix #508: PDF/.ai import keeps type strokes, wrapped lines and layer order
- Type left unfinished when a layer's marked content ends, and a clip that closes in a later layer,
  stay in their own layer (no stray "Page N" layer, no art moved to the next layer).
- Top-level layers stack as the pages mark them, so a layer whose art starts on a later page keeps its
  place; layers marked with no art come in empty.
- A stroke written as each glyph's outline stroked, right after (or before) the type, becomes the type
  object's stroke above (or below) its characters: the type stays one editable object.
- Spaces read from gaps wider than a space get their own tracking where even tracking would put the
  glyphs after them more than a tenth of an em off (barcode digit groups); lines are measured to their
  last visible glyph, so a wrapped line's trailing space no longer spreads into the tracking.
- Lines wrapped in a frame (each wrapped line ending in a space, one left edge, font, size and leading,
  with an optional paragraph spacing) come back as one area type object, left aligned or justified,
  only where laying it out breaks the lines exactly where the file does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:37:37 +07:00
bflatasticandClaude Opus 5.5 3585ef654c Part of #372: PDF/.ai import keeps strokes live and hidden and nested layers
An object Illustrator writes as a fill of its outline left open and then a
stroke of it closed imported as two objects: a filled path and a separate
stroke-only path. A fill and a stroke of the same outline (equal once every
subpath is closed) now become one path with the fill and a live stroke
(width, cap, join, miter limit, dash, paint), taking the stroke's outline.

Layers: a group whose view state is off (/Usage /View /ViewState /OFF, with or
without an /AS view event) comes in as a hidden layer with its art, as groups
off in the default configuration already did. The configuration's /Order
nesting (inline or as its own object, labels skipped) makes sublayers, which
take their top-level layer's colour; nesting depth, entries and groups are
capped. Splitting a page's art by group is no longer quadratic, so thousands
of layers import quickly.

The 6D art pen (rotation-aware brushes) is a separate feature, now on the
ROADMAP gap list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 06:55:51 +07:00
Hiroshi InukaiandClaude Opus 5.5 e2227849a1 PDF/.ai import: the last glyph of type on a path stays on its path
The path rebuilt through the glyphs ended where the last glyph ends, so
rounding in the spacing could push that glyph past the end, where type on
a path stops ("OFFICIAL ISSUED" lost its D). The path now runs an em
further.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:03:00 +07:00
Hiroshi InukaiandClaude Opus 5.5 ea5a04504a PDF/.ai import: type set on a path comes back as type on a path
Apps write type on a path one glyph at a time, each placed and turned along the
curve. The importer joined glyphs into a line only while they kept the first
glyph's direction. Type on a gentle curve was flattened into straight lines, and
type on a tighter curve fell apart into one object per glyph.

A glyph that starts about where the previous one ends, turned a little from it
(under about 20°), now continues the line. A line whose baseline turned more than
about 3° becomes type on a path: its path is a smooth curve (Catmull-Rom as cubic
Béziers) through the glyphs' baseline origins and the end of the last glyph.
Spaces between words are measured along the last glyph. Straight type, rotated or
not, imports as before.

Test: "ARCHING" written glyph by glyph along an arc imports as one
type-on-a-path object with that text and a curved path; slightly rotated straight
type stays point type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 13:03:00 +07:00
bflatasticandClaude Opus 5.5 a51083733e M4.61: PDF import fidelity: opacity masks, isolate/knockout, pattern swatches, editable text, gradient meshes, stop opacity and Extend
Luminosity soft masks become opacity masks (alpha masks as a white copy of
their art; backdrop colour gives Clip, an inverting transfer function Invert;
the PDF export's backdrop and Difference covers read back as the options; a
constant alpha mask is opacity). Transparency groups keep their /I and /K
flags (read by walking the content as the interpreter does). Tiling patterns
become pattern swatches (one per colour for uncoloured ones). Text becomes
point type, one object per line with a run per font and paint, fonts named
from the file (document.open textAs: text | outlines). Patch and triangle
mesh shadings become gradient meshes; gradients drawn through their grey
opacity mask get stop opacity back; shadings that don't extend clip the art.
A rectangular clip around all its art (a form's box) is dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 13:05:12 +07:00