From 65f7d3a6996350edca87646d1d6c1cc241f10cb7 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 29 Oct 2026 02:02:15 -0700 Subject: [PATCH 1/2] Image Trace: Document Library links to a global swatch that shares a process swatch's color When a process swatch listed before a global or spot swatch showed the same color, a traced fill of that color took the process swatch and stayed unlinked. Of the swatches that trace as one color, the first linked one now gives the fill, and the first one otherwise. --- crates/engine/src/cmd/buildcmds/trace.rs | 10 ++++--- crates/engine/src/tests/build.rs | 37 ++++++++++++++++++++++++ docs/image-trace-adjustments.md | 4 ++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/cmd/buildcmds/trace.rs b/crates/engine/src/cmd/buildcmds/trace.rs index 308e300ec..a44b4bbca 100644 --- a/crates/engine/src/cmd/buildcmds/trace.rs +++ b/crates/engine/src/cmd/buildcmds/trace.rs @@ -585,10 +585,12 @@ pub(super) fn trace_make(s: &mut Session, p: &Value, expand: bool) -> Result [200, 40, 40, 255], + 20..40 => [40, 160, 60, 255], + _ => [tr, tg, tb, 255], + }); + add_image(&mut s, &r, Affine::IDENTITY); + let params = json!({"mode": "color", "palette": "documentLibrary", "library": "document", "colors": 8}); + let res = s.execute("imageTrace.makeAndExpand", &json!({"params": params})).unwrap(); + let g = node(&s, NodeId(res["id"].as_u64().unwrap())); + let got: Vec = g.children().unwrap().iter().map(|n| n.appearance.fill_paint()).collect(); + let red = Color::rgb8(200, 40, 40); + let reds: Vec<&Paint> = got.iter().filter(|p| p.color().map(|c| c.to_rgba8(1.0)) == Some(red.to_rgba8(1.0))).collect(); + assert!(!reds.is_empty(), "{got:?}"); + assert!(reds.iter().all(|p| matches!(p, Paint::Solid { swatch: Some(w), .. } if w == "Ink")), "{got:?}"); + let tints: Vec<&Paint> = got.iter().filter(|p| p.color().map(|c| c.to_rgba8(1.0)) == Some([tr, tg, tb, 255])).collect(); + assert!(!tints.is_empty(), "{got:?}"); + assert!(tints.iter().all(|p| matches!(p, Paint::Solid { swatch: Some(w), tint, .. } if w == "Sky" && *tint == 0.5)), "{got:?}"); + // Editing the global swatch recolors the trace. + s.execute("swatch.edit", &json!({"name": "Ink", "color": "#ff8800"})).unwrap(); + let g = node(&s, NodeId(res["id"].as_u64().unwrap())); + let orange = Color::rgb8(255, 136, 0).to_rgba8(1.0); + assert!(g.children().unwrap().iter().any(|n| n.appearance.fill_paint().color().map(|c| c.to_rgba8(1.0)) == Some(orange))); +} + #[test] fn image_trace_document_library_matches_a_lab_spot_by_its_cmyk_equivalent() { let _g = crate::tests_colormgmt::GLOBAL.lock().unwrap_or_else(|e| e.into_inner()); diff --git a/docs/image-trace-adjustments.md b/docs/image-trace-adjustments.md index b124de96a..0de13b953 100644 --- a/docs/image-trace-adjustments.md +++ b/docs/image-trace-adjustments.md @@ -49,7 +49,9 @@ and traces as All. **Document Library linked colors.** With Library › Document Swatches, with or without a color group, a traced fill or stroke whose color comes from a global or spot swatch is linked to that swatch, and one whose color comes from a tint swatch is linked to its base at the tint. Editing the swatch -recolors the trace. Colors from process swatches and from swatch libraries are not linked. +recolors the trace. Colors from process swatches and from swatch libraries are not linked. When +several swatches show the same color, the first of them in the list that is a global, spot or tint +swatch gives the link. **Document Library** traces with the library's colors as they are. Each pixel takes the library color nearest to it in lightness and hue, with a difference in hue or chroma counted three times From a2d38415793e22b3b9259ceab15e5c1f2a319ce2 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Fri, 30 Oct 2026 06:44:47 -0700 Subject: [PATCH 2/2] Image Trace: look up library swatches once per trace Each traced path filtered the whole library for its color, twice when no swatch of that color was linked. The color-to-paint lookup is now built once before the paths are filled. The first linked swatch of a color still gives the fill, and the first swatch of that color otherwise. --- crates/engine/src/cmd/buildcmds/trace.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/engine/src/cmd/buildcmds/trace.rs b/crates/engine/src/cmd/buildcmds/trace.rs index a44b4bbca..832219d5f 100644 --- a/crates/engine/src/cmd/buildcmds/trace.rs +++ b/crates/engine/src/cmd/buildcmds/trace.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use vectorcraft_color::Swatch; use vectorcraft_doc::ImageObject; @@ -557,6 +559,16 @@ pub(super) fn trace_make(s: &mut Session, p: &Value, expand: bool) -> Result = HashMap::new(); + for (rgb, paint) in &library { + let chosen = by_color.entry(*rgb).or_insert(paint); + if !matches!(**chosen, Paint::Solid { swatch: Some(_), .. }) && matches!(paint, Paint::Solid { swatch: Some(_), .. }) { + *chosen = paint; + } + } let id = s.edit(label, |d, sel| { let src = d.node(target).cloned().ok_or(EngineError::NoNode(target))?; let mut image = if is_trace_group(&src) { @@ -584,14 +596,8 @@ pub(super) fn trace_make(s: &mut Session, p: &Value, expand: bool) -> Result