8

以下の DrawingSurfaceView クラスを利用した描画アプリを作成しています。そのクラスには、ユーザーがオンとオフを切り替えることができる eraserPaint と呼ばれるペイントがあります。代わりに、黒い線を描くだけです..

キャンバスを透明なpngとして保存すると、消しゴムは正しいのですが、画面には黒く表示されます..

ブロブに「Erik」と書くために使用される EraserPaint の電話のスクリーンショット

ここに画像の説明を入力

キャンバスから PNG を保存 ここに画像の説明を入力

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

5 に答える 5

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 をさらに送信できます。

于 2013-06-21T15:16:43.590 に答える
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();
        }
    }
}

参考までに、フォアグラウンド ビットマップが非常に大きい場合、パフォーマンスが低下します。これを解決するには、最後に指が触れた領域のみを無効にする必要があります。

于 2013-12-06T06:20:27.903 に答える
0

キャンバスを消去して無効にするには、キャンバスの setXfermode を null に設定する必要があります。コードの最後の行を確認してください。

if(view.getId()==R.id.erase_btn) {

        erase_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onDraw.setErase(true);
            }
        }
}

public void setErase(boolean isErase){
    erase=isErase;
    if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    else drawPaint.setXfermode(null);
}
于 2015-11-17T06:35:50.510 に答える
-2

isEraser = true消しゴム (つまり)を選択するときにブール変数を使用でき、onDraw()消しゴムでない場合はパスを描画できます。

@Override
protected void onDraw(Canvas canvas) {
  if(!isEraser ){
   canvas.drawPath(mPath, mPaint);
  }
}
于 2015-09-14T10:09:21.817 に答える