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.
This commit is contained in:
dotCooCoo
2026-10-24 14:39:58 -07:00
parent 8bf090b253
commit 179db957f7
2 changed files with 46 additions and 1 deletions
+6 -1
View File
@@ -642,7 +642,12 @@ fn trace_paths(img: &Raster, params: &TraceParams, max_anchors: usize) -> Result
let largest = job.boxes.iter().flatten().map(|b| (b.2 - b.0) * (b.3 - b.1)).max().unwrap_or(1).max(1);
let at_a_time = ((512 << 20) / (largest * 10)).max(1);
for (paths, &(_, ci)) in parallel_map_at_most(at_a_time, &layers, |&(r, ci)| job.layer(r, ci)).into_iter().zip(&layers) {
out.paths.extend(paths.ok_or(TraceError::TooComplex { max: max_anchors })?);
let paths = paths.ok_or(TraceError::TooComplex { max: max_anchors })?;
// A layer with no paths adds no color to the palette.
if paths.is_empty() {
continue;
}
out.paths.extend(paths);
let color = q.palette[ci];
if !out.palette.contains(&color) {
out.palette.push(color);
+40
View File
@@ -1355,6 +1355,46 @@ fn a_traced_pixel_that_straightens_to_no_area_is_left_out_of_fills_and_kept_as_a
}
}
#[test]
fn a_color_whose_every_path_straightens_to_no_area_is_left_out_of_the_palette() {
// A light rectangle with a black block on it and a one-pixel row of a pale blue along its lower
// edge, on a transparent background. Traced with a library of the light, the black and a
// blue, the row is the only part in the blue.
const BLUE: [u8; 3] = [40, 120, 240];
let img = Raster::from_fn(200, 120, |x, y| {
if (60..140).contains(&x) && (70..90).contains(&y) {
BLACK
} else if (20..180).contains(&x) && (20..100).contains(&y) {
[240, 240, 220, 255]
} else if y == 100 && (30..170).contains(&x) {
[140, 180, 230, 255]
} else {
[0, 0, 0, 0]
}
});
let params = TraceParams {
mode: Mode::Color,
palette: Palette::DocumentLibrary,
swatches: vec![[240, 240, 220], [0, 0, 0], BLUE],
colors: 3,
paths: 90.0,
corners: 60.0,
noise: 25,
method: Method::Abutting,
..TraceParams::default()
};
let used = |res: &TraceResult| res.palette.iter().all(|c| res.paths.iter().any(|p| p.color == *c));
// Left alone, the row is a path in the blue, and the blue is in the palette.
let res = trace(&img, &params);
assert!(res.paths.iter().any(|p| p.color == BLUE), "{:?}", res.paths.iter().map(|p| (p.color, p.path.bounds())).collect::<Vec<_>>());
assert!(res.palette.contains(&BLUE) && used(&res), "{:?}", res.palette);
// Snapped, both sides of the row straighten onto one line and its path is left out: no path is
// in the blue, and the palette leaves it out too.
let res = trace(&img, &TraceParams { snap_curves_to_lines: true, ..params });
assert!(res.paths.iter().all(|p| p.color != BLUE), "{:?}", res.paths.iter().map(|p| (p.color, p.path.bounds())).collect::<Vec<_>>());
assert!(!res.palette.contains(&BLUE) && used(&res), "{:?}", res.palette);
}
#[test]
fn a_straight_anti_aliased_line_is_two_anchors_in_its_middle_as_wide_as_its_ink() {
// 2.6 px wide, from (20.3, 30.7) to (170.6, 52.2): a little off the pixel rows.