从自定义图纸中裁剪透明空间保存时查看

时间:2017-10-09 17:55:15

标签: java android android-canvas

我正在开发一个用户可以在屏幕上绘图的应用程序。

我有一个名为View的自定义DrawingView,它使用Canvas对象进行绘制。

我能够成功绘制,并将绘图保存为PNG

问题

我遇到的问题是,当我保存图形时,它会保存整个屏幕,并且图形周围有所有透明空间。

例如:

House Drawing with white space

期望的结果

我希望实现的是从图纸中裁剪透明空间的方法。

例如:

House Drawing with no white space

DrawingView

public class DrawingView extends View {
    private final static String TAG = DrawingView.class.getSimpleName();

    private static final float TOLERANCE = 5f;
    private static final float STROKE_WIDTH = 15f;

    private final ArrayList<Pair<Path, Paint>> mPaths = new ArrayList<>();

    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Path mPath;
    private Paint mPaint;
    private float mX;
    private float mY;



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

        mPath = new Path();
        mPaint = new Paint(Paint.DITHER_FLAG);

        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(STROKE_WIDTH);

        mPaths.add(new Pair<>(mPath, new Paint(mPaint)));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, 0, 0, mPaint);

        if (!mPaths.isEmpty()) {
            canvas.drawPath(mPaths.get(mPaths.size() - 1).first, mPaths.get(mPaths.size() - 1).second);
        }
    }

    public void save(String path) {
        try {
            FileOutputStream writer = new FileOutputStream(path);
            mBitmap.compress(Bitmap.CompressFormat.PNG, 100, writer);
            writer.close();

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

    private void startTouch(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);

        mX = x;
        mY = y;

        mPaths.add(new Pair<>(mPath, new Paint(mPaint)));
        invalidate();
    }

    private void moveTouch(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(x - mY);

        if (dx >= TOLERANCE || dy >= TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
        invalidate();
    }

    private void upTouch() {
        mPath.lineTo(mX, mY);
        mCanvas.drawPath(mPath, mPaint);

        mPaths.add(new Pair<>(mPath, new Paint(mPaint)));
        invalidate();
    }

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

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN:
                startTouch(x, y);
                break;

            case MotionEvent.ACTION_MOVE:
                moveTouch(x, y);
                break;

            case MotionEvent.ACTION_UP:
                upTouch();
                break;
        }
        return true;
    }

    public void clear() {
        ArrayList<Pair<Path, Paint>> paths = new ArrayList<>();

        for (Pair pair : mPaths) {
            paths.add(pair);
        }
        mPaths.removeAll(paths);

        mBitmap = Bitmap.createBitmap(mCanvas.getWidth(), mCanvas.getHeight(), Bitmap.Config.ARGB_4444);
        mCanvas = new Canvas(mBitmap);
        invalidate();
    }
}

2 个答案:

答案 0 :(得分:1)

只是一个想法,但也许你可以存储正在绘制的每个点的x和y。然后,您可以在绘制点列表中获取最小x,最大x,最小y和最大y。最后,通过这些数据,您可以找到所需图像的宽度,高度和位置(就像在您绘制的图像周围创建矩形一样)。从那里,希望你能找到一种方法来调整屏幕大小或使用点数据保存图像。

我知道这不是代码解决方案的代码,但它只是一个我认为你应该尝试的想法!

答案 1 :(得分:0)

<强>解决方案

所以我在绘制图像时使用了班级RectF来跟踪我的最小和最大X,Y坐标。

我在构造函数中创建了一个名为RectF的{​​{1}}对象,然后我添加了一个方法来查找名为mDrawnAreaRect的最小和最大X,Y值:

findMinMax

然后我在Override private void findMinMax(int x, int y) { if (x < mDrawnAreaRect.left) { //min x mDrawnAreaRect.left = x; } if (y > mDrawnAreaRect.top) { //max y mDrawnAreaRect.top = y; } if (x > mDrawnAreaRect.right) { //max x mDrawnAreaRect.right = x; } if (y < mDrawnAreaRect.bottom) { //min y mDrawnAreaRect.bottom = y; } } 方法的底部实现了这个方法,如下所示:

onTouchEvent

最后,当我保存位图时,我使用@Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startTouch(x, y); break; case MotionEvent.ACTION_MOVE: moveTouch(x, y); break; case MotionEvent.ACTION_UP: upTouch(); break; } findMinMax((int) x, (int) y); //IMPLEMENTED HERE return true; } 中的左,上,右和下值来裁剪透明空间:mDrawnAreaRect

cropBitmap