Commit Graph
509 Commits
Author SHA1 Message Date
dotCooCoo 6c285d3042 .ai save: the editing copy keeps live effects
The editing copy of a PDF-compatible .ai wrote an object's live effects
as their result (geometry effects) or left them out (the others).
Objects with effects the .ai reader reads are now written as art styles:

- An object is written as its drawn look (a group of its vector art as
  its geometry effects leave it, without shadows, glows or feathers,
  with the object's transparency after it), then the object itself on
  %_ lines (its points painted with nothing, or with its gradient fill
  placed on the outline it draws; a group with its members), its name
  and opacity mask, and
  1 (style) XW naming its style.
- Styles are written in a non-printing block after the symbols, in
  %AI9_BeginArtStyles: a chain of the stack of fills and strokes (with
  the contents where the appearance puts them), the effects and the
  object's transparency. Objects of the same appearance share a style.
- The effects written are the ones the reader reads on objects, with
  their settings in the units it reads them in: Drop Shadow, Inner Glow,
  Outer Glow, Feather, Round Corners, Scribble, Convert to Shape, Offset
  Path, Outline Object, Outline Stroke and Pathfinder > Add.
- Each style is read back before it is written, by a new reader
  function, read_art_style, which runs the reader's style parser and its
  reading of a graphic style with the object's own gradient. An object
  whose style reads back differently (several fills or strokes, fills
  or strokes with transparency or effects of their own, pattern fills,
  other effects), a filled object that fills by the even-odd rule (a
  style's fill fills by the non-zero rule), a group whose effects change
  its members' outlines while a member is written on another outline
  (strokes as filled outlines, pattern fills as tiles, gradients that
  fit their object), or one in a container whose own
  effects change its members, is written as its drawn look with the
  warning, and a style that is not written leaves no gradient
  definition behind. Graphic styles and links to them are left out with
  a warning. No art style is written on a large canvas.

Appearance attributes:
https://helpx.adobe.com/illustrator/using/appearance-attributes.html

Tests: the round trip of objects with each effect, a gradient fill, a
group with transparency and a mask, Pathfinder > Add and a hidden
effect; the same bytes on a second write; the forms written; the
objects the reader would not read; a large canvas; the warning for
graphic styles; filled even-odd objects; a gradient placed on the
outline Offset Path draws; a style that is not written; effects in a
pattern a drawn look uses; the reader's check of a style; fuzz cases
for damaged written styles.

Docs: docs/file-format-parity.md.
2026-11-07 10:17:51 -08:00
M Balazs PC 88bc2ac06a .ai/EPS import: type keeps its paragraphs' tab stops
Key 30 of a paragraph's attributes holds its tab stops: each its position
(key 0) and alignment (key 1: 0 left, 1 center, 2 right, 3 decimal).
They were not read, so tabs fell on the default stops. At most 1,024 are
read a paragraph and 2^20 copied into a story's paragraphs, past which the
default stops apply with a warning. The fuzz test feeds hostile paragraph
attributes: alignments, auto leading, hyphenation options and tab stops.
2026-11-07 18:49:20 +01:00
M Balazs PC f2c1df1ec3 .ai/EPS import: the parity note says what still differs in the file it was checked on 2026-11-07 17:43:42 +01:00
dotCooCoo f8e0639d14 .ai save: the editing copy keeps symbols and their instances
The editing copy of a PDF-compatible .ai wrote every symbol instance as
its art. Symbols are now written as symbols, in the form the .ai reader
reads them:

- Every symbol is defined in the setup, in a non-printing block after the
  patterns: %AI14_BeginSymbol, its name, its art in the symbol's own
  space, its registration point as AI13PatternRegistrationType and
  %AI10_EndSymbol, each after the symbols its art uses. The nine points
  are numbered 1 to 9 row by row from the top left, in the order the
  scripting reference lists them. A definition is written the same
  wherever its first instance lies. The symbol list after the palette
  keeps the Symbols panel's order. A hidden root of a symbol's art is
  written shown, as the canvas draws it.
- Each instance is a /SymbolInstance with its symbol's name and the matrix
  that places the art (to ten decimals), followed by its name, opacity
  mask, opacity and blending mode as a group's. In a symbol's art, the
  matrices of instances, gradients and images are written in the
  canvas's space about the canvas point of the ruler origin.
- Pattern fills in a symbol's art are written as their tiles cut to the
  shape. A symbol whose definition holds such tiles, from its own
  objects, a brushed stroke's brush art, a live object, an opacity mask,
  a nested symbol or an inline graphic, has its instances written as
  their art.
- Instances with a fill, appearance changes, isolation, knockout or
  knockout shape of their own, instances of symbols with 9-slice guides
  or pattern paint, instances in pattern tiles or in art cut to a
  clipping object, instances scaled almost flat, instances that turn,
  mirror or scale symbols holding type, live objects, instances written
  as their art, shapes with rounded live corners or strokes written as
  outlines or brush art (the canvas works these out again where the
  instance puts them), instances that scale their symbol more than 100
  times, nested instances included (numbers are written to four
  decimals), and instances on the layers of a large canvas are written
  as their art (the symbols are still defined). Symbols past the 4,096
  the reader keeps are left out and their instances written as art; an
  instance of a symbol the document doesn't have is an empty group.
  9-slice guides, export types and the dynamic type are left out, and
  linked images and type in a symbol's art are embedded and written as
  outlines. Each comes with a warning.

The writer takes the reader's limit of 4,096 definitions (MAX_SYMBOLS)
and its symbol_art_member check, which now are pub(crate).

The editingData option's description lists what the copy now holds,
type written as text included.

Symbols and their instances:
https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/edit-symbols.html
https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/create-and-place-symbols.html
The nine registration points, in the order the scripting reference lists
them:
https://web.archive.org/web/20180219005134/https://wwwimages.adobe.com/content/dam/acom/en/devnet/illustrator/pdf/Illustrator-Scripting-Reference-JavaScript-cs6.pdf#page=252

Tests: the round trip of symbols, nested symbols and instances in every
state, symbols whose art is a group with a state of its own, images and
gradients in a symbol's art, every registration point, symbol names with
special characters, duplicate and missing symbols, a symbol first used
deep in opacity masks, symbols past the reader's count (one found only
while its holder's art is written included), a large canvas, symbols
with pattern fills (directly, nested, in an opacity mask, through an
inline graphic and through a brushed stroke), scaled instances of
symbols with an outside stroke, rounded live corners, type, a blend, a
tiny or thin object, an ellipse or an instance of a symbol with 9-slice
guides, a symbol whose root is hidden, instance matrices from a fixed
seed, a second write of what is read back giving the same bytes, the
forms written, the instances written as art and the options reported.

Docs: docs/file-format-parity.md, README.md, ROADMAP.md, docs/gaps.md,
docs/roadmap.md and docs/target-app-parity.md describe the editing copy
a saved .ai holds.
2026-11-07 08:35:54 -08:00
M Balazs PC b4199559f2 .ai/EPS import: cite Illustrator's documentation of auto leading 2026-11-07 17:17:00 +01:00
M Balazs PC eb03eacba6 .ai/EPS import: type keeps auto leading, hyphenation options and the file's last lines
- Auto leading stays auto: each line takes the paragraph's share (key 7)
  of the largest type on it. The leading was the first two lines'
  distance for every line, so 10 pt lines under a 15 pt heading came in
  18 pt apart.
- The paragraph's hyphenation options (keys 10 to 15) are read.
- Area type of one frame whose last lines the file sets, but which don't
  fit here (the fallback font, or a descent past the frame's bottom),
  gets a frame taller from its bottom (vectorcraft_text::fit_source_lines),
  with a warning.

A user's .ai whose type differed from its page by 6.6%, so that it opened
from its PDF part with each line its own text object, now opens from its
layers.
2026-11-07 16:57:21 +01:00
vangel76andClaude Sonnet 5.5 128d362730 Merge upstream/main into fix/2414-svg-classes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 16:21:40 +01:00
dotCooCoo 2a32d1bc65 .ai import: symbol libraries open with their symbols
A .ai or EPS whose editing data defines symbols but has no layers came
in as its PDF part or page without symbols, and Other Library in the
Symbols panel listed none. Such a file, and a file read as its PDF part
or page because its layers can't be used, now gets the symbols its
editing data defines before its first layer, as a file read from its
layers does: File > Open shows them in the Symbols panel in the order
of the symbol list, and Other Library lists them in a library panel.

- Each symbol keeps its registration point. A symbol that holds an
  instance of a symbol the file doesn't define is left out, and an
  object linked to a listed graphic style keeps the link.
- The symbols' art takes ids of the document, the art of opacity masks
  in it included, and the images it shows come with it. Instances
  drawn too deep are removed with the usual note.
- The global and spot colors the art is linked to come in as swatches.
  A color whose name another swatch has takes that swatch's place when
  it is a default swatch of a file without a palette; otherwise it
  comes in under a free variant of the name ("Ink 2"), which the art
  then names.
- Symbol art keeps the editing data's units, as in a file read from its
  layers, so in a file in larger units its linked graphic styles are
  drawn at the scaled size and the symbol art is not.
- The art of the patterns a palette or brush brings into a file read as
  its PDF part or page now also takes new ids for its opacity masks.

Part of #3349
2026-11-07 05:29:38 -08:00
Don Omondi 53f60823b2 EPS import: release only the image decoder's own buffers from the memory budget
What a data source procedure allocates stays counted: only the sample planes,
the decoder's copies of the strings a procedure returns, and the split buffers
of an interleaved masked image stop counting once the image is decoded.
2026-11-07 07:10:41 -05:00
Taha-Mahmoodi 3a1421e95e docs: restore the status lines damaged by merges (main's line plus this PR's note) 2026-11-07 13:51:03 +04:30
Taha-Mahmoodi c1e35047e4 Merge remote-tracking branch 'origin/main' into fix/import-document-title
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-07 12:40:04 +04:30
Don Omondi 5817cabb3a Merge remote-tracking branch 'upstream/main' into fix/eps-memory-cap
# Conflicts:
#	docs/file-format-parity.md
2026-11-07 00:12:50 -05:00
Don Omondi fbccefe17e Merge remote-tracking branch 'upstream/main' into fix/eps-sampled-function-shading
# Conflicts:
#	docs/file-format-parity.md
2026-11-07 00:12:44 -05:00
Don Omondi f906de86ff Merge remote-tracking branch 'upstream/main' into feat/ai-import-stacked-fills
# Conflicts:
#	crates/eps/src/import/ai/tests.rs
#	docs/file-format-parity.md
2026-11-07 00:12:40 -05:00
Don Omondi 21dc2bceff Merge remote-tracking branch 'upstream/main' into fix/ai-import-brushes
# Conflicts:
#	crates/eps/src/import/ai/brush.rs
#	docs/file-format-parity.md
#	docs/target-app-parity.md
2026-11-07 00:09:24 -05:00
Don Omondi d1b45aec9f Merge remote-tracking branch 'upstream/main' into fix/eps01-editing-overlay
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
2026-11-07 00:09:19 -05:00
dotCooCoo fe9d62e05e .ai import: legacy type keeps its writing direction, Tate-chu-yoko runs and upright Roman characters
The legacy reader skipped `TV`, `Tv`, `Ty` and `TY` of section 15.3.4 of
the version 7 file format specification, so type set with `1 TV` opened
horizontal.

- `TV` sets a text object's writing direction. VectorCraft keeps one
  direction for each text object, the one in force at its first
  character, with a warning when a later character has another.
- `Ty` marks a Kumi block as a Tate-chu-yoko run, which is VectorCraft's
  own mapping, and `TY` does the same in horizontal type. A `TY` block in
  vertical type opens unmarked. Two blocks with nothing between them open
  as one block.
- `Tv` sets Standard Vertical Roman Alignment.

All four are modal, and an operand other than 0 or 1 leaves the value as
it was.

Docs: docs/file-format-parity.md.
2026-11-07 09:17:53 +07:00
Don Omondi ed00a8870e EPS/.ai editing data: a transparency set inside a clipping group stays after it
Q restores the painting state but not the transparency (Xy): the writer
sets Xy only when the next object's state differs from the last one it
wrote. Restored at Q, type after a clipping group following a Screen glow
drew in Screen and nearly vanished on a light background.
2026-11-07 09:00:20 +07:00
Don Omondi 95ac8d7cc7 EPS/.ai editing data: blends with no spine written come in live
A blend whose spine was never edited has only its keys in the editing
data, no spine part. Its spine is the straight lines between the keys'
centres in the record's order; read as such, the blend comes in live
instead of as its drawn steps.
2026-11-07 09:00:15 +07:00
Don Omondi 2626791d7d EPS/.ai editing data: symbols defined before the art styles take them
Illustrator 24 writes its symbol definitions ahead of %AI9_BeginArtStyles,
so a styled object inside a symbol found no style and came in as its drawn
look. The pre-pass that finds swatch names now also keeps the first
top-level art styles section, which the reader parses before the art.
2026-11-07 08:59:55 +07:00
Don Omondi 06179bbf19 Merge remote-tracking branch 'upstream/main' into fix/eps-memory-cap
# Conflicts:
#	docs/file-format-parity.md
2026-11-06 20:58:27 -05:00
Don Omondi 1b1af20685 Merge remote-tracking branch 'upstream/main' into fix/eps-sampled-function-shading
# Conflicts:
#	docs/file-format-parity.md
2026-11-06 20:58:27 -05:00
Don Omondi e88d1b6380 EPS/.ai editing data: paths keep art styles of several fills and strokes live
Only type kept an art style that stacks several fills or strokes, or gives
one its own opacity or blend mode, as a live appearance; paths came in as
their drawn look. A path or compound path now takes such a style (solid
colours and gradients, strokes without a brush, no effects on the items,
object effects any object takes that don't move the outline) when every
gradient is its own swatch painted by the drawn look, which gives each its
placement. Anything else keeps the drawn look.
2026-11-06 20:34:10 -05:00
Don Omondi b6cf45737f EPS import: sampled functions interpolate between their samples
A sampled function (type 0) of two or more inputs took the nearest
sample, so a function-based shading over one came in as flat blocks.
It is now interpolated multilinearly, and with Order 3 by cubics through
the samples, kept in its range (PLRM 3rd ed. section 3.10.1). An axial or
radial shading over a linearly interpolated sampled function of one
input has a stop at each sample.
2026-11-06 20:22:47 -05:00
dotCooCoo 3d7dda200e .ai import: opacity mask art of one object opens as that object
The reader put an opacity mask's art in a group every time, so a mask
made from one path came back from a saved .ai as a group holding the
path, while Make Opacity Mask keeps one object as the art. This also
changes how existing files with single-object masks open, because
the editing data of a .ai, an EPS and a PDF goes through this reader:
the art is the object.

A hidden object or a guide stays in a group, because the canvas draws
the art's root whether it is shown or not and whether guides show. A
clipping path alone stays a clipping group.

The editing copy writes a plain group of one object as a group (u, the
object, U), so it reads back as a group. Its other plain groups are
still written as their members. Hidden mask art is written shown,
because the canvas draws it and a group read back would not.
2026-11-07 08:19:20 +07:00
Don Omondi 95dcbfe59f EPS import: an image's transient data stops counting against the memory budget
The sample planes an image is decoded from, and the strings a procedure
data source hands back to fill them, are freed once the image is
decoded, so they stop counting against the 1 GiB budget then; the pixels
kept still count. A file of many images whose procedure returns one
large buffer each time no longer runs out of budget.
2026-11-06 20:11:52 -05:00
Don Omondi 36646863fc .ai import: Art brushes in the older form of their objects come into the Brushes panel
Art brush objects whose first number is 1, as older files write them, have one
field fewer before their numbers and 8 numbers at the end. The reader wanted
exactly 15 and left every such brush out with a note, though an Art brush is
read from its art's name alone. Scatter brushes still need all 15 numbers.
2026-11-06 19:12:35 -05:00
Don Omondi 4c791f0f81 EPS import: gradients drawn as abutting strips come in as one gradient
A page that paints a gradient as a row of abutting one-colour strips (as
Level 2 writers draw smooth shades) imported as hundreds of separate
fills. Each anti-aliased on its own, they left seams where the art below
showed through every shared edge (PDF 32000-1 §10.6.4, conflation): thin
stripes, and a pale tint over strips a pixel or two wide. An Illustrator
EPS whose page drew its gradients that way then differed from its layers
and opened as its page with empty layers.

A run of at least six such strips under the same clips, side by side in
one direction with no gap, each a small colour step from the last, now
becomes one object filled with a linear gradient through the strips'
colours (stops on a straight colour ramp dropped), and the clip path
itself when it was the clip's only art. Abutting blocks of distinct
colours stay apart.
2026-11-06 17:58:45 -05:00
dotCooCoo 0c5ad8e242 .ai save: objects next to type keep their own transparency
The reader gives an Xy right after a compound path or a text object to
that object. The writer now writes XR before the Xy of type, images and
guides, so type next to type, a compound path before type, image or
guide, and type before an image or guide keep their own opacity, blend
mode and knockout shape flag.

- Type keeps its Isolate Blending and Knockout Group state in a state
  block after its text object, as its outlines did on their group.
- The reader no longer gives a layer the Xy before its last text object.
- The ASCII85 end marker of the text document stays on one line.
- The warning and docs/file-format-parity.md also list area type in an
  open frame, type on an open path whose ends meet, type of only white
  space and threads of type on a path as written as outlines.
- README.md, ROADMAP.md, docs/gaps.md, docs/roadmap.md and
  docs/target-app-parity.md describe the editing copy a saved .ai holds.
- clip_path's doc comment is back on clip_path.
- import_fuzz reaches threaded area type and vertical type.
2026-11-07 05:15:16 +07:00
dotCooCoo aed9898b8d .ai save: the editing copy keeps type as type
The editing copy of a PDF-compatible .ai wrote every text object as its
outlines. Point type, area type and type on a path are now written as
text: a text object in the layers that names its story, and the text
document after the document data (%AI11_BeginTextDocument) holding the
stories.

- Each story holds its characters (a paragraph ends in \r, a forced line
  break is \x03), its character runs (font, size, leading, tracking,
  baseline shift, horizontal and vertical scale, solid fill and stroke
  with its weight, capitals, Tate-chu-yoko) and its paragraph runs
  (alignment, indents, space before and after, hyphenation, right-to-left
  direction).
- Point type keeps its point and, when it is turned, its matrix. Type
  scaled by one factor, such as all type on a large canvas, has its scale
  in its sizes, frame and path. Area type keeps its frame, rows,
  columns, gutters and first baseline, type on a path its path and where
  it starts and ends, and vertical type its orientation. A threaded story
  is one story through its frames in order. Area type and type on a path
  carry their frame's path in the layers as well.
- Type the text document can't hold is written as its outlines, with a
  warning: type in opacity masks, pattern tiles and art cut to a clipping
  object, mirrored type, turned or unevenly scaled area type and type on
  a path, frames of several parts, area type that flows around a text wrap,
  threads whose frames differ in orientation or include a frame written
  as outlines, type and stories past the sizes the reader reads, and type
  with inline graphics, ruby, gradient or pattern paint or an appearance
  or opacity mask of its own. Other character and paragraph attributes are left out, with
  a warning.

Tracking is written as a whole number of thousandths of an em, and
solid paints as simple paints; tracking that isn't a whole number is
rounded, with the warning.

Each construct is written in the form VectorCraft's .ai reader reads
(crates/eps/src/import/ate.rs at 36ef34dfdd: Texts::read :407, story
:501, frame :456, para :562, style :588, paint :622, AreaFrame::read
:284; the text object in import/ai/read/art.rs:15 and its path in
import/ai/frames.rs:26), and the tests read the written data back
through that reader. The scripting
reference documents the same attributes on the reading side (text frame
kinds, columnCount, columnGutter, rowCount, startTValue, endTValue,
orientation, and the character attributes):
https://web.archive.org/web/20160410101607/https://wwwimages.adobe.com/content/dam/Adobe/en/devnet/illustrator/sdk/CC2014/Illustrator%20Scripting%20Reference%20-%20JavaScript.pdf

The reader now closes a text object's frame path painted with a closing
operator (n, f, s, b, h), so area type's frame comes back closed; places
point type whose story keeps no composed lines at its frame's point;
keeps a story's last empty paragraph (only the \r that ends the story is
dropped); gives type made from the text document its text object's lock,
as it gives it its visibility; and gives type its text object's knockout
shape flag, as it gives it its opacity and blend mode.

Tests: the round trip of every kind of type and its state, a second
write of what is read back giving the same bytes, the text document and
stubs, scaled point type, a story split between threaded frames, the
fallbacks and the warnings, and the engine's editing copy with every save
option; a fuzz case for damaged text documents and stubs.

Docs: docs/file-format-parity.md.
2026-11-07 05:15:15 +07:00
dotCooCoo 0c570dee87 .ai import: paths with an Art brush open with the brush on their stroke
A path with an Art brush comes in as the path, with the brush on its
stroke at its weight, instead of as its drawn look, when the brush
stretches art of solid-filled paths along the path, unflipped, at 100% in
Tints. The art runs on the side of the path the file draws it.

The drawn look stays for other colorizations and widths; Proportional,
between-guides and flipped brushes; type; a path with settings of its own,
a variable width, effects, a swatch stroke or an entry that isn't read;
and art with strokes, gradients, patterns, masks or effects, or no length.

A brushed stroke, Calligraphic ones too, takes the brush the Brushes panel
keeps under its name, and an image with a brush keeps its drawn look.

In every document, Tints and Tints and Shades take art in black ink alone
by its ink amount, and a process or gray stroke color's tints and shades
stay in that color's model.

Place and Expand bring the brushes the art uses, renaming on conflict.

Part of #637.
2026-11-07 05:15:09 +07:00
Don Omondi d16123efad Legacy .ai export: a flattened image's clip follows its edge smoothly (#5264)
The clipping path around a transparent image flattened for a version 7
.ai followed 2 pt cells, a visible staircase. It now follows the rendered
pixels (in blocks only past 4 million), grown by one pixel so the whole
anti-aliased edge is inside, through the middle of each pixel edge and
simplified with Douglas-Peucker, so slopes and curves are sloped lines.
2026-11-07 05:14:58 +07:00
dotCooCoo d45ebe465b .ai save: the editing copy names the active artboard
The editing copy of a .ai or .ait file that VectorCraft saves or exports
now has `%_<n> /Int (CropAreaActive) ,` after the ArtboardArray in its
recorded part, and marks that artboard as the selected one. The app
records its view's active artboard before each command
(DocState::active_artboard; an index past the last artboard is the last,
as in the Artboards panel); without a view, the artboard the document
opened on (Document::opened_artboard) is written, else the first. A .ai
file read from its editing copy opens on that artboard. Before, the copy
named no active artboard and always marked the first as selected.

Docs: docs/mcp.md, docs/file-format-parity.md, the editingData option text.
2026-11-07 00:17:17 +07:00
Don Omondi 591fc9b21e Paste: cells copied from a spreadsheet paste as a table of type over gridlines
Tab-separated rows with the same number of cells (quoted cells too)
become a group of point type, one per cell, in columns and rows over
0.5 pt gridlines; other text pastes as before. Fixes #5296.
2026-11-07 00:17:15 +07:00
Don Omondi f08381df8d SVG import: filter and mask regions clip what they declare (#5876, #5875)
Squashed from #5913 onto main.
2026-11-06 16:39:04 +07:00
Don Omondi 41ceaadc7e SVG import: Gaussian blurs keep color-interpolation-filters; Gaussian Blur can blur in linear light (#5877) 2026-11-06 16:05:55 +07:00
Don Omondi dbbe8a9298 PDF and .ai export: objects' URLs become clickable links (#5785)
Each visible object with a URL (Attributes panel) is written as a Link
annotation with a URI action over its bounds on the page, trimmed to its
clipping groups. Hidden objects, non-printing layers and printed sheets get
none; PDF/X files leave them out with a warning. URIs are percent-encoded
to 7-bit ASCII.
2026-11-06 15:48:02 +07:00
dotCooCoo d58d47312f Legacy .ai export: black-and-white colorized images save as image masks
A colorized image whose pixels are all black or white (or clear) is
written as a 1-bit image mask (ImageMask 1): its color as the fill, a 0
bit for each black pixel and a 1 bit for each white or clear one. The
legacy reader opens it colorized again with the same clear pixels, so
the engine no longer flattens or omits it. Other colorized images are
written with their color in their pixels, over white, with the note
for transparent images.
2026-11-06 15:33:35 +07:00
Don Omondi 427ec0017c SVG import: gradients with color-interpolation="linearRGB" mix their stops in linear light (#5878) 2026-11-06 15:33:02 +07:00
dotCooCoo 968bf1dc48 .ai import: a pattern or color named as another swatch keeps its swatch
Squashed from #5903 onto main.
2026-11-06 15:33:00 +07:00
dotCooCoo def29d0f97 Docs: .ai symbols are read with the file's layers
A .ai that comes in as its page or PDF part (editing data with no layers, layers that can't be read, or a page fallback) gets none of the editing data's symbols: layered_ai_from fills symbols only from build_from. The editing-data paragraph now says so.
2026-11-06 14:04:04 +07:00
dotCooCoo 31456a0cec .ai import: a file whose editing data has no layers also opens on its active artboard 2026-11-06 13:47:16 +07:00
dotCooCoo aac21aa076 .ai import: legacy type keeps one copy of tab stops its paragraphs share 2026-11-06 13:22:36 +07:00
dotCooCoo 0473fcad58 Docs: the .ai notes no longer list guides as a known failure
The Known failures bullet in docs/file-format-parity.md kept stale copies
of its earlier wording after several merges: guides were still listed as
lost although they open as ruler guides since #5057, and the same clauses
about #868, #1027 and #758 repeated several times. The bullet now states
each fact once, and keeps every legacy .ai reading note it carried.
2026-11-06 12:04:14 +07:00
dotCooCoo 0c272519fb .ai import: symbols and their instances open live
The reader measured a symbol's definition only to find the page art an
instance covered, so every file with a placed symbol instance opened
with that instance as drawn art, or as its page.

- Each `%AI14_BeginSymbol` definition is read by a reader of its own into
  a symbol of the document, with its art (in the symbol's space, y down),
  the registration point its dictionary gives
  (`AI13PatternRegistrationType`, 1 to 9 from the top left) and the
  instances of other symbols in its art. A definition whose art isn't
  read whole isn't kept: type, placed files, non-native art, pattern
  fills, a gradient or an image the reader can't read or place, and
  anything else the reader doesn't read. Its instances come in as the
  page draws them, within the box of the art that is read. A definition
  that holds an instance of a symbol the file doesn't have isn't kept
  either, nor is a definition holding an instance of one of those, and
  their instances aren't read. A definition after the first layer isn't
  read.
- `%AI24_BeginSymbolList` orders the symbols as the Symbols panel lists
  them. A name read twice is numbered ("Dot 2"), and instances name the
  first symbol with the file's name.
- `/SymbolInstance` with `/SymbolRef` and `/RTransformMatrix` comes in as
  a live instance, with the hide and lock set before it and the opacity,
  blending mode, isolation and knockout of the `Xy` after it, as a
  group's. An instance with appearance changes of its own
  (`AI19SymbolAppearanceMap`), of a symbol that isn't read, or placed
  only by `/Matrix` or `/Transform`, comes in as the page draws it.
- Symbol art takes the gradients and art styles read before it, and an
  object in it linked to a listed graphic style keeps the link.
- In a symbol's art, the matrices of instances, gradients and images are
  read in the canvas's space, y up, about the canvas point of the ruler
  origin. Without `%AI3_TemplateBox` an image can't be placed, so the
  symbol isn't kept.
- At most 4,096 definitions are read, and a symbol list names at most
  16,384 symbols.

Tests: reader tests for each case above, and fuzz cases for damaged and
hostile symbol data.
2026-11-06 01:32:42 +07:00
dotCooCoo ddb64fceb6 .ai import: objects other than type keep some Distort & Transform effects live
An art style with a Distort & Transform effect opened every object but
type as its drawn look. Objects other than type now open as themselves
with these effects live:

- Any object takes a Tweak that moves nothing and Pucker & Bloat at 0,
  beside the effects it already took.
- A path, compound path or group takes Transform without copies, or a
  Free Distort whose corners make a parallelogram, when it is the only
  effect. Neither the style nor anything in the object may paint with a
  gradient or pattern. Everything in the object must be a path, compound
  path or group without a clip, an opacity mask or effects of its own.
  When Transform scales, rotates or reflects, nothing in the object may
  be stroked.
- An unstroked path or compound path whose segments are all straight
  takes Twist when it is the only effect.

Other objects keep the drawn look, as do Zig Zag, Pucker & Bloat of
another amount, a Free Distort with other corners and Transform copies.

Docs: docs/file-format-parity.md, docs/target-app-parity.md.
2026-11-06 01:20:04 +07:00
dotCooCoo d1def50140 Docs: the .ai editing-data checklist lists how several clipping paths clip
The private editing data list in docs/file-format-parity.md now says
that several clipping paths in a clipping group, a layer or an opacity
mask's art clip to their intersection, that a compound path of clipping
paths stays one clip, and that clipping paths that would nest the art
past the document's 32 levels stop the editing data from being read, as
#5789 made the reader do.
2026-11-05 23:25:05 +07:00
Locme a3ec061995 .ai import: 6D Art Pen brushes open live, and Windows reads pen tilt and rotation (#372)
Squashed from #5815 onto main.
2026-11-05 23:25:05 +07:00
dotCooCoo f092b0b7a7 .ai import: legacy type keeps its tab stops
A tab definition in type of the legacy format (`numDots numTabs Xb`, a
`leader decimal tabType tabPosition Xe` for each stop, then `XB`) was
skipped, so every paragraph opened with only the default stops every
36 pt. The stops it describes now become the paragraph's tab stops
(left, center, right or decimal, at their positions), and they last
into the next paragraphs and text objects like the other paragraph
attributes. A definition with no stops, or whose descriptions were all
skipped, leaves the default ones. A description with an unknown type or
a position outside 0 to 100000 pt is skipped, and so is one past the
first 1024 of a definition. A text object's `To` ends a definition that
an earlier object left open.

Docs: docs/file-format-parity.md.
2026-11-05 22:26:49 +07:00
dotCooCoo 456487b873 .ai import: the file opens on its active artboard
VectorCraft now reads `CropAreaActive`, an `/Int` in the dictionary of
the editing data that holds the `ArtboardArray`, as the index of the
active artboard in that array. The reader ignored it before, and every
file opened on its first artboard.

The opened document starts with that artboard active, so the view the
document opens at and the Artboards panel use it. The index counts
every entry of the array, so an artboard that is left out (one with no
area) does not shift it. When the entry is missing, is not an `/Int`,
or names an artboard that does not open, the first artboard is active,
as before. A file that comes in as its PDF part, with its pages placed
where its artboards are, opens on the page of the active artboard, also
when the reading stops before the artboards. The same reader serves the
editing data of EPS and PDF files.

The active artboard is kept on the opened document only; native files
do not save it.
2026-11-05 22:03:55 +07:00