mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-01 13:47:21 -06:00
Fix #4923: Find Nearest Swatch matches colours to a library's swatches
Object > Plug-ins > Color Effects > Find Nearest Swatch... picks a library (the document's swatches, a built-in library, or a library or colour book the user saved or loaded) and Fill and Stroke, and lists each colour of the selection with its three closest swatches and their CIEDE2000 difference. Apply gives each colour its nearest swatch as one undo step. - addon.color.nearestSwatch (a query): the closest swatches of a library to each colour of the selection's fills and strokes (solid colours and gradient stops, inside groups and type), or to a colour given, with deltaE; count 1..50. - addon.color.applyNearestSwatch: recolours those paints (and gradient meshes) to their nearest swatch; global and spot swatches link, and a library's swatches the colours take are added to the document first (as swatch.library.add adds them), so a spot colour stays spot. - The library picker Image Trace's Document Library uses moves to the Swatches panel module and is shared. - No colour book data ships: only libraries VectorCraft computes or the user loads are searched.
This commit is contained in:
+3
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
**Stage: alpha** · next: beta, ~13 points (ready for real work ~62% → ~75%, and reliable `.ai` exchange) and ~170–270 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Progress log row for the Path Precision Tools add-on's Expand Dashes into Paths; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Progress log row for the Color Effects add-on's Find Nearest Swatch; headline numbers unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adobe Illustrator workflow. It runs
|
||||
on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive all of it over MCP, the CLI and a JSON
|
||||
@@ -129,6 +129,7 @@ Ranked; detail in [docs/roadmap.md](docs/roadmap.md) and [docs/gaps.md](docs/gap
|
||||
|
||||
## Progress log
|
||||
|
||||
- 2026-11-01: Find Nearest Swatch joins the Color Effects add-on (Object › Plug-ins › Color Effects): for each colour of the selection, the closest swatches of the document, a built-in library or a library or colour book the user loaded, with their CIEDE2000 difference; Apply gives each colour its nearest swatch as one undo step, linking global and spot swatches and adding a library's to the document first, so a process colour becomes the closest spot colour (`addon.color.nearestSwatch`, `addon.color.applyNearestSwatch`, #4923).
|
||||
- 2026-11-01: Expand Dashes into Paths joins the Path Precision Tools add-on (Object › Plug-ins › Path Precision Tools): each selected path's dashed stroke becomes separate open paths, one per dash, laid out exactly as the stroke draws them (pattern, offset, Align Dashes to Corners and Path Ends), each keeping the stroke with the dashes off, so the gaps are real gaps for cutters and plotters, as one undo step (`addon.pathtools.expandDashes`, #4922).
|
||||
- 2026-11-01: Randomize Opacity joins the Arrange Tools add-on (Object › Plug-ins › Arrange Tools): each selected object gets its own opacity at random between a minimum and a maximum percent, with a seed that repeats the result, as one undo step (`addon.arrange.randomizeOpacity`, #4925).
|
||||
- 2026-11-01: Sort Objects joins the Arrange Tools add-on (Object › Plug-ins › Arrange Tools): the selected objects are sorted by width, height, area, position, opacity or stacking order (small to large, large to small or at random) and take another of those in that order, trading their values or stepping them evenly, as one undo step (`addon.arrange.sort`, #4917).
|
||||
@@ -211,6 +212,7 @@ The full earlier record of what landed is kept in [docs/roadmap.md](docs/roadmap
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-01 | minor | Progress log row for the Color Effects add-on's Find Nearest Swatch (#4923); headline numbers unchanged. |
|
||||
| 2026-11-01 | minor | Progress log row for the Path Precision Tools add-on's Expand Dashes into Paths (#4922); headline numbers unchanged. |
|
||||
| 2026-11-01 | minor | Progress log row for the Arrange Tools add-on's Randomize Opacity (#4925); headline numbers unchanged. |
|
||||
| 2026-11-01 | minor | Progress log row for the Arrange Tools add-on's Sort Objects (#4917); headline numbers unchanged. |
|
||||
|
||||
@@ -120,7 +120,7 @@ fn number_in(p: &Value, key: &str, default: f64, (lo, hi): (f64, f64), cmd: &str
|
||||
}
|
||||
|
||||
/// Whole-number param `key` within `lo..=hi`, `None` when left out.
|
||||
fn whole_in(p: &Value, key: &str, (lo, hi): (u64, u64), cmd: &str) -> Result<Option<u64>> {
|
||||
pub(super) fn whole_in(p: &Value, key: &str, (lo, hi): (u64, u64), cmd: &str) -> Result<Option<u64>> {
|
||||
let Some(v) = p.get(key).filter(|v| !v.is_null()) else { return Ok(None) };
|
||||
let n = v.as_u64().ok_or_else(|| bad(cmd, format!("`{key}` must be a whole number")))?;
|
||||
if (lo..=hi).contains(&n) { Ok(Some(n)) } else { Err(bad(cmd, format!("`{key}` must be from {lo} to {hi}"))) }
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
//! Duotone and Invert Colors, in Effect › Color Effects) are the effects crate's; here, Apply as
|
||||
//! Filter writes any colour adjustment into the colours themselves, Select by Color Kind selects the
|
||||
//! objects that use spot colours, carry a live colour adjustment, or are images of a colour model,
|
||||
//! and Print Ink Fixes ([`print_fixes`]) prepares a CMYK document's inks for print. Its panel and
|
||||
//! its submenu, Object › Plug-ins › Color Effects, are the UI's.
|
||||
//! Print Ink Fixes ([`print_fixes`]) prepares a CMYK document's inks for print, and Find Nearest
|
||||
//! Swatch ([`nearest`]) matches colours to a swatch library's. Its panel and its submenu, Object ›
|
||||
//! Plug-ins › Color Effects, are the UI's.
|
||||
|
||||
mod nearest;
|
||||
mod print_fixes;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -50,6 +52,24 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
has_doc,
|
||||
print_fixes::run
|
||||
),
|
||||
cmd!(
|
||||
query "addon.color.nearestSwatch",
|
||||
"Find Nearest Swatch",
|
||||
["Object", "Plug-ins", "Color Effects"],
|
||||
None,
|
||||
"{library?: a swatch library's id or name (swatch.library.list: the built-in ones, and the colour books and libraries the user saved or loaded) or \"document\" (the document's swatches; the default), color?: colour (look this colour up; default: the selection's), fill?: true, stroke?: true (the selected objects' fills and strokes, their type's and those of the objects inside them: solid colours and gradient stops, once each, the first 100), count?: 1..50 (5), ids?: [id…] (default: the selection)} list the library's colour swatches closest to each colour, closest first, by CIEDE2000 difference (ΔE; under 1 hardly tells apart, about 2 to 3 close). Tint swatches, None and Registration aren't matched → {library, colors: [{values, hex, matches: [{name, values, hex, spot, deltaE}]}]}",
|
||||
has_doc,
|
||||
nearest::find
|
||||
),
|
||||
cmd!(
|
||||
"addon.color.applyNearestSwatch",
|
||||
"Apply Nearest Swatch",
|
||||
["Object", "Plug-ins", "Color Effects"],
|
||||
None,
|
||||
"{library?: as addon.color.nearestSwatch (default: \"document\"), fill?: true, stroke?: true, ids?: [id…] (default: the selection)} give each solid colour and gradient stop of the selected objects' fills and strokes (their type's and those of the objects inside them; gradient meshes too) the colour of its nearest swatch in the library, as addon.color.nearestSwatch finds it, as one undo step: a global or spot swatch's colour links to it. A library's swatches the colours take are added to the document's first, as swatch.library.add adds them (a spot colour stays spot); images and patterns keep their colours → {changed: paints changed, swatches: [the document swatches the colours took], added: [swatches added to the document]}",
|
||||
has_selection,
|
||||
nearest::apply
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
//! Find Nearest Swatch (`addon.color.nearestSwatch`, `addon.color.applyNearestSwatch`; Object ›
|
||||
//! Plug-ins › Color Effects › Find Nearest Swatch…): the swatches of a library, a colour book the
|
||||
//! user loaded or the document closest to each colour of the selection (CIEDE2000), and the
|
||||
//! colours replaced by them as one undo step (#4923).
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::cms::{Lab, delta_e2000};
|
||||
use vectorcraft_color::{Color, Paint, Swatch};
|
||||
use vectorcraft_doc::swatches::color_name;
|
||||
use vectorcraft_doc::{Document, NodeId, NodeKind};
|
||||
|
||||
use super::super::super::colorcmds::recolor_links;
|
||||
use super::super::super::menucmds::squash;
|
||||
use super::super::super::swatchlib::{DOCUMENT_SWATCHES, library_swatches};
|
||||
use super::super::super::{bad, checked_ids_or_selection, color_value, index, switch_or, text_param};
|
||||
use super::super::arrange::whole_in;
|
||||
use crate::{Result, Session};
|
||||
|
||||
const FIND: &str = "addon.color.nearestSwatch";
|
||||
const APPLY: &str = "addon.color.applyNearestSwatch";
|
||||
/// The most colours of the selection looked up.
|
||||
const MAX_COLORS: usize = 100;
|
||||
|
||||
/// The `library` param ([`DOCUMENT_SWATCHES`] when left out) and its colour swatches with their Lab
|
||||
/// values.
|
||||
fn candidates(s: &Session, p: &Value, cmd: &str) -> Result<(String, Vec<(Swatch, Lab)>)> {
|
||||
let key = text_param(p, "library", cmd)?.unwrap_or(DOCUMENT_SWATCHES).to_string();
|
||||
let swatches = library_swatches(s, &key).ok_or_else(|| bad(cmd, format!("no swatch library `{key}` (see swatch.library.list)")))?;
|
||||
let labs: Vec<(Swatch, Lab)> = swatches
|
||||
.into_iter()
|
||||
.filter(|w| !w.is_reserved())
|
||||
.filter_map(|w| {
|
||||
let lab = w.paint.color()?.to_lab();
|
||||
Some((w, lab))
|
||||
})
|
||||
.collect();
|
||||
if labs.is_empty() {
|
||||
return Err(bad(cmd, format!("`{key}` has no colours")));
|
||||
}
|
||||
Ok((key, labs))
|
||||
}
|
||||
|
||||
/// The `count` swatches of `among` closest to `c`, closest first, with their difference (ΔE 2000).
|
||||
fn nearest(among: &[(Swatch, Lab)], c: Color, count: usize) -> Vec<(&Swatch, f32)> {
|
||||
let lab = c.to_lab();
|
||||
let mut v: Vec<(&Swatch, f32)> = among.iter().map(|(w, l)| (w, delta_e2000(*l, lab))).collect();
|
||||
v.sort_by(|a, b| a.1.total_cmp(&b.1));
|
||||
v.truncate(count);
|
||||
v
|
||||
}
|
||||
|
||||
/// The solid colours and gradient stops of the fills (`fill`) and strokes (`stroke`) of `ids`, of
|
||||
/// everything inside them and of their type, once each and at most [`MAX_COLORS`].
|
||||
fn art_colors(d: &Document, ids: &[NodeId], fill: bool, stroke: bool) -> Vec<Color> {
|
||||
let mut out: Vec<Color> = vec![];
|
||||
let mut add = |p: &Paint| {
|
||||
let colors: Vec<Color> = match p {
|
||||
Paint::Solid { color, .. } => vec![*color],
|
||||
Paint::Gradient(g) => g.gradient.stops.iter().map(|s| s.color).collect(),
|
||||
_ => vec![],
|
||||
};
|
||||
for c in colors {
|
||||
if out.len() < MAX_COLORS && !out.contains(&c) {
|
||||
out.push(c);
|
||||
}
|
||||
}
|
||||
};
|
||||
for n in ids.iter().filter_map(|id| d.node(*id)) {
|
||||
n.walk(&mut |m| {
|
||||
for it in &m.appearance.items {
|
||||
if if it.is_fill() { fill } else { stroke } {
|
||||
add(it.paint());
|
||||
}
|
||||
}
|
||||
if let NodeKind::Text(t) = &m.kind {
|
||||
for r in &t.runs {
|
||||
if fill {
|
||||
add(&r.style.fill);
|
||||
}
|
||||
if stroke {
|
||||
add(&r.style.stroke);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// A swatch's name and values as the results give them.
|
||||
fn described(w: &Swatch) -> Value {
|
||||
let c = w.paint.color().unwrap_or_default();
|
||||
json!({ "name": w.name, "values": color_name(c), "hex": c.to_hex(), "spot": w.spot })
|
||||
}
|
||||
|
||||
pub(super) fn find(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let count = whole_in(p, "count", (1, 50), FIND)?.map_or(5, index);
|
||||
let (fill, stroke) = (switch_or(p, "fill", true, FIND)?, switch_or(p, "stroke", true, FIND)?);
|
||||
let colors = match p.get("color").filter(|v| !v.is_null()) {
|
||||
Some(v) => vec![color_value(v).ok_or_else(|| bad(FIND, "`color` is not a colour"))?],
|
||||
None => {
|
||||
let ids = checked_ids_or_selection(s, p, FIND)?;
|
||||
if ids.is_empty() {
|
||||
return Err(bad(FIND, "select objects or give `color`"));
|
||||
}
|
||||
art_colors(&s.doc()?.doc, &ids, fill, stroke)
|
||||
}
|
||||
};
|
||||
let (library, among) = candidates(s, p, FIND)?;
|
||||
let found: Vec<Value> = colors
|
||||
.iter()
|
||||
.map(|c| {
|
||||
let matches: Vec<Value> = nearest(&among, *c, count)
|
||||
.into_iter()
|
||||
.map(|(w, de)| {
|
||||
let mut m = described(w);
|
||||
m["deltaE"] = json!((f64::from(de) * 100.0).round() / 100.0);
|
||||
m
|
||||
})
|
||||
.collect();
|
||||
json!({ "values": color_name(*c), "hex": c.to_hex(), "matches": matches })
|
||||
})
|
||||
.collect();
|
||||
Ok(json!({ "library": library, "colors": found }))
|
||||
}
|
||||
|
||||
pub(super) fn apply(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let (fill, stroke) = (switch_or(p, "fill", true, APPLY)?, switch_or(p, "stroke", true, APPLY)?);
|
||||
let ids = checked_ids_or_selection(s, p, APPLY)?;
|
||||
if ids.is_empty() {
|
||||
return Err(bad(APPLY, "nothing selected"));
|
||||
}
|
||||
let (library, among) = candidates(s, p, APPLY)?;
|
||||
// The swatch each colour takes, once each.
|
||||
let colors = art_colors(&s.doc()?.doc, &ids, fill, stroke);
|
||||
let mut used: Vec<&Swatch> = vec![];
|
||||
for c in &colors {
|
||||
if let Some((w, _)) = nearest(&among, *c, 1).first()
|
||||
&& !used.iter().any(|u| u.name == w.name)
|
||||
{
|
||||
used.push(w);
|
||||
}
|
||||
}
|
||||
if used.is_empty() {
|
||||
return Ok(json!({ "changed": 0, "swatches": [], "added": [] }));
|
||||
}
|
||||
let undo = s.doc()?.history.undo.len();
|
||||
// A library's swatches join the document's first, as Add to Swatches adds them, so spot and
|
||||
// global colours stay linked to theirs.
|
||||
let mut added = vec![];
|
||||
let mut names: Vec<String> = used.iter().map(|w| w.name.clone()).collect();
|
||||
if library != DOCUMENT_SWATCHES {
|
||||
let r = s.execute("swatch.library.add", &json!({ "library": library, "names": names }))?;
|
||||
let listed = |k: &str| r.get(k).and_then(Value::as_array).cloned().unwrap_or_default();
|
||||
let in_doc: Vec<String> = listed("added").iter().chain(&listed("existing")).filter_map(Value::as_str).map(str::to_string).collect();
|
||||
let d = &s.doc()?.doc;
|
||||
// Each library swatch's copy: the document swatch with its paint among those added or kept.
|
||||
names = used
|
||||
.iter()
|
||||
.map(|w| in_doc.iter().find(|n| d.swatch(n).is_some_and(|x| x.paint == w.paint)).cloned().unwrap_or_else(|| w.name.clone()))
|
||||
.collect();
|
||||
added = listed("added");
|
||||
}
|
||||
// Each used swatch's paint as art takes it: linked to a global or spot swatch.
|
||||
let d = &s.doc()?.doc;
|
||||
let paints: Vec<(Lab, Paint)> = used
|
||||
.iter()
|
||||
.zip(&names)
|
||||
.filter_map(|(w, name)| {
|
||||
let lab = w.paint.color()?.to_lab();
|
||||
let paint = d.swatch(name).filter(|x| x.global).and_then(|_| d.tint_paint(name, 1.0)).unwrap_or_else(|| w.paint.clone());
|
||||
Some((lab, paint))
|
||||
})
|
||||
.collect();
|
||||
// shortcut: a colour past the MAX_COLORS looked up takes the closest of the swatches those
|
||||
// took; look up every colour if documents with more colours need their own matches.
|
||||
let to = |c: Color| -> Option<&Paint> {
|
||||
let lab = c.to_lab();
|
||||
paints.iter().min_by(|a, b| delta_e2000(a.0, lab).total_cmp(&delta_e2000(b.0, lab))).map(|(_, p)| p)
|
||||
};
|
||||
let links = |c: &mut Color, link: &mut Option<String>, tint: &mut f32| {
|
||||
let Some(Paint::Solid { color, swatch, .. }) = to(*c) else { return false };
|
||||
if *c == *color && *link == *swatch {
|
||||
return false;
|
||||
}
|
||||
(*c, *link, *tint) = (*color, swatch.clone(), 1.0);
|
||||
true
|
||||
};
|
||||
let given = json!({
|
||||
"ids": ids.iter().map(|i| i.0).collect::<Vec<_>>(), "fill": fill, "stroke": stroke, "includeImages": false, "includePatterns": false,
|
||||
});
|
||||
let r = recolor_links(s, &given, "Apply Nearest Swatch", &|c| to(c).and_then(Paint::color).unwrap_or(c), &links)?;
|
||||
squash(s, undo, "Apply Nearest Swatch");
|
||||
Ok(json!({ "changed": r["changed"], "swatches": names, "added": added }))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -0,0 +1,115 @@
|
||||
//! Find Nearest Swatch.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::{Color, Paint};
|
||||
use vectorcraft_doc::NodeId;
|
||||
|
||||
use crate::Session;
|
||||
|
||||
const FIND: &str = "addon.color.nearestSwatch";
|
||||
const APPLY: &str = "addon.color.applyNearestSwatch";
|
||||
|
||||
/// A document with a global swatch "Brand" and a selected rectangle filled `fill`, stroked `stroke`.
|
||||
fn doc(fill: &str, stroke: Option<&str>) -> (Session, NodeId) {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 200, "height": 200})).unwrap();
|
||||
s.execute("swatch.new", &json!({"name": "Brand", "color": "#ff8000", "global": true})).unwrap();
|
||||
let id = NodeId(s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 50, "height": 50})).unwrap()["id"].as_u64().unwrap());
|
||||
s.execute("paint.setFill", &json!({"color": fill})).unwrap();
|
||||
match stroke {
|
||||
Some(c) => s.execute("paint.setStroke", &json!({"color": c})).unwrap(),
|
||||
None => s.execute("paint.setStroke", &json!({"none": true})).unwrap(),
|
||||
};
|
||||
(s, id)
|
||||
}
|
||||
|
||||
fn paints(s: &Session, id: NodeId) -> (Paint, Paint) {
|
||||
let n = s.doc().unwrap().doc.node(id).unwrap().clone();
|
||||
(n.appearance.fill_paint(), n.appearance.items.iter().find(|i| !i.is_fill()).unwrap().paint().clone())
|
||||
}
|
||||
|
||||
fn names(matches: &Value) -> Vec<&str> {
|
||||
matches.as_array().unwrap().iter().map(|m| m["name"].as_str().unwrap()).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_closest_swatches_of_a_library_are_listed_closest_first() {
|
||||
let (mut s, _) = doc("#ff6634", None);
|
||||
let v = s.execute(FIND, &json!({"library": "web-safe-216", "count": 3})).unwrap();
|
||||
assert_eq!(v["library"], "web-safe-216");
|
||||
let colors = v["colors"].as_array().unwrap();
|
||||
assert_eq!(colors.len(), 1, "the fill; no stroke");
|
||||
assert_eq!((colors[0]["hex"].as_str(), colors[0]["values"].as_str()), (Some("#ff6634"), Some("R=255 G=102 B=52")));
|
||||
let m = &colors[0]["matches"];
|
||||
assert_eq!(names(m)[0], "#FF6633");
|
||||
let de: Vec<f64> = m.as_array().unwrap().iter().map(|x| x["deltaE"].as_f64().unwrap()).collect();
|
||||
assert_eq!(de.len(), 3);
|
||||
assert!(de[0] < 1.0 && de.windows(2).all(|w| w[0] <= w[1]), "{de:?}");
|
||||
// A colour given is looked up instead of the selection's.
|
||||
let v = s.execute(FIND, &json!({"library": "web-safe-216", "color": "#010203", "count": 1})).unwrap();
|
||||
assert_eq!(names(&v["colors"][0]["matches"]), ["#000000"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_document_swatches_are_the_default_library() {
|
||||
let (mut s, _) = doc("#ff8010", Some("#ff8010"));
|
||||
let v = s.execute(FIND, &json!({})).unwrap();
|
||||
assert_eq!(v["library"], "document");
|
||||
assert_eq!(v["colors"].as_array().unwrap().len(), 1, "fill and stroke share a colour: looked up once");
|
||||
assert_eq!(names(&v["colors"][0]["matches"])[0], "Brand");
|
||||
assert!(!names(&v["colors"][0]["matches"]).contains(&"[Registration]"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn applying_links_each_colour_to_its_nearest_document_swatch_as_one_undo_step() {
|
||||
let (mut s, id) = doc("#ff8010", Some("#ff8010"));
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
let v = s.execute(APPLY, &json!({"stroke": false})).unwrap();
|
||||
assert_eq!((v["changed"].as_u64(), v["swatches"].clone(), v["added"].clone()), (Some(1), json!(["Brand"]), json!([])));
|
||||
let (fill, stroke) = paints(&s, id);
|
||||
assert!(matches!(&fill, Paint::Solid { swatch: Some(n), color, .. } if n == "Brand" && color.to_hex() == "#ff8000"), "{fill:?}");
|
||||
assert_eq!(stroke.color().unwrap().to_hex(), "#ff8010", "strokes left alone");
|
||||
let st = s.doc().unwrap();
|
||||
assert_eq!((st.history.undo.len(), st.history.undo.last().unwrap().label.as_str()), (undo + 1, "Apply Nearest Swatch"));
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(paints(&s, id).0.color().unwrap().to_hex(), "#ff8010");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_library_spot_colour_joins_the_document_and_stays_spot() {
|
||||
let (mut s, id) = doc("#e01525", None);
|
||||
// A colour book of one spot colour, loaded as a user would load one they own.
|
||||
s.execute("swatch.new", &json!({"name": "Ink Red", "color": "#e01020", "spot": true})).unwrap();
|
||||
let data = s.execute("swatch.library.save", &json!({"names": ["Ink Red"]})).unwrap()["data"].as_str().unwrap().to_string();
|
||||
s.execute("swatch.delete", &json!({"names": ["Ink Red"]})).unwrap();
|
||||
let lib = s.execute("swatch.library.load", &json!({"data": data, "name": "Book.vcswatches"})).unwrap()["library"].as_str().unwrap().to_string();
|
||||
s.execute("select.set", &json!({"ids": [id.0]})).unwrap();
|
||||
let undo = s.doc().unwrap().history.undo.len();
|
||||
let v = s.execute(APPLY, &json!({"library": lib})).unwrap();
|
||||
assert_eq!((v["swatches"].clone(), v["added"].clone()), (json!(["Ink Red"]), json!(["Ink Red"])));
|
||||
let d = &s.doc().unwrap().doc;
|
||||
assert!(d.swatch("Ink Red").is_some_and(|w| w.spot && w.global));
|
||||
assert!(matches!(paints(&s, id).0, Paint::Solid { swatch: Some(n), .. } if n == "Ink Red"));
|
||||
assert_eq!(s.doc().unwrap().history.undo.len(), undo + 1, "adding and applying undo together");
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert!(s.doc().unwrap().doc.swatch("Ink Red").is_none());
|
||||
assert_eq!(paints(&s, id).0, Paint::solid(Color::from_hex("#e01525").unwrap()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_requests_are_refused() {
|
||||
let (mut s, _) = doc("#ff8010", None);
|
||||
for (p, why) in [
|
||||
(json!({"library": "nope"}), "no swatch library `nope`"),
|
||||
(json!({"library": "spectrum-gradients"}), "has no colours"),
|
||||
(json!({"count": 0}), "`count` must be from 1 to 50"),
|
||||
(json!({"color": "zzz"}), "`color` is not a colour"),
|
||||
(json!({"fill": "yes"}), "`fill` must be true or false"),
|
||||
] {
|
||||
let e = s.execute(FIND, &p).unwrap_err().to_string();
|
||||
assert!(e.contains(why), "{p}: {e}");
|
||||
}
|
||||
s.execute("select.none", &json!({})).unwrap();
|
||||
assert!(s.execute(FIND, &json!({})).unwrap_err().to_string().contains("select objects or give `color`"));
|
||||
assert!(s.execute(APPLY, &json!({})).is_err(), "nothing selected");
|
||||
}
|
||||
@@ -434,6 +434,11 @@ fn structured_junk() {
|
||||
("addon.color.printFixes", json!({"inkLimit": 1e308, "overprintBlack": -1e308})),
|
||||
("addon.color.printFixes", json!({"inkLimit": 1, "overprintBlack": 1, "removeWhiteOverprint": true, "scope": "document", "textOnly": true})),
|
||||
("addon.color.printFixes", json!({"inkLimit": [300], "scope": 3, "ids": "x"})),
|
||||
("addon.color.nearestSwatch", json!({"library": 7, "count": u64::MAX, "color": [1e308, -1e308, "x"]})),
|
||||
("addon.color.nearestSwatch", json!({"library": "web-safe-216", "color": {"l": 1e30, "a": -1e30, "b": 0}, "count": 50})),
|
||||
("addon.color.nearestSwatch", json!({"library": "spectrum-gradients", "fill": "x", "ids": [u64::MAX]})),
|
||||
("addon.color.applyNearestSwatch", json!({"library": "web-safe-216", "fill": true, "stroke": true})),
|
||||
("addon.color.applyNearestSwatch", json!({"library": "nope", "ids": "x", "stroke": 3})),
|
||||
("effect.apply", json!({"effect": "no.such.effect"})),
|
||||
("effect.remove", json!({"index": 99})),
|
||||
("effect.setParams", json!({"index": 0, "params": null})),
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
//! filter, into the colours themselves (`addon.color.filter`); below, under Inks, it opens Duotone's
|
||||
//! dialog and Print Ink Fixes' (`addon.color.printFixes`). The submenu applies the add-on's live
|
||||
//! effects, Duotone and Vector Halftone among them (Effect › Color Effects has them too), opens
|
||||
//! Print Ink Fixes and opens the panel.
|
||||
//! Print Ink Fixes and Find Nearest Swatch ([`nearest`]) and opens the panel.
|
||||
|
||||
pub mod nearest;
|
||||
|
||||
use egui::Ui;
|
||||
use serde_json::{Map, Value, json};
|
||||
@@ -97,6 +99,7 @@ pub fn menu() -> Vec<Item> {
|
||||
Item::Cmd("Vector Halftone…", "effect.dialog", json!({ "effect": "addon.color.halftone" })),
|
||||
Item::Sep,
|
||||
cmd(print_fixes()),
|
||||
Item::Cmd("Find Nearest Swatch…", nearest::COMMAND, Value::Null),
|
||||
Item::Sep,
|
||||
Item::Sub(
|
||||
"Select by Color Kind",
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
//! Find Nearest Swatch in the interface (Object › Plug-ins › Color Effects › Find Nearest
|
||||
//! Swatch…): a dialog that picks a library (the document's swatches, or a colour library or book)
|
||||
//! and Fill and Stroke, and lists each colour of the selection with its closest swatches and their
|
||||
//! difference, as `addon.color.nearestSwatch` finds them; Apply runs
|
||||
//! `addon.color.applyNearestSwatch`.
|
||||
|
||||
use egui::Ui;
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_color::{Color, Paint};
|
||||
use vectorcraft_engine::cmd::swatchlib::DOCUMENT_SWATCHES;
|
||||
|
||||
use crate::VectorcraftApp;
|
||||
use crate::dialogs::{DialogSpec, form};
|
||||
use crate::panels::swatches;
|
||||
use crate::state::Dialog;
|
||||
use crate::theme::Tokens;
|
||||
use crate::widgets;
|
||||
|
||||
/// The command Apply runs, and the dialog's kind.
|
||||
pub const COMMAND: &str = "addon.color.applyNearestSwatch";
|
||||
pub const KIND: &str = "nearestSwatch";
|
||||
/// The query that lists the matches, and how many of each colour's the dialog shows.
|
||||
const FIND: &str = "addon.color.nearestSwatch";
|
||||
const MATCHES: u64 = 3;
|
||||
const LABEL_W: f32 = 60.0;
|
||||
const CHIP: f32 = 14.0;
|
||||
|
||||
/// The dialog's fields to start with: the document's swatches, fills and strokes.
|
||||
pub(crate) fn fields() -> Value {
|
||||
json!({ "library": DOCUMENT_SWATCHES, "fill": true, "stroke": true })
|
||||
}
|
||||
|
||||
pub(crate) const SPEC: DialogSpec = DialogSpec {
|
||||
heading: |_| tl!("Find Nearest Swatch").to_string(),
|
||||
body,
|
||||
confirm,
|
||||
ok: Some("Apply"),
|
||||
min_width: 340.0,
|
||||
ok_enabled: Some(|app, _| app.session.active().is_some_and(|st| !st.selection.is_empty())),
|
||||
..DialogSpec::FORM
|
||||
};
|
||||
|
||||
/// A colour chip of `hex`, then `text`.
|
||||
fn chip_label(ui: &mut Ui, hex: &str, text: &str, color: egui::Color32) {
|
||||
let (r, _) = ui.allocate_exact_size(egui::vec2(CHIP, CHIP), egui::Sense::hover());
|
||||
widgets::swatch_tile(ui, r, &Paint::solid(Color::from_hex(hex).unwrap_or_default()), false, false);
|
||||
ui.label(egui::RichText::new(text).color(color));
|
||||
}
|
||||
|
||||
fn body(app: &mut VectorcraftApp, ui: &mut Ui, d: &mut Dialog) -> bool {
|
||||
let key = d.str("library");
|
||||
widgets::label_row(ui, tl!("Library:"), LABEL_W, |ui| {
|
||||
if let Some(k) = widgets::combo(ui, "nearest-library", &swatches::library_label(app, &key), 220.0, |ui| swatches::library_list(app, ui, &key))
|
||||
{
|
||||
d.fields.insert("library".into(), json!(k));
|
||||
}
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
form::check(ui, d, "fill", tl!("Fill"));
|
||||
form::check(ui, d, "stroke", tl!("Stroke"));
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
let t = Tokens::get(ui.ctx());
|
||||
if app.session.active().is_none_or(|st| st.selection.is_empty()) {
|
||||
ui.label(egui::RichText::new(tl!("Select objects to find the swatches nearest their colors.")).color(t.text_dim));
|
||||
return false;
|
||||
}
|
||||
let mut p = form::params(d);
|
||||
p["count"] = json!(MATCHES);
|
||||
let found = match app.session.execute(FIND, &p) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
ui.label(egui::RichText::new(crate::i18n::message(crate::i18n::current(), &e.to_string())).color(t.text_dim));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let colors = found["colors"].as_array().cloned().unwrap_or_default();
|
||||
// Each colour, then its matches indented, closest first.
|
||||
egui::ScrollArea::vertical().max_height(280.0).show(ui, |ui| {
|
||||
for c in &colors {
|
||||
ui.horizontal(|ui| chip_label(ui, c["hex"].as_str().unwrap_or_default(), c["values"].as_str().unwrap_or_default(), t.text));
|
||||
for m in c["matches"].as_array().into_iter().flatten() {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(CHIP + 8.0);
|
||||
let de = m["deltaE"].as_f64().unwrap_or_default();
|
||||
chip_label(ui, m["hex"].as_str().unwrap_or_default(), m["name"].as_str().unwrap_or_default(), t.text);
|
||||
ui.label(egui::RichText::new(format!("ΔE {de:.1}")).color(t.text_dim));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
false
|
||||
}
|
||||
|
||||
/// Apply: give each colour its nearest swatch and close.
|
||||
fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result<Value, String> {
|
||||
app.ui.dialog = None;
|
||||
app.run(COMMAND, form::params(d))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::json;
|
||||
use vectorcraft_color::Paint;
|
||||
use vectorcraft_engine::Session;
|
||||
|
||||
use crate::tests_labels::painted_text;
|
||||
use crate::{VectorcraftApp, menus};
|
||||
|
||||
#[test]
|
||||
fn find_nearest_swatch_lists_the_matches_and_applies_the_nearest() {
|
||||
let mut app = VectorcraftApp::new(Session::new(), Default::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
|
||||
app.run("swatch.new", json!({"name": "Brand", "color": "#ff8000", "global": true})).unwrap();
|
||||
app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 40, "height": 40})).unwrap();
|
||||
app.run("paint.setFill", json!({"color": "#ff8010"})).unwrap();
|
||||
app.run("paint.setStroke", json!({"none": true})).unwrap();
|
||||
let entries = menus::menu_entries(&app);
|
||||
let item = entries.iter().find(|e| e.path == ["Object", "Plug-ins", "Color Effects"] && e.label == "Find Nearest Swatch…").unwrap();
|
||||
let (cmd, p) = menus::click_target(&item.label, item.command.as_deref().unwrap(), &item.params);
|
||||
menus::invoke(&mut app, &cmd, p);
|
||||
assert_eq!(app.ui.dialog.as_ref().map(|d| d.kind.as_str()), Some(super::KIND));
|
||||
let shown = painted_text(&mut app, |app, ui| crate::dialogs::show(app, ui.ctx()));
|
||||
for s in ["Find Nearest Swatch", "Library:", "Document Swatches", "Fill", "Stroke", "R=255 G=128 B=16", "Brand", "ΔE", "Apply"] {
|
||||
assert!(shown.contains(s), "{s} in {shown}");
|
||||
}
|
||||
// Another library lists its own swatches.
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("library".into(), json!("web-safe-216"));
|
||||
assert!(painted_text(&mut app, |app, ui| crate::dialogs::show(app, ui.ctx())).contains("#FF6600"));
|
||||
app.ui.dialog.as_mut().unwrap().fields.insert("library".into(), json!("document"));
|
||||
let undo = app.session.doc().unwrap().history.undo.len();
|
||||
crate::dialogs::confirm(&mut app).unwrap();
|
||||
assert!(app.ui.dialog.is_none());
|
||||
let st = app.session.active().unwrap();
|
||||
assert_eq!(st.history.undo.len(), undo + 1);
|
||||
let fill = st.doc.node(st.selection.objects[0]).unwrap().appearance.fill_paint();
|
||||
assert!(matches!(fill, Paint::Solid { swatch: Some(n), .. } if n == "Brand"));
|
||||
// Nothing selected: the dialog says what to do and Apply is off.
|
||||
app.run("select.none", json!({})).unwrap();
|
||||
menus::invoke(&mut app, &cmd, serde_json::Value::Null);
|
||||
assert!(
|
||||
painted_text(&mut app, |app, ui| crate::dialogs::show(app, ui.ctx()))
|
||||
.contains("Select objects to find the swatches nearest their colors.")
|
||||
);
|
||||
assert!(!(super::SPEC.ok_enabled.unwrap())(&app, app.ui.dialog.as_ref().unwrap()), "Apply is off");
|
||||
}
|
||||
}
|
||||
@@ -402,6 +402,7 @@ registry! {
|
||||
RearrangeArtboards: [rearrange_artboards::KIND] => rearrange_artboards::SPEC,
|
||||
PathToolOptions: [crate::addons::pathtools::KIND] => crate::addons::pathtools::OPTIONS_SPEC,
|
||||
DivideDashes: [crate::addons::pathtools::dashes::KIND] => crate::addons::pathtools::dashes::SPEC,
|
||||
NearestSwatch: [crate::addons::color::nearest::KIND] => crate::addons::color::nearest::SPEC,
|
||||
ArrangeTools: [crate::addons::arrange::GRID, crate::addons::arrange::REPLACE, crate::addons::arrange::SIZE, crate::addons::arrange::OPACITY, crate::addons::arrange::SORT] => crate::addons::arrange::SPEC,
|
||||
ShortcutImport: [shortcut_import::KIND] => DialogSpec::window(shortcut_import::show, shortcut_import::confirm),
|
||||
}
|
||||
|
||||
@@ -5829,6 +5829,13 @@ anchor Points: Точки:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` задайте `inkLimit`, `removeWhiteOverprint` или `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Корекциите на мастилата за печат работят върху CMYK документи: първо изберете Файл › Цветен режим на документа › CMYK цвят
|
||||
@msg `{key}` must be 0..{max} `{key}` трябва да е 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Намиране на най-близкия образец…
|
||||
Find Nearest Swatch Намиране на най-близкия образец
|
||||
Apply Nearest Swatch Прилагане на най-близкия образец
|
||||
Select objects to find the swatches nearest their colors. Изберете обекти, за да намерите най-близките до цветовете им образци.
|
||||
@msg select objects or give `color` изберете обекти или задайте `color`
|
||||
@msg `color` is not a colour `color` не е цвят
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Инструмент „Ъгли“
|
||||
Slide Anchor Along Path Плъзгане на опорна точка по пътя
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5953,6 +5953,13 @@ shape Open Otvoren
|
||||
Gap 4 Razmak 4
|
||||
Dash 5 Crtica 5
|
||||
Gap 5 Razmak 5
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Pronađi najbliži uzorak boje…
|
||||
Find Nearest Swatch Pronađi najbliži uzorak boje
|
||||
Apply Nearest Swatch Primijeni najbliži uzorak boje
|
||||
Select objects to find the swatches nearest their colors. Odaberite objekte da pronađete uzorke boja najbliže njihovim bojama.
|
||||
@msg select objects or give `color` odaberite objekte ili navedite `color`
|
||||
@msg `color` is not a colour `color` nije boja
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Alat za uglove
|
||||
Slide Anchor Along Path Klizanje sidra po putanji
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5935,6 +5935,13 @@ anchor Points: Punts:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` indiqueu `inkLimit`, `removeWhiteOverprint` o `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Les correccions de tinta per a impressió funcionen en documents CMYK: trieu primer Fitxer › Mode de color del document › Color CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` ha de ser 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Cerca la mostra més propera…
|
||||
Find Nearest Swatch Cerca la mostra més propera
|
||||
Apply Nearest Swatch Aplica la mostra més propera
|
||||
Select objects to find the swatches nearest their colors. Seleccioneu objectes per trobar les mostres més properes als seus colors.
|
||||
@msg select objects or give `color` seleccioneu objectes o indiqueu `color`
|
||||
@msg `color` is not a colour `color` no és un color
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Eina de cantonades
|
||||
Slide Anchor Along Path Llisca l’ancoratge pel traçat
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5947,6 +5947,13 @@ anchor Points: Body:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` zadejte `inkLimit`, `removeWhiteOverprint` nebo `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Opravy tiskových barev fungují v dokumentech CMYK: nejprve zvolte Soubor › Barevný režim dokumentu › Barvy CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` musí být 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Najít nejbližší položku vzorníku…
|
||||
Find Nearest Swatch Najít nejbližší položku vzorníku
|
||||
Apply Nearest Swatch Použít nejbližší položku vzorníku
|
||||
Select objects to find the swatches nearest their colors. Vyberte objekty, k jejichž barvám chcete najít nejbližší položky vzorníku.
|
||||
@msg select objects or give `color` vyberte objekty nebo zadejte `color`
|
||||
@msg `color` is not a colour `color` není barva
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Nástroj Rohy
|
||||
Slide Anchor Along Path Posunout kotevní bod po cestě
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5845,6 +5845,13 @@ anchor Points: Punkter:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` angiv `inkLimit`, `removeWhiteOverprint` eller `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Trykfarverettelser virker på CMYK-dokumenter: vælg først Filer › Dokumentets farvetilstand › CMYK-farve
|
||||
@msg `{key}` must be 0..{max} `{key}` skal være 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Find nærmeste farveprøve…
|
||||
Find Nearest Swatch Find nærmeste farveprøve
|
||||
Apply Nearest Swatch Anvend nærmeste farveprøve
|
||||
Select objects to find the swatches nearest their colors. Markér objekter for at finde de farveprøver, der ligger tættest på deres farver.
|
||||
@msg select objects or give `color` markér objekter, eller angiv `color`
|
||||
@msg `color` is not a colour `color` er ikke en farve
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Hjørneværktøj
|
||||
Slide Anchor Along Path Skub ankerpunkt langs sti
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5532,6 +5532,13 @@ anchor Points: Punkte:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` geben Sie `inkLimit`, `removeWhiteOverprint` oder `overprintBlack` an
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Druckfarbkorrekturen wirken in CMYK-Dokumenten: Wählen Sie zuerst Datei › Dokumentfarbmodus › CMYK-Farbe
|
||||
@msg `{key}` must be 0..{max} `{key}` muss 0..{max} sein
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Ähnlichstes Farbfeld suchen…
|
||||
Find Nearest Swatch Ähnlichstes Farbfeld suchen
|
||||
Apply Nearest Swatch Ähnlichstes Farbfeld anwenden
|
||||
Select objects to find the swatches nearest their colors. Wählen Sie Objekte aus, um die Farbfelder zu finden, die ihren Farben am nächsten kommen.
|
||||
@msg select objects or give `color` wählen Sie Objekte aus oder geben Sie `color` an
|
||||
@msg `color` is not a colour `color` ist keine Farbe
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Ecken-Werkzeug
|
||||
Slide Anchor Along Path Ankerpunkt entlang des Pfads verschieben
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5898,6 +5898,13 @@ anchor Points: Σημεία:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` δώστε `inkLimit`, `removeWhiteOverprint` ή `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Οι διορθώσεις μελανιών εκτύπωσης ισχύουν σε έγγραφα CMYK: επιλέξτε πρώτα Αρχείο › Λειτουργία χρώματος εγγράφου › Χρώμα CMYK
|
||||
@msg `{key}` must be 0..{max} το `{key}` πρέπει να είναι 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Εύρεση πλησιέστερου δείγματος χρώματος…
|
||||
Find Nearest Swatch Εύρεση πλησιέστερου δείγματος χρώματος
|
||||
Apply Nearest Swatch Εφαρμογή πλησιέστερου δείγματος χρώματος
|
||||
Select objects to find the swatches nearest their colors. Επιλέξτε αντικείμενα για να βρείτε τα δείγματα χρωμάτων που πλησιάζουν περισσότερο τα χρώματά τους.
|
||||
@msg select objects or give `color` επιλέξτε αντικείμενα ή δώστε `color`
|
||||
@msg `color` is not a colour το `color` δεν είναι χρώμα
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Γωνίες (Corner Tool)
|
||||
Slide Anchor Along Path Ολίσθηση σημείου αγκύρωσης κατά μήκος διαδρομής
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 164 and column 5.
|
@@ -5889,6 +5889,13 @@ anchor Points: Puntos:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` indique `inkLimit`, `removeWhiteOverprint` u `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Las correcciones de tinta para impresión funcionan en documentos CMYK: elija primero Archivo › Modo de color del documento › Color CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` debe ser 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Buscar muestra más cercana…
|
||||
Find Nearest Swatch Buscar muestra más cercana
|
||||
Apply Nearest Swatch Aplicar muestra más cercana
|
||||
Select objects to find the swatches nearest their colors. Seleccione objetos para buscar las muestras más cercanas a sus colores.
|
||||
@msg select objects or give `color` seleccione objetos o indique `color`
|
||||
@msg `color` is not a colour `color` no es un color
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Herramienta Esquinas
|
||||
Slide Anchor Along Path Deslizar punto de ancla por el trazado
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5977,6 +5977,13 @@ anchor Points: Pisteet:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` anna `inkLimit`, `removeWhiteOverprint` tai `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Painovärien korjaukset toimivat CMYK-asiakirjoissa: valitse ensin Tiedosto › Asiakirjan väritila › CMYK-väri
|
||||
@msg `{key}` must be 0..{max} `{key}` on oltava 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Etsi lähin värimalli…
|
||||
Find Nearest Swatch Etsi lähin värimalli
|
||||
Apply Nearest Swatch Käytä lähintä värimallia
|
||||
Select objects to find the swatches nearest their colors. Valitse objektit, joiden väreille haluat etsiä lähimmät värimallit.
|
||||
@msg select objects or give `color` valitse objekteja tai anna `color`
|
||||
@msg `color` is not a colour `color` ei ole väri
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Kulmatyökalu
|
||||
Slide Anchor Along Path Liu’uta ankkuripistettä polkua pitkin
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5944,6 +5944,13 @@ anchor Points: Points :
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` indiquez `inkLimit`, `removeWhiteOverprint` ou `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Les corrections d’encres pour l’impression s’appliquent aux documents CMJN : choisissez d’abord Fichier › Mode colorimétrique du document › Couleur CMJN
|
||||
@msg `{key}` must be 0..{max} `{key}` doit être compris entre 0 et {max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Rechercher la nuance la plus proche…
|
||||
Find Nearest Swatch Rechercher la nuance la plus proche
|
||||
Apply Nearest Swatch Appliquer la nuance la plus proche
|
||||
Select objects to find the swatches nearest their colors. Sélectionnez des objets pour trouver les nuances les plus proches de leurs couleurs.
|
||||
@msg select objects or give `color` sélectionnez des objets ou indiquez `color`
|
||||
@msg `color` is not a colour `color` n’est pas une couleur
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Outil Angles
|
||||
Slide Anchor Along Path Faire glisser le point d’ancrage le long du tracé
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5933,6 +5933,13 @@ anchor Points: Pontok:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` adja meg: `inkLimit`, `removeWhiteOverprint` vagy `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first A nyomdai festékjavítások CMYK-dokumentumokon működnek: előbb válassza a Fájl › Dokumentum színmódja › CMYK-szín parancsot
|
||||
@msg `{key}` must be 0..{max} `{key}` értéke 0..{max} lehet
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Legközelebbi színminta keresése…
|
||||
Find Nearest Swatch Legközelebbi színminta keresése
|
||||
Apply Nearest Swatch Legközelebbi színminta alkalmazása
|
||||
Select objects to find the swatches nearest their colors. Jelöljön ki objektumokat a színeikhez legközelebbi színminták megkereséséhez.
|
||||
@msg select objects or give `color` jelöljön ki objektumokat, vagy adja meg ezt: `color`
|
||||
@msg `color` is not a colour a(z) `color` nem szín
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Sarok eszköz
|
||||
Slide Anchor Along Path Horgonypont csúsztatása az útvonal mentén
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5845,6 +5845,13 @@ anchor Points: Titik:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` berikan `inkLimit`, `removeWhiteOverprint`, atau `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Perbaikan Tinta Cetak bekerja pada dokumen CMYK: pilih dulu Berkas › Mode warna dokumen › Warna CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` harus 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Cari Swatch Terdekat…
|
||||
Find Nearest Swatch Cari Swatch Terdekat
|
||||
Apply Nearest Swatch Terapkan Swatch Terdekat
|
||||
Select objects to find the swatches nearest their colors. Pilih objek untuk menemukan swatch yang paling dekat dengan warnanya.
|
||||
@msg select objects or give `color` pilih objek atau berikan `color`
|
||||
@msg `color` is not a colour `color` bukan warna
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Alat sudut
|
||||
Slide Anchor Along Path Geser titik jangkar sepanjang jalur
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2196 and column 5.
|
@@ -5566,6 +5566,13 @@ anchor Points: Punti:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` indica `inkLimit`, `removeWhiteOverprint` o `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Le correzioni inchiostri di stampa funzionano nei documenti CMYK: scegli prima File › Metodo colore documento › Colore CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` deve essere 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Trova campione più vicino…
|
||||
Find Nearest Swatch Trova campione più vicino
|
||||
Apply Nearest Swatch Applica campione più vicino
|
||||
Select objects to find the swatches nearest their colors. Seleziona gli oggetti per trovare i campioni più vicini ai loro colori.
|
||||
@msg select objects or give `color` seleziona gli oggetti o indica `color`
|
||||
@msg `color` is not a colour `color` non è un colore
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Strumento Angoli
|
||||
Slide Anchor Along Path Fai scorrere il punto di ancoraggio lungo il tracciato
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5633,6 +5633,13 @@ anchor Points: ポイント:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` `inkLimit`、`removeWhiteOverprint` または `overprintBlack` を指定してください
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first 印刷インキの修正は CMYK ドキュメントで使用できます。先にファイル › ドキュメントのカラーモード › CMYK カラーを選択してください
|
||||
@msg `{key}` must be 0..{max} `{key}` は 0..{max} にしてください
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… 最も近いスウォッチを検索…
|
||||
Find Nearest Swatch 最も近いスウォッチを検索
|
||||
Apply Nearest Swatch 最も近いスウォッチを適用
|
||||
Select objects to find the swatches nearest their colors. カラーに最も近いスウォッチを探すオブジェクトを選択してください。
|
||||
@msg select objects or give `color` オブジェクトを選択するか `color` を指定してください
|
||||
@msg `color` is not a colour `color` はカラーではありません
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool コーナーツール
|
||||
Slide Anchor Along Path パスに沿ってアンカーポイントをスライド
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5936,6 +5936,13 @@ anchor Points: წერტილები:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` მიუთითეთ `inkLimit`, `removeWhiteOverprint` ან `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first საბეჭდი მელნის შესწორებები მუშაობს CMYK დოკუმენტებზე: ჯერ აირჩიეთ ფაილი › დოკუმენტის ფერის რეჟიმი › CMYK ფერი
|
||||
@msg `{key}` must be 0..{max} `{key}` უნდა იყოს 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… უახლოესი ფერის ნიმუშის პოვნა…
|
||||
Find Nearest Swatch უახლოესი ფერის ნიმუშის პოვნა
|
||||
Apply Nearest Swatch უახლოესი ფერის ნიმუშის გამოყენება
|
||||
Select objects to find the swatches nearest their colors. აირჩიეთ ობიექტები მათ ფერებთან უახლოესი ფერის ნიმუშების საპოვნელად.
|
||||
@msg select objects or give `color` აირჩიეთ ობიექტები ან მიუთითეთ `color`
|
||||
@msg `color` is not a colour `color` ფერი არ არის
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool კუთხეების ხელსაწყო
|
||||
Slide Anchor Along Path საყრდენი წერტილის სრიალი ტრაექტორიაზე
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -5529,6 +5529,13 @@ anchor Points: 포인트:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` `inkLimit`, `removeWhiteOverprint` 또는 `overprintBlack`을 지정하십시오
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first 인쇄 잉크 수정은 CMYK 문서에서 작동합니다. 먼저 파일 › 문서 색상 모드 › CMYK 색상을 선택하십시오
|
||||
@msg `{key}` must be 0..{max} `{key}`은(는) 0..{max}이어야 합니다
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… 가장 가까운 견본 찾기…
|
||||
Find Nearest Swatch 가장 가까운 견본 찾기
|
||||
Apply Nearest Swatch 가장 가까운 견본 적용
|
||||
Select objects to find the swatches nearest their colors. 색상에 가장 가까운 견본을 찾을 개체를 선택하십시오.
|
||||
@msg select objects or give `color` 개체를 선택하거나 `color`를 지정하십시오
|
||||
@msg `color` is not a colour `color`은(는) 색상이 아닙니다
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool 모퉁이 도구
|
||||
Slide Anchor Along Path 패스를 따라 앵커 포인트 밀기
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5889,6 +5889,13 @@ anchor Points: Punten:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` geef `inkLimit`, `removeWhiteOverprint` of `overprintBlack` op
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Drukinktcorrecties werken in CMYK-documenten: kies eerst Bestand › Documentkleurmodus › CMYK-kleur
|
||||
@msg `{key}` must be 0..{max} `{key}` moet 0..{max} zijn
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Dichtstbijzijnde staal zoeken…
|
||||
Find Nearest Swatch Dichtstbijzijnde staal zoeken
|
||||
Apply Nearest Swatch Dichtstbijzijnde staal toepassen
|
||||
Select objects to find the swatches nearest their colors. Selecteer objecten om de stalen te vinden die het dichtst bij hun kleuren liggen.
|
||||
@msg select objects or give `color` selecteer objecten of geef `color` op
|
||||
@msg `color` is not a colour `color` is geen kleur
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Hoekengereedschap
|
||||
Slide Anchor Along Path Ankerpunt langs pad schuiven
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5801,6 +5801,13 @@ anchor Points: Punkty:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` podaj `inkLimit`, `removeWhiteOverprint` lub `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Poprawki farb drukarskich działają w dokumentach CMYK: najpierw wybierz Plik › Tryb koloru dokumentu › Kolor CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` musi wynosić 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Znajdź najbliższą próbkę…
|
||||
Find Nearest Swatch Znajdź najbliższą próbkę
|
||||
Apply Nearest Swatch Zastosuj najbliższą próbkę
|
||||
Select objects to find the swatches nearest their colors. Zaznacz obiekty, aby znaleźć próbki najbliższe ich kolorom.
|
||||
@msg select objects or give `color` zaznacz obiekty lub podaj `color`
|
||||
@msg `color` is not a colour `color` nie jest kolorem
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Narzędzie Narożniki
|
||||
Slide Anchor Along Path Przesuń punkt kontrolny wzdłuż ścieżki
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5864,6 +5864,13 @@ anchor Points: Pontos:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` informe `inkLimit`, `removeWhiteOverprint` ou `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first As Correções de Tinta para Impressão funcionam em documentos CMYK: escolha antes Arquivo › Modo de Cor do Documento › Cor CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` deve ser 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Localizar Amostra Mais Próxima…
|
||||
Find Nearest Swatch Localizar Amostra Mais Próxima
|
||||
Apply Nearest Swatch Aplicar Amostra Mais Próxima
|
||||
Select objects to find the swatches nearest their colors. Selecione objetos para localizar as amostras mais próximas de suas cores.
|
||||
@msg select objects or give `color` selecione objetos ou informe `color`
|
||||
@msg `color` is not a colour `color` não é uma cor
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Ferramenta Cantos
|
||||
Slide Anchor Along Path Deslizar Ponto de Ancoragem pelo Caminho
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -5924,6 +5924,13 @@ anchor Points: Точки:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` задайте `inkLimit`, `removeWhiteOverprint` или `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Исправления печатных красок работают в документах CMYK: сначала выберите Файл › Цветовой режим документа › Цвет CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` должен быть 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Найти ближайший образец…
|
||||
Find Nearest Swatch Найти ближайший образец
|
||||
Apply Nearest Swatch Применить ближайший образец
|
||||
Select objects to find the swatches nearest their colors. Выделите объекты, чтобы найти образцы, ближайшие к их цветам.
|
||||
@msg select objects or give `color` выделите объекты или укажите `color`
|
||||
@msg `color` is not a colour `color` не является цветом
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Инструмент «Углы»
|
||||
Slide Anchor Along Path Сдвинуть опорную точку вдоль контура
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5999,6 +5999,13 @@ shape Open Öppen
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` ange `inkLimit`, `removeWhiteOverprint` eller `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Tryckfärgskorrigeringar fungerar i CMYK-dokument: välj först Fil › Dokumentets färgläge › CMYK-färg
|
||||
@msg `{key}` must be 0..{max} `{key}` måste vara 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Sök närmaste färgruta…
|
||||
Find Nearest Swatch Sök närmaste färgruta
|
||||
Apply Nearest Swatch Använd närmaste färgruta
|
||||
Select objects to find the swatches nearest their colors. Markera objekt för att hitta de färgrutor som ligger närmast deras färger.
|
||||
@msg select objects or give `color` markera objekt eller ange `color`
|
||||
@msg `color` is not a colour `color` är ingen färg
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Hörnverktyget
|
||||
Slide Anchor Along Path Skjut ankarpunkt längs bana
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5904,6 +5904,13 @@ anchor Points: Noktalar:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` `inkLimit`, `removeWhiteOverprint` veya `overprintBlack` verin
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Baskı Mürekkebi Düzeltmeleri CMYK belgelerinde çalışır: önce Dosya › Belge Renk Modu › CMYK Rengi'ni seçin
|
||||
@msg `{key}` must be 0..{max} `{key}` 0..{max} olmalıdır
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… En Yakın Renk Örneğini Bul…
|
||||
Find Nearest Swatch En Yakın Renk Örneğini Bul
|
||||
Apply Nearest Swatch En Yakın Renk Örneğini Uygula
|
||||
Select objects to find the swatches nearest their colors. Renklerine en yakın renk örneklerini bulmak için nesneleri seçin.
|
||||
@msg select objects or give `color` nesneleri seçin veya `color` verin
|
||||
@msg `color` is not a colour `color` bir renk değil
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Köşe Aracı
|
||||
Slide Anchor Along Path Bağlantı Noktasını Yol Boyunca Kaydır
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5546,6 +5546,13 @@ anchor Points: Точки:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` задайте `inkLimit`, `removeWhiteOverprint` або `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Виправлення друкарських фарб працюють у документах CMYK: спершу виберіть Файл › Колірний режим документа › Колір CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` має бути 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Знайти найближчий зразок…
|
||||
Find Nearest Swatch Знайти найближчий зразок
|
||||
Apply Nearest Swatch Застосувати найближчий зразок
|
||||
Select objects to find the swatches nearest their colors. Виділіть об’єкти, щоб знайти зразки, найближчі до їхніх кольорів.
|
||||
@msg select objects or give `color` виділіть об’єкти або вкажіть `color`
|
||||
@msg `color` is not a colour `color` не є кольором
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Інструмент «Кути»
|
||||
Slide Anchor Along Path Зсунути опорну точку вздовж контуру
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 178 and column 5.
|
@@ -5549,6 +5549,13 @@ anchor Points: Điểm:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` hãy cho `inkLimit`, `removeWhiteOverprint` hoặc `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first Sửa mực in hoạt động trên tài liệu CMYK: trước hết chọn Tệp › Chế độ màu tài liệu › Màu CMYK
|
||||
@msg `{key}` must be 0..{max} `{key}` phải là 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… Tìm mẫu màu gần nhất…
|
||||
Find Nearest Swatch Tìm mẫu màu gần nhất
|
||||
Apply Nearest Swatch Áp dụng mẫu màu gần nhất
|
||||
Select objects to find the swatches nearest their colors. Chọn đối tượng để tìm các mẫu màu gần nhất với màu của chúng.
|
||||
@msg select objects or give `color` chọn đối tượng hoặc cung cấp `color`
|
||||
@msg `color` is not a colour `color` không phải là màu
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool Công cụ Góc
|
||||
Slide Anchor Along Path Trượt điểm neo dọc đường dẫn
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 200 and column 5.
|
@@ -5790,6 +5790,13 @@ anchor Points: 点:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` 请指定 `inkLimit`、`removeWhiteOverprint` 或 `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first 印刷油墨修正适用于 CMYK 文档:请先选择 文件 › 文档颜色模式 › CMYK 颜色
|
||||
@msg `{key}` must be 0..{max} `{key}` 必须为 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… 查找最接近的色板…
|
||||
Find Nearest Swatch 查找最接近的色板
|
||||
Apply Nearest Swatch 应用最接近的色板
|
||||
Select objects to find the swatches nearest their colors. 选择对象以查找与其颜色最接近的色板。
|
||||
@msg select objects or give `color` 请选择对象或提供 `color`
|
||||
@msg `color` is not a colour `color` 不是颜色
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool 转角工具
|
||||
Slide Anchor Along Path 沿路径滑动锚点
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5586,6 +5586,13 @@ anchor Points: 點:
|
||||
@msg give `inkLimit`, `removeWhiteOverprint` or `overprintBlack` 請指定 `inkLimit`、`removeWhiteOverprint` 或 `overprintBlack`
|
||||
@msg Print Ink Fixes works on CMYK documents: choose File › Document Color Mode › CMYK Color first 印刷油墨修正適用於 CMYK 文件:請先選擇 檔案 › 文件色彩模式 › CMYK 色彩
|
||||
@msg `{key}` must be 0..{max} `{key}` 必須為 0..{max}
|
||||
# Color Effects add-on: Find Nearest Swatch (Object › Plug-ins › Color Effects).
|
||||
Find Nearest Swatch… 尋找最接近的色票…
|
||||
Find Nearest Swatch 尋找最接近的色票
|
||||
Apply Nearest Swatch 套用最接近的色票
|
||||
Select objects to find the swatches nearest their colors. 選取物件以尋找與其顏色最接近的色票。
|
||||
@msg select objects or give `color` 請選取物件或提供 `color`
|
||||
@msg `color` is not a colour `color` 不是顏色
|
||||
# Path Precision Tools add-on: the Corner Tool and Slide Anchor Along Path.
|
||||
Corner Tool 轉角工具
|
||||
Slide Anchor Along Path 沿路徑滑動錨點
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -69,6 +69,7 @@ pub(super) fn menu_dialog(app: &VectorcraftApp, id: &str) -> Option<(&'static st
|
||||
}
|
||||
"object.vectorHalftone" => (crate::dialogs::halftone::KIND, crate::dialogs::halftone::fields()),
|
||||
crate::addons::pathtools::dashes::COMMAND => (crate::addons::pathtools::dashes::KIND, crate::addons::pathtools::dashes::fields()),
|
||||
crate::addons::color::nearest::COMMAND => (crate::addons::color::nearest::KIND, crate::addons::color::nearest::fields()),
|
||||
"artboard.rearrange" => (crate::dialogs::rearrange_artboards::KIND, crate::dialogs::rearrange_artboards::open_fields(app)),
|
||||
_ => return None,
|
||||
})
|
||||
|
||||
@@ -17,7 +17,7 @@ use vectorcraft_doc::{Node, NodeId, NodeKind, TraceView};
|
||||
use vectorcraft_engine::cmd::TracePresetChange;
|
||||
use vectorcraft_engine::cmd::swatchlib::DOCUMENT_SWATCHES;
|
||||
|
||||
use super::{first_selected, library_panel, pstate, set_pstate, swatches};
|
||||
use super::{first_selected, pstate, set_pstate, swatches};
|
||||
use crate::VectorcraftApp;
|
||||
use crate::widgets::{self, menu_item};
|
||||
|
||||
@@ -46,24 +46,6 @@ fn palette_label(id: &str) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of Document Library's library `key` (the document's swatches or a swatch library); a
|
||||
/// library that is gone shows its key.
|
||||
fn library_label(app: &VectorcraftApp, key: &str) -> String {
|
||||
match swatches::limit_name(app, key) {
|
||||
Some(_) if key == DOCUMENT_SWATCHES => tl!(swatches::DOCUMENT_SWATCHES).to_string(),
|
||||
Some(name) => library_panel::library_name(key, &name).to_string(),
|
||||
None => key.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Document Library's choices: the document's swatches, then the colour libraries (`current`
|
||||
/// checked) → the key chosen.
|
||||
fn library_list(app: &VectorcraftApp, ui: &mut Ui, current: &str) -> Option<String> {
|
||||
let document = menu_item(ui, swatches::DOCUMENT_SWATCHES, true, current == DOCUMENT_SWATCHES).then(|| DOCUMENT_SWATCHES.to_string());
|
||||
ui.separator();
|
||||
library_panel::library_items(ui, &swatches::colour_libraries(app), &|id| id == current).or(document)
|
||||
}
|
||||
|
||||
/// Document Library's Colors choices with the document's swatches: All, then the document's color
|
||||
/// groups (`current` checked; `None` is All) → the choice, `Some(None)` for All.
|
||||
fn color_group_list(app: &VectorcraftApp, ui: &mut Ui, current: Option<&str>) -> Option<Option<String>> {
|
||||
@@ -656,7 +638,9 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
ui.horizontal(|ui| {
|
||||
widgets::dim_label(ui, tl!("Library:"));
|
||||
let key = st.params["library"].as_str().unwrap_or(DOCUMENT_SWATCHES).to_string();
|
||||
if let Some(k) = widgets::combo(ui, "it-library", &library_label(app, &key), 170.0, |ui| library_list(app, ui, &key)) {
|
||||
if let Some(k) =
|
||||
widgets::combo(ui, "it-library", &swatches::library_label(app, &key), 170.0, |ui| swatches::library_list(app, ui, &key))
|
||||
{
|
||||
if k != DOCUMENT_SWATCHES {
|
||||
st.params["colorGroup"] = Value::Null;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use crate::panels::library_panel;
|
||||
use egui::{Event, PointerButton, Pos2, Rect, vec2};
|
||||
|
||||
/// One headless frame of the panel (and its menu) with `events`: the texts drawn, with where.
|
||||
|
||||
@@ -39,8 +39,8 @@ use dnd::drag_of;
|
||||
use dnd::highlighted;
|
||||
pub(crate) use dnd::{click_selection, drag_preview};
|
||||
pub(crate) use libraries::{
|
||||
DOCUMENT_SWATCHES, SwatchLibraries, USER_SLOT, colour_libraries, limit_key, limit_name, load_library, open_library, other_library, user_library,
|
||||
window_menu,
|
||||
DOCUMENT_SWATCHES, SwatchLibraries, USER_SLOT, colour_libraries, library_label, library_list, limit_key, limit_name, load_library, open_library,
|
||||
other_library, user_library, window_menu,
|
||||
};
|
||||
#[cfg(test)]
|
||||
pub(crate) use tiles::describe;
|
||||
|
||||
@@ -16,6 +16,24 @@ pub(crate) fn colour_libraries(app: &VectorcraftApp) -> Vec<LibraryRef> {
|
||||
library_refs(swatchlib::libraries(&app.session).into_iter().filter(|l| l.category != "gradients" && has_colours(&l.id)).collect())
|
||||
}
|
||||
|
||||
/// The name of library choice `key` (the document's swatches or a swatch library, as Image
|
||||
/// Trace's Document Library and Find Nearest Swatch pick one); a library that is gone shows its key.
|
||||
pub(crate) fn library_label(app: &VectorcraftApp, key: &str) -> String {
|
||||
match limit_name(app, key) {
|
||||
Some(_) if key == swatchlib::DOCUMENT_SWATCHES => tl!(DOCUMENT_SWATCHES).to_string(),
|
||||
Some(name) => library_panel::library_name(key, &name).to_string(),
|
||||
None => key.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The library choices: the document's swatches, then the colour libraries (`current` checked) →
|
||||
/// the key chosen.
|
||||
pub(crate) fn library_list(app: &VectorcraftApp, ui: &mut Ui, current: &str) -> Option<String> {
|
||||
let document = menu_item(ui, DOCUMENT_SWATCHES, true, current == swatchlib::DOCUMENT_SWATCHES).then(|| swatchlib::DOCUMENT_SWATCHES.to_string());
|
||||
ui.separator();
|
||||
library_panel::library_items(ui, &colour_libraries(app), &|id| id == current).or(document)
|
||||
}
|
||||
|
||||
/// What Limit to Library menus call the document's own swatches ([`swatchlib::DOCUMENT_SWATCHES`]).
|
||||
pub(crate) const DOCUMENT_SWATCHES: &str = "Document Swatches";
|
||||
|
||||
|
||||
+24
@@ -6385,6 +6385,30 @@ one, out of range values and a request with no fix on.
|
||||
{"name":"run_command","arguments":{"command":"addon.color.printFixes","params":{"scope":"document","inkLimit":300,"removeWhiteOverprint":true,"overprintBlack":100}}}
|
||||
```
|
||||
|
||||
### Find Nearest Swatch
|
||||
|
||||
`addon.color.nearestSwatch {library?, color?, fill?, stroke?, count?, ids?}` (a query: no undo step) lists, for each
|
||||
colour of the selected objects, the colour swatches of a library closest to it, closest first, by CIEDE2000 difference
|
||||
(`deltaE`: under 1 hardly tells apart, about 2 to 3 close) (#4923). `library` is a swatch library's id or name, as
|
||||
`swatch.library.list` lists them: the built-in ones, and the libraries and colour books (`.acb`, `.ase`, `.gpl`) the
|
||||
user saved or loaded with `swatch.library.load`; `"document"` (the default) is the document's own swatches. The colours
|
||||
are the solid colours and gradient stops of the selection's fills (`fill`, true) and strokes (`stroke`, true), of the
|
||||
objects inside it and of its type, once each, the first 100; `color` looks one colour up instead. `count` is 1…50 (5).
|
||||
Tint swatches, None and Registration aren't matched. → `{library, colors: [{values, hex, matches: [{name, values, hex,
|
||||
spot, deltaE}]}]}` (`values` as a default swatch name reads them: `C=10 M=20 Y=30 K=0`, `R=255 G=128 B=0`…)
|
||||
|
||||
`addon.color.applyNearestSwatch {library?, fill?, stroke?, ids?}` (Object › Plug-ins › Color Effects › Find Nearest
|
||||
Swatch…, whose dialog lists each colour's three closest swatches with their difference; Apply runs it) gives each solid
|
||||
colour and gradient stop of the selected objects' fills and strokes (and gradient meshes) the colour of its nearest
|
||||
swatch, as one undo step. A global or spot swatch's colour links to it. The library's swatches the colours take are
|
||||
added to the document's first, as `swatch.library.add` adds them, so a spot colour from a colour book stays spot;
|
||||
images and patterns keep their colours. → `{changed, swatches: [the document swatches the colours took], added}`
|
||||
|
||||
```json
|
||||
{"name":"run_command","arguments":{"command":"addon.color.nearestSwatch","params":{"library":"web-safe-216","color":{"c":10,"m":80,"y":90,"k":0},"count":3}}}
|
||||
{"name":"run_command","arguments":{"command":"addon.color.applyNearestSwatch","params":{"library":"document","stroke":false}}}
|
||||
```
|
||||
|
||||
## Arrange Tools add-on
|
||||
|
||||
Arrange Tools is a built-in add-on that lays out, swaps, replaces and sizes selected objects: its commands are
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Parity with Adobe Illustrator
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Path Precision Tools add-on: Expand Dashes into Paths, #4922; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Color Effects add-on: Find Nearest Swatch, #4923; scores unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -1460,10 +1460,15 @@ Symbols area (#4938), from the public symbol documentation ([create and place sy
|
||||
|
||||
A VectorCraft addition, not a feature of the reference app, so no area score moves. Object › Plug-ins › Document Tools › Export All Open Documents as PDF (or as SVG) asks for a folder and writes a copy of every open document there, each named after its document with `-2`, `-3`… added when a name is taken, so no file is replaced (`addon.document.exportAllOpen {folder, format?}`, #4920). Each copy is written as Save a Copy writes it: the documents keep their paths, titles and modified state, and the active one stays active. A document that can't be written is named in the status bar and the others are still written. Tests: `addons::document::tests::export_all_open_documents_writes_each_to_the_folder_picked` (ui-egui), `cmd::addons::document::tests::export_all_open_documents_writes_each_and_reports_failures` (engine).
|
||||
|
||||
## Color Effects add-on: Find Nearest Swatch (2026-11-01)
|
||||
|
||||
A VectorCraft addition, not a feature of the reference app, so no area score moves. Object › Plug-ins › Color Effects › Find Nearest Swatch… lists each colour of the selection (fills and strokes, as ticked; solid colours and gradient stops, inside groups and type) with the three swatches of the chosen library closest to it by CIEDE2000 difference, with that difference (`addon.color.nearestSwatch`, #4923). The library is the document's swatches, a built-in library, or a library or colour book the user saved or loaded (no colour book data ships with VectorCraft). Apply gives each colour its nearest swatch as one undo step (`addon.color.applyNearestSwatch`): global and spot swatches link, and a library's swatches the colours take are added to the document first, so a spot colour stays spot. Remaining: typing a colour to look up in the dialog (the command takes `color`), and applying a match other than the nearest. Tests: `cmd::addons::color::nearest::tests` (engine), `addons::color::nearest::tests::find_nearest_swatch_lists_the_matches_and_applies_the_nearest` (ui-egui).
|
||||
|
||||
## Revision history
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-01 | minor | Color Effects add-on (a VectorCraft addition): Find Nearest Swatch (#4923); evidence added; scores unchanged. |
|
||||
| 2026-11-01 | minor | Document Tools add-on (a VectorCraft addition): Export All Open Documents as PDF or SVG (#4920); evidence added; scores unchanged. |
|
||||
| 2026-11-01 | minor | Path Precision Tools add-on (a VectorCraft addition): Expand Dashes into Paths (#4922); evidence added; scores unchanged. |
|
||||
| 2026-11-01 | minor | Type core: the Glyphs panel highlights the character selected with the Type tool and scrolls it into view (#4908); evidence added; scores unchanged. |
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
# UI and interaction parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Artboards panel: drag a row to reorder the artboards, #4687) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (Color Effects add-on: Find Nearest Swatch, #4923) · **Target:** Adobe Illustrator 2026 (30.x)
|
||||
|
||||
## Feature submission evidence
|
||||
|
||||
@@ -352,6 +352,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
|
||||
| Artwork Cleanup add-on (VectorCraft addition): Object › Plug-ins › Artwork Cleanup opens its panel, which checks the selection or the document for 16 kinds of issue, lists them with counts, and shows or fixes the picked rows or all of them, each fix one undo step; Simplify Anchors (Keep Shape), Rejoin Path Pieces and Deep Ungroup open their options first | done | `addon.cleanup.*`, `crates/ui-egui/src/addons/cleanup.rs` and its tests; not a feature of the reference app, so it is not scored |
|
||||
| Artwork Cleanup add-on text tools (VectorCraft addition): the panel's Text row, which the panel can hide, and Object › Plug-ins › Artwork Cleanup set the alignment of point type keeping its place, break type into lines (Shift-click: paragraphs), words or glyphs, split type at the cursor, reset a text transform (Alt-click: and its horizontal scale), combine point type, remove line or paragraph breaks and replace missing fonts, each one undo step | done | `addon.cleanup.*` text commands, `crates/ui-egui/src/addons/cleanup.rs` and its tests; a VectorCraft addition, so it is not scored |
|
||||
| Color Effects add-on (VectorCraft addition): live Exposure, Desaturate and Invert Colors in Effect › Color Effects and Object › Plug-ins › Color Effects; its panel picks a colour adjustment and its values and adds it as a live effect or applies it as a filter, into the colours, as one undo step; Select by Color Kind selects the objects that use spot colours, carry colour effects, or are RGB, CMYK or grayscale images; Vector Halftone draws an object as halftone dots live (the dots Object › Vector Halftone makes), which Expand Appearance and the exporters write as paths; Duotone prints each colour's tone with one to four inks (a tint of a spot tone's swatch, or the CMYK mix of several), live or as a filter, its dialog a row per tone and the picked tone's curve; Print Ink Fixes (a CMYK document's ink limit, white overprint removed, black overprint set) opens its options from the submenu and the panel's Inks | done | `addon.color.*`, `crates/ui-egui/src/addons/color.rs` and its tests; not a feature of the reference app, so it is not scored |
|
||||
| Color Effects add-on (VectorCraft addition): Object › Plug-ins › Color Effects › Find Nearest Swatch… picks a Library (Document Swatches, a built-in library, or a library or colour book the user saved or loaded) and Fill and Stroke, lists each colour of the selection with its three closest swatches (chip, name, ΔE 2000), and Apply gives each colour its nearest swatch (global and spot swatches linked; a library's swatches added to the document first), one undo step | done | #4923; `addon.color.nearestSwatch`, `addon.color.applyNearestSwatch`, `crates/engine/src/cmd/addons/color/nearest.rs`, `crates/ui-egui/src/addons/color/nearest.rs` and their tests; not a feature of the reference app, so it is not scored |
|
||||
|
||||
## Look and feel
|
||||
|
||||
@@ -394,6 +395,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-11-01 | minor | Color Effects add-on (a VectorCraft addition): Find Nearest Swatch (#4923); scores and estimates unchanged |
|
||||
| 2026-11-01 | minor | Artboards panel: a row dragged above or below another reorders the artboards (#4687); scores and estimates unchanged |
|
||||
| 2026-11-01 | minor | Document Tools add-on (a VectorCraft addition): Export All Open Documents as PDF or SVG (#4920); scores and estimates unchanged |
|
||||
| 2026-11-01 | minor | Path Precision Tools add-on (a VectorCraft addition): Expand Dashes into Paths (#4922); scores and estimates unchanged |
|
||||
|
||||
Reference in New Issue
Block a user