diff --git a/crates/engine/src/brush_cmds.rs b/crates/engine/src/brush_cmds.rs index e7178a74..1fa109e8 100644 --- a/crates/engine/src/brush_cmds.rs +++ b/crates/engine/src/brush_cmds.rs @@ -167,6 +167,12 @@ fn stroke_with(s: &mut Session, p: &Value, label: &str, brush: BrushSettings, pt let sel = doc.selection.clone(); let (surf, lock) = crate::channel_cmds::target_surface(doc, id, p)?; let mut brush = brush; + // Erasing a layer with locked transparency (e.g. the Background) can't remove opacity, so + // it paints the background colour instead (Photoshop). `gray` targets are handled above. + if brush.erase && lock { + brush.erase = false; + brush.color = bg; + } if auto_erase { // Pencil Auto Erase: starting on foreground-coloured pixels paints the background colour. let c = surf.rgba(pts[0].x.floor() as i32, pts[0].y.floor() as i32); diff --git a/crates/engine/src/brush_cmds/tests.rs b/crates/engine/src/brush_cmds/tests.rs index f60eaa91..c09d1f8f 100644 --- a/crates/engine/src/brush_cmds/tests.rs +++ b/crates/engine/src/brush_cmds/tests.rs @@ -226,3 +226,19 @@ fn brush_blend_mode_multiply() { let n = rgba(&s2, 20, 20); assert!(n[2] > 0.9 && n[0] < 0.1, "normal paints blue: {n:?}"); } + +#[test] +fn eraser_on_background_layer_paints_the_background_colour() { + // Issue #15: erasing the Background layer (locked transparency) must paint the background + // colour, not silently do nothing (opacity can't be removed there). + let mut s = Session::new(); + s.execute("file.new", json!({"width": 20, "height": 20, "background": "white"})).unwrap(); + s.execute("tools.setColors", json!({"background": "#ff0000"})).unwrap(); + s.execute("paint.stroke", json!({"points": [[2, 10], [18, 10]], "size": 8, "erase": true, "brush": {"hardness": 1.0}})).unwrap(); + let st = s.active().unwrap(); + let c = st.doc.layers[0].surface().unwrap().rgba(10, 10); + assert!(c[0] > 0.9 && c[1] < 0.1 && c[2] < 0.1 && c[3] > 0.99, "erased to opaque background red: {c:?}"); + // A corner the stroke didn't touch stays white. + let w = st.doc.layers[0].surface().unwrap().rgba(10, 2); + assert!(w[0] > 0.9 && w[1] > 0.9 && w[2] > 0.9, "untouched stays white: {w:?}"); +}