dataset.import replaced the reason for a refused cell with "value for
`X` must match its variable kind", so a visibility value such as
maybe and a graph value over 262,144 bytes gave the same message. The
error now keeps the line and gives the reason, and both messages have
a row in every complete-message catalog.
dataset.export checked only the 1 MiB size, so a document with more than
1000 data sets or 256 variables exported a CSV that dataset.import then
refused. Export now refuses such a document with a message naming the
limit, and the messages have rows in every complete-message catalog.
Undo, Redo and a canceled undo group put back an earlier document but
left the Variables panel highlight as it was. After renaming the
highlighted variable and undoing, the highlight still named the new
name: a variable defined later under that name showed highlighted
without a click, and Delete removed it.
Each of these paths now clears a highlight whose variable the restored
document does not define, as Delete Variables and Load Variable Library
already did.
The legacy type helpers and tests move from the end of crates/eps/src/import/ai/tests.rs to after text_objects_are_slots_named_after_their_story, and the helper stream7 is renamed type_stream7.
Legacy type (`To` ... `TO`) now reads `min opt max TC` and `min opt max TW`
into the paragraph's letter and word spacing, `hangingQuotes Tq` into Roman
hanging punctuation, and `hyphenate limit lead tail max Th` into hyphenation
on or off, After First, Before Last and the Hyphen Limit (0 when the limit
flag is 0). Values are kept to the ranges the Justification and Hyphenation
options take, and a spacing triple out of order goes back to its default.
Operands of the legacy type attributes are read by their place: an attribute
whose operands are missing, are not numbers, or are flags other than 0 and 1
stays as it was. Before, a value that was not a number shifted the later
operands (`5 /x 7 Ti` set indents of 5, 7 and 0), and a bad `TA` or `Ta`
turned kerning on or set the alignment to left. One long `Tx` no longer goes
past the reader's limit on characters.
A clipping path painted with a stroke (`W S`, `W B`) lost the stroke when
a .ai file opened from its editing data. The clipping path now keeps it,
and it paints over the clipped art as a clipping path's stroke does in
VectorCraft. A gradient-filled clipping path stroked with `1 BB` or `2 BB`
put the stroke on the painted copy of its fill, under the clipped art; it
now goes on the clipping path too. Several clipping paths in one group
make one compound path, which keeps their stroke, opacity and blend mode
when they all have the same ones.
View > Outline was one app-wide flag saved in the interface preferences,
so after Cmd+Y every later launch drew every opened or new document as
outlines, with no fills. The flag is now part of each document's view:
a document opens in Preview, each tab shows its own Outline or Preview,
and the setting is not saved at launch. An older preferences file that
holds the flag still loads, and its value is ignored.
The Outline command and ui.set's outline act on the active document and
are an error without one.
A row's empty text value fills its field with nothing, the same as a row without a value
for that variable, and OK left every empty field out of dataset.set. An untouched OK
therefore removed the empty value, and selecting the row afterward left the previous row's
text on the art.
Edit Data Set now marks the fields that hold the row's empty text value and keeps those
values on OK. Typing in such a field, or setting it with ui.dialog.set, removes the mark, so
emptying it still unsets the variable.
* Native format: the .vectorcraft envelope comes from craft-vectorcraft-format
vectorcraft-format reads and writes the file's envelope through the
craft-vectorcraft-format crate in craft-libs: Head and Image, the version
and size constants, the format and version check, Tail for the data after
the JSON, split_tail and entry, and base64. The constants, is_compressed,
json_part, base64_encode and base64_decode are re-exported from
vectorcraft_format, so callers do not change. load_file reads the members
it uses with Image entries and skips the preview and PDF data. The
document, its migrations, the version 1 writer, gzip writing, sniff and
the limits on decompression stay here.
A preview or pdf member of the wrong shape now reads as missing on its
own, so pdf_content still returns a file's PDF when its preview is
damaged.
A new test saves a document in every version, compressed and pretty,
with a preview, profiles and a PDF, reads it back, saves it again and
compares the bytes; it also reads each uncompressed file as the crate's
File. Another reads the PDF of a file whose preview is damaged.
* Native format: sniff from craft-vectorcraft-format, pinned at #408's head
- craft-vectorcraft-format moves to craft-libs 0fd7e75fe6, the head of
storytold/craft-libs#408.
- `sniff` is the crate's: a file is native when its top-level `format`
member, within the first 256 bytes after decompression, is
`vectorcraft` or `drawcraft`, read with JSON escapes decoded. The word
elsewhere in the head no longer counts. All 192 corpus files and
their resaved copies get the same answer as before.
- Envelope errors other than the format and the version keep the
crate's message instead of reading as a compressed file that unpacks
to too much.
- A test checks that a repeated `generator`, `preview` or `pdf` opens
and any other repeated member is refused, by `load_file` and by the
crate's `Contents` alike.
* Native format: read through the crate's Contents and Entries
Pins craft-vectorcraft-format at 420a27f18f, the current head of
craft-libs#408, and replaces VectorCraft's own copies with the crate's:
- load_file reads the JSON through Contents::read, which also refuses
another format or a newer version. Opened is removed. Messages are
those of main: serde names the struct File, as main's reader did.
- In-memory data after the JSON (uncompressed files, and compressed
files unpacked whole) is read through the crate's Entries.
entries_within keeps its streaming reader for compressed files, whose
data is unpacked entry by entry and is never one slice in memory.
- The streaming reader finds the marker through the crate's marker_at.
- MAX_BLOB is the crate's MAX_ENTRY (1 GiB).
save_to still writes the envelope member by member: it streams the
document into the output and looks for the images it uses as it
writes, and File would need the images before the document. A new test
checks that its output, compact, pretty and compressed, for versions 1
to 4, equals serde_json::to_vec or to_vec_pretty of the crate's File
holding the same members followed by the crate's Tail, so a change to
either side fails.
* Native format: pin craft-vectorcraft-format at craft-libs main
craft-libs#408 merged as 14d5dbb50c; the crate is unchanged from
420a27f18f. A test checks that the crate's sniff takes every layout
VectorCraft has written: the version 1 and 2 files from before the
rename, compact and pretty, and each version save_with writes.
A curve rejected for having more than 256 segments now counts the most points a curve may have against the document's pressure points, so linking it from many strokes reads it a bounded number of times. Once the points are used up, later strokes import as plain strokes with a warning.
A version 7 text object has no arbitrary-angle character rotation: its
character attributes include baseline shift (Ts), scaling (Tz) and
tracking (Tt), Tv only turns Roman characters 90 degrees in vertical
text, and the positioning operators such as Tm are ignored on reading.
Type with Character Rotation was written as editable text with the
rotation left out, so rotated characters opened upright.
Such type is now written as its glyphs' outlines, the way type 8-bit text
can't hold already is, with the warning "type with rotated characters is
written as outlines, which keep the rotation, and is no longer editable
text". The outlines keep each character's rotation, baseline shift and
scale. Type without rotated characters, and type turned a whole number of
times, is still written as text.
Docs: docs/file-format-parity.md, docs/mcp.md, docs/target-app-parity.md.
A Separation space whose colorant is named All paints every plate, and
one named None paints nothing (ISO 32000-1:2008, 8.6.6.4). EPS export
wrote a spot swatch's name as its colorant, so a spot color named All
printed on every plate and one named None did not print.
Such an ink is now written as All Spot or None Spot, numbered All Spot 2
and on when a spot swatch already has that name, in its Separation
space, DeviceN spaces and the %%DocumentCustomColors and
%%CMYKCustomColor comments. At PostScript Level 3, a gradient that mixes
one of these inks with another spot ink or with process or gray stops is
now a DeviceN shading instead of process colors. Registration still
writes All.
A gradient of one spot ink's tints and paper white is written as a
Separation shading in that ink, with each white stop at 0% of it. A
white stop linked to a swatch that is not a spot color (a global White
swatch, for example) did not count as paper white. In an RGB document
the spot ink was then dropped: a Classic gradient was written in the
stops' own colors, and a Perceptual one was exported as an image in
process colors.
Such a stop now counts as paper white in the Separation and DeviceN
paths and in the checks that pick them, as an unlinked white stop does.
A stop linked to a white spot color is still a stop of that ink.
An override on a dynamic symbol instance names an object of its symbol's
art by path. Replace Symbol kept every override whose path the new
symbol's art also had, so a change made to one object of the old symbol
was applied to an unrelated object of the new one. An instance given a
different symbol now drops its overrides; an instance replaced with its
own symbol keeps them. Undo brings them back.
- Each segment of a pressure curve is also sampled where its width stops
rising or falling, so a dip between the regular samples of a long
curve is kept. The segment's values are scaled into -1..1 before that
is solved, so huge values in a file can't overflow it.
- A curve counts as full width only within 1e-9 of it, so a curve just
under full width keeps its profile.
- The pressure points of all strokes in one read are limited to about a
million, as for characters and table cells. Curves at full width count
too, and once the limit is reached no more curves are read; the
strokes past it are imported as plain strokes with a warning.
The test for #3818 checked the tool tip's text color and the style's
window fill. It now also checks the fill of the box drawn behind the tool
tip's text, and that the text and the box have a contrast ratio of at
least 4.5, for every brightness and scheme.
The Spiral tool places its anchors on a logarithmic spiral, with the
radius shrinking by the decay each quarter turn, but gave every handle
the direction of a circle's tangent and a length from an averaged
radius. The curve bulged off the spiral between anchors and turned at
each anchor, so the spiral looked squared: up to 2.8% off its radius at
the default 80% decay and 23% at 30%.
The handles now follow the spiral's own tangent, with lengths that
differ at each segment's outer and inner end. The curve stays within
0.03% of the spiral at 80% decay and 0.8% at 20%. Anchor positions and
counts are unchanged.
An Affinity stroke shaped with the Width tool stores its pressure curve
(LDeP: position along the path against width). The importer warned and
drew the stroke at full width all along.
- The pressure curve is read and sampled into the stroke's width
profile (2 to 8 points per segment, 256 segments at most, widths up
to the full weight). A curve at full width all along stays a plain
stroke; one that can't be read is warned about.
- Brush strokes keep their own warning.
- The pinned Affinity 3 signatures for the five corpus files with such
strokes are updated.
The theme's colors went into egui's style for the current system theme
only. When the system's light or dark setting differed from it or
changed while the app ran, egui switched to its other style, which held
egui's defaults: tool tips became a white box with gray text, or with
the theme's light text. Applying a brightness now sets egui's theme to
match, starting from the current style so settings such as the tool tip
delay carry over.
Dropping rows with neither a label nor a value read the data padded to
the widest row, so a dropped row wider than the rest (`,,`) left every
kept row one blank cell wider. The graph then had an extra blank series,
and a right-axis assignment to that index was kept. Each kept row now
keeps its own width. This applies to graph.setData and to a graph
variable's data set.
With the clipping path of a clip group or a clipping layer selected, or a
member of a compound path that is the clipping path, Paste in Back put the
clipboard's objects below it. The bottom pasted object then became the
clipping path. With nothing selected in a clipping layer, Paste in Back did
the same at the bottom of the layer.
Paste in Back now puts the objects right above the clipping path, as Send to
Back keeps art above it.