试图为画布创建橡皮擦涂料

时间:2013-06-19 17:20:09

标签: android android-canvas paint

我正在创建一个利用下面的DrawingSurfaceView类的绘图应用程序。在那个类中,我有一个Paint Called橡皮图画,用户可以打开和关闭..当在那个画面上假设橡皮擦的路径是什么。但它只是画了一条黑线..

当我将画布保存为透明png时,橡皮擦是正确的,但在屏幕上它显示为黑色..

用于在blob上写“Erik”的EraserPaint手机屏幕截图

enter image description here

从画布中保存PNG enter image description here

eraserPaint看起来像这样:

eraserPaint = new Paint();
        eraserPaint.setAlpha(0);
        eraserPaint.setColor(Color.TRANSPARENT);
        eraserPaint.setStrokeWidth(60);
        eraserPaint.setStyle(Style.STROKE);
        eraserPaint.setMaskFilter(null);
        eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        eraserPaint.setAntiAlias(true);

整个班级

     public KNDrawingSurfaceView(Context c, float width, float height, KNSketchBookActivity parent) {

        super(c);

        myWidth = width;
        myHeight = height;

        mBitmap = Bitmap.createBitmap((int) myWidth, (int) myHeight, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);

        _parent = parent;


        mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f);


        tile = new Paint();

        tileImage = BitmapFactory.decodeResource(getResources(), R.drawable.checkerpattern);
        shader = new BitmapShader(tileImage, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
        tile.setShader(shader);


        mPath = new Path();
        eraserPaint = new Paint();
        eraserPaint.setAlpha(0x00);
        eraserPaint.setColor(Color.TRANSPARENT);
        eraserPaint.setStrokeWidth(60);
        eraserPaint.setStyle(Style.STROKE);
        //eraserPaint.setMaskFilter(null);
        eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        eraserPaint.setAntiAlias(true);

        mBitmapPaint = new Paint(Paint.DITHER_FLAG);



        mCanvas.drawRect(0, 0, myWidth, myHeight, tile);

        mCanvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {

        super.onSizeChanged(w, h, oldw, oldh);


    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (!_parent.isDrawerOpen()&&mPaint!=null) {
            Log.v("onDraw:", "curent paths size:" + paths.size());

            //mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            //canvas.drawPath(mPath, mPaint);
            for (int i=0;i< paths.size();i++) {
                tempPaint =  paints.get(i);
                eraserPaint.setStrokeWidth(tempPaint.getStrokeWidth());
                if(fills.get(i)){
                    tempPaint.setStyle(Style.FILL_AND_STROKE);
                    eraserPaint.setStyle(Style.FILL_AND_STROKE);
                }else{
                    tempPaint.setStyle(Style.STROKE);
                    eraserPaint.setStyle(Style.STROKE);
                }
                if(erasers.get(i)){
                    //tempPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                    canvas.drawPath(paths.get(i), eraserPaint);
                }else{
                    //tempPaint.setXfermode(null);
                    canvas.drawPath(paths.get(i), tempPaint);
                }
                //canvas.drawPath(paths.get(i), tempPaint);
            }
            if(_parent.toggleFill.isChecked()){
               mPaint.setStyle(Style.FILL_AND_STROKE); 
               eraserPaint.setStyle(Style.FILL_AND_STROKE);

            }else{
               mPaint.setStyle(Style.STROKE);
               eraserPaint.setStyle(Style.STROKE);
            }
            if(_parent.toggleErase.isChecked()){
               //mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                 canvas.drawPath(mPath, eraserPaint);
            }else{
                //mPaint.setXfermode(null);
                canvas.drawPath(mPath, mPaint);
            }
            //canvas.drawPath(mPath, mPaint);
        }
    }

    public void onClickUndo() {

        if (paths.size() > 0) {
            undonePaths.add(paths.remove(paths.size() - 1));
            undonePaints.add(paints.remove(paints.size() - 1));
            undoneFills.add(fills.remove(fills.size() - 1));
            undoneErasers.add(erasers.remove(erasers.size() - 1));
            clearCanvasCache();
            invalidate();
        } else {

        }
        _parent.checkButtonStates();
    }

    public void onClickRedo() {

        if (undonePaths.size() > 0) {
            paths.add(undonePaths.remove(undonePaths.size() - 1));
            paints.add(undonePaints.remove(undonePaints.size() - 1));
            fills.add(undoneFills.remove(undoneFills.size() - 1));
            erasers.add(undoneErasers.remove(undoneErasers.size() - 1));
            clearCanvasCache();
            invalidate();
        } else {

        }
        _parent.checkButtonStates();
    }

    public void onClickClear() {

        paths.clear();
        paints.clear();
        fills.clear();
        erasers.clear();
        undoneFills.clear();
        undonePaths.clear();
        undonePaints.clear();
        undoneErasers.clear();
        clearCanvasCache();
        invalidate();
        _parent.checkButtonStates();
    }

    public void saveDrawing() {

        FileOutputStream outStream = null;
        String fileName = "tempTag";
        try {

            outStream = new FileOutputStream("/sdcard/" + fileName + ".png");

            mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
            outStream.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

    }

    private float mX, mY;

    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y) {

        undonePaths.clear();
        undonePaints.clear();
        undoneFills.clear();
        mPath.reset();
        mPath.moveTo(x, y);

        mX = x;
        mY = y;
    }

    private void touch_move(float x, float y) {

        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {

        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        if(_parent.toggleErase.isChecked()){
            mCanvas.drawPath(mPath, eraserPaint);
            erasers.add(true);
            paints.add(eraserPaint);
        }else{
            mCanvas.drawPath(mPath, mPaint);
            erasers.add(false);
            paints.add(mPaint);
        }

        // kill this so we don't double draw

        paths.add(mPath);


        if(_parent.toggleFill.isChecked()){
            fills.add(true);
        }else{
            fills.add(false);
        }
        if(_parent.toggleErase.isChecked()){
            erasers.add(true);
        }else{
            erasers.add(false);
        }


        _parent.checkButtonStates();
        mPath = new Path();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(mPaint==null &&!_parent._showingAlert){
            _parent.showNoPaintAlert();
        }

        if (!_parent.isDrawerOpen()&&mPaint!=null) {
            float x = event.getX();
            float y = event.getY();
            if (x > myWidth) {
                x = myWidth;

            }
            if (y > myHeight) {
                y = myHeight;

            }
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
            }
            return true;
        } else {
            return true;
        }
    }

    public void clearCanvasCache() {

        mBitmap = Bitmap.createBitmap((int) myWidth, (int) myHeight, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }
}

我应该补充一点,我将这个自定义视图添加到具有方格图案作为背景图像的相对布局中。

请请帮助..我需要使用橡皮擦涂料后不显示黑色的预览图像..我需要它来显示背后的方格图案..我知道橡皮擦正在工作,因为那些黑色橡皮擦标记保存透明。

新笔记

我在玩耍,发现了一些好奇的东西。试验,我尝试从绘图切换到传递给canvas方法的onDraw并直接切换到我在名为mCanvas的构造函数中设置的画布,并注意到它没有画到目前为止我可以看到..所以我添加了一个日志onDraw,如此:

 protected void onDraw(Canvas canvas) {
       Log.v("DRAWING SURFACE", "canvas:"+canvas+" mCanvas:"+mCanvas);

吐出

06-21 11:10:43.994: V/DRAWING SURFACE(4532): canvas:android.view.Surface$CompatibleCanvas@42a8c030 mCanvas:android.graphics.Canvas@431df180

4 个答案:

答案 0 :(得分:7)

我的应用程序遇到了同样的问题。我甚至试过“手指画”示例代码,仍然有同样的问题。我从来没有能够将橡皮擦作为一条路径,但我能够找到一种解决方法。当我擦除时,不是绘制路径,而是当用户将手指放下或有“移动”事件时绘制一个圆圈(可能是任何形状):

case MotionEvent.ACTION_DOWN:
mPaint.setStrokeWidth(25);
            mPaint.setXfermode(new PorterDuffXfermode(
                    PorterDuff.Mode.CLEAR));
            mCanvas.drawCircle(x, y, 10, mPaint);
            isErase = true;
            invalidate();
        }
        touch_start(x, y);
        invalidate();
        break;
case MotionEvent.ACTION_MOVE:   
        if(isErase)
        {
            mCanvas.drawCircle(x, y, 20, mPaint);
        }
        else{
            touch_move(x, y);
        }invalidate();
        break;

将此功能合并到您的代码中需要一些时间,但我保证您花费的时间少于您尝试解决此问题所花费的时间。如果您认为它有用,我可以向您发送更多我的PaintView。

答案 1 :(得分:1)

遇到同样的问题,尝试了所有其他解决方案,没有运气。

但我有一个解决方法。您可以添加位图来存储笔划。

    public void init(int width, int height) {
    Log.i(TAG,"init with "+width+"x"+height);
    foreground = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    cacheCanvas = new Canvas();
    cacheCanvas.setBitmap(foreground);
}

每当有任何触摸时,使用当前绘画和当前笔划宽度记录笔划。 (油漆可以是任何颜色,包括橡皮擦油漆)

然后覆盖onDraw(Canvas)方法。由于位图支持橡皮擦而画布不支持,我们可以先在位图上绘制结果图像,然后将位图绘制到画布上。

    @Override
protected void onDraw(Canvas canvas) {
    // Log.i(TAG,"onDraw called");
    synchronized (strokes) {
        if (strokes.size() > 0) {
            for (Stroke s : strokes) {
                cacheCanvas.drawPath(s.path, s.color);
            }
            canvas.drawBitmap(foreground, 0, 0, null);
            strokes.clear();
        }
    }
}

仅供参考,如果前景位图非常大,性能会很低。为了解决这个问题,我们应该只使最新手指接触的区域无效。

答案 2 :(得分:0)

这只是一个猜测:它可能与硬件加速有关。尝试禁用硬件加速。如果这有帮助,您可以创建一个视图大小的位图,将所有东西绘制到该位图,然后将位图绘制到视图的画布中。

答案 3 :(得分:0)

要使画布擦除和无效,必须将画布的setXfermode设置为null。检查代码的最后一行。

public class SameTestDifferentBrowsers {

WebDriver driver;

@BeforeMethod
@Parameters("browser")
public void openBroswer(String browser) {

    if (browser.equalsIgnoreCase("Chrome")) {
        System.out.println(System.getProperty("user.dir"));
        System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir")+"//lib//browsers//chromedriverMac");

        driver = new ChromeDriver();

    } else if (browser.equalsIgnoreCase("Firefox")) {
        driver = new FirefoxDriver();
    } else if (browser.equalsIgnoreCase("safari")) {
        System.setProperty("webdriver.safari.driver", System.getProperty("user.dir")+"//lib//browsers//SafariDriver.safariextz");
        driver = new SafariDriver();
    }
}

@AfterMethod
public void closeBrowser() {
    driver.quit();
}

@Test
public void login_TestCase() {
    driver.get("https://www.google.com");

}
}

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Parallel test suite" parallel="tests">
  <test name="Firefox Test">
  <parameter name="browser" value="browser"/>
    <classes>
      <class name="ParallelBrowser.SameTestDifferentBrowsers"/>
    </classes>
  </test>
  <test name="Chrome Test">
  <parameter name="browser" value="browser"/>
    <classes>
      <class name="ParallelBrowser.SameTestDifferentBrowsers"/>
    </classes>
  </test>
    <test name="Safari Test">
    <parameter name="browser" value="browser"/>
    <classes>
      <class name="ParallelBrowser.SameTestDifferentBrowsers"/>
    </classes>
  </test>
</suite>