Commit Graph
9 Commits
Author SHA1 Message Date
bflatastic 77f81c8944 Image Trace: photos are smoothed within their tones first, and stacked layers go by lightness
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
2026-10-13 04:28:02 +07:00
bflatastic 4204ce36db Image Trace: a palette of the picture's own colours
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
2026-10-13 03:48:30 +07:00
japbcoelhoandClaude Opus 5.5 4268b8edd5 Trace: colour mode keeps close dark tones apart
The colour histogram used the top 5 bits of each channel, so tones less
than 8 values apart always shared a bin and could never get their own
palette entry, however many colours were asked for. A dark, low-contrast
photo (a book-cover texture with RGB 33..66) traced to 5 colours when 12
were requested, and eight grey stripes 32..39 traced to one:

  vectorcraft-cli run --in stripes-32-39.png --cmd select.all \
    --cmd imageTrace.makeAndExpand \
    --params '{"params":{"mode":"color","colors":8,"noise":0,"method":"overlapping"}}'
  -> {"anchors":4,"colors":1,"id":4,"paths":1}

The histogram keeps its 32x32x32 bins, now fitted to each channel's range
among the opaque pixels: a channel spanning at most 32 values keeps every
value apart, a full-range channel keeps the old 5-bit bins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:59:50 +07:00
mateususaandClaude Opus 5.5 ae9cd2a03c #819: more noise removal never gives more paths
Remove Noise merged each small component into its most common neighbour
in one pass. When a speck was merged into a small region that was itself
merged away later, the region's flood fill skipped the speck's pixels
(already seen), so they stayed behind as a new island of the region's old
label. Higher Noise values merge more regions, so they left more such
islands: on noisy images the path count rose with Noise (70 -> 126 -> 206
paths from Noise 50 to 200 on one test image). denoise now repeats its pass
until one changes nothing; each merge joins two components, so it ends
(with a cap of 64 passes as a backstop). Labels shorter than w x h are left
alone instead of indexed past their end.

Tests: the minimal one-row case, a property test on random blocky noise
(no mergeable region under the minimum is left, and a larger minimum never
leaves more regions), and two noisy images whose path count must not rise
with Noise (both fail without the fix).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:00:31 +07:00
Jax SpenserandClaude Sonnet 5.5 29310175af Image Trace: Flat Logo mode (sub-pixel edges, restored corners, true lines and circles)
A fourth Image Trace mode for flat-colour logos. The existing tracer follows hard pixel
edges, so an outline can only be as good as the pixel grid; here each pixel is read as a
blend of the logo's flat colours, the blend is interpolated smoothly (cubic B-spline), and
every outline is placed where two colours are equally present, to a fraction of a pixel.

Outlines are then cleaned the way a person would:
- corners the blur rounded are put back (line fits either side of a bend, intersected);
- near-straight runs and near-circular arcs become exact lines and arcs (Snap Curves To Lines);
- the rest is fitted with as few cubic Beziers as the tolerance allows (Schneider);
- touching colours overlap by 0.06 px so no hairline gap opens between independent fits;
- shapes are painted biggest first; transparent areas fully enclosed by artwork (letters
  knocked out of a badge, the counters of an "o") are painted white so the logo reads the
  same on any background, or become real holes with Ignore White (each hole belongs to the
  smallest outline containing it);
- an outline whose fit strays more than 1.4 px from the raw contour is fitted plainly.

Colours are found automatically (and completed from pixels no blend of the known colours
explains, so a small accent is not lost) or named with `logoColors: ["#rrggbb", ...]` (white is
always its own class; colours closer than 12 count as one; at most ten). Gradients and photos
are refused with advice to use Color (a flat-colour score of the solid areas, 0.93). A
hard-edged source with no anti-aliasing is softened by under a pixel and fitted with looser
snap tolerances. Images over 1024 px on the long side are averaged down first (further, if
they are busy enough to make the unmixing expensive) and the result is mapped back exactly.
More real outlines than we will fit are refused, not silently truncated.

Also: a "Flat Logo" preset, the mode in the Image Trace panel (Method hidden: it always
stacks), the command docs and MCP prompt, es/fr/it/ru translations for the two new messages
and the mode name, and the ROADMAP.

Never-crash: no unwrap/expect/panic, every size and float is bounded and checked, with
tests for degenerate and extreme input (NaN/infinite parameters, 0x0 and 1x1 images, sparse
outlines, an anchor budget, a 200,000-entry palette) and a 250-run randomised no-panic
property test. The B-spline interpolation follows Unser et al. and Thevenaz et al., and the
curve fitter follows Schneider (Graphics Gems); both are written from the papers.

Measured (local experiment, not in CI): a flat-colour logo's vector original rendered down
to a soft 199x100 px PNG and traced. Mean edge error vs the original at 1600 px wide:
built-in colour presets 2.5 to 3.4 px, Flat Logo 0.78 px (0.48 px from a crisp source);
region overlap 0.88-0.91 vs 0.966. About 0.1 s for a 200 px logo.

Tests: 60 new in the trace crate (unmix, field, contours, geometry, Beziers, corners,
outline fitting, palette, end-to-end on synthetic shapes made in code) and 3 in the engine.
cargo xtask ci passes (fmt, clippy, test, assets, brands, layers, wasm): 4,290 tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-09 17:57:04 +11:00
bflatasticandClaude Opus 5.5 4a81e549a2 Part of #641: Image Trace: Palette (Limited, Full Tone, Automatic, Document Library)
Color mode's colours now come from a Palette (`palette` in imageTrace.make's
params), shown in the Image Trace panel under Mode:
- Limited: the `colors` best colours (what Color did before; the default).
- Full Tone: median cut until no colour box spans more than 96 (Less) … 8
  (More) levels per channel, up to 256 colours, set by `colorDetail` 0-100
  (the panel's Colors slider for this palette).
- Automatic: flat art (90% of the pixels in a few tight colours) traces with
  exactly its colours, anything else as Full Tone.
- Document Library: the most used (at most `colors`) colours of the
  document's swatches or of a swatch library (`library`: "document" or a
  library id or name, chosen in the panel's Library list), used as they are;
  traced shapes fill with the swatch's own colour, its colour model kept.
  The library's colours are looked up at every trace, not saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:51:49 +07:00
Brandon ThomasandClaude Opus 5.5 0f241aac9f clippy: as_chunks for fixed-size pixel and pair chunks (Rust 1.99 lint was red on main)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 06:24:06 +07:00
Brandon ThomasandClaude Opus 5.5 f8136f1e35 Live Blends/Envelopes/Gradient Mesh, Shape Builder, Live Paint, Image Trace (drawcraft-trace), Recolor Artwork, Export for Screens, Actions panel, prefs persistence, real layer thumbnails; menus bound
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 11:02:16 -04:00
Brandon Thomas a7e49bfa72 continued work 2026-09-30 09:43:24 -04:00