From befa4f3c2625402fbf3b85e9b4b128f0c3c31e61 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sun, 25 Oct 2026 10:29:16 -0700 Subject: [PATCH] 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. --- crates/engine/src/cmd/buildcmds.rs | 9 ++++----- crates/trace/src/lib.rs | 7 ++++++- crates/trace/src/tests.rs | 8 ++++++++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/crates/engine/src/cmd/buildcmds.rs b/crates/engine/src/cmd/buildcmds.rs index 8fb73898b..7ab4829eb 100644 --- a/crates/engine/src/cmd/buildcmds.rs +++ b/crates/engine/src/cmd/buildcmds.rs @@ -1256,8 +1256,7 @@ pub(crate) fn keep_warnings(params: &tr::TraceParams, res: &tr::TraceResult) -> return vec![format!("Nothing was traced: none of the colors the trace found matches keepColors ({}).", params.keep_colors.join(", "))]; } let mut out = vec![]; - // The trace's palette holds each color it traced, also one that produced no paths. - if res.paths.is_empty() && params.ignore_white && res.palette.is_empty() { + if res.paths.is_empty() && res.keep_ignored { out.push("Nothing was traced: Ignore Color leaves out every area of the colors keepColors lists.".to_string()); } else if res.paths.is_empty() { out.push("Nothing was traced: the colors that match keepColors produce no paths.".to_string()); @@ -1341,8 +1340,8 @@ mod trace_limit_tests { #[test] fn keep_warnings_name_matched_colors_that_produce_no_paths() { let params = tr::TraceParams { keep_colors: vec!["#ff0000".into()], ..tr::TraceParams::default() }; - // A listed color was traced, and produced no paths. - let traced = tr::TraceResult { palette: vec![[255, 0, 0]], ..tr::TraceResult::default() }; + // A listed color was traced, and produced no paths: the palette lists no color without paths. + let traced = tr::TraceResult::default(); let none = vec!["Nothing was traced: the colors that match keepColors produce no paths.".to_string()]; assert_eq!(keep_warnings(¶ms, &traced), none); // With Ignore Color, too: Ignore Color did not leave that color out. @@ -1350,7 +1349,7 @@ mod trace_limit_tests { assert_eq!(keep_warnings(&ignoring, &traced), none); // Ignore Color left out every color that matches: none was traced. assert_eq!( - keep_warnings(&ignoring, &tr::TraceResult::default()), + keep_warnings(&ignoring, &tr::TraceResult { keep_ignored: true, ..tr::TraceResult::default() }), vec!["Nothing was traced: Ignore Color leaves out every area of the colors keepColors lists.".to_string()] ); } diff --git a/crates/trace/src/lib.rs b/crates/trace/src/lib.rs index 657365051..6f5776d7c 100644 --- a/crates/trace/src/lib.rs +++ b/crates/trace/src/lib.rs @@ -493,6 +493,9 @@ pub struct TraceResult { /// Keep Colors: the colors listed in [`TraceParams::keep_colors`] (as written) that no color /// the trace found matches, so that nothing of them is traced. (Flat Logo mode: empty.) pub keep_unmatched: Vec, + /// Keep Colors: whether Ignore Color left out every color the trace found that a listed color + /// matches, so that none of them was traced. (Flat Logo mode: false.) + pub keep_ignored: bool, /// Flat Logo: the size in pixels the image was traced at when it was averaged down first; /// `None` when it was traced at its own size. pub worked_at: Option<(u32, u32)>, @@ -658,6 +661,8 @@ fn trace_paths(img: &Raster, params: &TraceParams, max_anchors: usize) -> Result .filter(|&(_, &k)| !order.iter().any(|&ci| is_kept(q.palette[ci], &[k]))) .map(|(name, _)| name.clone()) .collect(); + // Every layer is left out although a listed color matches one: Ignore Color left those out. + let keep_ignored = !listed.is_empty() && layers.is_empty() && order.iter().any(|&ci| is_kept(q.palette[ci], &listed)); let job = Layers { q: &q, rank: &rank, @@ -673,7 +678,7 @@ fn trace_paths(img: &Raster, params: &TraceParams, max_anchors: usize) -> Result anchors: AtomicUsize::new(0), max_anchors, }; - let mut out = TraceResult { keep_unmatched, ..TraceResult::default() }; + let mut out = TraceResult { keep_unmatched, keep_ignored, ..TraceResult::default() }; // A layer takes about ten bytes a pixel of its box while it is traced (its mask, the labels // of its components, the stack that fills them, its edges): as many layers at a time as fit // in half a gigabyte, so that a large image is not traced at the cost of gigabytes. diff --git a/crates/trace/src/tests.rs b/crates/trace/src/tests.rs index 602fe85b2..73b903486 100644 --- a/crates/trace/src/tests.rs +++ b/crates/trace/src/tests.rs @@ -1310,6 +1310,14 @@ fn keep_colors_names_the_colors_nothing_matches() { // A color Ignore Color leaves out still matches one the trace found. let ignoring = TraceParams { ignore_white: true, ignore_color: Some("#14285a".into()), ..params.clone() }; assert_eq!(unmatched(&["#14285a"], &ignoring), (Vec::new(), 0)); + // The result says that Ignore Color left out every color that matches, and only then. + let keep = |keep: &[&str], params: &TraceParams| { + trace(&img, &TraceParams { keep_colors: keep.iter().map(|k| k.to_string()).collect(), ..params.clone() }) + }; + assert!(keep(&["#14285a"], &ignoring).keep_ignored); + assert!(!keep(&["#14285a", "#f0c832"], &ignoring).keep_ignored); + assert!(!keep(&["#14285a"], ¶ms).keep_ignored); + assert!(!keep(&["#ff00ff"], &ignoring).keep_ignored); // With none listed, none is named. assert!(trace(&img, ¶ms).keep_unmatched.is_empty()); // Flat Logo mode does not use the list.