mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 16:33:22 -06:00
M3.91: Object > Flatten Transparency turns transparent art into opaque art that looks the same
object.flattenTransparency {preset?|options, ids?} splits the targets into groups of overlapping
objects. Groups with transparency become atomic regions (faces of the arrangement of every fill,
outlined stroke and clipping path) filled with the colour the renderer composites there: blend
modes, group opacity, isolated and non-isolated groups, knockout groups and knockout shapes, over
white or (Preserve Alpha) over nothing. Regions reached by gradients, patterns, images, opacity
masks or raster effects are rendered into one image per group, under the regions, clipped to
them with Clip Complex Regions. The raster/vector balance rasterizes whole groups past its region
budget (all at 0). Options and presets live in FlattenOptions; single visible paints keep their
colour and overprint; text and strokes can be outlined everywhere. One undo step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
cc514957f5
commit
f75d7628c7
@@ -490,7 +490,7 @@ fn outlined_stroke(d: &mut Document, brushes: &[vectorcraft_brush::Brush], path:
|
||||
/// Path `l` with every stroke outlined, in appearance order: runs of fills stay on copies of
|
||||
/// the path, each stroke becomes its outline (or brush art), grouped when there are several.
|
||||
/// `None` when `l` has no stroke to outline.
|
||||
fn outline_strokes(d: &mut Document, brushes: &[vectorcraft_brush::Brush], l: &Node) -> Option<Node> {
|
||||
pub(crate) fn outline_strokes(d: &mut Document, brushes: &[vectorcraft_brush::Brush], l: &Node) -> Option<Node> {
|
||||
if !l.appearance.items.iter().any(|i| matches!(i, AppearanceItem::Stroke(st) if outlinable(st))) {
|
||||
return None;
|
||||
}
|
||||
@@ -536,6 +536,29 @@ fn outline_strokes(d: &mut Document, brushes: &[vectorcraft_brush::Brush], l: &N
|
||||
Some(root)
|
||||
}
|
||||
|
||||
/// Outline the strokes of every path under `root` in place: → (the id now standing for `root`,
|
||||
/// how many paths changed).
|
||||
pub(crate) fn outline_strokes_under(d: &mut Document, brushes: &[vectorcraft_brush::Brush], root: NodeId) -> Result<(NodeId, usize)> {
|
||||
let Some(n) = d.node(root).cloned() else { return Ok((root, 0)) };
|
||||
let mut lv = vec![];
|
||||
leaves(&n, &mut lv);
|
||||
let (mut replacement, mut changed) = (root, 0);
|
||||
for l in lv {
|
||||
if matches!(l.kind, NodeKind::Text(_)) {
|
||||
continue;
|
||||
}
|
||||
let Some(new) = outline_strokes(d, brushes, &l) else { continue };
|
||||
let (par, idx, _) = d.position(l.id).ok_or(EngineError::NoNode(l.id))?;
|
||||
let nid = d.insert(par, idx, new)?;
|
||||
d.remove(l.id)?;
|
||||
changed += 1;
|
||||
if l.id == root {
|
||||
replacement = nid;
|
||||
}
|
||||
}
|
||||
Ok((replacement, changed))
|
||||
}
|
||||
|
||||
fn outline_stroke(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
let roots = selected_roots(s)?;
|
||||
let ids = s.edit("Outline Stroke", |d, sel| {
|
||||
@@ -543,24 +566,9 @@ fn outline_stroke(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
let mut new_sel = vec![];
|
||||
let mut changed = 0;
|
||||
for root in &roots {
|
||||
let Some(n) = d.node(*root).cloned() else { continue };
|
||||
let mut lv = vec![];
|
||||
leaves(&n, &mut lv);
|
||||
let mut root_replacement = None;
|
||||
for l in lv {
|
||||
if matches!(l.kind, NodeKind::Text(_)) {
|
||||
continue;
|
||||
}
|
||||
let Some(new) = outline_strokes(d, &brushes, &l) else { continue };
|
||||
let (par, idx, _) = d.position(l.id).ok_or(EngineError::NoNode(l.id))?;
|
||||
let nid = d.insert(par, idx, new)?;
|
||||
d.remove(l.id)?;
|
||||
changed += 1;
|
||||
if l.id == *root {
|
||||
root_replacement = Some(nid);
|
||||
}
|
||||
}
|
||||
new_sel.push(root_replacement.unwrap_or(*root));
|
||||
let (id, n) = outline_strokes_under(d, &brushes, *root)?;
|
||||
new_sel.push(id);
|
||||
changed += n;
|
||||
}
|
||||
if changed == 0 {
|
||||
return Err(EngineError::Other("Outline Stroke: no stroked paths selected".into()));
|
||||
|
||||
Reference in New Issue
Block a user