I'm trying to write a semi-transparent eraser brush into an app I'm developing but have found two problems crop up depending on how it is implemented. Hopefully there is a workaround I can get pointed at.
Code samples are in mono droid / xamarin
So, pretty typically I have a setup which draws paths on to a drawing canvas. the OnDraw
method of my view draws its basic bitmap and then my path on top of that.
// Canvas is set up elsewhere
canvasBitmap = Bitmap.CreateBitmap(w, h, Bitmap.Config.Argb8888);
DrawCanvas.SetBitmap(canvasBitmap);
protected override void OnDraw(Canvas canvas)
{
base.OnDraw(canvas);
// Draw the saved canvas bitmap
canvas.DrawBitmap(canvasBitmap, 0, 0, canvasPaint);
// On top of that draw the current path
canvas.DrawPath(DrawPath, DrawPaint);
}
public bool OnTouch(View view, MotionEvent ev)
{
float touchX = ev.GetX();
float touchY = ev.GetY();
switch (ev.Action)
{
case MotionEventActions.Down:
if (Editable)
{
// I've removed a bunch of code here but it basically
// moves the path start to the touch point and sets
// up the brush to start erasing. It does set the
// porterduff mode to dstOur
DrawPaint.SetMaskFilter(null);
DrawPaint.SetXfermode( new PorterDuffXfermode(PorterDuff.Mode.DstOut));
DrawPath.MoveTo(touchX, touchY);
} else { return false; }
break;
case MotionEventActions.Move:
// Just draws a line to the new touch coordinates
DrawPath.LineTo(touchX, touchY);
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
// saves some data about the path and draws to the drawing canvas.
DrawCanvas.DrawPath(DrawPath, DrawPaint);
// Recycle it
DrawPath.Reset();
break;
}
return true;
}
So there are two ways to draw the eraser line while it is being drawn. The first is to draw on to the drawing canvas (which writes to the canvasBitmap
) and the second is to draw directly on the canvas
provided by OnDraw
.
My problems are as follows:
If I draw on to the DrawCanvas
I get a stacking effect where the erased line gets progressively more and more transparent. This is kind of understandable because during each OnDraw
loop the eraser path is being baked down into the canvasBitmap
.
If I draw directly on to the canvas
provided by OnDraw
I get the "black line" problem which also makes some sense as it is erasing on to nothing. When the path is drawn on to the canvasBitmap
in the Up
event then everything looks right and there's a nice semi-transparent eraser line.
Ideally there is a different solution of which I am not aware for the "black line" problem but I've not been able to find anything. I've also tried thinking of ways to cache the canvasBitmap
and while a draw event is in progress use that rather than the active copy being drawn to by the Move
events.
Does anyone have something I could take a look at which might suggest a solution? Java is fine as it's easy to port to c#.
Many thanks in advance! Nigel