A freeform gradient's image was sampled, encoded and written inline at
every fill, outside the reuse placed images have. Fields now go through
the same codes and placements: a fill whose encoded image (color setup,
image dictionary, filter, operator and samples) matches one already
kept draws from it, so its samples are written once in the setup as
VCim<i>. A field drawn once is still written where it is drawn.
A fill whose placement can't be drawn, or that arrives when the page is
already at the 256 MB limit, is no longer sampled first, and a field
image taken back with art that passed the limit is forgotten.
A path's guide lengths matched the brush's within 0.001, so on very short art guides at 30% and 35% of the art matched. The guides now also match as fractions of the art's length.
A path's Art brush settings matched the brush's within a small tolerance, and only the brush's were checked. A path with a Spacing of 0.0005, or guides that leave no art between them, opened live with the brush's settings. The path's settings now pass the same checks as the brush's, and such a path keeps its drawn look.
A linked image whose appearance is one Warp effect, with no opacity mask,
was saved to the .ai editing data as its drawn art, so its live Warp was
lost. It is now written with an art style of that Warp, as an embedded
image is: its bent pieces are its drawn look, and the image itself
follows on %_ lines as a placed file with its path, its folder relative
to the document's and its preview. In an opacity mask's art the copy is
embedded, with the existing warning for linked images in masks.
Opening such a file reads the image back linked, with its Warp live.
A hidden image with a Warp, embedded or linked, is now compared with its
drawn look shown, so it keeps its Warp too; before, the look drew
nothing and the image came in as its drawn pieces.
A .ai path with an Art brush opened with the brush on its stroke only
when the brush stretched its art at 100% in Tints, unflipped. Paths with
an Art brush in None, at another fixed width, with Stretch Between
Guides, or flipped along or across now open as the path with the brush
on its stroke too, and the brush in the Brushes panel has those options.
The guides come in as fractions of the art, from the lengths of the art
outside them. A brush with Scale Proportionately comes into the panel
with that option, and its paths keep their drawn look.
Paths keep their drawn look when their settings that change the drawing
differ from the brush's, and when the brush is in Tints and Shades or
Hue Shift, has a width that follows the pen, has guides that leave no
art between them, or has a Spacing, Adjustment or FoldAdjustment other
than 0, 1 and 1.
The .ai save writes the same options, so such brushes and the paths
that use them come back as they were; a path with a proportional brush
is written as its brush's art.
A straight `(N) *` guide path that runs across the canvas or an artboard
opens as a ruler guide, but a hidden one (`1 Xw`) stayed a guide path.
It now opens as a ruler guide too, and every ruler guide made from such a
path keeps the path's hide, lock and name, so its Layers row shows them.
Before, a locked guide opened unlocked and a named one lost its name.
Hidden or locked guide paths that are short, slanted, grouped or `(S) *`
stay guide paths, and commented copies (`%_`) are still left out.
Docs: docs/target-app-parity.md, docs/file-format-parity.md.
A symbol instance colored with the Symbol Stainer lost its stain in
export whenever the canvas's stained art was not used:
- An instance with geometry effects was reshaped for export from the
symbol's art with only its dynamic changes, so SVG, PDF, EPS, .ai,
DXF, EMF/WMF and HPGL wrote the unstained colors. A color adjustment
on an instance recolored the unstained art the same way.
- PDF, EPS, legacy .ai, DXF and EMF/WMF wrote an instance without
effects from the unstained art.
tint_node, stain and instance_art now live in
vectorcraft_doc::symbol_overrides, which both the effects and the
exporters can use; vectorcraft_brush re-exports them. Baking, color
adjustments and the writers above now use instance_art: dynamic changes
first, then the stain.
A straight compound path with Twist was read live up to 180° whatever
guides it held, and the live Twist was measured from bounds that take in
the guide members. A straight compound path with Twist whose guide
members reach past its other members now opens as its drawn look
instead of live, and so does a compound path made only of guides.
Compound paths whose guides lie inside their other members, a Twist of
0°, and single paths keep opening live.
The `.ai` writer keeps a graphic-style link only where the reader reads
the style live, so such an object is now written without the link, with
the existing style-link warning.
A PDF-compatible .ai saved with Include Editing Data for Other Apps
wrote no text wrap options, so a wrap object opened from the file no
longer wrapped type. An object with only wrap options got no
dictionary at all.
The writer now writes each wrap object's options in its dictionary as
`AI11TextWrapOffset` (`/Real`) and `AI11TextWrapInvert` (`/Bool`, 1 or
0), the entries `text_wrap` in crates/eps/src/import/ai/read/document.rs
reads, beside the object's name, variables and opacity mask.
- The offset is the one in the art's space, so on a large canvas it is
written at 1/10 and read back at its size. An offset that is not
finite is written as the default 6 pt, and one past the -1000 to
1000 pt the reader keeps as the nearer end of that range.
- Art the writer draws for an object (a blend's steps, a symbol
instance written as its art, a brushed stroke's pieces, pattern
tiles, an object's drawn look) is written without the options of the
objects it is made from. The object itself and a symbol's own art
keep theirs.
- A clipping path written as its fills and its strokes has its options
once.
Docs: docs/file-format-parity.md, docs/target-app-parity.md.
A legacy .ai graph (%_Gs ... %_GS) opened as plain art, with its table,
type, axes and settings left out. A grouped column, stacked column, line
or area graph now keeps them on its group when every record has the
shape and values the version 7 specification's appendix A gives, the
table holds at least one number, the drawn art strokes the plot's left
and bottom edges, and each series group is tagged once as a whole
column, holds only paths and paints them with one fill and one stroke.
The saved art stays as it is on open; Graph Data redraws the graph from
its data afterward, with each series' fill and stroke kept.
Any other graph (pie and scatter graphs, designs, customizations, record
shapes of later versions, tables past 10,000 categories, 256 series or
2,600,000 cells) keeps its art as plain objects with the existing note.
Saving a graph to .ai, in either form, now warns that its data and
settings are not written.
An object in an opacity mask's art is written with its art style, as on
the layers, so a mask whose art has Offset Path opens from the editing
data with the effect live and draws the masked object as it did. This
covers a hidden art root and masks inside another mask's art.
Geometry effects on mask art that no art style holds, such as Roughen,
are applied to the art written, in the masks of layers, symbols and
pattern tiles. Before, the mask's art was written without them.
With repeated names numbered when a brush library is read, a stroke that
names a repeated brush draws the first brush of that name, and a later
brush of the name is read as "Name 2". Three tests built a library with a
repeated name and expected the later brush:
- Document Info lists a name two stored brushes share with the first
brush's type (art), not the last one's.
- The two render memory tests add their own `Dots` scatter brush beside
the default library's `Dots`. They now remove the default `Dots` first,
so the stroke draws their brush.
- The .ai writer test that leaves out a Pattern brush "X" gets the
Calligraphic brush after it back as "X 2", the name it had in the
document.
A path or compound path with straight segments and nothing stroked was
read with its Twist live at any angle. It is now read live up to 180°
either way, a limit VectorCraft sets, and one twisted further keeps the
file's drawn look, as curves and groups already do past 90°.
The .ai writer keeps a graphic-style link only where the reader reads the
style live, so a straight object twisted past 180° is now written without
the link, with the existing style-link warning.
Docs: docs/file-format-parity.md, docs/target-app-parity.md.
A pair with manual kerning of 0 was saved with no Tk and opened with automatic kerning. It is now written as 0 0 Tk and reads back as manual kerning of 0.
A line breaking value (TG) or Japanese layout rules (Xu, Tu) with missing or non-numeric operands no longer mark the setting as set, so the next visible text object gives no warning about a setting the file did not specify.
Legacy .ai type (version 7) now reads the operators it used to skip:
- `autoKern kernValue Tk` (and `TK` in overflow text) sets the manual
kerning of the character before the pair, or at the start of a line
the space before the line's first character; autoKern 1 sets the
pair back to automatic. Values are kept to -1000..10000.
- `T+` and `T-` (discretionary hyphens) become soft hyphens.
- `languageID XL` sets the characters' language (ids 0 to 11).
- A visible text object read while a line breaking value (`TG`) or
Japanese layout rules (`Xu`, `Tu`) are set opens with a warning,
once per file for each.
Final-form positions (Tc, Tw, Tm, Td, T*, TR) stay ignored.
Legacy .ai saves now write manual kerning as `0 value Tk` after each
character that has it and before a paragraph's first character with
space before it, and soft hyphens as `T+`; manual kerning is no longer
listed among the attributes left out. The writer's prolog defines Tk
and T+.
Docs: docs/file-format-parity.md, docs/target-app-parity.md.
An envelope around type of only spaces and a rectangle mapped from the
union of the rectangle and the type's laid-out box, so the empty type
moved and scaled how the rectangle was distorted. Type that draws
nothing now adds no box while other content in the envelope has one,
in groups and layers and as a clipping path too. When nothing else in
the envelope has a box, the type keeps its laid-out box, so an envelope
of only empty type keeps its frame, Make with Mesh and Reset with Mesh
still work, and Release still gives back the warp shape.
This applies to Make with Warp, Make with Mesh, Make with Top Object,
Reset with Mesh, Edit Contents and the stroke margins. Type that has
not been measured yet keeps its laid-out box as before.
The PDF/.ai import's boxes for envelopes with Distort Appearance
measure each object as the whole contents measure it, so the margins
the import tries match the contents' geometric box. The three import
tests that measure type without registering the glyph measure now
register it first, so another test registering it while they run no
longer changes their result.
The Gradient panel's Method menu gets two methods of VectorCraft's own
beside Classic and Perceptual. They mix a linear, radial, conic or
diamond gradient's colors around the hue wheel: hue, saturation and
brightness each change evenly from one stop to the next, and the hue
angle keeps one direction, as the fixed-direction rules of
https://www.w3.org/TR/css-color-4/#hue-interpolation do. Hue Clockwise
lowers the angle (red, magenta, blue), which is clockwise on the color
wheels, and Hue Counterclockwise raises it (red, yellow, green).
Two stops whose hues are less than half a color level apart count as
one hue and keep it, so a color and a tint or shade of it do not turn
the whole wheel. A stop whose RGB numbers are less than half a color
level apart is gray and takes the hue of the stop it mixes with, and
black takes that stop's saturation too.
- `paint.editGradient` and `paint.setFill` take `method: hue-clockwise`
or `hue-counterclockwise`, in any case, with a space or an underscore
for the hyphen or without it; other spellings are an error. The native
file writes `HueClockwise` and `HueCounterclockwise`.
- The canvas and raster exports draw the gradient through stops on its
curve, within half a color level.
- Reverse turns the method the other way with the stops, and a Reflect
spread is repeated from the curve's stops, so both keep the colors.
- SVG and PDF write the gradient as an RGB image, CMYK and spot color
stops included, with the spot warning. EPS writes a shading in process
colors with a warning for spot stops. A legacy .ai file and the .ai
editing data get the colors between the stops as stops of their own,
in process colors, at most 256, with a warning. CSS gets those stops
too.
- The `method` error names the four values, in every catalog.
- The Method menu is as wide as its longest name in the interface
language, within the panel.
Docs: docs/mcp.md, docs/plugins.md, docs/target-app-parity.md, ROADMAP.
Two findings in the review of #7146, in how layers whose differing
objects come in as the page's art treat envelopes of type:
- The envelopes of type the page holds against the layers were weighed
on the layers as read only, and that choice was also applied at the
placed files' other placement, which can move a placed file over or
under an envelope. Each placement is now weighed on its own. The
places of those left live, for layers that open alone, still come
from the layers as read: a .ai that opens alone has no other
placement.
- A placement that draws as the page with only the held envelopes put
back was dropped, as nothing in it differs for its objects to come in
as the page's art. It is now used as it is, as layers that draw as the
page with every live envelope's drawn art put back already are. The
try with every envelope of type put back keeps its order: objects
that differ come in as the page's art, as before.
Part of #7141.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An embedded image whose appearance is one Warp effect, with no opacity
mask, is written to the editing data with an art style of that Warp:
its bent pieces as its drawn look and the image itself on `%_` lines,
as other styled objects are written. The reader takes such an image
with its Warp live when the live warp draws as the drawn look, using
the comparison and budget it uses for warped type; otherwise the drawn
look stays, with the drawn-look note. A linked image with a Warp is
written as its drawn art, as before, without its live Warp. Images with
an opacity mask and images with another effect keep their drawn art.
An embedded image whose samples are on `%_` lines is now read as the
hidden copy it is. Before, it came in as a second visible object beside
its drawn look.
When the layers with their live envelopes didn't draw as the page, and
didn't with the drawn art of every live envelope put back either, every
envelope of type got its drawn art back wherever the layers were still
used: the editing data trusted, the objects that differ coming in as
the page's art, or a .ai whose layers would open alone opening alone.
Art that differed anywhere on the page cost every envelope of type its
editable type, though putting its drawn art back changed nothing.
Now each envelope of type is weighed in the page check's own drawing,
on the pixels that it and its drawn art ink (the two drawn together on
a layer of their own, without the rest of the layers). It keeps its
drawn art and hidden type where the layers with it differ from the page
in more of those pixels than its own check allows against its drawn art
(10%, or 3% with all their neighbours), or where the envelopes that stay
live would together differ there in more of a page than half of what
the page check allows (a budget of its own, the same size as the one
their own checks share). Art differing on its pixels still holds it.
It also keeps its drawn art, as before, where the layers don't draw it
where it is and as itself, on the page or off it: under a clip or an
opacity mask, in a group with an appearance of its own, or in another
envelope, a repeat or a blend. Another envelope on no page stays live,
except on a page that holds all the art (an EPS's art box), where one
reaching past the page keeps its drawn art. Past 12 on the pages, all
keep it.
A .ai whose layers would open alone still opens alone: its envelopes of
type are settled again as they were with the page, in the same order
and with the same checks, so each that opens live draws as it was
weighed, and those the page held get their drawn art back. Where the
differing objects are to come in as the page's art and can't with
envelopes of type live (an object that holds type isn't replaced),
every envelope of type gets its drawn art back and that is tried again,
as before. Where putting back the drawn art of every live envelope
makes the layers draw as the page, it is still put back.
On 224 of our own files (used locally), envelopes of type that open
live go from 174 to 186 in 8 files, none fewer; no file changes between
its layers and its PDF part.
Part of #3179.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An image placed several times in an EPS file (the pieces of an envelope
or a Warp effect, copies of one image, a symbol's instances) wrote its
whole ASCII85 data at every placement: 200 copies for one envelope at
the default fidelity, enough for a large photo to pass the 256 MB page
limit and lose pieces.
The samples of such an image are now written once in the setup as
VCim<i>, and each placement reads them from there:
- Level 3: a ReusableStreamDecode stream, rewound with resetfile and
read through a new FlateDecode filter at each placement.
- Level 2: an array of strings of at most 49,152 compressed bytes, fed
to RunLengthDecode by a procedure.
An image placed once is written where it is drawn, byte for byte as
before. The page limit counts a repeated image's samples once, and a
colorized image is reused per ink.