A photo's noise is as large as the step from one palette colour to the next, so noise decided pixel by pixel
which of two neighbouring colours a pixel got: tens of thousands of specks, or (since the palette change)
neighbouring tones merged into one.
- A continuous-tone image (eight colours leave much of it unsaid; flat art, however noisy or unevenly lit, is
not one) is smoothed before it is quantised: three rounds of a small bilateral filter, which averages noise
away within a tone and keeps the edges between tones where and as sharp as they were.
- With Method: Overlapping, layers are stacked by lightness, from the largest colour's end of the scale,
instead of by area. Each layer reaches under those above it, so where two colours meet every layer between
them in the stack ends on that same edge and shows through its anti-aliasing: by area that was an unrelated
colour's hairline around every region; by lightness it is a neighbouring tone.
- Ignore White with Overlapping: no layer reaches under the white that is left out.
On each preset's own inputs, all sizes and variants (docs/image-trace-quality.md), before -> after:
- High Fidelity Photo: colour error 2.37 -> 1.75 (2.30 at the baseline), edge error 2.59 -> 1.98, 639 -> 121
paths (3,653 at the baseline), 25,604 -> 9,818 anchors, specks 152 -> 10; a 16 megapixel photo-like image is
traced in 3.5 s (31,131 paths) where it was refused
- Low Fidelity Photo: colour error 2.67 -> 2.45, 55 -> 37 paths
- Shades of Gray: 73 -> 17 paths, colour error 9.33 -> 9.26
- The other presets' numbers are unchanged
The theme's widget fill matches the dialog background, so the sliders of
Save for Web, the raster export options, Preferences and the opacity
popup showed only their handle. They share one slider widget now, with a
visible rail filled up to the handle.
In Outline view a template layer drew as outlines like any other, so a
picture placed to be traced turned into a box. It now keeps drawing in
Preview (dimmed as before) while the other layers are in outline.
Color and Grayscale chose their colours from every pixel, so the blends along anti-aliased edges took palette
entries and traced as slivers, and with more colours asked for than the art has, k-means split flat colours
along their noise and the halves traced as specks all over each other.
- The palette is made from the picture's own colours: a pixel that lies between the pixels on opposite sides
of it is a blend and counts for nothing (lines one pixel wide and noise are no blends).
- Colours that noise made of one colour merge: close colours whose pixels are mixed through each other. The
bands of a gradient keep to themselves and stay apart.
- A blend pixel whose nearest palette colour is a third colour (halfway from navy to yellow lies an olive that
is nearer to a green elsewhere) goes to the nearer of the two colours it lies between.
- Boxes are cut where their two sides differ most (Otsu's criterion) instead of at the median, which split the
largest colour of flat art along its noise and left two smaller colours in one box.
- Colours are compared in Oklab when pixels are assigned and in k-means.
On each preset's own inputs, all sizes and variants (docs/image-trace-quality.md), before -> after:
- 16 Colors: 69.9 -> 4.2 paths, 1743 -> 66 anchors, outlines 5.08 -> 0.13 px off on average (largest 85.9 ->
1.09), kinks 1376 -> 4.4, paths in a colour the art doesn't have 5.9 -> 0
- 6 Colors: 21.2 -> 4.0 paths, 4.44 -> 0.14 px off; 3 Colors: colour error 4.86 -> 0.43, 0.33 -> 0.09 px off
- High Fidelity Photo: 3636 -> 639 paths, 81,597 -> 25,604 anchors, colour error 2.50 -> 2.37; a 1 megapixel
photo-like image 1.98 -> 0.42 s (51,389 -> 4,298 paths), a 4 megapixel one traced (27,583 paths) where it was
refused
- Low Fidelity Photo: 128 -> 55 paths, colour error 2.59 -> 2.67; Shades of Gray: 91 -> 73 paths, 9.29 -> 9.33
text.create, text.createInPath, text.setText and text.setStyle answer with
overflow: [id…] for the area type and type on a path whose text doesn't fit (left
out when all fits), and MCP add_text with overflow: true. add_text takes area
type's fit and fitMinPercent.
A point outside the grid can be nearer an edge further along the grid's side than one
straight ahead of it; the search stopped a ring early there. The bucket lookup is one
function.
Selected text in a numeric or text field was drawn in the accent colour on the accent-tinted
selection, in every brightness. The fields that draw their own frame (panel and Control bar fields,
dialog fields, the hex field) now draw it in the strong text colour.
File > Place, Relink and Open refused a grayscale TIFF whose pixels carry an alpha channel or
another extra channel: the image decoder reads neither. They are now read like CMYK TIFFs with
alpha: the first extra sample is the transparency when the file says it is alpha (associated alpha
divided back out), and other channels are left out.
Object > Path > Split Into Grid took a number of rows and columns and one gutter, and split each
selected path on its own. The dialog now has the documented options, the rows beside the columns:
number, height or width, gutter and total, with Add Guides and Preview. Several selected paths
become one grid over them all, painted as the topmost one, as documented.
object.path.splitIntoGrid takes rowGutter and columnGutter (gutter still sets both), totalHeight
and totalWidth, height and width (the size of each row and column, which sets the total) and
addGuides, which adds ruler guides along the row and column edges on the grid's layer.
Behaviour reference:
https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/divide-or-split-objects.html
Each crack between an inside and an outside pixel is moved to where the pixels across it say the edge is (the
blend of the two tones in the column of pixels across the crack; a thin line by the centroid and sum of its
tone; hard-edged images are read as staircases), and the outline is fitted as Flat Logo mode fits its own:
corners put back, straight runs as lines, a round outline as a circle, the rest as few curves as Paths allows.
Snap Curves To Lines straightens slightly curved runs and makes arcs. A fit that strays from its outline
gives way to a plainer one, and at last to the outline's own points.
On each preset's own inputs, all sizes and variants (docs/image-trace-quality.md):
- Default: outlines 0.313 -> 0.091 px off on average, largest 1.51 -> 1.02; edge error 17.2 -> 10.1;
gaps between abutting paths 63.5 -> 22.2 px, overlaps 67.0 -> 22.4 px
- Black and White Logo: 0.270 -> 0.064 px off, kinks 15.3 -> 0.3, anchors 3.78 -> 2.73 times the art's
- Technical Drawing: 0.201 -> 0.086 px off; Line Art: 0.158 -> 0.093
- Worse: anchors on blurred and scanned thin lines (Line Art 25 -> 77 on average), High Fidelity Photo
(colour error 2.30 -> 2.50, anchors 46,866 -> 81,597, 1 megapixel photo-like image 0.37 -> 1.98 s)
Bevel Shape, Space, Bevel Inside, Bevel both sides and Presets, as the public 3D and Materials panel
options page names them. The 3D effects' error messages get rows in the twelve complete catalogs.
crates/trace/tests/quality draws its inputs from known vector art (no image files), traces them with every
built-in preset and measures fidelity, distance from the true outlines, economy, artefacts, time and memory.
docs/image-trace-quality.md records the numbers on main before any change, beside the same measures of an
open tracer run as a black box. No change to the tracer.
The check added for #1396 dropped the inner contour only when the path itself fell in the hole, which takes a stroke more than twice as wide as the shape. Between one and two times the size (a 30 pt ellipse with a 50 pt stroke), and on rectangles with round or bevel joins, the hole stayed.
An offset contour is now left out when no point of it lies half the weight from its subpath: it is then nowhere the edge of the stroke. Subpaths are judged one by one, and only when the stroke is at least as wide as the subpath's bounds, so ordinary strokes take the same single call as before.
Area type whose frame is too short for a line of the font it shows in here
drew nothing: a font that isn't available shows in the fallback font, whose
line may be taller than a frame made for one line of the file's font (overset
type isn't drawn). Where the file itself lays lines out in the frame, the
frame of the imported text object is made taller, from its top, by what its
first line needs, and the open result says how many frames were.
- The type in a text object's drawn look (1 /FreeUndo) is a story of the
undo-free text document, which counts its stories on its own. It was read
as the story of that number in the text document, so a label could show
another object's text in another object's frame. The object itself, which
follows the look, is the type now.
- The page's type of a text object on a hidden layer stays with that object
(hidden) instead of going to the nearest text object that shows.
- The type on the page of a later artboard is matched where the layers have
that artboard, not by the first page's place.
The editing data places a gradient with matrices after Bg: Xm for a linear
gradient's whole ramp and one Bm for each pair of stops next to each other.
The reader kept the last Bm, so a gradient of three stops drew only its last
part. It now uses Xm (or, without one, the span of the Bm's from the first
stop to the last), and a radial gradient's one Bm as before. The angle and
length are in the matrices, so Bg's own numbers are used only without them.
An object's own note of its gradient after it (Bb, Bg, BB with no path) no
longer becomes the fill of the next path.
A dialog opened by a click is drawn in the frame of that click, and in that
frame egui takes the focus from any field the click missed. The first time a
dialog's window shows, that frame only measures it, so its first field took
the focus a frame later and kept it; every later time the field took it in
the click's frame and lost it at once. The field now takes it the frame after
the click.
A .ai file with placed files opened from its PDF part (no guides, no sublayers,
no hidden objects), because the editing-data reader stopped at them.
- Lexer: a placed file's preview section is one token (it was skipped).
- Reader: %AI5_BeginPlace ... ~ becomes a linked image with the file's path,
showing the preview the data keeps of it (premultiplied ARGB, capped at
MAX_PIXELS, its rows checked against the bytes there), in its place: the
matrix takes the file's pixels from the canvas, where they start at the point
of art space's origin. A placed file without a preview, a path or a matrix
still makes the file open from its PDF part.
- The open result lists one warning saying linked pictures show the
low-resolution preview until their files are found (rows in the catalogs).
- Engine: a link nothing is known of whose image shows a preview is read where
it is found as the document opens, into the image's bounds, and isn't
reported as modified.
- Tests: lexer, reader (hand-written data), engine open with the link missing
and found, fuzz tokens.
- Docs: file-format-parity, target-app-parity, gaps, ROADMAP.