diff --git a/crates/engine/src/cmd/buildcmds/trace.rs b/crates/engine/src/cmd/buildcmds/trace.rs index 11519b84be..024ae851f5 100644 --- a/crates/engine/src/cmd/buildcmds/trace.rs +++ b/crates/engine/src/cmd/buildcmds/trace.rs @@ -288,8 +288,9 @@ fn trace_library(c: &str, s: &Session, params: &mut tr::TraceParams) -> Result= 2_000_000 && MAX_TRACE_ANCHORS <= 16_000_000); } diff --git a/crates/trace/src/params.rs b/crates/trace/src/params.rs index 9c430dd19d..156d6fbef2 100644 --- a/crates/trace/src/params.rs +++ b/crates/trace/src/params.rs @@ -241,19 +241,19 @@ pub fn preset(name: &str) -> Option { // many as its tones need where it is not. // (Color detail 85: a colour on a hundredth of the picture is still one of its colours.) "auto color" => TraceParams { palette: Palette::Automatic, color_detail: 85.0, ..color(6, 65.0, 60.0, 16, Method::Abutting) }, - "high fidelity photo" => color(64, 90.0, 25.0, 4, Method::Overlapping), - "low fidelity photo" => color(20, 60.0, 50.0, 12, Method::Overlapping), - "3 colors" => color(3, 60.0, 60.0, 20, Method::Abutting), - "6 colors" => color(6, 65.0, 60.0, 16, Method::Abutting), - "16 colors" => color(16, 70.0, 55.0, 10, Method::Abutting), - "shades of gray" => TraceParams { mode: Mode::Grayscale, colors: 8, paths: 60.0, corners: 50.0, noise: 10, method: Method::Overlapping, ..d }, - "black and white logo" => bw(128, 95.0, 80.0, 8, true), - "sketched art" => bw(150, 50.0, 50.0, 100, false), - "silhouettes" => bw(200, 40.0, 60.0, 30, false), - "line art" => bw(128, 80.0, 70.0, 10, false), - "technical drawing" => bw(128, 95.0, 90.0, 4, true), + "high fidelity photo" => color(64, 50.0, 50.0, 5, Method::Overlapping), + "low fidelity photo" => color(20, 50.0, 50.0, 10, Method::Overlapping), + "3 colors" => color(3, 50.0, 50.0, 15, Method::Abutting), + "6 colors" => color(6, 50.0, 50.0, 15, Method::Abutting), + "16 colors" => color(16, 50.0, 50.0, 15, Method::Abutting), + "shades of gray" => TraceParams { mode: Mode::Grayscale, colors: 8, paths: 50.0, corners: 50.0, noise: 15, method: Method::Overlapping, ..d }, + "black and white logo" => bw(128, 50.0, 75.0, 25, true), + "sketched art" => bw(150, 50.0, 50.0, 20, false), + "silhouettes" => bw(200, 50.0, 50.0, 90, false), + "line art" => bw(128, 50.0, 75.0, 20, false), + "technical drawing" => bw(128, 50.0, 100.0, 1, true), // Black outlines: lines as stroked centre lines, wider areas as stroked outlines. - "outline" => TraceParams { fills: false, strokes: true, ..bw(128, 80.0, 70.0, 10, false) }, + "outline" => TraceParams { fills: false, strokes: true, ..bw(128, 50.0, 75.0, 20, false) }, // Flat-colour logos: colours found automatically, edges placed to a fraction of a pixel. "flat logo" => TraceParams { mode: Mode::Logo, colors: 8, paths: 60.0, corners: 50.0, noise: 6, snap_curves_to_lines: true, ..d }, _ => return None, diff --git a/crates/trace/src/tests.rs b/crates/trace/src/tests.rs index fbedb07e29..e8d9fab828 100644 --- a/crates/trace/src/tests.rs +++ b/crates/trace/src/tests.rs @@ -892,6 +892,35 @@ fn presets_resolve() { assert!(preset("nope").is_none()); } +#[test] +fn presets_have_their_paths_corners_and_noise() { + let expected: &[(&str, f64, f64, u32)] = &[ + ("Default", 50.0, 75.0, 25), + ("High Fidelity Photo", 50.0, 50.0, 5), + ("Low Fidelity Photo", 50.0, 50.0, 10), + ("3 Colors", 50.0, 50.0, 15), + ("6 Colors", 50.0, 50.0, 15), + ("16 Colors", 50.0, 50.0, 15), + ("Shades of Gray", 50.0, 50.0, 15), + ("Black and White Logo", 50.0, 75.0, 25), + ("Sketched Art", 50.0, 50.0, 20), + ("Silhouettes", 50.0, 50.0, 90), + ("Line Art", 50.0, 75.0, 20), + ("Technical Drawing", 50.0, 100.0, 1), + ("Outline", 50.0, 75.0, 20), + ]; + for &(name, paths, corners, noise) in expected { + let p = preset(name).unwrap(); + assert_eq!((p.paths, p.corners, p.noise), (paths, corners, noise), "{name}"); + } + // The color counts stay as they were. + let colors: Vec = ["High Fidelity Photo", "Low Fidelity Photo", "3 Colors", "6 Colors", "16 Colors", "Shades of Gray"] + .iter() + .map(|n| preset(n).unwrap().colors) + .collect(); + assert_eq!(colors, [64, 20, 3, 6, 16, 8]); +} + #[test] fn params_json_roundtrip_and_partial() { let p = preset("6 Colors").unwrap(); diff --git a/docs/image-trace-adjustments.md b/docs/image-trace-adjustments.md index f1c0b7d3dd..e35fe5453b 100644 --- a/docs/image-trace-adjustments.md +++ b/docs/image-trace-adjustments.md @@ -18,6 +18,13 @@ its current location. Opening the controls does not add a document undo step. | Create | Fills / Strokes | Creates filled areas, stroked lines, or both. | | Ignore Color | Color picker | Leaves out the selected color (white by default). | +The built-in presets other than Auto Color and Flat Logo all use Paths 50. Corners is 100 in +Technical Drawing, 75 in Default, Black and White Logo, Line Art and Outline, and 50 in the others. +Noise is 1 px in Technical Drawing, 5 in High Fidelity Photo, 10 in Low Fidelity Photo, 15 in 3 Colors, +6 Colors, 16 Colors and Shades of Gray, 20 in Sketched Art, Line Art and Outline, 25 in Default and +Black and White Logo, and 90 in Silhouettes (see +[image-trace-quality.md](image-trace-quality.md#preset-paths-corners-and-noise)). + Sliders apply on release, and their numeric fields can be edited directly. Each committed adjustment re-traces the selected object as one undo step and changes the preset to Custom. While dragging, the preset and Enhanced row stay in place until release so the @@ -123,7 +130,8 @@ color is averaged down further: the factor doubles until at most 150,000 remain most 16,384 pixels (at most six times). A trace that would make more than 8,000,000 anchor points (2,000,000 on the web) is refused to protect memory, with advice: raise Noise, lower Paths or Colors, or pick a lower-fidelity preset. A trace keeps -about 90 bytes an anchor; a 4000 × 3000 photo at High Fidelity Photo makes about 1.9 million. +about 90 bytes an anchor; a 4000 × 3000 photo at Limited 64 colors, Paths 90, Corners 25 and Noise 4 +makes about 1.9 million. **Tracing in the background.** On the desktop a trace runs on a thread of its own, so the window keeps answering while a photo or a large image is traced (#3098). Make, Make and Expand, the task bar's Image Trace and the panel's Trace and presets start it. The status bar says "Tracing the diff --git a/docs/image-trace-quality.md b/docs/image-trace-quality.md index 40f6fe43b9..2b2b363433 100644 --- a/docs/image-trace-quality.md +++ b/docs/image-trace-quality.md @@ -82,6 +82,9 @@ gradient, texture, sensor noise): (The last two rows were measured without a limit; they are refused now.) The 4000 × 3000 High Fidelity Photo trace was 86,000 anchors under the old limit; a noisier scan of the same size would have been refused. At 8,000,000 anchors a trace keeps about 0.7 GB, with a peak of about 0.9 GB while tracing. +The preset rows were measured with the earlier preset values: High Fidelity Photo at Paths 90, Corners 25 +and Noise 4, Low Fidelity Photo at Paths 60, Noise 12 and 16 Colors at Paths 70, Corners 55 and Noise 10 +(see [Preset Paths, Corners and Noise](#preset-paths-corners-and-noise)). ## Collapsed loops keep few segments A small closed loop (or a piece that returns to its own junction) whose fit collapsed to a single cubic cannot stay as one, so it kept every positioned point as a straight segment. A looser Paths @@ -225,6 +228,42 @@ in a smooth area), `a_staircase_that_runs_on_from_a_smooth_area_into_an_edge_kee `a_staircase_of_mixed_one_pixel_and_longer_steps_is_one_slope_without_a_notch`, `a_run_of_two_steps_keeps_its_corners`, `a_junction_on_a_step_ends_the_staircase_there` and `a_step_whose_cracks_read_as_an_edge_ends_the_staircase_there`. +## Preset Paths, Corners and Noise +Every built-in preset other than Auto Color and Flat Logo traces at Paths 50. Corners and Noise are: + +| preset | Paths | Corners | Noise | before | +|:--|--:|--:|--:|:--| +| Default | 50 | 75 | 25 | unchanged | +| High Fidelity Photo | 50 | 50 | 5 | 90, 25, 4 | +| Low Fidelity Photo | 50 | 50 | 10 | 60, 50, 12 | +| 3 Colors | 50 | 50 | 15 | 60, 60, 20 | +| 6 Colors | 50 | 50 | 15 | 65, 60, 16 | +| 16 Colors | 50 | 50 | 15 | 70, 55, 10 | +| Shades of Gray | 50 | 50 | 15 | 60, 50, 10 | +| Black and White Logo | 50 | 75 | 25 | 95, 80, 8 | +| Sketched Art | 50 | 50 | 20 | 50, 50, 100 | +| Silhouettes | 50 | 50 | 90 | 40, 60, 30 | +| Line Art | 50 | 75 | 20 | 80, 70, 10 | +| Technical Drawing | 50 | 100 | 1 | 95, 90, 4 | +| Outline | 50 | 75 | 20 | 80, 70, 10 | + +The palettes, color counts, thresholds and other options of the presets did not change. + +Measured with the harness below (section 1, each preset on the inputs it is meant for), before and after: +anchors fall in 10 of the 12 changed presets, for example 5,494 to 3,136 (High Fidelity Photo), 33 to 27 +(16 Colors), 27 to 14 (Black and White Logo) and 43 to 28 (Line Art); Silhouettes rises from 13 to 15 and +Sketched Art does not change. Outlines on flat art lie further from the true edge: off mean 0.100 to 0.123 +px (16 Colors), 0.101 to 0.119 (6 Colors), 0.104 to 0.129 (3 Colors), 0.064 to 0.092 (Black and White Logo) +and 0.056 to 0.074 (Line Art), and off max 1.00 to 1.16 px in 6 Colors and 16 Colors. Technical Drawing +leaves 1.4 specks (was 0.5), and Outline's stroked centre lines lie 0.095 px off (was 0.086) with 2.7 +anchors a stroke (was 3.0). ΔE changes by 0.01 or less except Line Art and Outline (2.62 and 2.61 to 2.66 +and 2.67); edge ΔE rises in 8 of the 12, for example 4.79 to 5.25 (16 Colors), 3.98 to 4.46 (3 Colors) and 9.46 to 10.03 +(Black and White Logo). On synthetic shapes and photos of 300 to 4,000 px traced outside this harness, +High Fidelity Photo makes 41% fewer anchors and 16 Colors 15% fewer; the mean pixel difference of each +trace changes by −0.23 to +0.25 of a level; 16 Colors leaves 91 staircases of steps of 2 px or more where it left 85, and High +Fidelity Photo 473 where it left 461. The tables below are the previous measurement, not a rerun. +Test: `presets_have_their_paths_corners_and_noise` in `crates/trace/src/tests.rs`. + ## A simpler contour walk `contour::trace_mask` follows each region's outline along the pixel cracks with the inside on the right. It used to build a table of outgoing directions for every pixel corner in a raster pass and diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 26681e5b7f..4cecc0dc06 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1397,6 +1397,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - **Image Trace, cut-out edges:** in Color and Grayscale, a semi-transparent pixel (alpha 128 to 254) on the edge of a cut-out image, beside a pixel that is less than half opaque, traces as a color of the fully opaque pixels within two pixels of it when its own color is that color or a darker shade of it, and of several such colors, as the one the most of those pixels have (art across a transparent gap does not count), so a darkened edge tone no longer traces as a 1 px sliver of an unrelated palette color, while a thin semi-transparent outline of another color keeps its own; code-drawn cut-out, opaque-edge and thin-outline tests in `crates/trace`. - **Image Trace, cut-out edges choose no color:** in Color and Grayscale, the edge pixels that take the color beside them, and the semi-transparent pixels within two pixels of them whose color is also the opaque art's color blended with the background, do not count when the palette or the grays are chosen, so the edge of a cut-out image no longer adds a second shade of a color to Auto Color's palette, takes away an outline's color or takes a gray of its own; beside those pixels, the anti-aliasing between a color and an outline drawn along the edge is no color of Auto Color's own when it lies at least 0.45 of the way from the color to the outline and at least one in 32 of its pixels has both around it (edge pixels that choose no color count when they lie within 2.5 Oklab × 100 of the nearest of those colors): its pixels trace as the outline, so a thin outline stays a ring of few pieces, except beside an outline along the edge with a region of 8 pixels of its own, where each takes the nearer of the two, so a wider outline is not drawn wider; an outline over the edge in the color of other art traces in that color, while an opaque rim drawn along the edge keeps its color, also where other art reaches it; a thin semi-transparent outline of another color still counts, and opaque images trace as before; code-drawn cut-out outline, rim, opaque line and grayscale edge tests in `crates/trace`. - **Image Trace, blurred edges:** in Color with a Limited palette of at most 16 colors (3 Colors, 6 Colors, 16 Colors) and in Grayscale with at most 16 grays (Shades of Gray), by VectorCraft's own rule (RGB distances, 0 to 255 a channel), a blend pixel with no unblended pixel of its own color within 4 pixels takes the nearer side of the pair of colors within 8 pixels that it is best a blend of, of the 8 colors within 8 pixels nearest to its color, when that pair explains it twice as well as its own color, or when it lies between the two and off the line between them by less than 0.15 of their distance apart; it keeps its color when it is one of the pair. Grayscale compares lightness. The in-between tones of an edge blurred over several pixels no longer trace as rings around it. High Fidelity Photo, Low Fidelity Photo and Black and White trace as before, and so do Automatic, Full Tone and Document Library palettes. Noisy and textured images settle more of their pixels. By `crates/trace/tests/quality` (256 px variants), 16 Colors on blurred flat art went from 9.0 paths to 3.0, 158 anchors to 34 and 0.239 px off to 0.069, and 6 Colors from 6.0 paths to 3.0 and 0.226 px off to 0.071; askew shapes take up to 11 px more area in colors the art does not have, and with 16 Colors the largest distance from a thin line's outline to the trace goes from 23.5 px to 45.3 (see [quality notes](image-trace-quality.md#blurred-edges)). Code-drawn blurred-disc and grayscale ramp tests in `crates/trace`. +- **Image Trace, preset Paths, Corners and Noise:** every built-in preset but Auto Color and Flat Logo traces at Paths 50; Corners is 100 in Technical Drawing, 75 in Default, Black and White Logo, Line Art and Outline and 50 in the others; Noise is 1 to 90 px by preset. Palettes and color counts are unchanged. By `crates/trace/tests/quality`, High Fidelity Photo goes from 5,494 anchors to 3,136 and Black and White Logo from 27 to 14, while 16 Colors on flat art goes from 0.100 px off to 0.123 (see [quality notes](image-trace-quality.md#preset-paths-corners-and-noise)). Test `presets_have_their_paths_corners_and_noise` in `crates/trace`. - **Image Trace, simpler contour walk:** `contour::trace_mask` works out each turn from the pixels during the walk, with no precomputed direction table and no assertion; identical loops to the previous walk on every 4 × 4 mask (see [quality notes](image-trace-quality.md#a-simpler-contour-walk)). - **Image Trace, measured:** `crates/trace/tests/quality` traces drawings made from known vector art with every preset and [`image-trace-quality.md`](image-trace-quality.md) records the numbers against the baseline. Black and White, Grayscale and Color place each edge by the blend of the pixels across it (to a fraction of a pixel on anti-aliased and blurred images; hard-edged images are read as staircases) and fit outlines as Flat Logo does. *Measured* on each preset's own inputs, all sizes and variants: Default's outlines went from 0.31 px off on average to 0.09 (largest 1.51 to 1.02), Black and White Logo's from 0.27 to 0.06 with 0.3 kinks per trace where it had 15, and the gaps between abutting paths from 64 px to 22. On clean curved shapes Black and White Logo is 0.02 px off (the open tracer measured beside it: 0.20). The palette is made of the picture's own colours (blends along edges take none of it, colours that noise made of one colour merge, a blend pixel goes to one of the two colours it lies between; #1504): 16 Colors on flat art, all variants, went from 70 paths to 4.2 and from 5.1 px off to 0.13, with no path left in a colour the art doesn't have (5.9 before). Photos are smoothed within their tones before they are quantised and stacked layers go by lightness (#1516): High Fidelity Photo went from 3,653 paths to 121 with its colour error down from 2.30 to 1.75, and a 16 megapixel photo-like image is traced in 3.5 s where 4 megapixels were refused. Since then, by the same harness: outlines are cut at their junctions and each shared piece is fitted once (#1535: gaps and overlaps between abutting paths 22 to 50 px of area down to under 2); layers are traced within the box of their pixels and a few at a time (#1546: a 16 megapixel photo 3.9 GB to 0.9 GB); black and white are read against the image's own black and the paper near each edge (#1563, for thin lines in blurred and scanned art); Ignore Color and the Auto Color and Outline presets (#1574); Snap Curves To Lines levels lines within 2.5 degrees of level or upright (#1593, the angle our choice); Create: Strokes puts centre lines in the middle of their ink and makes them as wide as it (#1595: Outline 0.295 to 0.052 px from the true centre line, 18.4 to 2.7 anchors a stroke); sharp corners whose pixel is mostly outside the shape stay corners (#1609: Default 69% to 76% kept). Three options, each off unless asked for as the legacy presets have them: Shapes (#1609: 57 to 62% of plain circles, ellipses, rectangles and regular polygons come out as live shapes, rounded rectangles rarely), Auto Grouping (#1618: paths grouped with what lies inside them, the same picture) and Gradients (#1627: linear gradients traced as one gradient-filled path; on gradient inputs 6 Colors' colour error 2.12 to 0.62 with 6.4 to 3.4 paths, none found in flat art). Snap Curves To Lines moves no end of a line by more than 1.6 px, so long lines a degree or two off stay as the image has them (#1647: Technical Drawing's largest distance 4.21 px to 1.46). Flat Logo takes the tones a scan's uneven paper makes of one colour for one colour (#1657: on scans 470 paths and 21 px off to 8.5 paths and 0.09 px). Shapes finds rounded rectangles and shapes in aliased, blurred and scanned art (#1845: 57 to 62% of the plain shapes up to 98 to 100%, no false shape but one line 2 px wide). Stroked lines get square caps where their ink is cut square, and a wide end that turned towards a corner goes back on its line (#1846: Outline's largest distance 2.94 px to 0.88, 14 anchors to 10). Each of the 14 documented presets has an enhanced version with Auto Grouping and, in all but High Fidelity Photo, Shapes (#1847), measured beside its preset: equal or better within 0.005 px and 1% of edge ΔE on every preset's own inputs (Default 0.091 to 0.083 px); Auto Grouping keeps traced order in its groups, which removed a light seam along the counters of letters. Gradients grows a gradient over the pixels noise and soft rims took off it (#1848: blurred and noisy linear gradients 3 to 11 paths beside the gradient down to 0.5 with 6 Colors, 24 to 56 down to 0.5 to 1.5 with High Fidelity Photo). Silhouettes is 0.52 px off because its threshold is 200 (0.11 px at 128). Still weak, by the same numbers: rounded rectangles and other line-and-arc outlines take 12 to 16 anchors (the fitter does not split lines from arcs), blurred and scanned polygons lose corners, hairlines under half a pixel are lost to the threshold, aliased art is about 0.25 px off, a scan's uneven paper splits into tones when more colours are asked for than the art has, stroke junctions stay at their skeleton pixels, a three-stop gradient in a small or scanned disc is not found, radial gradients stay bands (a draft, #1849, traces them; the documented option is for linear ones, so it waits for a decision), near-regular polygons a few dozen pixels across are made regular with Shapes (up to 0.5 px off), and aliased stroked lines are 0.8 px off at worst. - **Gradient mesh from an image:** Object › Create Gradient Mesh (`object.mesh.create`) on an embedded image makes a mesh of 1 to 50 rows and columns over the picture's rectangle, placed with the image's transform; each point takes the alpha-weighted average colour and the opacity of the area around it, and Appearance and Highlight apply. A linked image is refused with a message to embed it (#1676). Scores and hours unchanged.