mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-09 03:48:01 +00:00
Save As .ai: keep the group fills and strokes of pattern tiles in the editing data
A pattern fill is written as its tiles cut to the shape. A group in the tile art with fills or strokes of its own was written as its members alone, without that paint, because only the layers and the symbols' art were baked before writing. The patterns' tile art is now baked the same way as the symbols' art, so its group paint and geometry effects are written as plain paths.
This commit is contained in:
@@ -156,26 +156,35 @@ fn crlf(s: &str) -> Vec<u8> {
|
||||
s.replace('\n', "\r\n").into_bytes()
|
||||
}
|
||||
|
||||
/// `doc` with its geometry effects baked ([`vectorcraft_effects::bake_document`]), in its symbols'
|
||||
/// art too (which instances are written as); `None` when nothing changes.
|
||||
/// `doc` with its geometry effects and group paint baked ([`vectorcraft_effects::bake_document`]),
|
||||
/// in its symbols' art and its patterns' tile art too (which instances and pattern fills are
|
||||
/// written as); `None` when nothing changes.
|
||||
fn baked(doc: &Document) -> Option<Document> {
|
||||
let baked = vectorcraft_effects::bake_document(doc);
|
||||
let d = baked.as_ref().unwrap_or(doc);
|
||||
if !d.symbols.iter().any(|s| vectorcraft_effects::needs_bake(&s.art)) {
|
||||
let needs = vectorcraft_effects::needs_bake;
|
||||
if !d.symbols.iter().any(|s| needs(&s.art)) && !d.patterns.iter().any(|p| p.art.iter().any(|a| needs(a))) {
|
||||
return baked;
|
||||
}
|
||||
// The symbols' art baked as the layers of a copy of the document.
|
||||
// The symbols' art, then each pattern's art, baked as the layers of a copy of the document.
|
||||
let mut art = d.clone();
|
||||
art.layers = d.symbols.iter().map(|s| Arc::new(Node::group(s.art.id, vec![s.art.clone()]))).collect();
|
||||
let symbols = d.symbols.iter().map(|s| Arc::new(Node::group(s.art.id, vec![s.art.clone()])));
|
||||
let patterns = d.patterns.iter().map(|p| Arc::new(Node::group(vectorcraft_doc::NodeId(0), p.art.clone())));
|
||||
art.layers = symbols.chain(patterns).collect();
|
||||
// The copy keeps what baking adds to the document (the images color adjustments make).
|
||||
let Some(mut out) = vectorcraft_effects::bake_document(&art) else { return baked };
|
||||
let arts: Vec<Option<Arc<Node>>> = out.layers.iter().map(|l| l.children().and_then(|c| c.first()).cloned()).collect();
|
||||
out.layers = d.layers.clone();
|
||||
for (s, a) in out.symbols.iter_mut().zip(arts) {
|
||||
if let Some(a) = a {
|
||||
let layers = std::mem::replace(&mut out.layers, d.layers.clone());
|
||||
let mut members = layers.iter().map(|l| l.children().cloned().unwrap_or_default());
|
||||
for s in out.symbols.iter_mut() {
|
||||
if let Some(a) = members.next().and_then(|m| m.first().cloned()) {
|
||||
s.art = a;
|
||||
}
|
||||
}
|
||||
for p in out.patterns.iter_mut() {
|
||||
if let Some(m) = members.next() {
|
||||
p.art = m;
|
||||
}
|
||||
}
|
||||
Some(out)
|
||||
}
|
||||
|
||||
|
||||
@@ -718,6 +718,27 @@ fn an_adjusted_image_in_a_symbol_is_written_in_its_adjusted_color() {
|
||||
assert_ne!(fill, paint(&solid(Color::rgb(0.0, 0.0, 0.0))), "the image is adjusted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_group_fill_in_a_pattern_tile_is_written() {
|
||||
let mut doc = Document::new(200.0, 100.0);
|
||||
let layer = doc.layers[0].id;
|
||||
let dot = Node::path(doc.alloc_id(), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), Appearance::default());
|
||||
let mut group = Node::group(doc.alloc_id(), vec![Arc::new(dot)]);
|
||||
group.appearance = Appearance::basic(solid(Color::rgb(1.0, 0.0, 0.0)), Paint::None, 0.0).into();
|
||||
doc.patterns.push(vectorcraft_doc::PatternDef::new("Dots", vec![Arc::new(group)]));
|
||||
let filled = Node::path(
|
||||
doc.alloc_id(),
|
||||
shapes::rectangle(Rect::new(20.0, 20.0, 40.0, 40.0)),
|
||||
Appearance::basic(Paint::Pattern { pattern: "Dots".into(), xf: Affine::IDENTITY }, Paint::None, 0.0),
|
||||
);
|
||||
doc.insert(Some(layer), usize::MAX, filled).unwrap();
|
||||
let back = read_back(&doc);
|
||||
let mut all = vec![];
|
||||
paths(back.layers[0].children().unwrap(), &mut all);
|
||||
let red = paint(&solid(Color::rgb(1.0, 0.0, 0.0)));
|
||||
assert!(all.iter().any(|p| p.appearance.items.iter().any(|i| paint(i.paint()) == red)), "the tiles keep their group's fill");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effects_on_a_fill_are_reported_left_out() {
|
||||
let mut doc = Document::new(200.0, 100.0);
|
||||
|
||||
Reference in New Issue
Block a user