mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 05:24:44 +00:00
Document Info: hidden and clear objects list no brushes or paints
Brushes, Spot Color Objects, Pattern Objects and Gradient Objects left out a fill or stroke that was hidden or at an opacity of 0, but still listed an object that was itself hidden or at an opacity of 0, and the objects inside such a group or layer. They now leave those out, their characters' paints and colorized images included. With Selection Only, an object selected inside a hidden group or layer, or one at an opacity of 0, is left out too. Objects still counts every object.
This commit is contained in:
@@ -18,7 +18,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Document Info",
|
||||
["Window", "Document Info"],
|
||||
None,
|
||||
"{selectionOnly?, category?: document|objects|graphicStyles|brushes|spotColors|patterns|gradients|symbols|fonts|fontDetails|linkedImages|embeddedImages|repeats (only that one in sections and the text), format?: \"text\" (→ {text}: the report Document Info › Save… and Package write)} → {document, objects: {paths, compoundPaths, groups, …}, pathLength: pt (the paths' total length, compound paths' included, guides left out), fonts (the type in opacity masks and in the art of symbols and patterns included; with selectionOnly: the selected type's), images, swatches, graphicStyleNames (with selectionOnly: the styles the selected objects are linked to), brushNames (the brushes the art's drawn strokes use, each once; with selectionOnly: those the selected objects' strokes use), brushes: [{name, type: calligraphic|scatter|art|pattern|bristle|null}] (those brushes with their types; null: not in the Brushes panel), panelBrushNames (the Brushes panel's brushes), repeatObjects: [{id, name, type: radial|grid|mirror, instances, rows?, cols?}] (the Repeat objects, those in groups and other repeats included; with selectionOnly: those in the selection), spotObjects: [{id, name, spotColors}] (the objects filled or stroked with a spot color swatch, as a solid color or in the stops of a gradient with a stop above opacity 0, at a tint above 0, and grayscale images colorized with one, each once, by the rules patternObjects follows, with the spot colors they use; Registration and process colors are not spot colors; objects.spots counts them), spotColorNames and spotColors (the spot colors those objects use), patternObjects: [{id, name, patterns}] (the objects filled or stroked with a pattern, each once, those in groups and type whose drawn characters use one included, hidden fills and strokes, fills and strokes at an opacity of 0, strokes with no width, guides, compound path members' own fills and strokes, images' fills and strokes without a shape and characters that draw nothing left out, with the patterns they use, which objects.patterns counts; with selectionOnly: those in the selection), patternNames (the patterns those objects use), gradientObjects: [{id, name, gradients}] (the objects filled or stroked with a gradient, by the same rules, with the gradients they use: a linked gradient swatch's name, else Linear gradient, Radial gradient or Freeform gradient; objects.gradients counts them), gradientNames (the gradients those objects use), …, sections: [{id, title, rows: [[label, value]]}] (the panel's categories; fontDetails: each font's file and whether its license lets it be embedded)}. An image linked to a file outside the automation read roots has link null, and its Linked Images row names the file alone",
|
||||
"{selectionOnly?, category?: document|objects|graphicStyles|brushes|spotColors|patterns|gradients|symbols|fonts|fontDetails|linkedImages|embeddedImages|repeats (only that one in sections and the text), format?: \"text\" (→ {text}: the report Document Info › Save… and Package write)} → {document, objects: {paths, compoundPaths, groups, …}, pathLength: pt (the paths' total length, compound paths' included, guides left out), fonts (the type in opacity masks and in the art of symbols and patterns included; with selectionOnly: the selected type's), images, swatches, graphicStyleNames (with selectionOnly: the styles the selected objects are linked to), brushNames (the brushes the art's drawn strokes use, each once; with selectionOnly: those the selected objects' strokes use), brushes: [{name, type: calligraphic|scatter|art|pattern|bristle|null}] (those brushes with their types; null: not in the Brushes panel), panelBrushNames (the Brushes panel's brushes), repeatObjects: [{id, name, type: radial|grid|mirror, instances, rows?, cols?}] (the Repeat objects, those in groups and other repeats included; with selectionOnly: those in the selection), spotObjects: [{id, name, spotColors}] (the objects filled or stroked with a spot color swatch, as a solid color or in the stops of a gradient with a stop above opacity 0, at a tint above 0, and grayscale images colorized with one, each once, by the rules patternObjects follows, with the spot colors they use; Registration and process colors are not spot colors; objects.spots counts them), spotColorNames and spotColors (the spot colors those objects use), patternObjects: [{id, name, patterns}] (the objects filled or stroked with a pattern, each once, those in groups and type whose drawn characters use one included, hidden fills and strokes, fills and strokes at an opacity of 0, strokes with no width, guides, compound path members' own fills and strokes, images' fills and strokes without a shape and characters that draw nothing left out, with the patterns they use, which objects.patterns counts; with selectionOnly: those in the selection), patternNames (the patterns those objects use), gradientObjects: [{id, name, gradients}] (the objects filled or stroked with a gradient, by the same rules, with the gradients they use: a linked gradient swatch's name, else Linear gradient, Radial gradient or Freeform gradient; objects.gradients counts them), gradientNames (the gradients those objects use), …, sections: [{id, title, rows: [[label, value]]}] (the panel's categories; fontDetails: each font's file and whether its license lets it be embedded)}. An image linked to a file outside the automation read roots has link null, and its Linked Images row names the file alone. brushNames, brushes, spotObjects, patternObjects and gradientObjects leave out hidden objects, objects at an opacity of 0 and the objects inside a hidden group or layer or one at an opacity of 0 (with selectionOnly too), their characters' paints and colorized images included; objects still counts them as paths, groups and the other kinds",
|
||||
has_doc,
|
||||
info
|
||||
),
|
||||
@@ -425,6 +425,64 @@ fn applied_brushes(d: &Document, n: &Node, members: &HashSet<*const Node>) -> Ve
|
||||
if follows { used } else { vec![] }
|
||||
}
|
||||
|
||||
/// Whether `n` draws, as far as its own state goes: a hidden object, and an object at an opacity
|
||||
/// of 0, paint no color, and neither do their members.
|
||||
fn draws(n: &Node) -> bool {
|
||||
n.visible && n.opacity > 0.0
|
||||
}
|
||||
|
||||
/// The object of `d` at index path `path`, with whether the groups and layers around it draw
|
||||
/// ([`draws`]).
|
||||
fn node_and_drawn<'a>(d: &'a Document, path: &[usize]) -> Option<(&'a Node, bool)> {
|
||||
let (first, rest) = path.split_first()?;
|
||||
let mut at: &Node = d.layers.get(*first)?;
|
||||
let mut drawn = true;
|
||||
for &i in rest {
|
||||
drawn &= draws(at);
|
||||
at = &**at.children()?.get(i)?;
|
||||
}
|
||||
Some((at, drawn))
|
||||
}
|
||||
|
||||
/// The spot colors, the patterns and the gradients (`spots`: [`spot_swatches`]) that object `n`
|
||||
/// paints, each once: those of its own fills and strokes ([`own_paints`], `members` included), of
|
||||
/// its drawn characters and, for a grayscale or 1-bit image, of the color it is colorized with.
|
||||
fn object_paints(d: &Document, spots: &HashSet<&str>, members: &HashSet<*const Node>, n: &Node) -> [Vec<String>; 3] {
|
||||
let (spot, pattern, gradient) = (|p: &Paint| spot_labels(spots, p), one_label(pattern_label), one_label(gradient_label));
|
||||
let labels: [&PaintNames<'_>; 3] = [&spot, &pattern, &gradient];
|
||||
let painted_runs = painted_runs(d, spots, n);
|
||||
let mut used = labels.map(|label| own_paints(d, n, members, painted_runs.as_ref(), label));
|
||||
// The characters' own paints: an inline graphic draws no outline and does not take its run's
|
||||
// paint (a list marker set in its run does), and a stroke with no width paints nothing.
|
||||
if let Some((t, painted)) = &painted_runs {
|
||||
for run in painted.iter().filter_map(|i| t.runs.get(*i)) {
|
||||
let stroke = (run.style.stroke_width > 0.0).then_some(&run.style.stroke);
|
||||
for paint in std::iter::once(&run.style.fill).chain(stroke) {
|
||||
for (used, label) in used.iter_mut().zip(labels) {
|
||||
for name in label(paint) {
|
||||
if !used.contains(&name) {
|
||||
used.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// A grayscale or 1-bit image colorized with a spot color prints it, while its pixels take the
|
||||
// color, as the renderer draws it.
|
||||
if let NodeKind::Image(im) = &n.kind
|
||||
&& let Some(colorize) = n.extras().colorize.as_deref()
|
||||
&& d.image_blob(im).is_some_and(|b| b.takes_colorize())
|
||||
{
|
||||
for name in spot(colorize) {
|
||||
if !used[0].contains(&name) {
|
||||
used[0].insert(0, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
used
|
||||
}
|
||||
|
||||
fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
const C: &str = "document.info";
|
||||
let category = str_param(p, "category");
|
||||
@@ -440,8 +498,13 @@ fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let st = s.doc()?;
|
||||
let d = &st.doc;
|
||||
let selection_only = bool_or(p, "selectionOnly", false);
|
||||
let roots: Vec<&Node> =
|
||||
if selection_only { st.selection.objects.iter().filter_map(|id| d.node(*id)).collect() } else { d.layers.iter().map(|l| &**l).collect() };
|
||||
// Each root with whether the groups and layers around it draw: a selected object inside a hidden group or layer, or one
|
||||
// at an opacity of 0, paints nothing.
|
||||
let roots: Vec<(&Node, bool)> = if selection_only {
|
||||
st.selection.objects.iter().filter_map(|id| node_and_drawn(d, &d.index_path(*id)?)).collect()
|
||||
} else {
|
||||
d.layers.iter().map(|l| (&**l, true)).collect()
|
||||
};
|
||||
let mut counts: BTreeMap<&str, usize> = BTreeMap::new();
|
||||
// The paths' total length, as Document Info › Objects shows it (the length of a cut line, a
|
||||
// strip of LEDs along the letters, #1958).
|
||||
@@ -467,7 +530,6 @@ fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let mut spot_objects: Vec<Value> = vec![];
|
||||
let mut spot_rows: Vec<(String, String)> = vec![];
|
||||
let mut spot = BTreeSet::new();
|
||||
let (spot_label, pattern, gradient) = (|p: &Paint| spot_labels(&spot_swatches, p), one_label(pattern_label), one_label(gradient_label));
|
||||
let mut styles: Vec<&str> = if selection_only { vec![] } else { d.graphic_styles.iter().map(|g| g.name.as_str()).collect() };
|
||||
// `library` holds the Brushes panel's brushes, and `brushes` the brushes the visited objects' strokes draw with, each once,
|
||||
// in walk order.
|
||||
@@ -494,10 +556,18 @@ fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
members.extend(children.iter().map(|c| std::ptr::from_ref(&**c)));
|
||||
}
|
||||
});
|
||||
for r in roots {
|
||||
r.walk(&mut |n| {
|
||||
// Depth first, in paint order, as `Node::walk` visits: each object with whether it and the groups and layers around it
|
||||
// draw. An object that does not draw is still counted, and its members are visited.
|
||||
let mut stack: Vec<(&Node, bool)> = vec![];
|
||||
for (r, drawn) in roots {
|
||||
stack.push((r, drawn));
|
||||
while let Some((n, around)) = stack.pop() {
|
||||
if !seen.insert(std::ptr::from_ref(n)) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
let drawn = around && draws(n);
|
||||
if let Some(ch) = n.children() {
|
||||
stack.extend(ch.iter().rev().map(|c| (&**c, drawn)));
|
||||
}
|
||||
let k = match &n.kind {
|
||||
// The Guides row counts paths made into guides; ruler guides are not objects.
|
||||
@@ -545,42 +615,8 @@ fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if let Some(k) = k {
|
||||
*counts.entry(k).or_default() += 1;
|
||||
}
|
||||
// The spot colors, the patterns and the gradients this object's fills and strokes paint, each once.
|
||||
let painted_runs = painted_runs(d, &spot_swatches, n);
|
||||
let mut used_spots = own_paints(d, n, &members, painted_runs.as_ref(), &spot_label);
|
||||
let mut used_patterns = own_paints(d, n, &members, painted_runs.as_ref(), &pattern);
|
||||
let mut used_gradients = own_paints(d, n, &members, painted_runs.as_ref(), &gradient);
|
||||
// The characters' own paints: an inline graphic draws no outline and does not take its
|
||||
// run's paint (a list marker set in its run does), and a stroke with no width paints
|
||||
// nothing.
|
||||
if let Some((t, painted)) = &painted_runs {
|
||||
for run in painted.iter().filter_map(|i| t.runs.get(*i)) {
|
||||
let stroke = (run.style.stroke_width > 0.0).then_some(&run.style.stroke);
|
||||
for paint in std::iter::once(&run.style.fill).chain(stroke) {
|
||||
let labels: [(&mut Vec<String>, &PaintNames<'_>); 3] =
|
||||
[(&mut used_spots, &spot_label), (&mut used_patterns, &pattern), (&mut used_gradients, &gradient)];
|
||||
for (used, label) in labels {
|
||||
for name in label(paint) {
|
||||
if !used.contains(&name) {
|
||||
used.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// A grayscale or 1-bit image colorized with a spot color prints it, while its pixels take
|
||||
// the color, as the renderer draws it.
|
||||
if let NodeKind::Image(im) = &n.kind
|
||||
&& let Some(colorize) = n.extras().colorize.as_deref()
|
||||
&& d.image_blob(im).is_some_and(|b| b.takes_colorize())
|
||||
{
|
||||
for name in spot_label(colorize) {
|
||||
if !used_spots.contains(&name) {
|
||||
used_spots.insert(0, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// The spot colors, the patterns and the gradients this object paints, each once; none when it does not draw.
|
||||
let [used_spots, used_patterns, used_gradients] = if drawn { object_paints(d, &spot_swatches, &members, n) } else { Default::default() };
|
||||
// Objects counts the objects that Spot Color Objects, Pattern Objects and Gradient Objects list.
|
||||
if !used_spots.is_empty() {
|
||||
let name = n.display_name();
|
||||
@@ -615,9 +651,11 @@ fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
{
|
||||
styles.push(&g.name);
|
||||
}
|
||||
for b in applied_brushes(d, n, &members) {
|
||||
if !brushes.contains(&b) {
|
||||
brushes.push(b);
|
||||
if drawn {
|
||||
for b in applied_brushes(d, n, &members) {
|
||||
if !brushes.contains(&b) {
|
||||
brushes.push(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let NodeKind::Repeat(spec) = &n.kind {
|
||||
@@ -625,7 +663,7 @@ fn info(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
repeats.push(entry);
|
||||
repeat_rows.push(row);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// The document's fonts include those of the type in opacity masks and in the art of its
|
||||
// symbols and patterns, as Find Font lists them.
|
||||
@@ -1455,6 +1493,115 @@ mod tests {
|
||||
assert_eq!(spots(&mut s), (vec![], None, None));
|
||||
}
|
||||
|
||||
/// Brushes, Spot Color Objects, Pattern Objects and Gradient Objects leave out a hidden object,
|
||||
/// an object at an opacity of 0 and the objects inside a hidden layer or a group at an opacity of
|
||||
/// 0, with Selection Only too: their fills, strokes, characters and colorized pixels paint no
|
||||
/// color. Objects still counts them.
|
||||
#[test]
|
||||
fn info_skips_paints_on_hidden_and_clear_objects_and_their_members() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 400, "height": 400})).unwrap();
|
||||
s.execute("swatch.new", &json!({"name": "Ink", "color": {"model": "cmyk", "c": 0, "m": 1, "y": 1, "k": 0}, "spot": true})).unwrap();
|
||||
let square = |s: &mut Session, x: f64| {
|
||||
s.execute("shape.rectangle", &json!({"x": x, "y": 0, "width": 10, "height": 10})).unwrap()["id"].as_u64().unwrap()
|
||||
};
|
||||
let tile = square(&mut s, 0.0);
|
||||
s.execute("object.pattern.make", &json!({"ids": [tile], "name": "Dots", "edit": false})).unwrap();
|
||||
// A patterned square that stays drawn, an object at an opacity of 0 and a hidden one.
|
||||
let (shown, clear, hidden) = (square(&mut s, 20.0), square(&mut s, 40.0), square(&mut s, 60.0));
|
||||
s.execute("paint.setFill", &json!({"ids": [shown, clear], "swatch": "Dots"})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"ids": [hidden], "swatch": "Ink"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"ids": [shown, clear, hidden], "none": true})).unwrap();
|
||||
// A brushed square in a group.
|
||||
let (brushed, other) = (square(&mut s, 80.0), square(&mut s, 100.0));
|
||||
s.execute("brush.apply", &json!({"ids": [brushed], "name": "Charcoal"})).unwrap();
|
||||
s.execute("select.set", &json!({"ids": [brushed, other]})).unwrap();
|
||||
let group = s.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap();
|
||||
// Type whose characters are filled with the spot color.
|
||||
let word = s.execute("text.create", &json!({"x": 0, "y": 200, "text": "Hi"})).unwrap()["id"].as_u64().unwrap();
|
||||
s.execute("paint.setFill", &json!({"ids": [word], "swatch": "Ink"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"ids": [word], "none": true})).unwrap();
|
||||
// A grayscale image colorized with the spot color.
|
||||
let mut bytes = Vec::new();
|
||||
image::DynamicImage::ImageLuma8(image::GrayImage::from_raw(2, 1, vec![0, 255]).unwrap())
|
||||
.write_to(&mut std::io::Cursor::new(&mut bytes), image::ImageFormat::Png)
|
||||
.unwrap();
|
||||
let image = s
|
||||
.edit("Place", |d, sel| {
|
||||
d.images.insert("gray".into(), vectorcraft_doc::ImageBlob::png(bytes));
|
||||
let id = d.alloc_id();
|
||||
let im = vectorcraft_doc::ImageObject {
|
||||
key: "gray".into(),
|
||||
width: 2,
|
||||
height: 1,
|
||||
xf: Default::default(),
|
||||
link: None,
|
||||
placement: Default::default(),
|
||||
pixels: None,
|
||||
};
|
||||
d.insert(d.default_layer(), 0, Node::new(id, NodeKind::Image(Box::new(im))))?;
|
||||
sel.set([id]);
|
||||
Ok(id)
|
||||
})
|
||||
.unwrap();
|
||||
s.execute("paint.setFill", &json!({"swatch": "Ink"})).unwrap();
|
||||
// A square with a gradient on a layer of its own.
|
||||
let layer = s.execute("layer.new", &json!({"name": "Back"})).unwrap()["id"].as_u64().unwrap();
|
||||
let ramp = square(&mut s, 120.0);
|
||||
s.execute(
|
||||
"paint.setFill",
|
||||
&json!({"ids": [ramp], "gradient": {"kind": "linear", "stops": [{"offset": 0, "color": "#000"}, {"offset": 1, "color": "#fff"}]}}),
|
||||
)
|
||||
.unwrap();
|
||||
s.execute("paint.setStroke", &json!({"ids": [ramp], "none": true})).unwrap();
|
||||
let listed = |s: &mut Session, p: Value| {
|
||||
let i = s.execute("document.info", &p).unwrap();
|
||||
let ids = |k: &str| -> Vec<u64> {
|
||||
let mut ids: Vec<u64> = i[k].as_array().unwrap().iter().map(|o| o["id"].as_u64().unwrap()).collect();
|
||||
ids.sort_unstable();
|
||||
ids
|
||||
};
|
||||
(i["brushNames"].clone(), ids("spotObjects"), ids("patternObjects"), ids("gradientObjects"), i["objects"].clone())
|
||||
};
|
||||
// Everything drawn: each object is listed.
|
||||
let (brushes, spots, patterns, gradients, before) = listed(&mut s, json!({}));
|
||||
assert_eq!(brushes, json!(["Charcoal"]));
|
||||
// New squares take the new spot color as their fill, the group's members included.
|
||||
assert_eq!((spots, patterns, gradients), (vec![hidden, brushed, other, word, image.0], vec![shown, clear], vec![ramp]));
|
||||
s.edit("hide", |d, _| {
|
||||
d.node_mut(NodeId(clear)).unwrap().opacity = 0.0;
|
||||
d.node_mut(NodeId(hidden)).unwrap().visible = false;
|
||||
d.node_mut(NodeId(group)).unwrap().opacity = 0.0;
|
||||
d.node_mut(NodeId(word)).unwrap().opacity = 0.0;
|
||||
d.node_mut(image).unwrap().opacity = 0.0;
|
||||
d.node_mut(NodeId(layer)).unwrap().visible = false;
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
let (brushes, spots, patterns, gradients, after) = listed(&mut s, json!({}));
|
||||
assert_eq!((brushes, spots, patterns, gradients), (json!([]), vec![], vec![shown], vec![]));
|
||||
// Objects counts the listed objects, and every object as before.
|
||||
assert_eq!((after["spots"].clone(), after["patterns"].clone(), after["gradients"].clone()), (Value::Null, json!(1), Value::Null));
|
||||
for k in ["paths", "groups", "textObjects", "images"] {
|
||||
assert_eq!(after[k], before[k], "{k}: {after}");
|
||||
}
|
||||
let rows = s.execute("document.info", &json!({"category": "brushes"})).unwrap()["sections"][0]["rows"].clone();
|
||||
assert_eq!(rows, json!([]));
|
||||
// Selection Only: an object selected inside a group at an opacity of 0 or a hidden layer paints nothing either.
|
||||
s.execute("select.set", &json!({"ids": [brushed, ramp]})).unwrap();
|
||||
let (brushes, _, _, gradients, after) = listed(&mut s, json!({"selectionOnly": true}));
|
||||
assert_eq!((brushes, gradients, after["paths"].clone()), (json!([]), vec![], json!(2)));
|
||||
// Drawn again, the group's brush and the layer's gradient are listed.
|
||||
s.edit("show", |d, _| {
|
||||
d.node_mut(NodeId(group)).unwrap().opacity = 1.0;
|
||||
d.node_mut(NodeId(layer)).unwrap().visible = true;
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
let (brushes, _, _, gradients, _) = listed(&mut s, json!({"selectionOnly": true}));
|
||||
assert_eq!((brushes, gradients), (json!(["Charcoal"]), vec![ramp]));
|
||||
}
|
||||
|
||||
/// Document Info › Objects counts an object with a gradient or a pattern on both its fill and
|
||||
/// its stroke once, and with Selection Only a selection that holds a group and an object inside
|
||||
/// it counts that object once.
|
||||
|
||||
@@ -7083,6 +7083,10 @@ color, even one of the same color, and Registration are not spot colors; the spo
|
||||
Color Objects and `objects.spots` counts them; spot swatches no art uses are not listed; with `selectionOnly`, those
|
||||
in the selection), `spotColorNames` and `spotColors` (the spot colors those objects use) and `pathLength` (pt: the total length of the paths, compound paths' pieces included and guides left
|
||||
out, which objects lists as Path Length in the document's units, say for a cut line or an LED strip along the letters);
|
||||
`brushNames`, `brushes`, `spotObjects`, `patternObjects` and `gradientObjects` leave out hidden objects, objects at an
|
||||
opacity of 0 and the objects inside a hidden group or layer or one at an opacity of 0, their characters' paints and
|
||||
colorized images included, and so does `selectionOnly` for an object selected inside such a group or layer, while
|
||||
`objects` still counts them as paths, groups and the other kinds;
|
||||
`format: "text"` returns the plain-text report Document Info › Save… (`docInfo.save {path?, selectionOnly?, category?}`:
|
||||
only `category` when given, else every category) and the package report write.
|
||||
|
||||
|
||||
@@ -1471,6 +1471,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
|
||||
Document Info's Pattern Objects category lists the objects whose fill or stroke is a pattern, the category the [Document Info panel](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/document-info-panel.html) page describes, each by name with the patterns it uses. With Selection Only it lists those in the selection, and the Document Info report and Package's report list them too (`document.info {category: "patterns"}`, `patternObjects`). Listing an object with a pattern fill and a pattern stroke once, listing objects inside groups and type objects whose characters use a pattern, and leaving out hidden fills and strokes, fills and strokes at an opacity of 0, strokes with no width, guides, a compound path member's own fills and strokes, an image's fills and strokes without a shape, characters the type does not draw and patterns no art uses, and counting the listed objects in Objects, are VectorCraft's own rules. Test: `cmd::docinfo::tests::info_lists_the_pattern_objects` (vectorcraft-engine).
|
||||
Document Info's Gradient Objects category lists the objects whose fill or stroke is a gradient, the category the [Document Info panel](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/document-info-panel.html) page describes as the count of objects with gradient fills or strokes. Each object is listed by name with the gradients it uses. With Selection Only it lists those in the selection, and the Document Info report and Package's report list them too (`document.info {category: "gradients"}`, `gradientObjects`). Naming a linked gradient by its swatch and any other gradient by its kind, and leaving out paint that draws nothing by the rules Pattern Objects follows, gradient swatches no art uses, gradient meshes and gradients drawn by effects, are VectorCraft's own rules. Objects counts the listed objects as Gradient Objects. Test: `cmd::docinfo::tests::info_lists_the_gradient_objects` (vectorcraft-engine).
|
||||
Document Info's Spot Color Objects category lists the objects that use spot colors, the category the [Document Info panel](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/document-info-panel.html) page describes as objects using spot color separations. Each object is listed by name with the spot colors it uses. With Selection Only it lists those in the selection, and the Document Info report and Package's report list them too (`document.info {category: "spotColors"}`, `spotObjects`). Taking a solid color or a gradient stop linked to a spot swatch at a tint above 0 and a grayscale image colorized with one, leaving out process colors that look the same, Registration, gradients whose stops are all at an opacity of 0, fills and strokes at an opacity of 0, paint that draws nothing by the rules Pattern Objects follows, spot swatches no art uses and spot colors inside patterns, symbols, opacity masks, effects and placed files, are VectorCraft's own rules. Objects counts the listed objects as Spot Color Objects. Tests: `cmd::docinfo::tests::info_lists_the_spot_color_objects`, `spot_color_objects_take_colorized_images_and_skip_clear_gradients` and `spot_color_objects_skip_clear_fills_and_strokes` (vectorcraft-engine).
|
||||
Document Info's Brushes, Spot Color Objects, Pattern Objects and Gradient Objects categories leave out hidden objects, objects at an opacity of 0 and the objects inside a hidden group or layer or one at an opacity of 0, their characters' paints and colorized images included. With Selection Only an object selected inside such a group or layer is left out too, and Objects still counts every object as before. This is VectorCraft's own rule. Test: `cmd::docinfo::tests::info_skips_paints_on_hidden_and_clear_objects_and_their_members` (vectorcraft-engine).
|
||||
Document Info's Save… writes the category the panel shows, with Selection Only applied, as the [Document Info panel](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/document-info-panel.html) page describes ("Exports the selected category's visible information to a text file"). With All Categories shown it writes every category, which is VectorCraft's own rule (`docInfo.save {category}`). Test: `panels::doc_info::tests::save_writes_the_category_the_panel_shows`.
|
||||
Document Info's category menu and headings show every category title in the interface language, Font Details, Linked Images and Embedded Images included, and the Objects category shows every count label in it too: Compound Paths, Text Objects, Placed Documents, Symbol Instances, Gradient Meshes, Blends, Envelopes, Intertwine Groups, Opacity Masks and Objects with Effects. The Document category's Pattern Swatches row and the Objects category's Path Length row are translated in every catalog that has every menu label. `document.info` and the saved report keep the English labels. Showing these labels in the interface language is VectorCraft's own rule. Test: `i18n::tests::document_info_labels_are_in_complete_catalogs` (vectorcraft-ui-egui).
|
||||
The Brushes panel menu's Select All Unused selects the brushes that are not used in the document, as the [Brushes](https://web.archive.org/web/20241230205225/https://helpx.adobe.com/illustrator/using/brushes.html) page (archived copy) describes. A brush counts as used when a stroke paints with it in the art (opacity masks included), in symbols, graph designs, pattern tiles or graphic styles, or in the art of a used brush (`brush.unused`).
|
||||
|
||||
Reference in New Issue
Block a user