【问题标题】:How to calculate the percentage of erased area of a bitmap in android?如何计算android中位图擦除区域的百分比?
【发布时间】:2013-08-22 13:36:24
【问题描述】:

我是安卓新手。我正在做一个可以用手指擦除画布上的位图的应用程序。像手指画橡皮擦之类的东西。我想计算擦除区域的百分比(例如,60% 已从完整图像中擦除)。请帮我这样做..提前谢谢..

我尝试了一些方法。它总是给我0%。它不工作。请参阅该方法的代码底部..

自定义视图

public class MyView extends View
{
    private final Paint mPaint;
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private final Path mPath;
    private final Paint mBitmapPaint;
    private Bitmap eraseableBitmap;

    public MyView(Context context)
    {
        super(context);
        if (Build.VERSION.SDK_INT >= 11)
        {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        mPaint = new Paint();
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    }

    protected void PaintObjectInit()
    {
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(30);
    }

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

        try
        {
            //mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            eraseableBitmap =
                BitmapFactory.decodeResource(this.getResources(), R.drawable.tharu_rena_over).copy(
                    Bitmap.Config.ARGB_8888, true);

            eraseableBitmap = getResizedBitmap(eraseableBitmap, h, w);

            mCanvas = new Canvas(eraseableBitmap );
        }
        catch (Exception e)
        {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

    public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth)
    {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // CREATE A MATRIX FOR THE MANIPULATION
        Matrix matrix = new Matrix();
        // RESIZE THE BIT MAP
        matrix.postScale(scaleWidth, scaleHeight);

        // "RECREATE" THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {

        //canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawBitmap(eraseableBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, mPaint);
    }

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    private void touch_start(float x, float y)
    {
        //        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
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        Toast.makeText(getContext(), "Deleted: " + percentTransparent(eraseableBitmap, 10), Toast.LENGTH_SHORT).show();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        float x = event.getX();
        float y = event.getY();

        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;
    }

    static public float percentTransparent(Bitmap bm, int scale)
    {

        final int width = bm.getWidth();
        final int height = bm.getHeight();

        // size of sample rectangles
        final int xStep = width / scale;
        final int yStep = height / scale;

        // center of the first rectangle
        final int xInit = xStep / 2;
        final int yInit = yStep / 2;

        // center of the last rectangle
        final int xEnd = width - xStep / 2;
        final int yEnd = height - yStep / 2;

        int totalTransparent = 0;

        for (int x = xInit; x <= xEnd; x += xStep)
        {
            for (int y = yInit; y <= yEnd; y += yStep)
            {
                if (bm.getPixel(x, y) == Color.TRANSPARENT)
                {
                    totalTransparent++;
                }
            }
        }
        return ((float) totalTransparent) / (scale * scale);

    }

}

在 Activity 类 onCreate 内

try
{
    MyView myView = new MyView(this);
    myView.requestFocus();
    myView.PaintObjectInit();
    // setContentView(myView);

    LinearLayout upper = (LinearLayout) findViewById(R.id.LinearLayout01);
    upper.addView(myView);
}
catch (Exception e)
{
    // TODO: handle exception
    e.printStackTrace();
}

【问题讨论】:

  • 我不知道为什么它不起作用,但你为什么不调试你的函数,看看你的所有变量是否都正确,比如xStep,或者尝试以 1 像素为步长的函数并检查它是否甚至出现在 for 循环中,如果是,您可以记录 bm.getPixel(x, y)。然后,您可能会自己弄清楚为什么它不起作用
  • Thnx,我调试了。它进入循环内部。并且总是 bm.getPixel(x, y) 不为零。由于我给它缩放 10,所以它每次迭代 100 次。所以我经历了大约 20 次迭代。对于所有这些像素,我得到了一个非零值。并且总是它敬酒 0.0 % 已删除。我不知道为什么。
  • 您在哪里将“已擦除”像素设置为 Color.TRANSPARENT?
  • 触摸时,会使像素点Color.TRANSPARENT沿路径对吗?我认为覆盖绘制路径的所有像素都将设置为 Color.TRANSPARENT。我从 sdk 的手指画示例应用程序中获得了该代码。
  • 你知道如何计算擦除区域的百分比吗?请分享!谢谢。

标签: android canvas bitmap paint touch-event


【解决方案1】:

问题是你没有调用你的PaintObjectInit() 方法,所以你使用默认的绘画,所以用Color.BLACK 而不是Color.TRANSPARENT 绘画。在构造函数的底部添加对PaintObjectInit() 的调用,它应该可以工作。

此外,以下创建一个不可变位图!见createBitmap。因此,您的位图永远不会被修改。您通过绘制路径和位图在用户界面上隐藏了这一事实。

// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;

尝试像这样制作可变位图 --

// "RECREATE" THE NEW BITMAP
        Bitmap resizedBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(resizedBitmap);
        c.setMatrix(matrix);
        c.drawBitmap(bm, matrix, null);
        return resizedBitmap;

【讨论】:

  • 不。在将该视图对象添加到布局之前,我在我的活动类中调用它。所以我的擦除部分正在工作。
  • 如果 PaintObjectInit() 是您视图的受保护方法,您如何从活动类中调用它?您是否在此代码之外对对象的状态进行了任何其他更改?
  • 最好让视图自己初始化,所以这一步是在您重用视图时执行。这是很容易忘记的事情,当我复制您的代码时,显然会遇到麻烦。错误的根源是您在 getResizedBitmap 方法中分配的不可变位图。编辑答案。
  • 现在我还有一个问题。现在像素变得透明。但是当我画线时,它会被复制。(画了两条线)当我触摸图像中的上述区域时。底部区域也被删除。我想现在有2个位图。我使用矩阵(作为你的答案)扩展了它,它只拉伸图像而不改变原始位图中的宽度和高度(我实际上想要从那个方法中得到什么)。请帮我整理一下。谢谢。
猜你喜欢
  • 1970-01-01
  • 2020-03-08
  • 2021-04-12
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
相关资源
最近更新 更多