如何只擦除 Android 上 Canvas 上的绘图路径而不是图像?

How Do I ONLY Erase The Draw Path Not The Image On The Canvas On Android?

我正在 android 上制作绘图应用程序,它能够将图像加载到 canvas 并在其上绘图,但我不知道如何只擦除绘图路径,现在,如果我要擦除绘图路径,它也会删除我放在 canvas 上的图像,有没有办法只擦除绘图路径?

这是我的代码:

public class DrawingView extends View {

    private Path drawPath;
    private Paint drawPaint, canvasPaint;
    private Canvas drawCanvas;
    private Bitmap canvasBitmap,image=null;

    private Rect clipBounds;
    private Rect destImageRect;

    private int paintColor = 0xFF660000;
    private float mScaleFactor = 1.f,pivotPointX = 0.f,pivotPointY=0.f,offSetX=1.00f,offSetY=1.00f;
    private float brushSize, lastBrushSize;
    private boolean isGesture = false;
    private boolean brushScalling = true,erase = false;

    private ScaleGestureDetector SGD;
    private GestureDetector GD;




    public DrawingView(Context context, AttributeSet attrs){
        super(context, attrs);

        SGD = new ScaleGestureDetector(context,new ScaleGestureListener());
        GD = new GestureDetector(context, new GestureListener());

        setupDrawing();
    }

    protected void setupDrawing(){
        drawPath = new Path();
        drawPaint = new Paint();

        brushSize = getResources().getInteger(R.integer.medium_size);
        lastBrushSize = brushSize;

        drawPaint.setColor(paintColor);
        drawPaint.setAntiAlias(true);
        drawPaint.setStrokeWidth(brushSize);
        drawPaint.setStyle(Paint.Style.STROKE);
        drawPaint.setStrokeJoin(Paint.Join.ROUND);
        drawPaint.setStrokeCap(Paint.Cap.ROUND);

        canvasPaint = new Paint(Paint.DITHER_FLAG);

        destImageRect = new Rect(0,0,getWidth(),getHeight());
    }

    public void setBrushSize(float newSize){
        float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, newSize, getResources().getDisplayMetrics());
        brushSize = pixelAmount;
        drawPaint.setStrokeWidth(brushSize);
    }

    public void setLastBrushSize(float lastSize){
        lastBrushSize = lastSize;
    }

    public float getLastBrushSize(){
        return lastBrushSize;
    }

    public void setErase(boolean isErase){
        erase = isErase;

        if(erase) {
            drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        }else{
            drawPaint.setXfermode(null);
        }
    }

    public void changeBackground(Bitmap bitmap){
        //store image to local var
        image = bitmap;
        //get offset of resolution between image and canvas
        offSetY = (float)image.getHeight()/getHeight();
        offSetX = (float)image.getWidth()/getWidth();
        //creating new canvas
        canvasBitmap = image.copy(Bitmap.Config.ARGB_8888, true);
        drawCanvas = new Canvas(canvasBitmap);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //when size changed, store the new size
        destImageRect = new Rect(0,0,w,h);
        //check whether to use image as background or not
        if(image == null) {
            canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            drawCanvas = new Canvas(canvasBitmap);
        }else{
            canvasBitmap = image.copy(Bitmap.Config.ARGB_8888, true);
            drawCanvas = new Canvas(canvasBitmap);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.scale(mScaleFactor, mScaleFactor, pivotPointX, pivotPointY);
        clipBounds = canvas.getClipBounds();
        canvas.drawPath(drawPath, drawPaint);
        canvas.drawBitmap(canvasBitmap,null, destImageRect,canvasPaint);
        canvas.restore();


    }


    public class GestureListener extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            //zoom out with zoom point of (0,0) top,left
            mScaleFactor=1.f;
            pivotPointX=pivotPointY=0;

            return super.onDoubleTap(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            //need two finger to be on the screen to be register as scrolling
            if(e1.getPointerCount()==2 || e2.getPointerCount()==2){
                pivotPointX += distanceX / mScaleFactor;
                pivotPointY += distanceY / mScaleFactor;
            }

            return super.onScroll(e1, e2, distanceX, distanceY);
        }
    }


    public class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            //get the zoom point or center point of the zoom
            pivotPointX = (detector.getFocusX()/mScaleFactor)+clipBounds.left;
            pivotPointY = (detector.getFocusY()/mScaleFactor)+clipBounds.top;

            return super.onScaleBegin(detector);
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            //get scale factor
            mScaleFactor*=detector.getScaleFactor();
            //set the limit of zoom
            mScaleFactor = Math.max(1f, Math.min(mScaleFactor, 20.0f));

            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
            super.onScaleEnd(detector);

            drawPaint.setStrokeWidth(brushSize/mScaleFactor);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        float touchX = (event.getX()*offSetX/mScaleFactor) + clipBounds.left;
        float touchY = (event.getY()*offSetY/mScaleFactor) + clipBounds.top  ;
        //pass the motion event to the gesture detector first
        SGD.onTouchEvent(event);
        GD.onTouchEvent(event);
        //preventing the used of two finger to trigger drawing event
        if(event.getPointerCount() == 1) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (!isGesture) {
                        drawPath.moveTo(touchX, touchY);
                        drawCanvas.drawPath(drawPath, drawPaint);
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (!isGesture) {
                        drawPath.lineTo(touchX, touchY);
                        drawCanvas.drawPath(drawPath, drawPaint);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    isGesture = false;
                    drawPath.reset();
                    break;
                default:
                    return true;
            }
        }else if(event.getPointerCount() > 1){
            //if two finger are registered at the screen then it is flag as gesture
            //until no finger are on the screen
            isGesture = true;
        }
        //trigger the onDraw() function
        invalidate();

        return true;

    }

    public void setColor(String newColor){
        invalidate();
        paintColor = Color.parseColor(newColor);
        drawPaint.setColor(paintColor);
    }
}

只需更改您的 onDraw 代码以分两个阶段绘制。

首先,您绘制图像。由于它是单独绘制的,因此您不会将图像放入 canvas 位图中。

然后绘制 canvas 位图并渲染路径。 ARGB8888 位图应该是透明的,所以这样做看起来应该没有什么不同。

    public void changeBackground(Bitmap bitmap){
        //store image to local var
        image = bitmap;
        //get offset of resolution between image and canvas
        offSetY = (float)image.getHeight()/getHeight();
        offSetX = (float)image.getWidth()/getWidth();
        //creating new canvas
        // DON'T COPY IMAGE canvasBitmap = image.copy(Bitmap.Config.ARGB_8888, true);
        // just make a blank bitmap
        canvasBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //when size changed, store the new size
        destImageRect = new Rect(0,0,w,h);

        // DON'T COPY IMAGE - just make a blank bitmap
        canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.scale(mScaleFactor, mScaleFactor, pivotPointX, pivotPointY);
        clipBounds = canvas.getClipBounds();
        if (image != null) {
            canvas.drawBitmap(image, 0, 0, canvasPaint);
        }
        // first update the canvas bitmap
        drawCanvas.drawPath(drawPath, drawPaint);
        // then draw it on top of the image
        canvas.drawBitmap(canvasBitmap,null, destImageRect,canvasPaint);
        canvas.restore();
    }