mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 02:19:56 -06:00
.ai import: a palette gradient swatch's paint is not linked to itself
The editing-data reader set the paint of each gradient swatch in the palette to link to the swatch's own name. The default gradient swatches and a gradient swatch given a new gradient with swatch.edit hold their gradient without a link, so a document saved as .ai and opened again had swatches that differed from the ones it was saved with. The swatch now holds the gradient alone. Art filled with the gradient is not changed: it still links to a swatch by the gradient's name. The fix also applies to a .ai whose layers are not read, such as a gradient library, where only the palette comes in. Three tests cover a hand-written palette with a gradient swatch named by its gradient and one with a name of its own, a new document's four gradient swatches written by the editing-data writer and read back, and a gradient library without layers.
This commit is contained in:
@@ -2047,6 +2047,37 @@ fn gradients_and_patterns_are_read_back() {
|
||||
same_lines(&gradient_looks(&read_back(&doc)), &gradient_looks(&doc));
|
||||
}
|
||||
|
||||
/// A new document's gradient swatches read back with the paint they were written with, not linked
|
||||
/// to a swatch, and art filled with one of them reads back linked to it.
|
||||
#[test]
|
||||
fn gradient_swatches_read_back_unlinked() {
|
||||
let mut doc = Document::new(200.0, 100.0);
|
||||
let Some(Paint::Gradient(sunset)) = doc.swatch("Sunset").map(|s| s.paint.clone()) else { panic!("no Sunset swatch") };
|
||||
let layer = doc.layers[0].id;
|
||||
let linked = gradient_paint(sunset.gradient.clone(), None, Some("Sunset"));
|
||||
let rect = painted(&mut doc, shapes::rectangle(Rect::new(10.0, 10.0, 90.0, 50.0)), vec![AppearanceItem::Fill(FillLayer::new(linked))]);
|
||||
doc.insert(Some(layer), usize::MAX, rect).unwrap();
|
||||
let back = read_back(&doc);
|
||||
let gradients = |d: &Document| -> Vec<String> {
|
||||
d.swatches_iter()
|
||||
.filter_map(|s| match &s.paint {
|
||||
Paint::Gradient(g) => {
|
||||
Some(format!("{} {:?} stops={} geom={:?} swatch={:?}", s.name, g.gradient.kind, g.gradient.stops.len(), g.geom, g.swatch))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
let want = gradients(&doc);
|
||||
assert_eq!(want.len(), 4, "{want:?}");
|
||||
assert_eq!(gradients(&back), want);
|
||||
let link = back.layers[0].children().and_then(|c| c.first()).map(|n| match n.appearance.items.first().map(AppearanceItem::paint) {
|
||||
Some(Paint::Gradient(g)) => g.swatch.clone(),
|
||||
other => panic!("{other:?}"),
|
||||
});
|
||||
assert_eq!(link, Some(Some("Sunset".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gradients_and_patterns_write_the_same_bytes_again() {
|
||||
let doc = gradients_and_patterns();
|
||||
|
||||
@@ -820,12 +820,13 @@ impl<'a> Reader<'a> {
|
||||
let (paint, global, spot) = match e.cell {
|
||||
Cell::Color { color, global, spot } => (Paint::solid(color), global, spot),
|
||||
// A swatch named by its gradient or pattern takes the name that got in the document.
|
||||
// A gradient swatch's own paint does not link to a swatch; art painted with the
|
||||
// gradient links to it.
|
||||
Cell::Gradient(g) => {
|
||||
let mut gp = vectorcraft_color::gradient::GradientPaint::new(self.gradients.get(&g)?.clone());
|
||||
let gp = vectorcraft_color::gradient::GradientPaint::new(self.gradients.get(&g)?.clone());
|
||||
if e.name == g {
|
||||
e.name = self.global_names.get(Global::Gradient, &g).to_string();
|
||||
}
|
||||
gp.swatch = Some(e.name.clone());
|
||||
(Paint::Gradient(Box::new(gp)), false, false)
|
||||
}
|
||||
Cell::Pattern(p) => {
|
||||
|
||||
@@ -906,6 +906,26 @@ fn a_color_named_as_a_palette_gradient_or_pattern_is_numbered() {
|
||||
assert_eq!(links, [Some("Brand 3".to_string()), Some("Brand 2".to_string())]);
|
||||
}
|
||||
|
||||
/// A palette's gradient swatch holds its gradient without a link to a swatch, whether it is named
|
||||
/// by its gradient or has a name of its own, and the art filled with the gradient links to the
|
||||
/// swatch named by the gradient.
|
||||
#[test]
|
||||
fn a_palette_gradient_swatch_is_not_linked_to_itself() {
|
||||
let gradient = "%AI5_BeginGradient: (Sky)\n(Sky) 0 2 Bd\n[\n%_1 0 50 0 Bs\n%_0 0 50 100 Bs\nBD\n%AI5_EndGradient\n";
|
||||
let palette = "%AI5_BeginPalette\n0 0 Pb\nBb\n2 (Sky) 0 0 0 1 1 0 0 1 0 0 1 Bg\n0 BB\n(Sky)\nPc\n\
|
||||
Bb\n2 (Sky) 0 0 0 1 1 0 0 1 0 0 1 Bg\n0 BB\n(Brand)\nPc\nPB\n%AI5_EndPalette\n";
|
||||
let filled = format!("Bb\n1 (Sky) 0 0 0 10 1 0 0 1 0 0 Bg\n{}f\n0 BB\n", rect_path(0.0, 0.0, 10.0, 10.0));
|
||||
let doc = read_ok(&format!("{gradient}{palette}{}", layer(&filled))).doc;
|
||||
for name in ["Sky", "Brand"] {
|
||||
let sw = doc.swatch(name).unwrap_or_else(|| panic!("no {name} swatch"));
|
||||
let Paint::Gradient(g) = &sw.paint else { panic!("{sw:?}") };
|
||||
assert_eq!(g.swatch, None, "{name}'s own paint");
|
||||
assert_eq!(g.geom, None);
|
||||
assert_eq!(g.gradient.stops.len(), 2);
|
||||
}
|
||||
assert!(matches!(fill(&art(&doc)[0]), Paint::Gradient(g) if g.swatch.as_deref() == Some("Sky")));
|
||||
}
|
||||
|
||||
/// A palette's pattern swatch named by its pattern takes the name the pattern is shown with.
|
||||
#[test]
|
||||
fn a_palette_pattern_swatch_takes_its_patterns_shown_name() {
|
||||
|
||||
@@ -444,7 +444,7 @@ fn a_version_7_palette_keeps_its_swatches_without_names() {
|
||||
let spot = d.swatch("Spot A").unwrap();
|
||||
assert!(spot.spot && spot.global, "{spot:?}");
|
||||
assert!(d.swatches.iter().filter(|s| s.name != "Spot A").all(|s| !s.spot && !s.global));
|
||||
assert!(matches!(&d.swatch("B&W").unwrap().paint, Paint::Gradient(g) if g.swatch.as_deref() == Some("B&W")));
|
||||
assert!(matches!(&d.swatch("B&W").unwrap().paint, Paint::Gradient(g) if g.swatch.is_none()));
|
||||
assert_eq!(d.swatch("Gray K=0").unwrap().paint.color(), Some(Color::gray(0.0)), "1 g is white");
|
||||
}
|
||||
|
||||
@@ -481,8 +481,8 @@ fn gradient_names_are_shown_up_to_their_newline() {
|
||||
let names: Vec<&str> = d.swatches.iter().map(|s| s.name.as_str()).collect();
|
||||
let expected: Vec<&str> = ["[None]"].into_iter().chain((!own.is_empty()).then_some("Sky")).chain([first, second]).collect();
|
||||
assert_eq!(names, expected, "{:?}", r.warnings);
|
||||
assert_eq!(first_stop(&d.swatch(first).unwrap().paint), (Some(first.into()), Some(Color::gray(0.0))));
|
||||
assert_eq!(first_stop(&d.swatch(second).unwrap().paint), (Some(second.into()), Some(Color::gray(0.5))));
|
||||
assert_eq!(first_stop(&d.swatch(first).unwrap().paint), (None, Some(Color::gray(0.0))));
|
||||
assert_eq!(first_stop(&d.swatch(second).unwrap().paint), (None, Some(Color::gray(0.5))));
|
||||
let art = d.layers[0].children().unwrap();
|
||||
let fills: Vec<_> = art.iter().map(|n| first_stop(&n.appearance.fill().unwrap().paint)).collect();
|
||||
assert_eq!(fills, [(Some(second.into()), Some(Color::gray(0.5))), (Some(first.into()), Some(Color::gray(0.0)))]);
|
||||
|
||||
@@ -1331,6 +1331,22 @@ fn an_ai_file_that_comes_in_as_its_pdf_part_keeps_the_swatches_of_its_palette()
|
||||
assert!(d.swatch("Red ink").is_some_and(|s| s.spot));
|
||||
}
|
||||
|
||||
/// A `.ai` gradient library (a palette of gradient swatches and no layers) gets the palette's
|
||||
/// gradient swatches, each holding its gradient without a link to a swatch.
|
||||
#[test]
|
||||
fn an_ai_file_without_layers_keeps_the_gradients_of_its_palette_unlinked() {
|
||||
let sky = "%AI5_BeginGradient: (Sky)\n(Sky) 0 2 Bd\n[\n%_1 0 50 0 Bs\n%_0 0 50 100 Bs\nBD\n%AI5_EndGradient\n";
|
||||
let palette = "%AI5_BeginPalette\n0 0 Pb\nBb\n2 (Sky) 0 0 0 1 1 0 0 1 0 0 1 Bg\n0 BB\n(Sky)\nPc\nPB\n%AI5_EndPalette\n";
|
||||
let art = native(&format!("{sky}{palette}"));
|
||||
let (d, warnings, read) = crate::layered_ai(&private(&art), pdf_part(10.0, 86.0), vec![], false, true, 1.0);
|
||||
assert!(!read, "{warnings:?}");
|
||||
let swatches: Vec<&str> = d.swatches.iter().map(|s| s.name.as_str()).collect();
|
||||
assert_eq!(swatches, ["[None]", "Sky"], "{warnings:?}");
|
||||
let Some(vectorcraft_color::Paint::Gradient(g)) = d.swatch("Sky").map(|s| &s.paint) else { panic!("{:?}", d.swatch("Sky")) };
|
||||
assert_eq!(g.swatch, None, "the swatch's own paint");
|
||||
assert_eq!(g.gradient.stops.len(), 2);
|
||||
}
|
||||
|
||||
/// A `.ai` pattern library (a palette of pattern swatches and no layers) whose PDF part defines no
|
||||
/// pattern gets the patterns its editing data defines with the palette's pattern swatches.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user