Commit Graph
105 Commits
Author SHA1 Message Date
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
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
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
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
dotCooCoo 76c014b732 Image Trace: Flat Logo traces named colors a few levels off at the image's own size
Squashed from #3999 onto main.
2026-10-24 19:02:09 +07:00
dotCooCoo 68e4392491 Image Trace: Flat Logo says when it traces a large image at a reduced size
Flat Logo traces a copy of the image at most 1024 pixels on a side,
averaged down by a whole factor, so a 1025-pixel image is traced at
513 pixels. The trace's warnings did not say so, because they compared
the image only with the decoded raster. For an image over 1500 pixels
they said instead that it is traced more slowly, which Flat Logo does
not do.

The trace result now carries Flat Logo's working size when it averaged
the image down. imageTrace.make and imageTrace.makeAndExpand then name
both sizes in their warnings, and the status bar shows that note, in
place of the slower-trace and megapixel notes. Other modes keep their
warnings. The message has a row in each catalog that translates the
other Image Trace warnings.
2026-10-24 19:02:09 +07:00
NetterSilverandClaude Haiku 5.5 5068dfc73f Reject plus signs in logo palette hex parser
Found while testing crates/trace/src/logo/palette.rs:9-15 (parse_hex)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 19:02:09 +07:00
dotCooCoo f3f9e1035d Image Trace: keepColors says when the matching colors produce no paths
A trace whose kept colors were traced and produced no paths gave no
warning, or, with Ignore Color on, said that Ignore Color left those
colors out. The Ignore Color warning now shows only when no kept color
was traced at all, and otherwise the first warning says that the colors
that match keepColors produce no paths. The new message has a row in
each complete-message catalog.

Whether Ignore Color or keepColors leaves a palette entry out is now
decided once per entry, so tracing a layer no longer scans the
keepColors list for each pixel.

Docs: docs/image-trace-adjustments.md.
2026-10-24 03:48:30 -07:00
dotCooCoo b049e45b88 Image Trace: Auto Grouping looks up containing paths in a grid instead of testing every pair
Auto Grouping compared the box of every traced path with the box of every
path that can hold something, and with Overlapping it also compared each
grouped path with every path below it. On a 1400 x 1400 px noise image
traced with Limited 8, Overlapping (18,653 paths), parents() made
442,998,298 box tests and took 3.0 s in a release build.

parents() now keeps the holders and, for stacked traces, the paths below in
a grid of about one cell per path. A path's candidates are the holders in the
cell of its box center, smallest first, and the paths below it come from the
cells its box reaches. When a box reaches more cells or entries than there
are paths below it, the old scan is used. The cells grow larger when the
boxes would otherwise be listed in more than 32 cells each on average. The
same trace now takes 142,289 box tests and 0.08 s, and every parent is the
same as before. The 20,000-path limit is unchanged.

The tests compare parents() with the pairwise version on rings, faces and
noise traced Abutting and Overlapping, check that a dense trace takes at most
64 box tests per path while the pairwise version takes more, check that 300
nested discs take no more box tests than the pairwise version, and check
that boxes covering the whole image make the cells larger.
2026-10-24 17:29:33 +07:00