Commit Graph
117 Commits
Author SHA1 Message Date
dotCooCoo 093f04952c Image Trace: Create Strokes makes a wide shape's thin features strokes and keeps its body a fill
Stroke is the widest feature that can be stroked, and it was applied to
each connected shape as a whole: a thick body with thin arms stayed one
filled area. Now a shape wider than Stroke somewhere keeps as its area
every disc wider than Stroke that fits in it, and each piece outside
those discs that reaches out of them at least one and a half times its
own width (and 3 px) is traced as a stroked center line. A line's end at
the area goes to the cut, so the line's cap closes the join. Corners and
edge slivers stay in the area, and a piece that cannot be traced stays
in it too. Shapes no wider than Stroke trace as before.

Each line keeps one width; without Fills, the area is still a 1 px
outline.

Docs: docs/target-app-parity.md.
2026-11-13 01:01:59 -08:00
dotCooCoo ac76040014 Merge main into feat/outline-object-image-alpha 2026-11-12 20:16:33 -08:00
BFlat 321aa13251 Merge pull request #6962 from dotCooCoo/fix/trace-tinted-photos
Image Trace: sepia, single-hue and duotone photos are smoothed as gray photos are
2026-11-13 04:25:36 +07:00
dotCooCoo 950494802e Merge main into feat/outline-object-image-alpha
# Conflicts:
#	crates/effects/src/tests.rs
2026-11-12 12:45:45 -08:00
BFlat 28d97a82a8 Merge pull request #6954 from dotCooCoo/fix/trace-logo-flatness-own-colors
Image Trace: Flat Logo judges flat art by the image's own colors
2026-11-13 03:27:17 +07:00
dotCooCoo eee6fb51fd Image Trace: sepia, single-hue and duotone photos are smoothed as gray photos are
Color and Grayscale traces smoothed a gray photo before choosing its
colors, but a tinted photo with the same tones skipped smoothing: the
0.065 error rule applied only to pictures whose channels stay within 8
levels of each other. A picture whose opaque pixels lie, 19 in 20, within
6 levels of one tone curve now takes the same rule. The curve runs
through the median color of each 8-level stretch along the colors' main
direction, and a pixel on it must also lie within 6 levels of the plane
the colors spread along most, so art in several unrelated colors is not
counted. The sixteen-versus-eight exception still keeps clean flat art
on the flat-art route.
2026-11-12 11:39:53 -08:00
dotCooCoo 74e61c9b74 Image Trace: Flat Logo judges flat art by the image's own colors
With logoColors named, Flat Logo measured how flat the image is against
the named colors. A solid pixel counts as flat only within 22 (RGB
distance) of one of those colors or white. Flat art whose named colors
were 20 levels off in every channel was refused as not flat, and the
refusal score of a gradient changed with the names.

The check now uses the image's own colors, found the same way as when
no colors are named. It looks for as many colors as are named, with
white, or as the Colors setting gives, whichever is more. How far the named colors are
from the image's colors no longer changes whether the image is refused.

This changes one existing behavior: an image with large areas of a
color that was not named used to be refused, and it is now traced in
the named colors.

Docs: docs/image-trace-adjustments.md, docs/target-app-parity.md, the
imageTrace.make params text.
2026-11-12 10:48:20 -08:00
dotCooCoo f4e1db029e Merge main into feat/outline-object-image-alpha 2026-11-12 10:12:18 -08:00
BFlat f63827478c Merge pull request #6892 from dotCooCoo/fix/trace-gray-photos-smoothed
Image Trace: gray photos are smoothed before tracing, as color photos are
2026-11-13 00:49:52 +07:00
dotCooCoo 108b3d9912 Image Trace: band borders in smooth areas follow the image's contours
In a gradient or a shaded area the palette colors on either side of a band
border differ by more than the image changes across it, so pixel noise
decided where the border ran, and it was smoothed over 0.5 px like a real
edge: borders wobbled, kept stair steps and took many anchors.

Each crack between two colors now records how much of the step between
them the image makes next to it and a few pixels further out, how much the
image changes there along the line between the two colors and in any
direction, and how much it changes within each side (RGB distances, 0 to
255 a channel). A piece of outline is the contour of a smooth area when its
cracks show less than half of the step; either more of it further out, a
change along the line under 12, or no opaque pixels further out; some change
within the sides, at least 1/32 of the change along the line; and a whole change
under twice the change along the line, or under 24. Such a piece is
smoothed over 4 px (a closed one over at most an eighth of its smaller
width or height), keeps no corners, is fitted to at least 0.5 px and is
checked against its smoothed points. The values are the same from either
side of the crack.

Grayscale reads each pixel as its gray, for this rule and for every edge's
sub-pixel shift, which compared the pixels' colors with gray palette
entries.

Color traces of clean flat-color art and Black and White traces are
unchanged. Specks rise by up to 0.8 per image on gradient and photo
inputs, and Auto Color with Shapes leaves a 0.3 px gap there.

Docs: docs/target-app-parity.md, docs/image-trace-quality.md.
2026-11-12 07:11:30 -08:00
dotCooCoo 1854911078 Image Trace: gray photos are smoothed before tracing, as color photos are
The continuous-tone test asked whether 8 colors leave more than a tenth
of the error of one color. A gray picture's tones lie along one line,
where 8 colors come nearer to them, so some gray photos scored 0.078 to
0.093 and were traced as flat art, without the smoothing color photos
get. Their noise then mixed neighboring tones (a 16 Colors trace could
keep 10 or 12 colors) and stepped the edges.

A picture with at least 95% of its opaque pixels within 8 levels across
their channels now also counts as continuous tone when 8 colors leave
more than 0.065 of the error of one color, unless 16 colors leave at
most a fifth of the error of 8. These are VectorCraft's own values. The
exception keeps gray flat art of up to 16 clean levels on its old
route. Pictures with more than 5% of their opaque pixels outside that
8-level range are unchanged.

Anti-aliased or noisy gray flat art can now take the smoothed route as
well. Very noisy gray scans of flat art get fewer specks and staircase
edges; some gray illustrations and sketches get more anchors and
staircase edges at 16 Colors and High Fidelity Photo. Some 16 Colors
and High Fidelity Photo palettes of gray photos grow toward the
requested count, with more anchors and regions, and some 6 Colors
traces get more staircase edges.
2026-11-12 06:16:48 -08:00
dotCooCoo 1d41b403e1 Effects: Outline Object on an image's fill or stroke follows its opaque pixels
An image's own fill or stroke with Outline Object now follows the outline of
the image's pixels that are at least 50% opaque, traced from the alpha and
fitted with curves, instead of the image's frame. An image without
transparency, one whose pixels can't be read, one of more than 64 megapixels
or whose decoded pixels take more than 256 MB, and one whose outline would
need more than 100,000 anchor points keep the frame. An image with no pixel
at least half opaque gives nothing to paint. Images of more than 4 megapixels
are traced from their alpha averaged down to 4 megapixels, and an averaged
pixel that covers a pixel at least half opaque stays at least half opaque, so
thin opaque lines stay in the outline. Each outline is traced once for its
pixels, kept for the next redraw while those pixels are loaded, and dropped
after them; a second thread that needs the same outline waits for the trace.

- vectorcraft-trace: `decode_alpha` reads an image's alpha, and
  `opaque_outline` traces it as Black and White mode at threshold 128.
- vectorcraft-effects: the reshaped image art uses it for rows whose first
  effect is Outline Object; Convert to Shape rows keep the frame.
- Docs: docs/mcp.md, the Outline Object params text and an evidence line in
  docs/target-app-parity.md. docs/mcp.md also says that Use Preview Bounds
  takes in the shapes an image's fills and strokes paint.
2026-11-12 04:58:03 -08:00
Dylan M. Taylor f4bbf33b51 Trace: refuse a GIF frame larger than the pixel ceiling before decoding 2026-11-11 22:46:07 +00:00
dotCooCoo b817baca58 Merge main into feat/trace-keep-colors 2026-11-08 13:45:04 -08:00
dotCooCoo 0de0cb7cb9 Image Trace: Ignore Color can leave out only the background
Squashed from #3952 onto main.
2026-11-09 03:38:46 +07:00
dotCooCoo 0f926b571f Merge main into feat/trace-keep-colors 2026-11-08 10:58:31 -08:00
dotCooCoo 8888128822 Image Trace: Flat Logo can trace only the named colors, without a white of its own
Squashed from #3946 onto main.
2026-11-08 23:50:25 +07:00
dotCooCoo 2facf55c29 Image Trace: the logo fitter keeps no piece over its tolerance
The fitter accepted a piece at depth 14, or with fewer than six points,
whatever its error, so a traced outline could stay farther than the
tolerance from its points. Synthetic 2 px block noise at Paths 100 and
Corners 0 kept a piece 2.7 px off at a tolerance of 0.1.

Such a piece is now accepted only when each point is within the tolerance
of the curve. Otherwise a short run is cut at its worst point, down to
two points, and a run at the depth limit is cut in the middle, which keeps
the recursion shallow. Every other piece is unchanged. Noisy art can get
more anchors.

a_traced_pixel_that_straightens_to_no_area_... now traces at Paths 80. At
Paths 90 that pixel's no-area result came from pieces over the tolerance.
2026-11-07 08:19:44 +07:00
vangel76andClaude Sonnet 5.5 f258124086 Component fit chunking: review fixes (#5464)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:32 +07:00
vangel76andClaude Sonnet 5.5 007e15ad8b Image Trace: fit the components of a layer in parallel, in chunks (#5464)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:32 +07:00
vangel76andClaude Sonnet 5.5 6ede10de4d all_within hasher: mix the high bits into the low ones (#5463)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:28 +07:00
vangel76andClaude Sonnet 5.5 f4ba106e39 Image Trace: all_within hashes its grid cells with a small hasher (#5463)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:28 +07:00
vangel76andClaude Sonnet 5.5 c0465969c8 Denoise: comment fixes from review (#5462)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:25 +07:00
vangel76andClaude Sonnet 5.5 63b8c88168 Image Trace: noise removal keeps its regions in u32 arrays (#5462)
Regions are a linked list of pixels with a union-find over region ids instead of a Vec<usize> per region and BTreeMaps per merge. Same merge order and output; about 2.7x less peak memory and up to 1.9x faster on 25 MP noisy labels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:25 +07:00
vangel76andClaude Sonnet 5.5 df3f18329e Trace: cover the column pass and mixed pairs in the smoothing tests (#5454)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:22 +07:00
vangel76andClaude Sonnet 5.5 5bc34676ce Trace: look up the smoothing weights instead of computing them per pixel (#5454)
The bilateral smoothing pass worked out a squared colour distance, a powi, a
division and a weight for every pixel and neighbour, and called round() per
channel. The distance is a whole number up to 195,075, so the weights come from
a table built once per trace, and the rounding is a truncation plus a compare
that gives the same level as round() for 0..=255. Rows are read through slices.

The output is byte for byte what it was; tests compare the pass with the old
formula on several images and on every pair of grey levels.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-04 08:13:22 +07:00
Dylan M. Taylor 8f8d04e5b5 fix(trace): empty and mismatched rasters, swatch dedupe by set 2026-11-03 23:29:37 +07:00
dotCooCoo f4ee10b2ec Merge main into feat/trace-keep-colors 2026-11-02 01:25:05 -08:00
NetterSilverandClaude Haiku 5.5 c0872ff9c6 Fix enhanced_preset Shapes for decorated High Fidelity Photo names
Found while testing crates/trace/src/params.rs:248-251 (enhanced_preset)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-31 20:44:04 +07:00
VoiceLessQ 1411a821c1 Fix #3098: Image Trace traces off the UI thread, with progress and Cancel
Tracing a photo or a large image ran inside imageTrace.make on the UI
thread, so the window froze for as long as the trace took, with nothing
to say it was working.

A trace the user asks for (Object > Image Trace > Make and Make and
Expand, the task bar's Image Trace, the Image Trace panel's Trace and
presets) now runs on a thread of its own, as heavy plug-in filters do.
The status bar says so, and after 0.4 s a progress window shows how
many of the image's colors are traced, with Cancel and Continue in
Background (imageTrace.cancelRuns, imageTrace.hideRuns).

The result goes back to the command it was prepared for
(cmd::TraceRun, Traced::hand_in), which takes it only for the same
object, image and settings, so the edit is one undo step as before. A
newer trace of the same object replaces one still running, and a trace
whose image or settings changed meanwhile changes nothing. The control
channel, MCP, scripts and the web trace at once, as before.

The tracer reports its stages and color layers to a callback and stops
when it says so (trace_watched).
2026-10-29 22:39:34 +07:00
dotCooCoo 3c0c010522 Merge main into feat/trace-keep-colors 2026-10-28 02:58:05 -07:00
Dylan M. Taylor 7b05e55a69 refactor(trace): separate graph construction and quantization 2026-10-27 17:47:12 +00:00
aiongg 22f59b6aea refactor(trace): move quantize.rs items to quantize/{cut_edge,denoise,palette,rare}.rs 2026-10-26 22:01:25 +00:00
aiongg 6c562d5f41 refactor(trace): move lib.rs items to {layers,params,pipeline,raster}.rs 2026-10-26 21:45:32 +00:00
aiongg 7695057780 refactor(trace): move centerline/mod.rs logo/mod.rs to foo.rs files 2026-10-26 18:15:22 +00:00
dotCooCoo 5d2a9099f1 Image Trace: a cut-edge blend past the rare-color budget traces as its kept color
The loop that keeps rare colors stopped at the first color past the
budget of six, so a cut-edge blend listed after it was not recorded as
tracing as its rare color, even when that rare color was kept, and its
pixels went to the nearest color instead. The loop now goes on past the
budget and only stops keeping new rare colors. It moves into
`kept_rare`, which a new test calls with seven rare colors and a blend
of the first.

The test of an outline over a cut edge in the color of other art also
checks that the dark paths reach the top and the bottom of the disc,
which no bar comes near: before, the bars alone met its checks.
2026-10-26 10:41:54 +07:00
dotCooCoo df716c3118 Image Trace: Document Library traces with a color group from the Swatches panel
Squashed from #3975 onto main.
2026-10-26 09:25:42 +07:00
dotCooCoo 58767abe0f Image Trace: the blended edge of a cut-out image adds no color to the palette
Squashed from #4075 onto main.
2026-10-26 09:09:45 +07:00
dotCooCoo bc674bec64 Image Trace: the empty-palette test uses a library blue the row maps to
The test of a color whose every path straightens to no area traced a
pale blue row with a library of a light color, black and [40, 120, 240].
With Document Library weighing hue and chroma three times as much as
lightness, the row takes the light color instead of that blue, so the
test no longer traced any blue. The library blue is now [60, 130, 235],
which the row still maps to; the assertions are unchanged.
2026-10-26 09:09:45 +07:00
dotCooCoo c9cc2ef076 Image Trace: Document Library keeps neutral tones off saturated library colors
With the Document Library palette, each pixel took the library color
nearest in plain Oklab distance. A 50% gray lies nearer in that distance
to a saturated blue of the same lightness than to black or a light
cream, and a muted brown is also nearer to the blue than to either. With
a black, cream and blue library, both traced as the blue.

This changes how Document Library matches pixels: each pixel now takes
the library color nearest with differences in hue and chroma (Oklab a
and b) counted three times as much as lightness. The same measure picks
which library colors are used. Neutral and muted tones take a neutral
library color, and the other palettes are unchanged.
2026-10-26 09:09:45 +07:00
dotCooCoo 0629d4e9a5 Image Trace: Overlapping layers reach only under areas that hold their own color
With Method Overlapping, each color layer covered every pixel of the colors
above it in the stack. A small dot or square on a background was then traced
once in its own color and again, at the same bounds, in every color between
the background and it, and with Shapes on each copy became its own live shape.
Those layers also ended on edges they never touched and showed through the
anti-aliased rim there.

Each layer now leaves out every 4-connected part of its stacked area that holds
no pixel of its own color. This changes the result of many Overlapping traces,
the photo presets included: fewer paths (High Fidelity Photo 121 to 69.6 on its
own quality inputs, Low Fidelity Photo 37.1 to 26.1) and no rim, around a
shape, of a color that sits apart from it. One existing test that counted the
extra copies now expects one layer per area, and another that compared layer
pixel counts now checks that the bottom layer covers the whole image.
2026-10-26 09:09:45 +07:00
dotCooCoo befa4f3c26 Image Trace: keepColors tells Ignore Color apart without the palette
Since main leaves a color with no paths out of the trace's palette, an
empty palette no longer shows that Ignore Color left out every color
keepColors matches. The trace result now says so in keep_ignored, and
the warning reads it, so a matched color that produces no paths is
reported as such with Ignore White on.
2026-10-25 10:29:16 -07:00
dotCooCoo 1f74202767 Merge main into feat/trace-keep-colors 2026-10-25 10:23:44 -07:00
Brandon Thomas a25360483f Merge pull request #4077 from dotCooCoo/fix/trace-palette-drops-unused-colors
Image Trace: a color with no traced paths is left out of the palette
2026-10-25 10:38:08 -04:00
Brandon Thomas 45afd85452 Merge pull request #4066 from dotCooCoo/fix/flat-logo-anchor-limit-counts-kept-outlines
Image Trace: Flat Logo counts only the outlines it keeps toward the anchor limit
2026-10-25 10:38:04 -04:00
dotCooCoo 179db957f7 Image Trace: a color with no traced paths is left out of the palette
A filled path that straightens to no area is left out of the trace
(#3949). When that removed every path of a color, the color stayed in
the trace's palette, so the Image Trace panel's Colors count and the
`colors` that `imageTrace.make` returns included it. The palette now
lists only the colors that have a path.
2026-10-24 14:39:58 -07:00
dotCooCoo 678b22ec73 Image Trace: Flat Logo finds a bar two pixels wide and three pixels long in its own color
The check for colors the palette cannot explain counted a pixel of a
bar two pixels wide only when its neighbors on both sides along the
bar were bar pixels. In a bar three pixels long only the two pixels of
its middle row passed, so its color had fewer than the three pixels a
color needs and was not added to the palette. A pixel now counts when
it lies at either end or in the middle of three such pixels in a row,
so all six pixels of a 2 × 3 bar count.
2026-10-24 13:00:06 -07:00
dotCooCoo 2fedb4c254 Image Trace: Flat Logo counts only the outlines it keeps toward the anchor limit
Flat Logo counted the anchors of every fitted outline and hole before it
left out the ones with no area, so a trace whose kept paths fit the
anchor limit could still be refused as too complex. The limit now counts
the anchors of the subpaths that go into the result.

The limit on outlines per color also counted holes, which are cut only
with Ignore White on. Holes now count toward it only when they are cut.
2026-10-24 11:55:31 -07:00
dotCooCoo 465ddfded9 Image Trace: Flat Logo finds a bar two pixels wide in its own color
When Flat Logo finds the colors itself (no colors named), a flat bar
two pixels wide (whole pixels of one color) on a ground beside other
art was lost or traced in another color. No bar pixel has a uniform
3 x 3 neighborhood, so neither the first clustering nor the check for
unexplained colors took it. A gray bar on white beside black art was
traced as white, and a red or green bar was traced as black. Bars
three pixels wide or more were already found.

The check for unexplained colors now also takes the pixels of such a
bar: two rows or columns of one color (within about 3.5 in RGB
distance), three pixels long, with the same ground on both sides. They
count when the known colors do not explain them, and also when their
color lies less than two thirds as far from the ground's known color
as from every other known color, where the bar would otherwise be
traced as the ground. A gray bar darker than about #9B9B9B on white
beside black art stays black, #808080 included, because a black stroke
1 to 1.6 px wide on the pixel grid gives the same pixels. Named colors
are unchanged.
2026-10-24 19:52:18 +07:00
dotCooCoo 6010dae0f0 Image Trace: Flat Logo leaves out a traced outline that has no area
The fit of a thin outline can lose all its area. Its two sides can
straighten onto one line, which leaves two anchors whose segments run
back and forth along it. Or the fit can be a single cubic, which becomes
one anchor and has no segment. Both occur when Flat Logo traces noise
whose cells are one pixel in size. The trace kept such an outline as a
selectable path that paints nothing.

Flat Logo now leaves out an outline whose area is below 1e-6 px^2,
together with its holes, and a hole whose area is below 1e-6 px^2. The
area is summed about the outline's first anchor, as the other trace
modes already do for a filled loop (crates/trace/src/lib.rs:996-1001).
Outlines with an area of 1e-6 px^2 or more, thin slivers included, are
kept as before.

One test traces a black and cream noise with both colors named exactly
and checks that no subpath of the result lacks an area. Two more build
shapes from straight cubics: a hole without area is left out, and an
outline without area is left out with its hole.
2026-10-24 19:15:08 +07:00