#1063: keep the Gradient Ramp inside the layer's alpha
The Gradient Ramp wrote alpha 1.0 to every pixel, so a shape layer's transparent area filled up with the ramp and the layer's bounds showed instead of the shape. The ramp now uses the pixel's own alpha on the CPU and in the GPU kernel, as the #939 fix does for the noise effects. A regression test checks that transparent pixels stay transparent at two Blend With Original values. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
470ea7a3af
commit
8eece41c7e
|
|
@ -44,7 +44,9 @@ fn gradient_ramp(ctx: &EffectCtx, mut b: Buf) -> Buf {
|
|||
}
|
||||
let t = t.clamp(0.0, 1.0);
|
||||
let c = [c0[0] + (c1[0] - c0[0]) * t, c0[1] + (c1[1] - c0[1]) * t, c0[2] + (c1[2] - c0[2]) * t];
|
||||
put(px, c, 1.0, blend);
|
||||
// The ramp fills only where the layer has alpha (#1063), so it keeps the source alpha.
|
||||
let a = px[3];
|
||||
put(px, c, a, blend);
|
||||
}
|
||||
});
|
||||
b
|
||||
|
|
@ -400,6 +402,24 @@ mod generator_tests {
|
|||
Image::filled(32, 32, [1.0, 0.0, 0.0, 1.0])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gradient_ramp_stays_inside_the_layer_alpha() {
|
||||
// #1063: a shape's transparent pixels stay transparent; the ramp fills only the shape.
|
||||
let mut img = Image::filled(40, 24, [1.0, 0.0, 0.0, 1.0]);
|
||||
for (i, p) in img.data.iter_mut().enumerate() {
|
||||
let a = if i % 40 < 10 { 0.0 } else { 1.0 };
|
||||
*p = p.map(|c| c * a);
|
||||
}
|
||||
for blend in [0.0, 50.0] {
|
||||
let o = run_fx("ec.generate.gradientramp", &[("blend", num(blend))], img.clone(), 0.0, EffectEnv::default());
|
||||
for (src, out) in img.data.iter().zip(&o.img.data) {
|
||||
assert!((src[3] - out[3]).abs() < 1e-6, "blend {blend}: alpha {} became {}", src[3], out[3]);
|
||||
assert!(out[..3].iter().all(|&c| c <= out[3] + 1e-6), "blend {blend}: premultiplied colour above alpha");
|
||||
}
|
||||
assert!(o.img.data.iter().any(|p| p[3] > 0.99), "blend {blend}: the ramp is drawn inside the shape");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checkerboard_blending_none_shows_pattern_only_and_size_from_width() {
|
||||
let set = [("width", num(8.0)), ("height", num(2.0))];
|
||||
|
|
|
|||
|
|
@ -806,7 +806,8 @@ fn pointwise(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|||
t = clamp(t, 0.0, 1.0);
|
||||
let c0 = P.f[1].xyz;
|
||||
let c1 = P.f[2].xyz;
|
||||
px = put(px, c0 + (c1 - c0) * t, 1.0, P.f[3].z);
|
||||
// Keep the source alpha, as the CPU path does (#1063): the ramp fills only the shape.
|
||||
px = put(px, c0 + (c1 - c0) * t, px.w, P.f[3].z);
|
||||
}
|
||||
case 10u: {
|
||||
let contrast = P.f[0].x;
|
||||
|
|
|
|||
Loading…
Reference in New Issue