Commit Graph
831 Commits
Author SHA1 Message Date
dotCooCoo 2faec2fa11 .ai import: Skew, Stair Step and Gravity measure the path's turn square to it
The spacing fitted from a type-on-a-path layout measured each turn against
the glyph's own foot. Skew's feet stay upright, so on a tilted or leftward
path the turn picked up a false angle and the fitted spacing was wrong (a
straight path at 30 degrees gave -9.7 instead of 0). Effects other than
Rainbow and 3D Ribbon now measure the turn against the baseline turned a
right angle.

The file-format doc states that a frame whose options set key 6 to true
keeps the default effect, alignment and Flip.
2026-11-08 11:22:31 +07:00
dotCooCoo 53f6aafe87 .ai import: type on a path keeps its effect, alignment and flip
Type on a path from a file's text document opened as Rainbow on its
baseline, not flipped, whatever Type on a Path Options the frame kept.
Each frame now keeps its effect (Rainbow, Skew, 3D Ribbon, Stair Step,
Gravity), Align to Path (Ascender, Descender, Center, Baseline) and Flip.
A code or flag that can't be read leaves that option at its default.

Flipped type opens with the frame's path reversed once, after a copied
object takes its own art path, and an open path's end bracket stays so
the type starts where the file's range ends.

Spacing is still fitted from the file's layout. The fit now measures along
the path when Align to Path moves the baselines off it, and it follows the
glyphs' feet under 3D Ribbon, whose baselines stay level.
2026-11-08 11:22:30 +07:00
dotCooCoo b8233f7c19 .ai save: a reopened file opens on the artboard active when it was saved
Squashed from #5975 onto main.
2026-11-08 11:22:28 +07:00
dotCooCoo 3967847772 .ai save: the large-canvas warning says geometry effects are applied to the art
On a large canvas no art style is written, so the editing data holds an
object's geometry effects only as the artwork they made: the effects can
no longer be edited when the file is opened again. The warning now says
that the geometry effects are applied to the artwork and can no longer be
edited, and that the object's other effects are left out.
2026-11-07 19:18:10 -08:00
dotCooCoo 71ce0a3c1d Merge feat/ai-editing-data-s6b into feat/ai-editing-data-s6b2 2026-11-07 15:57:45 -08:00
dotCooCoo 7ca34c522d .ai save: the large-canvas warning names every effect the editing copy leaves out
On a large canvas no art style is written, so objects with live effects
keep only their geometry effects in the editing data for other apps:
blurs are left out as well as shadows, glows and feathers. The warning
now says that no art styles are written and that only geometry effects
are kept.

The comment on rgb_without_cmyk in art_styles_write_the_same_bytes_again
now gives the cause of the Windows difference: the Generic CMYK
separation of the default Pink swatch, at the edge of the press gamut,
lands on C0 M93.9 Y16.3 or C0 M93.2 Y15.3 when its RGB changes in the
last float bits, and the platform's float math decides which. The
comment also says that named and spot RGB colors are not blanked.
2026-11-07 15:49:34 -08:00
dotCooCoo 2b8cefe728 Merge feat/ai-editing-data-s6b into feat/ai-editing-data-s6b2 2026-11-07 14:55:16 -08:00
dotCooCoo a1842028da Tests: compare the RGB values of colors in the art-style round trip
art_styles_write_the_same_bytes_again failed on Windows (MSVC) on the
Pink swatch: the first save wrote its CMYK equivalent as 0 0.9317
0.1527 0 and the save of the reopened file as 0 0.9389 0.1629 0. The
writer computes the CMYK equivalent of an RGB color from its RGB values,
and the save of the reopened file computes it from the RGB values read
back at four decimals; for this out-of-gamut color the Generic CMYK
conversion moves by more than the test's 0.002 there. On macOS the two
saves of this document differ by at most 0.0016 in these numbers.

The test now blanks the CMYK equivalents of RGB colors (the first four
numbers of `c m y k r g b Xa` and of an RGB gradient stop's
`c m y k r g b 2 ... Bs`) and compares every other number, the RGB
values included. With them blanked, the two saves are identical on
macOS. The large-canvas test's comment also says what such objects are
written as.
2026-11-07 14:52:43 -08:00
dotCooCoo 66b4c171d4 .ai save: the large-canvas warning says what the editing copy keeps
On a large canvas no art style is written, so objects with live effects
are written as their vector art with their geometry effects applied, and
their shadows, glows and feathers are left out. The warning now says
that, as file-format-parity.md does, instead of "written as their drawn
look".
2026-11-07 14:52:43 -08:00
dotCooCoo 188142a792 .ai save: a symbol first defined inside a drawn look warns of its art's effects
A symbol whose first instance is written in the drawn look of an object
with a style (through a member's scatter brush) was defined while the
look's flag was set, so the warning for the effects its art loses was
left out, and the cached definition kept it out for later instances.
The definition now writes its art with the flag cleared and restores it
afterwards.
2026-11-07 12:49:12 -08:00
dotCooCoo 9c0e7ccb80 .ai save: the editing copy keeps graphic styles and links to them
The editing copy of a PDF-compatible .ai left out the Graphic Styles
panel's styles and objects' links to them, with a warning. They are now
written as art styles:

- The panel's styles come first in %AI9_BeginArtStyles and are listed in
  its order in %AI9_BeginArtStyleList after the palette, with their
  fills, strokes, transparency and effects. Fills and strokes may have
  transparency and effects of their own, and a style may also hold Warp,
  Transform, Free Distort, Pucker & Bloat, Twist, Zig Zag or Gaussian
  Blur. A style of an object's own holds the same effects as before.
- A path, compound path or group linked to a graphic style names it when
  it has the style's appearance, the style is written, and the reader
  reads that style on that object. Objects linked
  to a new document's styles keep their link: the panel is written for
  them too.
- The writer reads each style back with the reader before it writes
  it. A style with gradient or pattern fills, with anything the
  reader does not read back, with a name another style has, with a name
  over 1,024 bytes or past 4,096 styles is left out with a warning. Other
  links are left out with a warning, and a panel with no style written
  warns that it opens with a new document's styles. No graphic style is
  written on a large canvas, with a warning.

Graphic styles:
https://helpx.adobe.com/illustrator/desktop/special-effects-styles/apply-graphic-styles/apply-graphic-styles.html

Tests: the round trip of the panel's styles and of links; each effect a
style can hold; the forms written; the list's limits; duplicate names; an
empty panel; links left out; a style's opacity at the written precision;
a large canvas; Twist and Transform on an object with no link; a link
to a style whose Transform moves the outline, with and without an
opacity mask; the
reader's reading of warp numbers; fuzz cases for damaged written styles.

Docs: docs/file-format-parity.md.
2026-11-07 12:02:18 -08:00
M Balazs PC 0234de1302 Merge branch 'fix/ai-type-leading-forced-breaks' into fix/ai-right-aligned-tabs
# Conflicts:
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-11-07 19:31:52 +01:00
M Balazs PC 4bfd7a207d Docs: the functions the line layout fixes touch say what they do 2026-11-07 19:30:49 +01:00
M Balazs PC 4c5ba22fdd .ai/EPS import: a paragraph's tab stops past the limit are reported too 2026-11-07 19:25:01 +01:00
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
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
Don Omondi 9272663228 EPS/.ai editing data: a stack's one gradient lies where its drawn look has it
A stacked style with a single gradient took the object's own gradient
fill whenever the object had one, even where the drawn look placed the
gradient elsewhere. A stack now always takes the placement of its drawn
look, which it already requires for each of its gradients.
2026-11-07 11:14:20 -05: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
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
Don Omondi 9c8eef4111 EPS import: a sampled function's sample reads count against the operation budget
Each evaluation of a sampled function copied its DataSource and read
every tap combination without counting that work: a shading evaluates
its function once per stop, so a long DataSource or many interpolated
inputs did far more work than the budget charged. Both now count. The
nearest-sample fallback is kept at the last sample, which a fractional
Size could put it past.
2026-11-07 05:24:15 -05:00
Don Omondi 120bcf102e .ai import: an Art brush with neither form's count of numbers isn't read
An Art brush object whose last field had neither 15 numbers nor the
older form's 8 came in with default settings. It is now left out like
other brushes whose values can't be read. An older-form Art brush keeps
the Art brush's default colorization, as the note says.
2026-11-07 05:07:25 -05:00
Don Omondi 28f8f84fd5 EPS import: strips under a larger clip keep the clip
A run of gradient strips under a clip larger than the strips became the
clip path filled with the gradient, painting where the strips did not.
The clip path now takes the gradient only when every point of the clip
lies inside the run; otherwise the gradient stays clipped to the strips'
area.
2026-11-07 05:01:25 -05:00
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
dotCooCoo 0d91749c74 .ai import: drawn looks in pattern and brush art count in the note
An object read as its drawn look counted in the import's "came in as
their drawn look" note when it was on the page or in a kept symbol, but
not when it was in a pattern's art or a brush's art. A file whose only
such objects were in a pattern or a brush opened without the note.

- A kept pattern's drawn looks count, once for each pattern name: a
  definition that a later one of the same name replaces no longer counts.
- A brush's art counts once a brush that is kept uses it; art no kept
  brush uses adds nothing.
2026-11-07 09:00:23 +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
Don Omondi dfa9548938 EPS import: an image too large to read skips its data
An image over the pixel cap was left out without reading its data, so
the program went on to read that data as PostScript and the file failed
to open (Ghostscript's eps2write writes a page with a large inline image
this way). The data is now skipped: the filters that find their own end
(ASCIIHexDecode, ASCII85Decode, SubFileDecode) read the file up to it,
without decoding what they pass.
2026-11-07 08:19:40 +07:00
Don Omondi fdbd116577 EPS import: cvi and cvr read radix numbers
cvi and cvr read a string as the PostScript syntax reads a number
(PLRM 3rd ed., cvi, cvr), so (16#20) cvi is 32. The reader parsed strings
as decimal only. Ghostscript's eps2write prolog undoes a name's #20 escape
that way, so its files with a spot colour named with spaces stopped
reading at that colour.
2026-11-07 08:19:36 +07:00
Don Omondi 8c57a65ee0 EPS import: SubFileDecode reads counts past the allocation cap
The count of a SubFileDecode filter bounds what it passes through, not
what it allocates, but the reader refused counts over 4 MiB as a
rangecheck. Ghostscript's eps2write files read each content stream with
currentfile Length () /SubFileDecode filter, so a page whose stream is
longer than 4 MiB failed to open.
2026-11-07 08:19:33 +07:00
Don Omondi 06a035e86b EPS import: bind leaves the procedures it already bound alone
bind makes each procedure it goes into read-only and ignores read-only
procedures (PLRM 3rd ed., bind). The reader bound them again, so a prolog
that binds a procedure holding an earlier-bound one, after defining a name
such as M as an operator, turned that procedure's own variable M into
setmiterlimit. Ghostscript's eps2write prolog does this, and its files with
sampled functions (transfer, black generation) failed to open.
2026-11-07 08:19:29 +07: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
bflatastic ccdccb1299 Tests: an image next to type keeps its knockout shape flag 2026-11-07 07:36:26 +07: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 0be78766f4 .ai import: a compound of clipping paths keeps their knockout shape flag
Clipping paths in a compound path that holds a drawn look become one
compound path. It took the paths' shared stroke, opacity and blend mode
but dropped the knockout shape flag. It now has the flag when every
clipping path has it.
2026-11-07 05:15:19 +07:00
dotCooCoo a9b49f716b .ai import: images, meshes and blends keep the knockout shape flag
An `Xy` whose shape operand is set now reaches an image (embedded or
linked) and a gradient mesh when it is written before the object, and a
mesh or blend when it is written after the object's end. A live blend
takes the flag from its drawn steps. Before, the reader dropped the flag
on these objects, so an image saved with Opacity & Mask Define Knockout
Shape lost it on reopening, with no warning.

A styled object takes the flag written on its drawn look. For a text
object, the flag goes to the object when the look draws only its type,
and otherwise to the group that holds the look and the type. An opaque
look that draws more than the type and sets the flag now goes into that
group as well.
2026-11-07 05:15:19 +07:00