这篇博客主要想实现的功能是:1、用canvas实现自定义绘图,包括绘制资源图片和手势涂画 2、将手势涂抹过的区域(矩形)保存成一张图片。
一提到裁剪图片,就想到canvas里面的clipXXX接口。事实上,clipXXX接口并不能实现所谓”裁剪图片“的功能,只能指定一块区域显示绘画内容,超出区域的部分就会被裁剪掉(不显示)。
先简单说下原理:
1、新生成一个画布 canvas
2、为画布指定一个bitmap对象,用来保存自定义绘制过程中的图像
3、自定义绘图(画线、画路径、画什么的,这里就不提了),ondraw方法里面只将bitmap对象重新绘制下就ok了
4、最后,生成一个指定宽高的bitmap对象用来保存指定区域图像。(如何指定区域?那得看什么需求了,这里计算最后一次涂抹所占的矩形区域为指定区域)
自定义视图:
import java.io.File;
import java.io.FileOutputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.example.test4_0.R;
/**
*
* 作者:zg 创建时间:2014-8-3 上午11:18:43
*
**/
public class TestDrawView extends View {
private Paint mPaint;
private Path mPath;
boolean isMove;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private Canvas mCanvas;
private Bitmap mDrawBitmap;
private Bitmap mBmp;
boolean isChange;
private int windowHeight;
private int windowWidth;
public TestDrawView(Context context) {
super(context);
init();
}
public TestDrawView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TestDrawView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setWH(int w, int h) {
windowHeight = h;
windowWidth = w;
mDrawBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);
mCanvas.setBitmap(mDrawBitmap);
mCanvas.drawBitmap(mBmp, 0, 0, null);
}
private void init() {
mBmp = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
mPath = new Path();
mPaint = new Paint();
mCanvas = new Canvas();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(15);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(mDrawBitmap, 0, 0, null);
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
mCanvas.drawPath(mPath, mPaint);
}
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;
}
mCanvas.drawPath(mPath, mPaint);
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
saveBitmap();
}
private void saveBitmap() {
RectF rect = new RectF();
mPath.computeBounds(rect, true);
Log.i("info", "mPath.getWidth()=" + (rect.width()));
Log.i("info", "mPath.getHeight()=" + (rect.height()));
Bitmap bmp = Bitmap.createBitmap((int) rect.width(),
(int) rect.height(), Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
// canvas.clipRect(rect);
canvas.translate(-rect.left, -rect.top);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(mDrawBitmap, 0, 0, null);
// canvas.drawBitmap(mBitmap, null, rect, null);
// canvas.drawPath(mPath, mPaint);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
File file = new File("/sdcard/akai/");
if (!file.exists())
file.mkdirs();
try {
FileOutputStream fos = new FileOutputStream(file.getPath()
+ "/4.png");
bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
System.out.println("saveBmp is here");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
isMove = false;
isChange = false;
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:
isMove = true;
touch_move(x, y);
invalidate();
return true;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
if (!isMove) {
return true;
}
return super.onTouchEvent(event);
}
}
activity:
import android.app.Activity;
import android.os.Bundle;
import com.example.test4_0.definedview.TestDrawView;
/**
*
* 作者:zg 创建时间:2014-8-3 下午1:43:05
*
**/
public class TestDrawSaveActivity extends Activity {
private TestDrawView mView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_draw_save);
mView = (TestDrawView) findViewById(R.id.test_save);
int windowHeight = getWindowManager().getDefaultDisplay().getHeight();
int windowWidth = getWindowManager().getDefaultDisplay().getWidth();
// mView.setBgBitmap(BitmapFactory.decodeResource(getResources(),
// R.drawable.ic_launcher));
mView.setWH(windowWidth,windowHeight);
}
}
test_draw_save.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.test4_0.definedview.TestDrawView
android:id="@+id/test_save"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
不要忘记写SD卡权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />