我正在开发一个用户可以在屏幕上绘图的应用程序。
我有一个名为View
的自定义DrawingView
,它使用Canvas
对象进行绘制。
我能够成功绘制,并将绘图保存为PNG
。
问题
我遇到的问题是,当我保存图形时,它会保存整个屏幕,并且图形周围有所有透明空间。
例如:
期望的结果
我希望实现的是从图纸中裁剪透明空间的方法。
例如:
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();
}
}
答案 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