mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 01:15:25 +00:00
Plug-ins: unlinking a gradient stop's spot swatch also clears its plates
A filter or importer that changes a gradient paint unlinks each stop from its swatch and resets its tint, but left the stop's process plates. The PDF and EPS writers read plates only with a spot swatch, so the stop kept a plates array with no ink, saved with the document and compared in later edits. Unlinking now clears the plates too, in fills and strokes; a paint returned unchanged keeps its link, tint and plates. The plate clamping test now checks the decoded output, before admission.
This commit is contained in:
@@ -951,7 +951,8 @@ fn paints(ap: &Appearance, fill: bool) -> Vec<&Paint> {
|
||||
}
|
||||
|
||||
/// `p` without swatch links: a plug-in's colours are its own, so only paints it returned
|
||||
/// unchanged keep theirs.
|
||||
/// unchanged keep theirs. A gradient stop also loses its process plates, which print only with
|
||||
/// a spot swatch.
|
||||
fn unlinked(mut p: Paint) -> Paint {
|
||||
match &mut p {
|
||||
Paint::Solid { swatch, tint, .. } => {
|
||||
@@ -961,8 +962,7 @@ fn unlinked(mut p: Paint) -> Paint {
|
||||
Paint::Gradient(g) => {
|
||||
g.swatch = None;
|
||||
for s in &mut g.gradient.stops {
|
||||
s.swatch = None;
|
||||
s.tint = 1.0;
|
||||
s.set_color(s.color, None);
|
||||
}
|
||||
}
|
||||
Paint::None | Paint::Pattern { .. } => {}
|
||||
|
||||
@@ -109,27 +109,81 @@ fn only_a_radial_keeps_a_focal_point_through_a_plug_in() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A gradient stop's process plates handed back out of range are clamped to 0..1, each in its
|
||||
/// A gradient stop's process plates handed back out of range are read clamped to 0..1, each in its
|
||||
/// place, in a fill and in a stroke (a JSON number too large for `f32` is infinite); plates in range
|
||||
/// and a stop without plates are kept.
|
||||
#[test]
|
||||
fn gradient_stop_plates_are_clamped_through_a_plug_in() {
|
||||
use vectorcraft_color::{Gradient, GradientKind, GradientPaint, GradientStop};
|
||||
let (mut d, ids, _) = doc();
|
||||
let (_, ids, _) = doc();
|
||||
let stops = vec![GradientStop::new(0.0, Color::WHITE), GradientStop::new(0.5, Color::gray(0.5)), GradientStop::new(1.0, Color::BLACK)];
|
||||
let mut p = serde_json::to_value(Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops))))).unwrap();
|
||||
p["gradient"]["stops"][0]["plates"] = json!([-0.5, 1.5, -1e300, 1e300]);
|
||||
p["gradient"]["stops"][1]["plates"] = json!([0.25, 2.0, 0.75, -3.0]);
|
||||
for (i, plates) in [(0, json!([-0.5, 1.5, -1e300, 1e300])), (1, json!([0.25, 2.0, 0.75, -3.0]))] {
|
||||
p["gradient"]["stops"][i]["plates"] = plates;
|
||||
p["gradient"]["stops"][i]["swatch"] = json!("Spot");
|
||||
}
|
||||
let out = json!({"objects": [{"id": ids[0].0, "fills": [p.clone()], "strokes": [{"paint": p}]}]});
|
||||
apply_output(&mut d, &ids, decode_json(out).unwrap(), None, &keep).unwrap();
|
||||
let ap = &d.node(ids[0]).unwrap().appearance;
|
||||
for (what, paint) in [("fill", ap.fill_paint()), ("stroke", ap.stroke_paint())] {
|
||||
let out = decode_json(out).unwrap();
|
||||
let fill = &out[0].fills.as_ref().unwrap()[0];
|
||||
let stroke = &out[0].strokes.as_ref().unwrap()[0].paint;
|
||||
for (what, paint) in [("fill", fill), ("stroke", stroke)] {
|
||||
let Paint::Gradient(g) = paint else { panic!("a gradient {what}") };
|
||||
let plates: Vec<_> = g.gradient.stops.iter().map(|s| s.plates).collect();
|
||||
assert_eq!(plates, [Some([0.0, 1.0, 0.0, 1.0]), Some([0.25, 1.0, 0.75, 0.0]), None], "{what}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A gradient linked to a gradient swatch, whose first stop is linked to a spot swatch at a tint
|
||||
/// with process plates.
|
||||
fn spot_gradient(color: Color) -> Paint {
|
||||
use vectorcraft_color::{Gradient, GradientKind, GradientPaint, GradientStop};
|
||||
let mut spot = GradientStop::new(0.0, color);
|
||||
spot.midpoint = 0.3;
|
||||
spot.opacity = 0.75;
|
||||
spot.set_color(color, Some(("Spot".into(), 0.4)));
|
||||
spot.plates = Some([0.1, 0.2, 0.3, 0.4]);
|
||||
let mut g = GradientPaint::new(Gradient::new(GradientKind::Linear, vec![spot, GradientStop::new(1.0, Color::BLACK)]));
|
||||
g.swatch = Some("Blend".into());
|
||||
Paint::Gradient(Box::new(g))
|
||||
}
|
||||
|
||||
/// A changed gradient handed back loses each stop's spot link, tint and process plates, in a fill
|
||||
/// and in a stroke, and keeps the stop's color, offset, opacity and midpoint; a new stop handed back
|
||||
/// with plates and no link has none.
|
||||
#[test]
|
||||
fn changed_gradient_fill_and_stroke_drop_spot_plates() {
|
||||
let (mut d, ids, _) = doc();
|
||||
let a = ids[0];
|
||||
let was = Color::cmyk(0.0, 0.5, 1.0, 0.0);
|
||||
d.node_mut(a).unwrap().appearance.set_fill(spot_gradient(was));
|
||||
d.node_mut(a).unwrap().appearance.set_stroke(spot_gradient(was));
|
||||
let now = Color::cmyk(0.0, 0.25, 0.5, 0.0);
|
||||
let mut p = serde_json::to_value(spot_gradient(now)).unwrap();
|
||||
p["gradient"]["stops"][1]["plates"] = json!([0.5, 0.5, 0.5, 0.5]);
|
||||
let out = json!({"objects": [{"id": a.0, "fills": [p.clone()], "strokes": [{"paint": p}]}]});
|
||||
apply_output(&mut d, &[a], decode_json(out).unwrap(), None, &keep).unwrap();
|
||||
let ap = &d.node(a).unwrap().appearance;
|
||||
for (what, paint) in [("fill", ap.fill_paint()), ("stroke", ap.stroke_paint())] {
|
||||
let Paint::Gradient(g) = paint else { panic!("a gradient {what}") };
|
||||
assert_eq!(g.swatch, None, "{what}");
|
||||
let stops: Vec<_> = g.gradient.stops.iter().map(|s| (s.offset, s.color, s.opacity, s.midpoint, s.swatch.clone(), s.tint, s.plates)).collect();
|
||||
assert_eq!(stops, [(0.0, now, 0.75, 0.3, None, 1.0, None), (1.0, Color::BLACK, 1.0, 0.5, None, 1.0, None)], "{what}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A gradient handed back as it was keeps its stops' spot links, tints and process plates.
|
||||
#[test]
|
||||
fn unchanged_gradient_paint_keeps_spot_plates() {
|
||||
let (mut d, ids, _) = doc();
|
||||
let a = ids[0];
|
||||
d.node_mut(a).unwrap().appearance.set_fill(spot_gradient(Color::cmyk(0.0, 0.5, 1.0, 0.0)));
|
||||
d.node_mut(a).unwrap().appearance.set_stroke(spot_gradient(Color::cmyk(0.0, 0.5, 1.0, 0.0)));
|
||||
let input: Value = serde_json::from_slice(&encode_input(&d, &[a])).unwrap();
|
||||
let before = d.clone();
|
||||
apply_output(&mut d, &[a], decode(&serde_json::to_vec(&input).unwrap()).unwrap(), None, &keep).unwrap();
|
||||
assert_eq!(d, before);
|
||||
}
|
||||
|
||||
/// A plate that is not a number is 0; infinities go to the nearest end of 0..1.
|
||||
#[test]
|
||||
fn plates_that_are_not_finite_are_in_range() {
|
||||
|
||||
Reference in New Issue
Block a user