Commit Graph
505 Commits
Author SHA1 Message Date
BFlat baa7248e76 Merge pull request #5158 from dotCooCoo/fix/ai-os23-2831
.ai import: names that aren't UTF-8 can be read in a legacy code page
2026-11-09 12:46:30 +08:00
BFlat 6ced5794ee Merge pull request #6016 from mockydevs/feat/ai-import-stacked-fills
EPS/.ai editing data: paths keep art styles of several fills and strokes live
2026-11-09 12:13:08 +08:00
dotCooCoo 3258785476 Merge main into fix/ai-os23-2831 2026-11-08 19:44:24 -08:00
BFlat 8eb3d4166a Merge pull request #2552 from dotCooCoo/feat/print-copies-per-sheet
Print: Copies per Sheet prints as many copies of each artboard as fit the sheet
2026-11-09 11:17:48 +08:00
Don Omondi d15f7fbfba Merge remote-tracking branch 'upstream/main' into feat/ai-import-stacked-fills 2026-11-08 22:02:57 -05:00
dotCooCoo d3a323284c Merge main into fix/ai-os23-2831 2026-11-08 18:52:59 -08:00
BFlat c5c1913f48 Merge pull request #6265 from dotCooCoo/feat/plugin-effect-paint
Plug-ins: live effects at API level 2 can paint the pieces they return
2026-11-09 10:50:46 +08:00
Don Omondi 8c8d88e286 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-08 21:08:47 -05:00
BFlat 04aedc87e5 Merge pull request #6268 from dotCooCoo/fix/freeform-mixes-in-point-model
Gradients: freeform points that share a color model mix in that model
2026-11-09 10:08:22 +08:00
dotCooCoo ec3f0a2288 Merge main into feat/plugin-effect-paint 2026-11-08 17:59:42 -08:00
dotCooCoo bd5ea2a1bf Merge main into feat/plugin-effect-paint 2026-11-08 17:59:33 -08:00
BFlat 196a6e815c Merge pull request #6007 from mockydevs/fix/ai-import-brushes
.ai import: Art brushes in the older form of their objects come into the Brushes panel
2026-11-09 09:47:00 +08:00
BFlat 9ddcd40098 Merge pull request #6220 from dotCooCoo/fix/ai-writer-object-limit-2
.ai save: the editing copy stops at the reader's object limit
2026-11-09 09:28:24 +08:00
dotCooCoo d6a91b6142 Merge main into feat/plugin-effect-paint 2026-11-08 17:26:35 -08:00
dotCooCoo b1236c469b Print: Copies per Sheet prints as many copies of each artboard as fit the sheet
File › Print printed each artboard on a sheet of its own. A 2 × 3.5 in
card on Letter printed once in the middle of the page, and Print had no
option to fill the sheet with copies.

The Print dialog's General section has Copies per Sheet (off by
default) and a Gutter. With it on, a sheet holds as many copies of the
artboard as fit the imageable area, each with its bleed and marks,
across then down, gutter pt apart. The card prints 4 × 3 on Letter,
and 3 × 3 with an 18 pt gutter. The copies are not turned, and the
placement places the whole grid as it places one copy. An artboard
that does not fit prints one copy per sheet with a warning, and more
than 1,000 copies on a sheet is an error. Tiling leaves the option
out. The PDF and PostScript writers draw the art and the marks once
per copy, the PDF TrimBox holds every copy, the preview draws each
copy, and print.preview lists them as `copies`. With the option off,
the layout lists no copies and the writers draw the page as before.

Docs: docs/mcp.md (Print, Printing), docs/target-app-parity.md.
2026-11-08 17:22:46 -08:00
dotCooCoo ac0bb3c4ce Gradients: freeform points that share a color model mix in that model
The canvas, the gradient chips and the SVG, PDF, EPS and EMF writers mixed
freeform points in display RGB, while Object > Expand and Create Gradient
Mesh mixed them in the model the points share. Points that are all CMYK,
Gray, Lab or RGB now mix in that model in those places too. Points in
different models mix as before: in display RGB, and on ink planes as the
inks of each point.

This changes how existing art looks:

- CMYK and Lab points. With the default Generic CMYK working space and no
  ink planes, halfway between C100 and K100 the canvas drew (17, 106, 139)
  and now draws (54, 118, 143).
- RGB points in a working RGB space other than sRGB mix in that space.
- On ink planes (a CMYK document that shows transparency), RGB and Lab
  points mix first and then separate.

Gray mixes keep their values, and CMYK and Gray points on ink planes draw
as before. RGB points in an sRGB working space draw as before except on
ink planes.

- PDF and EPS write a gradient whose points are all CMYK, or all Gray in a
  CMYK file, as a CMYK image. PDF's Output settings convert it as they
  convert any CMYK image.
- Darkening applies to the points before they mix.
- With Appearance of Black set to Rich, the canvas mixes a gradient with a
  pure CMYK black point in display RGB, and the point fades from RGB black.
2026-11-08 17:18:43 -08:00
BFlat 44a37b0729 Merge pull request #6233 from dotCooCoo/fix/fitted-gradient-turns-with-transform
Effects: fitted gradients turn with the Transform effect
2026-11-09 08:58:30 +08:00
dotCooCoo 68cd7f63c2 Merge main into fix/ai-writer-object-limit-2 2026-11-08 16:47:31 -08:00
Don Omondi 499a78b0bf Merge remote-tracking branch 'upstream/main' into fix/ai-import-brushes
# Conflicts:
#	docs/file-format-parity.md
#	docs/target-app-parity.md
2026-11-08 19:21:57 -05:00
BFlat 7724463e00 Merge pull request #5991 from mockydevs/fix/eps01-editing-overlay
EPS import: gradients drawn as abutting strips come in as one gradient, without seams
2026-11-09 07:57:02 +08:00
dotCooCoo e2bac253f1 Merge main into fix/fitted-gradient-turns-with-transform 2026-11-08 15:56:12 -08:00
BFlat 22f5ede66f Merge pull request #6161 from dotCooCoo/feat/ai-editing-data-s6b2
.ai save: the editing copy keeps graphic styles and links to them
2026-11-09 07:52:12 +08:00
BFlat 7adc2f66a3 Merge pull request #6109 from dotCooCoo/feat/ai-symbol-libraries
.ai import: symbol libraries open with their symbols
2026-11-09 07:47:36 +08:00
dotCooCoo 83f1333d1c Effects: a Transform effect that flattens the object leaves a fitted gradient fitted with its options on
With Scale Strokes & Effects or Transform Patterns on, the path and each copy are moved by Node::transform, which fixed a fitted gradient to its fit before a scale of 0 flattened it to one color. Scaling::keep_fit_when_flat keeps the gradient fitted under a map that flattens the object (node::flattens, the gate fixes_fit already used), and the Transform effect's path transforms set it.

docs/target-app-parity.md also says that the Gradient tool still shows a fitted gradient's vector at its unturned fit.
2026-11-08 15:38:07 -08:00
Don Omondi abeb7e3167 Merge remote-tracking branch 'upstream/main' into fix/ai-import-brushes
# Conflicts:
#	docs/file-format-parity.md
#	docs/target-app-parity.md
2026-11-08 18:18:16 -05:00
dotCooCoo 48fe46be1f Tests: .ai object limit tests check the symbol's limit and derive the mask's
The symbol test now requires a warning and at most the given number of
objects at every limit below what the reader reads. The mask test takes
its limits from the objects the reader reads and finds where the mask
first fits.
2026-11-08 15:04:51 -08:00
dotCooCoo 230fbb96a3 Merge main into feat/ai-editing-data-s6b2 2026-11-08 15:00:10 -08:00
dotCooCoo b8ab981058 Merge main into feat/ai-symbol-libraries 2026-11-08 14:56:51 -08:00
dotCooCoo e32212326a Merge main into fix/ai-writer-object-limit-2 2026-11-08 14:52:07 -08:00
Don Omondi 8383b2af6d Merge remote-tracking branch 'upstream/main' into fix/eps01-editing-overlay
# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
2026-11-08 17:39:34 -05:00
dotCooCoo 1940d3e529 .ai import: opacity mask art in pattern and brush art takes document ids
A pattern's or a brush's art was copied into the document with new ids,
but the art of an opacity mask inside it kept the ids of the reader that
read the definition. Those ids could repeat ids of objects in the
layers. The mask art now takes document ids, as a symbol's art already
does.
2026-11-08 14:06:24 -08:00
dotCooCoo 11703bd350 Merge main into feat/plugin-effect-paint 2026-11-08 12:56:42 -08:00
dotCooCoo c539c04625 Merge main into feat/plugin-effect-paint 2026-11-08 12:23:39 -08:00
dotCooCoo 11f1d228de Type: Align to Path moves each character by its own font's metrics
Align to Path moved the whole line by the largest ascent and descent
among its characters. Each character now moves by its own font, size
and vertical scale. Ascender runs the top of the font's em box along
the path: the ideographic em box that the font's BASE table gives, or
in a Chinese, Japanese or Korean font the one that its typographic or
hhea box, a one-em box-drawing cross or its ideographs give; else an
em box centered on the cap height. Descender runs the bottom of the font's
bounding box along the path, and Center runs a line at half the height
of the top of the font's H along it. In vertical type, Ascender and
Descender move the characters half an em, and Center leaves them on
the path.

Existing documents with Align to Path set to Ascender, Descender or
Center lay their type out at a new distance from the path.
2026-11-09 03:14:41 +07:00
dotCooCoo c94269ff72 Type: Composite Fonts… sets each class of character in a font of its own
Squashed from #6244 onto main.
2026-11-09 03:08:23 +07:00
dotCooCoo b5adb679e4 .ai import: images past 2^25 pixels in the editing data keep the layers
Squashed from #5143 onto main.
2026-11-09 02:43:13 +07:00
dotCooCoo 81c5b047bc Merge main into feat/plugin-effect-paint 2026-11-08 11:36:48 -08:00
Don Omondi 21e6464e6f EPS import: scaling a named descendant counts its dictionary's size; test Type 3 descendants and that unreadable Type 42 data is read once 2026-11-09 02:24:54 +07:00
Don Omondi 70353f003e EPS import: reading sfnts data is charged before the copy, whatever its result
Joining a Type 42 font's strings is charged per byte (as other bulk
copies are) before it runs, so data that turns out unreadable, read
again after leaving the cache, no longer copies for free.
2026-11-09 02:24:54 +07:00
Don Omondi e61f0940d0 EPS import: composite fonts' Type 42 review fixes
widthshow matches a composite character by font number times 256 plus
its code; measuring Type 42 glyphs counts against the operation budget;
the Type 42 data cache keeps the least recently used order, remembers
fonts whose data can't be read and counts each font's data against the
memory budget once; composite font arrays are borrowed, not copied.
2026-11-09 02:24:54 +07:00
Don Omondi 3bb43b2fe6 EPS import: composite fonts draw their Type 42 descendants' glyphs
A composite (Type 0) font with the 8/8 mapping picks a descendant font
and a code in it with each pair of bytes (PLRM 3rd ed., 5.10). The reader
set its strings as type in a font of the composite font's name, the
bytes read as Latin-1 and at a thousand times the size, so EPS from
pdftops of a PDF with embedded TrueType fonts showed nothing, or one
black shape, where its type was.

Characters now go to their descendants: a Type 42 font's glyphs are drawn
from the TrueType outlines its sfnts strings carry (Adobe Technical Note
5012), by the glyph index CharStrings gives their names, spaced by their
own widths or the show operator's numbers; charpath and stringwidth read
them too. A Type 3 descendant runs its procedures, and a descendant found
by name sets its character as type at the composite font's size.
2026-11-09 02:24:54 +07:00
el-j d499fb25da Fix #6205: support Registration and named swatches in AI art styles
Resolve missing Registration (Xs, XS, Xz, XZ) and named color (Xx, XX)
operators in AI ArtStyle filter definitions so objects styled with
Registration swatches correctly resolve their paint instead of falling
back to the previously set graphics state color.

Also exclude Registration paints from color-model inference when read via
Xx/XX, and correctly extract tint (penultimate operand) for name-free Xz.
2026-11-09 02:03:09 +07:00
M Balazs PC 7f7c4cf9ad .ai import: test every paint mask art takes, and that it stays in the mask
The mask test now checks the whole fill and stroke (colour, overprint,
width, cap, join, miter, dash) and the fill rule against the owner's,
and that an object after the mask's dictionary paints with the owner's
paint, not the paint the mask's art set. open_mask_object gets a doc
comment.
2026-11-09 02:03:02 +07:00
M Balazs PC 500ff6ed4c .ai import: opacity mask art without its own paint takes the paint before its dictionary
A dictionary's state starts afresh, with a black fill. Mask art is written
going on from the paint before the mask's dictionary, which the writer leaves
out when it doesn't change, so a mask rectangle with no colour of its own
came in black and hid the white letters it masks. Mask art now starts from
the paint (fill, stroke, line style, fill rule, overprint) before the
dictionaries it is in; lock, visibility and transparency still start afresh.
2026-11-09 02:03:02 +07:00
Don Omondi d4f6fa0744 EPS/.ai editing data: art-style strokes aligned inside or outside keep their alignment
Squashed from #6010 onto main.
2026-11-09 02:03:01 +07:00
NetterSilverandClaude Opus 5.5 05a242ff77 Scale the EPS operation budget with the program's length
Fixes #5363

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 02:03:00 +07:00
dotCooCoo 64817c2e8c Merge main into feat/plugin-effect-paint 2026-11-08 10:46:47 -08:00
dotCooCoo fb848d28ac .ai import: objects in pattern and brush art take the file's art styles
A pattern's definition (in either form) and a brush's art were read
without the file's art styles, so an object there with a style came in
as the look it draws, with a "drawn look" note, while the same object on
a layer or in a symbol came in as itself with its effects live. The
three definition readers now take the art styles as the symbol reader
does, and an object in a pattern's art with a style in the file's style
list keeps that graphic style's id.

An art styles section inside a symbol's, a pattern's or a brush's art
is now skipped, so it no longer replaces the file's own art styles.
2026-11-09 00:36:09 +07:00
dotCooCoo 7b06cc070b .ai save: the editing copy keeps Standard Vertical Roman Alignment
The editing-data writer wrote a run's key 35 only for Tate-chu-yoko (3).
Type with Standard Vertical Roman Alignment, on or off, was saved with no
key, so the setting was lost from the editing data. Every run now carries
key 35 in the form the reader reads it (crates/eps/src/import/ate.rs,
Texts::style, lines 669-670): 1 when the setting is on, 2 when it is off
and 3 for Tate-chu-yoko. The document's defaults and the normal character
style carry 1.

Key 35 holds one value, so a run with both Tate-chu-yoko and the setting
is written as Tate-chu-yoko, and the save reports the type attributes
warning for it.

- writer/texts.rs: baseline_direction() gives each run's value;
  normal_char() writes 1; loses() and TYPE_ATTRIBUTES name the setting.
- tests.rs: a vertical and a horizontal object with the setting on, off
  and Tate-chu-yoko come back the same through the reader, lay out as
  before, and carry the expected keys; a run with both is reported.
- docs/file-format-parity.md: the .ai save section lists the written
  values.
2026-11-09 00:35:51 +07:00
dotCooCoo cae5b356c7 .ai import: a palette gradient swatch's paint is not linked to itself
The editing-data reader set the paint of each gradient swatch in the
palette to link to the swatch's own name. The default gradient swatches
and a gradient swatch given a new gradient with swatch.edit hold their
gradient without a link, so a document saved as .ai and opened again
had swatches that differed from the ones it was saved with. The swatch
now holds the gradient alone. Art filled with the gradient is not
changed: it still links to a swatch by the gradient's name.

The fix also applies to a .ai whose layers are not read, such as a
gradient library, where only the palette comes in.

Three tests cover a hand-written palette with a gradient swatch named
by its gradient and one with a name of its own, a new document's four
gradient swatches written by the editing-data writer and read back, and
a gradient library without layers.
2026-11-09 00:35:12 +07:00