Android 使用 PorterDuff 模式擦除位图部分

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3467334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 10:18:24  来源:igfitidea点击:

Erase bitmap parts using PorterDuff mode

androidimage-manipulation

提问by Philipp

I try to erase parts of a bitmap in my Android application by using Porter-Duff Xfermodes.

我尝试使用 Porter-Duff Xfermodes 在我的 Android 应用程序中擦除部分位图。

I have a green background which is overlayed by a blue bitmap. When I touch the screen a "hole" in the overlaying bitmap is supposed to be created making the green background visible. Instead of a hole my current code produces a black dot.

我有一个由蓝色位图覆盖的绿色背景。当我触摸屏幕时,应该在覆盖位图中创建一个“洞”,使绿色背景可见。我当前的代码产生了一个黑点,而不是一个洞。

Below is my code. Any ideas, what I am doing wrong here?

下面是我的代码。任何想法,我在这里做错了什么?

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(new DrawView(this));
}

public class DrawView extends View implements OnTouchListener {

    private int x = 0;
    private int y = 0;

    Bitmap bitmap;
    Canvas bitmapCanvas;

    private final Paint paint = new Paint();
    private final Paint eraserPaint = new Paint();

    public DrawView(Context context) {
        super(context);
        setFocusable(true);
        setFocusableInTouchMode(true);

        this.setOnTouchListener(this);

        // Set background
        this.setBackgroundColor(Color.GREEN);

        // Set bitmap
        bitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.RGB_565);
        bitmapCanvas = new Canvas();
        bitmapCanvas.setBitmap(bitmap);
        bitmapCanvas.drawColor(Color.BLUE);

        // Set eraser paint properties
        eraserPaint.setAlpha(0);
        eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        eraserPaint.setAntiAlias(true);
    }

    @Override
    public void onDraw(Canvas canvas) {
        bitmapCanvas.drawColor(Color.BLUE);
        bitmapCanvas.drawCircle(x, y, 10, eraserPaint);

        canvas.drawBitmap(bitmap, 0, 0, paint);
    }

    public boolean onTouch(View view, MotionEvent event) {
        x = (int) event.getX();
        y = (int) event.getY();

        invalidate();
        return true;
    }

}

采纳答案by Josh

First thought, I'm not sure if setting alpha to 0 on your erase paint object is a good idea. That might make the whole thing ineffective.

首先想到的是,我不确定在擦除绘画对象上将 alpha 设置为 0 是否是个好主意。这可能会使整个事情变得无效。

Also, you should always use Bitmap.Config.ARGB_8888 if you're dealing with alphas.

此外,如果您要处理 alpha,则应始终使用 Bitmap.Config.ARGB_8888。

If you're having trouble with the PorterDuff stuff, though, I would suggest simplifying your approach to ONLY do that (temporarily). That will help you narrow down the part which isn't working. Comment out everything to do with touch and view updates.

但是,如果您在 PorterDuff 的东西上遇到问题,我建议您简化您的方法,只(暂时)这样做。这将帮助您缩小不起作用的部分。注释掉与触摸和查看更新有关的所有内容。

Then you can single out what part of the drawing isn't working right. Set up your constructor like this:

然后你可以挑出图纸的哪一部分工作不正常。像这样设置你的构造函数:

DrawView()
{
    /* Create the background green bitmap */
    ...

    /* Create foreground transparent bitmap */
    ...

    /* Draw a blue circle on the foreground bitmap */
    ...

    /* Apply the foreground to the background bitmap
       using a PorterDuff method */
    ...
}

onDraw()
{
    /* Simply draw the background bitmap */
    ...
}

If you set things up like that, you should be able to tell how your PD method is affecting the green bitmap, and change things accordingly.

如果您这样设置,您应该能够知道您的 PD 方法如何影响绿色位图,并相应地进行更改。

回答by pawan

Here is working code... may help somebody

这是工作代码......可能会帮助某人

public class ImageDemo extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(new Panel(this));   
    }

    class Panel extends View {

        private Bitmap  mBitmap;
        private Canvas  mCanvas;
        private Path    mPath;
        private Paint   mPaint;

        Bitmap bitmap;
        Canvas pcanvas;

        int x = 0;
        int y =0;
        int r =0;

        public Panel(Context context) {
            super(context);

            Log.v("Panel", ">>>>>>");

            setFocusable(true);
            setBackgroundColor(Color.GREEN);

            // setting paint 
            mPaint = new Paint();
            mPaint.setAlpha(0);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
            mPaint.setAntiAlias(true);

            // getting image from resources
            Resources r = this.getContext().getResources();

            Bitmap bm = BitmapFactory.decodeResource(getResources(),  R.drawable.mickey);

            // converting image bitmap into mutable bitmap  
            bitmap =  bm.createBitmap(295, 260, Config.ARGB_8888);
            pcanvas = new Canvas();
            pcanvas.setBitmap(bitmap);    // drawXY will result on that Bitmap
            pcanvas.drawBitmap(bm, 0, 0, null);           
        }

        @Override
        protected void onDraw(Canvas canvas) {  
            // draw a circle that is  erasing bitmap            
            pcanvas.drawCircle(x, y, r, mPaint);

            canvas.drawBitmap(bitmap, 0, 0,null);

            super.onDraw(canvas);
        }       

        @Override
        public boolean onTouchEvent(MotionEvent event) {        
             // set parameter to draw circle on touch event
             x = (int) event.getX();
             y = (int) event.getY();

             r =20;
             // At last invalidate canvas
             invalidate();
             return true;
        }
    }
}

回答by Daniel Nyamasyo

Here is another advancement for your solution ... See Demo example

这是您的解决方案的另一项进步......请参阅演示示例

public class MainActivity extends Activity {

    Bitmap bp;
    Canvas bitmapCanvas;
    DrawView drawImg;
    LinearLayout ln1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        ln1 = (LinearLayout) findViewById(R.id.ln1);
        drawImg = new DrawView(this);
        ln1.addView(drawImg);

    }



    public class DrawView extends View implements View.OnTouchListener {

        private int x = 0;
        private int y = 0;

        Bitmap bitmap;
        Path circlePath;
        Paint circlePaint;

        private final Paint paint = new Paint();
        private final Paint eraserPaint = new Paint();


        public DrawView(Context context){
            super(context);
            setFocusable(true);
            setFocusableInTouchMode(true);
            this.setOnTouchListener(this);

            // Set background
            this.setBackgroundColor(Color.CYAN);
            bp = BitmapFactory.decodeResource(getResources(), R.drawable.bg);

            // Set bitmap
            bitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
            bitmapCanvas = new Canvas();
            bitmapCanvas.setBitmap(bitmap);
            bitmapCanvas.drawColor(Color.TRANSPARENT);
            bitmapCanvas.drawBitmap(bp, 0, 0, null);

            circlePath = new Path();
            circlePaint = new Paint();
            circlePaint.setAntiAlias(true);
            circlePaint.setColor(Color.BLUE);
            circlePaint.setStyle(Paint.Style.STROKE);
            circlePaint.setStrokeJoin(Paint.Join.MITER);
            circlePaint.setStrokeWidth(4f);

            // Set eraser paint properties
            eraserPaint.setAlpha(0);
            eraserPaint.setStrokeJoin(Paint.Join.ROUND);
            eraserPaint.setStrokeCap(Paint.Cap.ROUND);
            eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            eraserPaint.setAntiAlias(true);

        }

        @Override
        public void onDraw(Canvas canvas) {

            canvas.drawBitmap(bitmap, 0, 0, paint);
            bitmapCanvas.drawCircle(x, y, 30, eraserPaint);

            canvas.drawPath(circlePath, circlePaint);
        }

        public boolean onTouch(View view, MotionEvent event) {
            x = (int) event.getX();
            y = (int) event.getY();

            bitmapCanvas.drawCircle(x, y, 30, eraserPaint);

            circlePath.reset();
            circlePath.addCircle(x, y, 30, Path.Direction.CW);

            int ac=event.getAction();
            switch(ac){
                case MotionEvent.ACTION_UP:
                    Toast.makeText(MainActivity.this, String.valueOf(x), Toast.LENGTH_SHORT).show();
                    circlePath.reset();
                    break;
            }
            invalidate();
            return true;
        }
    }
}

read more

阅读更多