mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-26 10:47:11 -06:00
Image Trace: Document Library traces with a color group from the Swatches panel
Squashed from #3975 onto main.
This commit is contained in:
@@ -129,7 +129,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Make",
|
||||
["Object", "Image Trace"],
|
||||
None,
|
||||
"{id?: image or Image Trace group (default: selection), preset?: name (imageTrace.presets), enhanced?: false (the preset's enhanced version: with Auto Grouping, and with Shapes in all but High Fidelity Photo; Flat Logo has none and is traced as it is), params?: {mode: \"blackAndWhite\"|\"grayscale\"|\"color\"|\"logo\", threshold: 0-255, palette: \"limited\"|\"fullTone\"|\"automatic\"|\"documentLibrary\" (color mode; limited: the `colors` best colours, fullTone: as many as the tones need, more with colorDetail, automatic: flat art with its own colours, else fullTone, documentLibrary: at most `colors` of the library's colours, as they are), colors: 2-256, colorDetail: 0-100 (fullTone, automatic), library: \"document\" (the document's swatches) or a swatch library id or name (swatch.library.list; documentLibrary), paths: 0-100, corners: 0-100, noise: px, method: \"abutting\"|\"overlapping\", ignoreWhite (leave out white areas), ignoreColor?: \"#rrggbb\" (with ignoreWhite: the colour left out instead of white), snapCurvesToLines, shapes: false (filled outlines that are a circle, an ellipse, a rectangle or a regular polygon come out as that live shape), autoGrouping: false (each path that has others inside it is grouped with them), gradients: false (grayscale and color: an area whose colour changes evenly along one direction is one path with a linear gradient fill), fills: true, strokes: false (Create: lines up to strokeWidth wide become stroked centre lines; without fills, wider areas become stroked outlines), strokeWidth: px (10), logoColors?: [\"#rrggbb\"…] (mode logo: flat-colour logos only; colours found automatically or named here, white is always its own colour, at most ten; noise = areas under noise/10 px ignored; edges to a fraction of a pixel, sharp corners restored, lines and circles snapped; enclosed transparent areas are painted white unless ignoreWhite makes them holes; fills/strokes are ignored; gradients and photos are refused)}, view?: as imageTrace.setView (default: the traced object's own, else tracingResult), ids?: [id…] (instead of id)} → {id, paths, anchors, colors, warnings: [text…] (the image is over 1500 px on a side, so it traces more slowly; or it was traced scaled down; Flat Logo names only the size it traced a larger image at)}",
|
||||
"{id?: image or Image Trace group (default: selection), preset?: name (imageTrace.presets), enhanced?: false (the preset's enhanced version: with Auto Grouping, and with Shapes in all but High Fidelity Photo; Flat Logo has none and is traced as it is), params?: {mode: \"blackAndWhite\"|\"grayscale\"|\"color\"|\"logo\", threshold: 0-255, palette: \"limited\"|\"fullTone\"|\"automatic\"|\"documentLibrary\" (color mode; limited: the `colors` best colours, fullTone: as many as the tones need, more with colorDetail, automatic: flat art with its own colours, else fullTone, documentLibrary: at most `colors` of the library's colours, as they are), colors: 2-256, colorDetail: 0-100 (fullTone, automatic), library: \"document\" (the document's swatches) or a swatch library id or name (swatch.library.list; documentLibrary), colorGroup?: name (color mode, documentLibrary with library \"document\": the colors of that document color group instead of every swatch; \"\" is every swatch), paths: 0-100, corners: 0-100, noise: px, method: \"abutting\"|\"overlapping\", ignoreWhite (leave out white areas), ignoreColor?: \"#rrggbb\" (with ignoreWhite: the colour left out instead of white), snapCurvesToLines, shapes: false (filled outlines that are a circle, an ellipse, a rectangle or a regular polygon come out as that live shape), autoGrouping: false (each path that has others inside it is grouped with them), gradients: false (grayscale and color: an area whose colour changes evenly along one direction is one path with a linear gradient fill), fills: true, strokes: false (Create: lines up to strokeWidth wide become stroked centre lines; without fills, wider areas become stroked outlines), strokeWidth: px (10), logoColors?: [\"#rrggbb\"…] (mode logo: flat-colour logos only; colours found automatically or named here, white is always its own colour, at most ten; noise = areas under noise/10 px ignored; edges to a fraction of a pixel, sharp corners restored, lines and circles snapped; enclosed transparent areas are painted white unless ignoreWhite makes them holes; fills/strokes are ignored; gradients and photos are refused)}, view?: as imageTrace.setView (default: the traced object's own, else tracingResult), ids?: [id…] (instead of id)} → {id, paths, anchors, colors, warnings: [text…] (the image is over 1500 px on a side, so it traces more slowly; or it was traced scaled down; Flat Logo names only the size it traced a larger image at)}",
|
||||
has_selection_or_ids,
|
||||
|s, p| trace_make(s, p, false)
|
||||
),
|
||||
@@ -1000,18 +1000,49 @@ fn trace_params(c: &str, p: &Value) -> Result<tr::TraceParams> {
|
||||
if !(params.stroke_width.is_finite() && params.stroke_width > 0.0) {
|
||||
return Err(bad(c, "strokeWidth must be a positive number of pixels"));
|
||||
}
|
||||
// A color group is refused unless the trace uses it: Color mode with Document Library and the
|
||||
// document's swatches.
|
||||
if params.color_group.as_deref().is_some_and(|g| !g.is_empty()) {
|
||||
if params.palette != tr::Palette::DocumentLibrary {
|
||||
return Err(bad(c, "`colorGroup` needs `palette: \"documentLibrary\"`"));
|
||||
}
|
||||
if params.library != super::swatchlib::DOCUMENT_SWATCHES {
|
||||
return Err(bad(c, "`colorGroup` needs `library: \"document\"`"));
|
||||
}
|
||||
if params.mode != tr::Mode::Color {
|
||||
return Err(bad(c, "`colorGroup` needs `mode: \"color\"`"));
|
||||
}
|
||||
}
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
/// Document Library in Color mode: look the library's colours up into `params.swatches` → each
|
||||
/// one as traced (sRGB) with the colour to fill with. Errors name command `c`.
|
||||
/// Document Library with `colorGroup`: the solid colors of the active document's color group
|
||||
/// `name` (so named exactly, else ignoring case). Errors name command `c`.
|
||||
/// ([`trace_params`] has checked that the library is the document's swatches.)
|
||||
fn trace_group_colors(c: &str, s: &Session, name: &str) -> Result<Vec<Color>> {
|
||||
let groups = &s.doc()?.doc.swatch_groups;
|
||||
let lower = name.to_lowercase();
|
||||
let group = groups
|
||||
.iter()
|
||||
.find(|g| g.name == name)
|
||||
.or_else(|| groups.iter().find(|g| g.name.to_lowercase() == lower))
|
||||
.ok_or_else(|| bad(c, format!("no color group `{name}` in the document (see swatch.list)")))?;
|
||||
Ok(group.swatches.iter().filter_map(|w| w.paint.color()).collect())
|
||||
}
|
||||
|
||||
/// Document Library in Color mode: look the library's colors (or its color group's) up into
|
||||
/// `params.swatches` → each one as traced (sRGB) with the color to fill with. Errors name command `c`.
|
||||
fn trace_library(c: &str, s: &Session, params: &mut tr::TraceParams) -> Result<Vec<([u8; 3], Color)>> {
|
||||
if params.mode != tr::Mode::Color || params.palette != tr::Palette::DocumentLibrary {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
let key = params.library.as_str();
|
||||
let colors = super::swatchlib::library_colors(s, key)
|
||||
.ok_or_else(|| bad(c, format!("no swatch library `{key}` (see swatch.library.list; \"document\": the document's swatches)")))?;
|
||||
let group = params.color_group.as_deref().filter(|g| !g.is_empty());
|
||||
let key = group.unwrap_or(params.library.as_str());
|
||||
let colors = match group {
|
||||
Some(name) => trace_group_colors(c, s, name)?,
|
||||
None => super::swatchlib::library_colors(s, key)
|
||||
.ok_or_else(|| bad(c, format!("no swatch library `{key}` (see swatch.library.list; \"document\": the document's swatches)")))?,
|
||||
};
|
||||
if colors.is_empty() {
|
||||
return Err(bad(c, format!("`{key}` has no colours")));
|
||||
}
|
||||
|
||||
@@ -2802,6 +2802,71 @@ fn image_trace_palettes_and_swatch_libraries() {
|
||||
assert!(bad(json!({"palette": "rainbow"})));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn image_trace_document_library_uses_a_color_group() {
|
||||
let mut s = session();
|
||||
let r = vectorcraft_trace::Raster::from_fn(60, 60, |x, y| match (x < 30, y < 30) {
|
||||
(true, _) => [200, 40, 40, 255],
|
||||
(false, true) => [40, 160, 60, 255],
|
||||
(false, false) => [50, 60, 200, 255],
|
||||
});
|
||||
add_image(&mut s, &r, Affine::IDENTITY);
|
||||
// Ungrouped swatches of the image's own colors, and a group of colors a little off them.
|
||||
s.execute("swatch.new", &json!({"colors": ["#c82828", "#28a03c", "#323cc8"]})).unwrap();
|
||||
s.execute("swatch.newGroup", &json!({"name": "Brand", "colors": ["#b43c3c", "#3c8c50", "#4650b4"]})).unwrap();
|
||||
s.execute("swatch.newGroup", &json!({"name": "Empty"})).unwrap();
|
||||
s.execute("swatch.newGroup", &json!({"name": "Été", "colors": ["#b43c3c", "#3c8c50", "#4650b4"]})).unwrap();
|
||||
let hex = |c: &Color| {
|
||||
let [r, g, b, _] = c.to_rgba8(1.0);
|
||||
format!("#{r:02x}{g:02x}{b:02x}")
|
||||
};
|
||||
let trace = |s: &mut Session, extra: Value| {
|
||||
let mut params = json!({"mode": "color", "palette": "documentLibrary", "library": "document", "colors": 3});
|
||||
params.as_object_mut().unwrap().extend(extra.as_object().unwrap().clone());
|
||||
s.execute("imageTrace.makeAndExpand", &json!({"params": params}))
|
||||
};
|
||||
let fills = |s: &Session, id: &Value| -> Vec<String> {
|
||||
let g = node(s, NodeId(id.as_u64().unwrap()));
|
||||
let mut v: Vec<String> = g.children().unwrap().iter().filter_map(|n| n.appearance.fill_paint().color()).map(|c| hex(&c)).collect();
|
||||
v.sort();
|
||||
v.dedup();
|
||||
v
|
||||
};
|
||||
// Every swatch: the image's own colors win.
|
||||
let r = trace(&mut s, json!({})).unwrap();
|
||||
assert_eq!(fills(&s, &r["id"]), ["#28a03c", "#323cc8", "#c82828"]);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
// The group: its colors only, and its name matches whatever its case.
|
||||
for name in ["Brand", "brand", "Été", "été", "ÉTÉ"] {
|
||||
let r = trace(&mut s, json!({"colorGroup": name})).unwrap();
|
||||
assert_eq!(fills(&s, &r["id"]), ["#3c8c50", "#4650b4", "#b43c3c"], "{name}");
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
}
|
||||
// An empty name is every swatch.
|
||||
let r = trace(&mut s, json!({"colorGroup": ""})).unwrap();
|
||||
assert_eq!(fills(&s, &r["id"]), ["#28a03c", "#323cc8", "#c82828"]);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
let err = |s: &mut Session, extra: Value| trace(s, extra).unwrap_err().to_string();
|
||||
assert!(err(&mut s, json!({"colorGroup": "Nope"})).contains("no color group `Nope`"));
|
||||
assert!(err(&mut s, json!({"colorGroup": "Empty"})).contains("`Empty` has no colours"));
|
||||
assert!(err(&mut s, json!({"colorGroup": "Brand", "library": "web-safe-216"})).contains("needs `library: \"document\"`"));
|
||||
// Every other palette refuses a group too, in any mode; an empty name is no group.
|
||||
for palette in ["limited", "fullTone", "automatic"] {
|
||||
let e = err(&mut s, json!({"colorGroup": "Brand", "palette": palette}));
|
||||
assert!(e.contains("`colorGroup` needs `palette: \"documentLibrary\"`"), "{palette}: {e}");
|
||||
}
|
||||
let e = err(&mut s, json!({"colorGroup": "Brand", "mode": "grayscale", "palette": "limited"}));
|
||||
assert!(e.contains("needs `palette: \"documentLibrary\"`"), "{e}");
|
||||
// Document Library uses the group in Color mode only.
|
||||
for mode in ["blackAndWhite", "grayscale", "logo"] {
|
||||
let e = err(&mut s, json!({"colorGroup": "Brand", "mode": mode}));
|
||||
assert!(e.contains("`colorGroup` needs `mode: \"color\"`"), "{mode}: {e}");
|
||||
}
|
||||
s.execute("imageTrace.makeAndExpand", &json!({"params": {"mode": "color", "palette": "limited", "colors": 3, "colorGroup": ""}})).unwrap();
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
trace(&mut s, json!({"mode": "grayscale", "colorGroup": ""})).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn image_trace_create_strokes_makes_stroked_centre_lines() {
|
||||
let mut s = session();
|
||||
|
||||
@@ -281,8 +281,12 @@ pub struct TraceParams {
|
||||
/// Document Library: the swatch library, `"document"` (the document's swatches) or a library id
|
||||
/// or name. The caller looks its colours up into `swatches`.
|
||||
pub library: String,
|
||||
/// Document Library with the document's swatches: the name of the color group whose colors are
|
||||
/// used. `None` (or empty) uses every swatch. `imageTrace.make` refuses a name with any other
|
||||
/// palette, library or mode.
|
||||
pub color_group: Option<String>,
|
||||
/// Document Library: the library's colours (sRGB). Not saved: they are looked up from
|
||||
/// `library` at every trace.
|
||||
/// `library` (and `color_group`) at every trace.
|
||||
#[serde(skip)]
|
||||
pub swatches: Vec<[u8; 3]>,
|
||||
/// Paths (fidelity) 0–100: higher follows the pixels more tightly.
|
||||
@@ -333,6 +337,7 @@ impl Default for TraceParams {
|
||||
colors: 6,
|
||||
color_detail: 50.0,
|
||||
library: "document".into(),
|
||||
color_group: None,
|
||||
swatches: vec![],
|
||||
paths: 50.0,
|
||||
corners: 75.0,
|
||||
|
||||
@@ -5399,6 +5399,10 @@ mark-style Japanese Japonské
|
||||
Snap to Perpendicular Přichytávat ke kolmici
|
||||
@msg unknown snap option `{key}` (use {options}) neznámá možnost přichytávání `{key}` (použijte {options})
|
||||
Gap Length: Délka mezery:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` vyžaduje `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` vyžaduje `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` vyžaduje `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) skupina barev `{name}` v dokumentu neexistuje (viz swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Režim Ploché logo vektorizoval obraz v rozlišení {_1} × {_2} pixelů, zmenšený průměrováním z {_3} × {_4}.
|
||||
Artboard {n} of {total} Pracovní plocha {n} z {total}
|
||||
File {n} of {total} Soubor {n} z {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4978,6 +4978,10 @@ effect Soft Weich
|
||||
Snap to Perpendicular An Senkrechter ausrichten
|
||||
@msg unknown snap option `{key}` (use {options}) unbekannte Einrastoption `{key}` (möglich: {options})
|
||||
Gap Length: Lückenlänge:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` erfordert `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` erfordert `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` erfordert `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) keine Farbgruppe `{name}` im Dokument (siehe swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Der Modus „Flaches Logo“ hat das Bild mit {_1} × {_2} Pixeln nachgezeichnet, durch Mittelung verkleinert von {_3} × {_4}.
|
||||
Artboard {n} of {total} Zeichenfläche {n} von {total}
|
||||
File {n} of {total} Datei {n} von {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5351,6 +5351,10 @@ effect Points Σημεία
|
||||
Snap to Perpendicular Προσκόλληση σε κάθετο
|
||||
@msg unknown snap option `{key}` (use {options}) άγνωστη επιλογή προσκόλλησης `{key}` (χρησιμοποιήστε {options})
|
||||
Gap Length: Μήκος κενού:
|
||||
@msg `colorGroup` needs `library: "document"` το `colorGroup` απαιτεί `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` το `colorGroup` απαιτεί `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` το `colorGroup` απαιτεί `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) δεν υπάρχει ομάδα χρωμάτων `{name}` στο έγγραφο (δείτε swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Η λειτουργία Επίπεδο λογότυπο ανίχνευσε την εικόνα σε {_1} × {_2} εικονοστοιχεία, σμικρυμένη με μέσο όρο από {_3} × {_4}.
|
||||
Artboard {n} of {total} Πίνακας σχεδίασης {n} από {total}
|
||||
File {n} of {total} Αρχείο {n} από {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2070 and column 19.
|
@@ -5341,6 +5341,10 @@ mark-style Japanese Japonesas
|
||||
Snap to Perpendicular Ajustar a perpendicular
|
||||
@msg unknown snap option `{key}` (use {options}) opción de ajuste desconocida `{key}` (use {options})
|
||||
Gap Length: Longitud del hueco:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` requiere `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` requiere `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` requiere `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) no existe el grupo de colores `{name}` en el documento (consulta swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. El modo Logotipo plano calcó la imagen a {_1} × {_2} píxeles, reducida promediando desde {_3} × {_4}.
|
||||
Artboard {n} of {total} Mesa de trabajo {n} de {total}
|
||||
File {n} of {total} Archivo {n} de {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5363,6 +5363,10 @@ mark-style Japanese Japanilainen
|
||||
Snap to Perpendicular Kohdista kohtisuoraan
|
||||
@msg unknown snap option `{key}` (use {options}) tuntematon tartuntavalinta `{key}` (käytä: {options})
|
||||
Gap Length: Aukon pituus:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` edellyttää arvoa `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` edellyttää arvoa `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` edellyttää arvoa `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) asiakirjassa ei ole väriryhmää `{name}` (ks. swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Tasainen logo -tila jäljitti kuvan kokoon {_1} × {_2} kuvapistettä keskiarvoistamalla pienennettynä koosta {_3} × {_4}.
|
||||
Artboard {n} of {total} Piirtoalusta {n}/{total}
|
||||
File {n} of {total} Tiedosto {n}/{total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5398,6 +5398,10 @@ theme Appearance Apparence
|
||||
Snap to Perpendicular Magnétisme de la perpendiculaire
|
||||
@msg unknown snap option `{key}` (use {options}) option de magnétisme inconnue `{key}` (utilisez {options})
|
||||
Gap Length: Longueur de lacune :
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` nécessite `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` nécessite `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` nécessite `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) aucun groupe de couleurs `{name}` dans le document (voir swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Le mode Logo en aplats a vectorisé l’image à {_1} × {_2} pixels, réduite par moyennage de {_3} × {_4}.
|
||||
Artboard {n} of {total} Plan de travail {n} sur {total}
|
||||
File {n} of {total} Fichier {n} sur {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5385,6 +5385,10 @@ imageTrace Outline Körvonal
|
||||
Snap to Perpendicular Illesztés merőlegesre
|
||||
@msg unknown snap option `{key}` (use {options}) ismeretlen illesztési beállítás: `{key}` (használható: {options})
|
||||
Gap Length: Rés hossza:
|
||||
@msg `colorGroup` needs `library: "document"` a `colorGroup` használatához `library: "document"` szükséges
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` a `colorGroup` használatához `palette: "documentLibrary"` szükséges
|
||||
@msg `colorGroup` needs `mode: "color"` a `colorGroup` használatához `mode: "color"` szükséges
|
||||
@msg no color group `{name}` in the document (see swatch.list) nincs ilyen színcsoport a dokumentumban: `{name}` (lásd: swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Az Egyszínű logó mód {_1} × {_2} képponton vektorizálta a képet, {_3} × {_4} méretről átlagolással kicsinyítve.
|
||||
Artboard {n} of {total} Rajztábla: {n} / {total}
|
||||
File {n} of {total} Fájl: {n} / {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5012,6 +5012,10 @@ lighting Light Luce
|
||||
Snap to Perpendicular Aggancia alla perpendicolare
|
||||
@msg unknown snap option `{key}` (use {options}) opzione di aggancio sconosciuta `{key}` (usare {options})
|
||||
Gap Length: Lunghezza lacuna:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` richiede `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` richiede `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` richiede `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) nessun gruppo colori `{name}` nel documento (vedi swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. La modalità Logo piatto ha vettorializzato l’immagine a {_1} × {_2} pixel, ridotta per media da {_3} × {_4}.
|
||||
Artboard {n} of {total} Tavola da disegno {n} di {total}
|
||||
File {n} of {total} File {n} di {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5052,6 +5052,10 @@ lighting Light ライト
|
||||
Snap to Perpendicular 垂線にスナップ
|
||||
@msg unknown snap option `{key}` (use {options}) 不明なスナップオプション `{key}` ({options} を使用してください)
|
||||
Gap Length: ギャップの長さ:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` には `library: "document"` が必要です
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` には `palette: "documentLibrary"` が必要です
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` には `mode: "color"` が必要です
|
||||
@msg no color group `{name}` in the document (see swatch.list) ドキュメントにカラーグループ `{name}` が見つかりません (swatch.list を参照)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. フラットロゴモードは画像を {_3} × {_4} から平均化して縮小した {_1} × {_2} ピクセルでトレースしました。
|
||||
Artboard {n} of {total} アートボード {n} / {total}
|
||||
File {n} of {total} ファイル {n} / {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5237,6 +5237,10 @@ imageTrace Outline კონტური
|
||||
@msg Save writes {_1}, not {_2}: use file.saveAsTemplate to write it „შენახვა“ წერს ფორმატს {_1} და არა {_2}: ამისთვის გამოიყენეთ file.saveAsTemplate
|
||||
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. გამოსახულება არის {_1} × {_2} პიქსელი, ანუ ერთ მხარეზე {LARGE_TRACE_SIDE}-ზე მეტი: ის ვექტორიზდება, მაგრამ უფრო ნელა. ნაკლები სიზუსტის პრესეტი ან გამოსახულების უფრო პატარა ასლი უფრო სწრაფად ვექტორიზდება.
|
||||
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). გამოსახულება ვექტორიზდა {_1} × {_2} პიქსელზე, შემცირდა {_3} × {_4}-დან (მაქსიმუმ {_5} მეგაპიქსელი).
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup`-ს სჭირდება `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup`-ს სჭირდება `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup`-ს სჭირდება `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) დოკუმენტში ფერების ჯგუფი `{name}` არ არის (იხ. swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. ბრტყელი ლოგოს რეჟიმში გამოსახულება ვექტორიზდა {_1} × {_2} პიქსელზე, საშუალოს გამოთვლით შემცირდა {_3} × {_4}-დან.
|
||||
@msg `{given}` isn't a library panel (see window.swatchLibrary) `{given}` ბიბლიოთეკის პანელი არ არის (იხ. window.swatchLibrary)
|
||||
@msg `{key}` must be a #rrggbb color `{key}` უნდა იყოს #rrggbb ფერი
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -4975,6 +4975,10 @@ lighting Light 광원
|
||||
Snap to Perpendicular 수직선에 스냅
|
||||
@msg unknown snap option `{key}` (use {options}) 알 수 없는 스냅 옵션 `{key}` ({options} 중에서 사용하세요)
|
||||
Gap Length: 간격 길이:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup`에는 `library: "document"`가 필요합니다
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup`에는 `palette: "documentLibrary"`가 필요합니다
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup`에는 `mode: "color"`가 필요합니다
|
||||
@msg no color group `{name}` in the document (see swatch.list) 문서에 색상 그룹 `{name}`이(가) 없습니다(swatch.list 참조)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. 단색 로고 모드에서 이미지를 {_3} × {_4}에서 평균을 내어 축소한 {_1} × {_2}픽셀로 추적했습니다.
|
||||
Artboard {n} of {total} 아트보드 {n} / {total}
|
||||
File {n} of {total} 파일 {n} / {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5251,6 +5251,10 @@ mark-style Japanese Japońskie
|
||||
Snap to Perpendicular Przyciągaj do prostopadłych
|
||||
@msg unknown snap option `{key}` (use {options}) nieznana opcja przyciągania `{key}` (użyj: {options})
|
||||
Gap Length: Długość przerwy:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` wymaga `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` wymaga `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` wymaga `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) brak grupy kolorów `{name}` w dokumencie (patrz swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Tryb Płaskie logo obrysował obraz w rozdzielczości {_1} × {_2} pikseli, po zmniejszeniu przez uśrednienie z {_3} × {_4}.
|
||||
Artboard {n} of {total} Obszar kompozycji {n} z {total}
|
||||
File {n} of {total} Plik {n} z {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5316,6 +5316,10 @@ mark-style Japanese Japonesas
|
||||
Snap to Perpendicular Ajustar à Perpendicular
|
||||
@msg unknown snap option `{key}` (use {options}) opção de ajuste desconhecida `{key}` (use {options})
|
||||
Gap Length: Comprimento da Lacuna:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` requer `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` requer `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` requer `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) nenhum grupo de cores `{name}` no documento (veja swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. O modo Logotipo Plano traçou a imagem em {_1} × {_2} pixels, reduzida por média de {_3} × {_4}.
|
||||
Artboard {n} of {total} Mesa de Trabalho {n} de {total}
|
||||
File {n} of {total} Arquivo {n} de {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -5008,6 +5008,10 @@ lighting Light Свет
|
||||
Snap to Perpendicular Привязать к перпендикуляру
|
||||
@msg unknown snap option `{key}` (use {options}) неизвестный параметр привязки `{key}` (допустимо: {options})
|
||||
Gap Length: Длина зазора:
|
||||
@msg `colorGroup` needs `library: "document"` для `colorGroup` нужен `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` для `colorGroup` нужен `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` для `colorGroup` нужен `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) в документе нет цветовой группы `{name}` (см. swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Режим «Плоский логотип» трассировал изображение в размере {_1} × {_2} пикселей, уменьшенное усреднением с {_3} × {_4}.
|
||||
Artboard {n} of {total} Монтажная область {n} из {total}
|
||||
File {n} of {total} Файл {n} из {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -5422,6 +5422,10 @@ swatch Yellow Green Gulgrön
|
||||
Snap to Perpendicular Fäst mot vinkelrät
|
||||
@msg unknown snap option `{key}` (use {options}) okänt fästalternativ `{key}` (använd {options})
|
||||
Gap Length: Lucklängd:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` kräver `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` kräver `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` kräver `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) ingen färggrupp `{name}` i dokumentet (se swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Läget Platt logotyp vektoriserade bilden vid {_1} × {_2} pixlar, nedskalad genom medelvärdesbildning från {_3} × {_4}.
|
||||
Artboard {n} of {total} Rityta {n} av {total}
|
||||
File {n} of {total} Fil {n} av {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -5393,6 +5393,10 @@ theme Appearance Görünüm
|
||||
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. Görüntü {_1} × {_2} piksel, bir kenarı {LARGE_TRACE_SIDE} değerinden büyük: izlenir, ancak daha yavaş. Daha düşük doğruluklu bir ön ayar veya görüntünün daha küçük bir kopyası daha hızlı izlenir.
|
||||
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). Görüntü {_3} × {_4} boyutundan küçültülerek {_1} × {_2} pikselde izlendi (en fazla {_5} megapiksel).
|
||||
Gap Length: Boşluk Uzunluğu:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` için `library: "document"` gerekir
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` için `palette: "documentLibrary"` gerekir
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` için `mode: "color"` gerekir
|
||||
@msg no color group `{name}` in the document (see swatch.list) belgede `{name}` adlı renk grubu yok (bkz. swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Düz Logo modu görüntüyü {_3} × {_4} boyutundan ortalama alarak küçültüp {_1} × {_2} pikselde izledi.
|
||||
@plural {n} more export waiting|{n} more exports waiting {n} dışa aktarma daha bekliyor|{n} dışa aktarma daha bekliyor
|
||||
@msg Export cancelled Dışa aktarma iptal edildi
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 25.
|
@@ -4992,6 +4992,10 @@ lighting Light Світло
|
||||
Snap to Perpendicular Прив’язати до перпендикуляра
|
||||
@msg unknown snap option `{key}` (use {options}) невідомий параметр прив’язки `{key}` (використовуйте {options})
|
||||
Gap Length: Довжина проміжку:
|
||||
@msg `colorGroup` needs `library: "document"` для `colorGroup` потрібен `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` для `colorGroup` потрібен `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` для `colorGroup` потрібен `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) у документі немає колірної групи `{name}` (див. swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Режим «Плоский логотип» трасував зображення в розмірі {_1} × {_2} пікселів, зменшене усередненням з {_3} × {_4}.
|
||||
Artboard {n} of {total} Монтажна область {n} з {total}
|
||||
File {n} of {total} Файл {n} з {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 749 and column 40.
|
@@ -4992,6 +4992,10 @@ theme Appearance Giao diện
|
||||
Snap to Perpendicular Hút vào đường vuông góc
|
||||
@msg unknown snap option `{key}` (use {options}) tùy chọn hút không hợp lệ `{key}` (dùng {options})
|
||||
Gap Length: Độ dài khoảng hở:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` cần `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` cần `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` cần `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) không có nhóm màu `{name}` trong tài liệu (xem swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. Chế độ Logo phẳng đã dò ảnh ở {_1} × {_2} điểm ảnh, thu nhỏ bằng cách lấy trung bình từ {_3} × {_4}.
|
||||
Artboard {n} of {total} Bảng vẽ {n} / {total}
|
||||
File {n} of {total} Tệp {n} / {total}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 4053 and column 10.
|
@@ -5231,6 +5231,10 @@ lighting Light 光源
|
||||
Snap to Perpendicular 对齐垂线
|
||||
@msg unknown snap option `{key}` (use {options}) 未知的对齐选项 `{key}`(可用:{options})
|
||||
Gap Length: 间隙长度:
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` 需要 `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` 需要 `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` 需要 `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) 文档中没有颜色组 `{name}` (请参阅 swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. “扁平徽标”模式已按 {_1} × {_2} 像素描摹图像,由 {_3} × {_4} 平均缩小而来。
|
||||
# Links and Attributes: files and URLs handed to other apps.
|
||||
@msg Edit Original opens image and document files only; “{name}” is not one 编辑原稿只能打开图像和文档文件;“{name}” 不是其中之一
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 73.
|
@@ -2377,6 +2377,10 @@ file-filter Templates 範本
|
||||
@msg too many library panels were opened in this session 本次工作階段開啟的資料庫面板過多
|
||||
@msg The image is {_1} × {_2} pixels, more than {LARGE_TRACE_SIDE} on a side: it is traced, but more slowly. A lower-fidelity preset or a smaller copy of the image traces faster. 影像為 {_1} × {_2} 像素,有一邊超過 {LARGE_TRACE_SIDE}:仍會描圖,但速度較慢。使用精確度較低的預設集或較小的影像拷貝,描圖會較快。
|
||||
@msg The image was traced at {_1} × {_2} pixels, scaled down from {_3} × {_4} ({_5} megapixels at most). 影像已以 {_1} × {_2} 像素描圖,由 {_3} × {_4} 縮小而來 (最多 {_5} 百萬像素)。
|
||||
@msg `colorGroup` needs `library: "document"` `colorGroup` 需要 `library: "document"`
|
||||
@msg `colorGroup` needs `palette: "documentLibrary"` `colorGroup` 需要 `palette: "documentLibrary"`
|
||||
@msg `colorGroup` needs `mode: "color"` `colorGroup` 需要 `mode: "color"`
|
||||
@msg no color group `{name}` in the document (see swatch.list) 文件中沒有顏色群組 `{name}` (請參閱 swatch.list)
|
||||
@msg Flat Logo traced the image at {_1} × {_2} pixels, averaged down from {_3} × {_4}. 「扁平標誌」模式已以 {_1} × {_2} 像素描圖,由 {_3} × {_4} 平均縮小而來。
|
||||
# Links and Attributes: files and URLs handed to other apps.
|
||||
@msg Edit Original opens image and document files only; “{name}” is not one 「編輯原稿」只能開啟影像與文件檔案;「{name}」不屬於這兩類
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -61,6 +61,31 @@ fn library_list(app: &VectorcraftApp, ui: &mut Ui, current: &str) -> Option<Stri
|
||||
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>> {
|
||||
let mut chosen = menu_item(ui, "All", true, current.is_none()).then_some(None);
|
||||
let groups: Vec<String> = app.session.active().map(|d| d.doc.swatch_groups.iter().map(|g| g.name.clone()).collect()).unwrap_or_default();
|
||||
if !groups.is_empty() {
|
||||
ui.separator();
|
||||
}
|
||||
for g in groups {
|
||||
if widgets::menu_item_name(ui, &g, true, current == Some(g.as_str())) {
|
||||
chosen = Some(Some(g));
|
||||
}
|
||||
}
|
||||
chosen
|
||||
}
|
||||
|
||||
/// `params`' color group when the active document has it, found as `imageTrace.make` finds it (so
|
||||
/// named exactly, else ignoring case); `None` is All. A group of another document, or a deleted
|
||||
/// one, is All.
|
||||
fn color_group<'a>(app: &VectorcraftApp, params: &'a Value) -> Option<&'a str> {
|
||||
let name = params["colorGroup"].as_str().filter(|g| !g.is_empty())?;
|
||||
let lower = name.to_lowercase();
|
||||
app.session.active()?.doc.swatch_groups.iter().any(|g| g.name.to_lowercase() == lower).then_some(name)
|
||||
}
|
||||
|
||||
/// Panel state: the preset name, the current parameters, the view and the last result's counts.
|
||||
#[derive(Clone, Default)]
|
||||
struct TraceUi {
|
||||
@@ -258,6 +283,10 @@ pub fn control_bar(app: &mut VectorcraftApp, ui: &mut Ui) -> bool {
|
||||
}
|
||||
|
||||
fn trace(app: &mut VectorcraftApp, st: &mut TraceUi) {
|
||||
// A group the active document does not have traces with All, as the panel shows.
|
||||
if color_group(app, &st.params).is_none() && !st.params["colorGroup"].is_null() {
|
||||
st.params["colorGroup"] = Value::Null;
|
||||
}
|
||||
let preset = if st.preset == "Custom" { "Default" } else { st.preset.as_str() };
|
||||
match app.run("imageTrace.make", json!({ "preset": preset, "params": st.params, "view": st.view.id() })) {
|
||||
Ok(r) => {
|
||||
@@ -378,6 +407,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
let label = MODES.iter().find(|m| m.0 == mode).map_or("Black and White", |m| m.1);
|
||||
let labels: Vec<&str> = MODES.iter().map(|m| m.1).collect();
|
||||
if let Some(i) = widgets::dropdown(ui, "it-mode", label, &labels, 170.0) {
|
||||
// Only Color mode uses a color group.
|
||||
if MODES[i].0 != "color" {
|
||||
st.params["colorGroup"] = Value::Null;
|
||||
}
|
||||
st.params["mode"] = json!(MODES[i].0);
|
||||
st.preset = "Custom".into();
|
||||
retrace = true;
|
||||
@@ -390,6 +423,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
|
||||
widgets::dim_label(ui, tl!("Palette:"));
|
||||
let labels = PALETTES.map(palette_label);
|
||||
if let Some(p) = widgets::dropdown_names(ui, "it-palette", palette_label(&palette), &labels, 170.0).and_then(|i| PALETTES.get(i)) {
|
||||
// Every other palette refuses a color group.
|
||||
if *p != "documentLibrary" {
|
||||
st.params["colorGroup"] = Value::Null;
|
||||
}
|
||||
st.params["palette"] = json!(p);
|
||||
st.preset = "Custom".into();
|
||||
retrace = true;
|
||||
@@ -400,11 +437,27 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut 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, false, |ui| library_list(app, ui, &key)) {
|
||||
if k != DOCUMENT_SWATCHES {
|
||||
st.params["colorGroup"] = Value::Null;
|
||||
}
|
||||
st.params["library"] = json!(k);
|
||||
st.preset = "Custom".into();
|
||||
retrace = true;
|
||||
}
|
||||
});
|
||||
// The document's swatches: every one, or one color group's.
|
||||
if st.params["library"].as_str().unwrap_or(DOCUMENT_SWATCHES) == DOCUMENT_SWATCHES {
|
||||
ui.horizontal(|ui| {
|
||||
widgets::dim_label(ui, tl!("Colors:"));
|
||||
let group = color_group(app, &st.params).map(str::to_string);
|
||||
let label = group.clone().unwrap_or_else(|| tl!("All").to_string());
|
||||
if let Some(g) = widgets::combo(ui, "it-color-group", &label, 170.0, false, |ui| color_group_list(app, ui, group.as_deref())) {
|
||||
st.params["colorGroup"] = json!(g);
|
||||
st.preset = "Custom".into();
|
||||
retrace = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Full Tone and Automatic: how many colours (Less … More); else a count or the threshold.
|
||||
@@ -1250,6 +1303,97 @@ mod tests {
|
||||
assert!(has(&texts, "50") && !has(&texts, "Library:"), "{texts:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn document_library_colors_lists_the_documents_color_groups() {
|
||||
let mut app = traced_app();
|
||||
app.run("swatch.newGroup", json!({"name": "Brand", "colors": ["#000000", "#ffffff"]})).unwrap();
|
||||
app.run("imageTrace.make", json!({"preset": "6 Colors", "params": {"palette": "documentLibrary"}})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
let has = |texts: &[(String, Rect)], s: &str| texts.iter().any(|(t, _)| t == s);
|
||||
let stored = |app: &VectorcraftApp, key: &str| target(app).2.map(|t| t["params"][key].clone());
|
||||
let texts = frame(&mut app, &ctx, vec![]);
|
||||
assert!(has(&texts, "Colors:") && has(&texts, "All"), "{texts:?}");
|
||||
// The list holds All and the document's groups; a group traces again with its colors.
|
||||
click(&mut app, &ctx, "All");
|
||||
assert!(has(&frame(&mut app, &ctx, vec![]), " Brand"));
|
||||
let steps = app.session.active().unwrap().history.undo.len();
|
||||
click(&mut app, &ctx, " Brand");
|
||||
assert_eq!(stored(&app, "colorGroup"), Some(json!("Brand")));
|
||||
assert_eq!(target(&app).2.unwrap()["preset"], "Custom");
|
||||
assert_eq!(app.session.active().unwrap().history.undo.len(), steps + 1);
|
||||
assert!(has(&frame(&mut app, &ctx, vec![]), "Brand"));
|
||||
// All again.
|
||||
click(&mut app, &ctx, "Brand");
|
||||
click(&mut app, &ctx, " All");
|
||||
assert_eq!(stored(&app, "colorGroup"), Some(Value::Null));
|
||||
// Another library clears the group, and the row goes.
|
||||
click(&mut app, &ctx, "All");
|
||||
click(&mut app, &ctx, " Brand");
|
||||
let lib = swatches::colour_libraries(&app).into_iter().find(|l| l.submenu.is_none()).unwrap();
|
||||
click(&mut app, &ctx, "Document Swatches");
|
||||
click(&mut app, &ctx, &format!(" {}", library_panel::library_name(&lib.id, &lib.name)));
|
||||
assert_eq!((stored(&app, "library"), stored(&app, "colorGroup")), (Some(json!(lib.id)), Some(Value::Null)));
|
||||
assert!(!has(&frame(&mut app, &ctx, vec![]), "Colors:"));
|
||||
// Another palette clears the group too, and traces again (the object stores the settings of
|
||||
// a trace that was made).
|
||||
click(&mut app, &ctx, library_panel::library_name(&lib.id, &lib.name));
|
||||
click(&mut app, &ctx, " Document Swatches");
|
||||
click(&mut app, &ctx, "All");
|
||||
click(&mut app, &ctx, " Brand");
|
||||
assert_eq!(stored(&app, "colorGroup"), Some(json!("Brand")));
|
||||
click(&mut app, &ctx, "Document Library");
|
||||
click(&mut app, &ctx, "Limited");
|
||||
assert_eq!((stored(&app, "palette"), stored(&app, "colorGroup")), (Some(json!("limited")), Some(Value::Null)));
|
||||
// Another mode clears it too, and traces again.
|
||||
click(&mut app, &ctx, "Limited");
|
||||
click(&mut app, &ctx, "Document Library");
|
||||
click(&mut app, &ctx, "All");
|
||||
click(&mut app, &ctx, " Brand");
|
||||
assert_eq!(stored(&app, "colorGroup"), Some(json!("Brand")));
|
||||
click(&mut app, &ctx, "Color");
|
||||
click(&mut app, &ctx, "Grayscale");
|
||||
assert_eq!((stored(&app, "mode"), stored(&app, "colorGroup")), (Some(json!("grayscale")), Some(Value::Null)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_color_group_the_active_document_lacks_is_all() {
|
||||
let mut app = traced_app();
|
||||
app.run("swatch.newGroup", json!({"name": "Brand", "colors": ["#000000", "#ffffff"]})).unwrap();
|
||||
app.run("imageTrace.make", json!({"preset": "6 Colors", "params": {"palette": "documentLibrary"}})).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install_fonts(&ctx);
|
||||
click(&mut app, &ctx, "All");
|
||||
click(&mut app, &ctx, " Brand");
|
||||
assert_eq!(target(&app).2.map(|t| t["params"]["colorGroup"].clone()), Some(json!("Brand")));
|
||||
let shows_brand = |app: &mut VectorcraftApp| frame(app, &ctx, vec![]).iter().any(|(t, _)| t == "Brand");
|
||||
// Without the group the row shows All; undoing its removal shows it again.
|
||||
app.run("swatch.ungroup", json!({"name": "Brand"})).unwrap();
|
||||
assert!(!shows_brand(&mut app));
|
||||
app.run("edit.undo", json!({})).unwrap();
|
||||
assert!(shows_brand(&mut app));
|
||||
// Another document without the group, with an image that is not traced yet.
|
||||
app.session.execute("file.new", &json!({"width": 100, "height": 100})).unwrap();
|
||||
let img = image::RgbaImage::from_fn(20, 20, |x, _| image::Rgba(if x < 10 { [0, 0, 0, 255] } else { [255, 255, 255, 255] }));
|
||||
let mut png = vec![];
|
||||
img.write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).unwrap();
|
||||
let data = vectorcraft_format::base64_encode(&png);
|
||||
app.run("file.place", json!({"name": "half.png", "dataBase64": data, "link": false})).unwrap();
|
||||
let texts = frame(&mut app, &ctx, vec![]);
|
||||
let has = |s: &str| texts.iter().any(|(t, _)| t == s);
|
||||
assert!(has("Colors:") && has("All") && !has("Brand"), "{texts:?}");
|
||||
// Back in the first document, its Image Trace object shows its group again.
|
||||
app.session.set_active(0);
|
||||
assert!(shows_brand(&mut app));
|
||||
app.session.set_active(1);
|
||||
assert!(!shows_brand(&mut app));
|
||||
// Trace uses every document swatch.
|
||||
click(&mut app, &ctx, "Trace");
|
||||
let stored = target(&app).2.unwrap_or_else(|| panic!("not traced: {}", app.ui.status));
|
||||
assert!(stored["params"]["colorGroup"].as_str().is_none_or(str::is_empty), "{stored}");
|
||||
assert_eq!(stored["params"]["palette"], "documentLibrary");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_strokes_traces_again_and_keeps_one_kind_on() {
|
||||
let mut app = traced_app();
|
||||
|
||||
@@ -32,11 +32,24 @@ white beside a cream), at most six; scattered specks of a colour add none. Adobe
|
||||
its own palettes are chosen; this is VectorCraft's own method (see
|
||||
[image-trace-quality.md](image-trace-quality.md#auto-color-keeps-rare-colours)).
|
||||
|
||||
**Document Library color groups.** With Palette › Document Library and Library › Document Swatches,
|
||||
the panel's **Colors** menu traces with every document swatch (**All**) or with the colors of one
|
||||
color group from the Swatches panel, as the public
|
||||
[Image Trace panel options](https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/image-trace-panel-options.html)
|
||||
page ([archived](https://web.archive.org/web/20251230195658/https://helpx.adobe.com/illustrator/desktop/manage-objects/traces-mockups-symbols/image-trace-panel-options.html))
|
||||
describes Document Library. In the params of `imageTrace.make` or `imageTrace.makeAndExpand`,
|
||||
`"colorGroup": "<name>"` names the group. It needs `"mode": "color"`, `"palette": "documentLibrary"` and
|
||||
`"library": "document"`; a `colorGroup` with a nonempty name and any other mode, palette or library is refused. An
|
||||
empty name names no group and is accepted with any mode, palette or library; with Document Library and
|
||||
`"library": "document"` it traces with every document swatch. A group whose name matches exactly is used first, then one whose name differs only in case. At
|
||||
most `colors` of its colors are used. A missing group and a group with no solid colors are refused. Choosing another
|
||||
mode, palette or library in the panel clears the group. A group the active document does not have shows as All
|
||||
and traces as All.
|
||||
|
||||
**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
|
||||
as much as one in lightness, so a gray or a muted brown takes a black, white or other neutral
|
||||
library color rather than a saturated color of the same lightness.
|
||||
|
||||
**Abutting and Overlapping.** Abutting is the default Method, and the Default, Auto Color, 3 Colors,
|
||||
6 Colors and 16 Colors presets use it. With Abutting, two neighboring colors share one exact edge. The
|
||||
canvas smooths the edges of each path on its own, so each of the two paths covers only part of the
|
||||
|
||||
@@ -793,6 +793,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
- **Transparency:** opacity masks (clip/invert/disable/link), exported as SVG `<mask>` and PDF soft masks. The constant alpha soft mask that PDF and `.ai` export draw a CMYK page with transparency through is white, so applications that read every soft mask by its luminosity show the page too (#1359, part of #1286).
|
||||
Disable, Enable, Unlink and Link Opacity Mask and Opacity Mask Options (`transparency.setOpacityMask`) record no undo step when every mask they act on already has the flags they set.
|
||||
- **Image Trace, thin closed outlines:** generated `fit::snap_area_tests` verify nonzero interiors after straightening, opposite closed-boundary winding and Noise controls; see [quality notes](image-trace-quality.md#thin-closed-outlines-with-snap-curves-to-lines). Scores and hours unchanged; open-piece fitting is unchanged.
|
||||
- **Image Trace, Document Library color groups:** with Document Swatches, the panel's Colors menu and `"colorGroup"` trace with one color group's colors instead of every swatch, as the public panel documentation describes Document Library; code-drawn tests in `crates/engine` and the panel.
|
||||
- **Image Trace, flattened slivers:** in a Color, Grayscale or Black and White trace with Fills, a traced region whose outline straightens onto one line (a single pixel, or a one-pixel row along an edge, its pieces shared with the regions beside it) is left out instead of becoming a selectable path with no area, which paints nothing. Snap Curves To Lines straightens more outlines, so it leaves out more of these. Without Fills, the region's 1 px stroke draws it, and it is kept. Code-drawn tests in `crates/trace`.
|
||||
- **Image Trace, Auto Color rare colours:** the Automatic palette keeps colours too rare for its area count when they are distinct (Oklab) and drawn as coherent regions, at most six, protected from mixed-colour merging and Noise; code-drawn stem, highlight, low-contrast and scattered-noise tests (see [quality notes](image-trace-quality.md#auto-color-keeps-rare-colours)).
|
||||
- **Image Trace, Document Library keeps neutral tones neutral:** each pixel takes the library color nearest in Oklab with differences in hue and chroma counted three times, so a gray or a muted brown traces as a neutral library color instead of a saturated one of similar lightness; a code-drawn test of gray and brown patches with a black, light and blue library in `crates/trace`.
|
||||
|
||||
Reference in New Issue
Block a user