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.
This commit is contained in:
dotCooCoo
2026-10-30 23:57:40 +07:00
committed by bflatastic
parent 65f7d3a699
commit a2d3841579
+14 -8
View File
@@ -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<Val
let unit = xf.determinant().abs().sqrt();
let (npaths, anchors, colors) = (res.paths.len(), res.anchor_count(), res.palette.len());
let label = if expand { "Image Trace (Make and Expand)" } else { "Image Trace" };
// A library color fills with the swatch's own color (its model kept), linked to a
// global or spot swatch of the document. Of the swatches that trace as this color,
// the first linked one is taken, else the first. Build the lookup once per trace.
let mut by_color: HashMap<[u8; 3], &Paint> = 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<Val
*path = shape.to_path();
*live = Some(Box::new(shape));
}
// A library color fills with the swatch's own color (its model kept), linked to a
// global or spot swatch of the document. Of the swatches that trace as this color,
// the first linked one is taken, else the first.
let same = || library.iter().filter(|(rgb, _)| *rgb == tp.color);
let solid = same()
.find(|(_, p)| matches!(p, Paint::Solid { swatch: Some(_), .. }))
.or_else(|| same().next())
.map_or_else(|| Paint::solid(Color::rgb8(tp.color[0], tp.color[1], tp.color[2])), |l| l.1.clone());
let solid =
by_color.get(&tp.color).map_or_else(|| Paint::solid(Color::rgb8(tp.color[0], tp.color[1], tp.color[2])), |paint| (*paint).clone());
// Gradients: a path the tracer found to be a linear gradient is filled with it.
let paint = tp.gradient.as_ref().map_or(solid, |g| traced_gradient(g, xf));
n.appearance = match tp.stroke {