Canvas Android:在原始位图上绘制路径,或在缩放时使用抽屉保存整个图像
我面临的问题是,我创建了一个自定义imagview,您可以缩放它,当您选择“绘制”时,您可以在其上绘制。但使用save函数保存图像时出现问题。当我保存的图像和绘图图像在那个时候我只是得到图像覆盖在缩放部分。其他的都没有。所以先谢谢你Canvas Android:在原始位图上绘制路径,或在缩放时使用抽屉保存整个图像,canvas,bitmap,Canvas,Bitmap,我面临的问题是,我创建了一个自定义imagview,您可以缩放它,当您选择“绘制”时,您可以在其上绘制。但使用save函数保存图像时出现问题。当我保存的图像和绘图图像在那个时候我只是得到图像覆盖在缩放部分。其他的都没有。所以先谢谢你 导入android.annotation.SuppressLint; 导入android.content.Context; 导入android.graphics.Bitmap; 导入android.graphics.BitmapFactory; 导入android.
导入android.annotation.SuppressLint;
导入android.content.Context;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.graphics.Canvas;
导入android.graphics.Color;
导入android.graphics.Matrix;
导入android.graphics.Paint;
导入android.graphics.Path;
导入android.graphics.RectF;
导入android.graphics.drawable.drawable;
导入android.util.AttributeSet;
导入android.util.FloatMath;
导入android.util.Log;
导入android.view.GestureDetector;
导入android.view.MotionEvent;
导入android.view.view;
导入android.view.view.OnTouchListener;
导入android.widget.ImageView;
@SuppressLint(“DrawAllocation”)
公共类ScaleImageView扩展ImageView实现OnTouchListener{
静态最终浮动行程_宽度=10f;
静态最终浮动半行程宽度=行程宽度/2;
浮动lastTouchX;
浮触;
final RectF dirtyRect=new RectF();
私有静态浮动缩放图像偏移量;
私有静态浮点scaledImageOffsetY;
私有上下文;
专用浮点数最大刻度=2f;
私有静态矩阵mMatrix;
私有最终浮动[]mMatrixValues=新浮动[9];
//显示宽度和高度。
私人英特姆维兹;
私营机构;
私有内部宽度;
私家车;
私人浮动mScale;
私人浮动货币;
私人浮动距离;
私有布尔标度;
私有int-mPrevMoveX;
私家车;
私人手势检测器;
公共静态油漆=新油漆();
公共静态路径路径=新路径();
公共静态int-imageheight、imagewidth;
String TAG=“ScaleImageView”;
公共静态位图finalbitmap=null;
公共ScaleImageView(上下文、属性集属性){
超级(上下文,attr);
this.mContext=上下文;
初始化();
}
公共ScaleImageView(上下文){
超级(上下文);
this.mContext=上下文;
初始化();
}
私有void resetDirtyRect(float-eventX,float-eventY){
dirtyRect.left=Math.min(lastTouchX,eventX);
dirtyRect.right=Math.max(lastTouchX,eventX);
dirtyRect.top=Math.min(lastTouchY,eventY);
dirtyRect.bottom=Math.max(lastTouchY,eventY);
}
@凌驾
公共void setImageBitmap(位图bm){
super.setImageBitmap(bm);
这是初始化();
}
公共矩阵getImageMatrix(){
返回mMatrix;
}
公共位图getBitmap(){
ScaleImageViewActivity.imageview.setImageMatrix(空);
此.setDrawingCacheEnabled(true);
这是buildDrawingCache();
位图bmp=Bitmap.createBitmap(this.getDrawingCache());
此.setDrawingCacheEnabled(false);
返回bmp;
}
@凌驾
公共void setImageResource(int resId){
super.setImageResource(resId);
这是初始化();
}
私有void初始化(){
此.setScaleType(ScaleType.MATRIX);
this.mMatrix=新矩阵();
Drawable d=getDrawable();
paint.setAntiAlias(真);
油漆。设置颜色(颜色。红色);
绘制.设置样式(绘制.样式.笔划);
绘制.设置行程连接(绘制.连接.圆形);
油漆。设置行程宽度(行程宽度);
如果(d!=null){
mIntrinsicWidth=d.getIntrinsicWidth();
mIntrinsicHeight=d.getIntrinsicHeight();
setOnTouchListener(这个);
}
mDetector=新的手势检测器(mContext,
新的GestureDetector.SimpleOnGestureListener(){
@凌驾
公共布尔onDoubleTap(运动事件e){
maxZoomTo((int)e.getX(),(int)e.getY());
切割();
返回super.onDoubleTap(e);
}
});
}
@凌驾
受保护的布尔集合框架(int l,int t,int r,int b){
mWidth=r-l;
mHeight=b-t;
mMatrix.reset();
int r_norm=r-l;
mScale=(float)r_norm/(float)mIntrinsicWidth;
int paddingHeight=0;
int paddingWidth=0;
//垂直缩放
如果(mScale*mIntrinsicHeight>mHeight){
mScale=(浮动)mhweight/(浮动)mIntrinsicHeight;
mMatrix.后量表(mScale,mScale);
填充宽度=(r-mWidth)/2;
填充高度=0;
//水平缩放
}否则{
mMatrix.后量表(mScale,mScale);
填充高度=(b-mhweight)/2;
填充宽度=0;
}
mMatrix.postTranslate(填充宽度、填充高度);
setImageMatrix(mMatrix);
mMinScale=mScale;
zoomTo(mScale,mWidth/2,mHweight/2);
切割();
返回super.setFrame(l,t,r,b);
}
受保护的浮点getValue(矩阵,int whichValue){
矩阵。获取值(mMatrixValues);
返回mMatrixValues[whichValue];
}
受保护的浮点getScale(){
返回getValue(mMatrix,Matrix.MSCALE_X);
}
公共浮点数getTranslateX(){
返回getValue(mMatrix,Matrix.MTRANS_X);
}
受保护的浮点getTranslateY(){
返回getValue(mMatrix,Matrix.MTRANS_Y);
}
受保护的无效maxZoomTo(整数x,整数y){
如果(mMinScale!=getScale()&(getScale()-mMinScale)>0.1f){
//阈值0.1f
浮动比例=mMinScale/getScale();
缩放(缩放,x,y);
}否则{
浮动刻度=最大刻度/getScale();
缩放(缩放,x,y);
}
}
公共空间缩放(浮动比例,整数x,整数y){
如果(getScale()*比例=1&&getScale()*比例>最大比例){
返回;
}
mMatrix.后标度(标度,标度);
//移到中间
mMatrix.postTranslate(-(mWidth*刻度-mWidth)/2,
-(mHeight*刻度-mHeight)/2);
//移动x和y距离
mMatrix.postTranslate(-(x-(mWidth/2))*刻度,0;
mMatrix.postTranslate(0-(
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
@SuppressLint("DrawAllocation")
public class ScaleImageView extends ImageView implements OnTouchListener {
static final float STROKE_WIDTH = 10f;
static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
float lastTouchX;
float lastTouchY;
final RectF dirtyRect = new RectF();
private static float scaledImageOffsetX;
private static float scaledImageOffsetY;
private Context mContext;
private float MAX_SCALE = 2f;
private static Matrix mMatrix;
private final float[] mMatrixValues = new float[9];
// display width height.
private int mWidth;
private int mHeight;
private int mIntrinsicWidth;
private int mIntrinsicHeight;
private float mScale;
private float mMinScale;
private float mPrevDistance;
private boolean isScaling;
private int mPrevMoveX;
private int mPrevMoveY;
private GestureDetector mDetector;
public static Paint paint = new Paint();
public static Path path = new Path();
public static int imageheight, imagewidth;
String TAG = "ScaleImageView";
public static Bitmap finalbitmap = null;
public ScaleImageView(Context context, AttributeSet attr) {
super(context, attr);
this.mContext = context;
initialize();
}
public ScaleImageView(Context context) {
super(context);
this.mContext = context;
initialize();
}
private void resetDirtyRect(float eventX, float eventY) {
dirtyRect.left = Math.min(lastTouchX, eventX);
dirtyRect.right = Math.max(lastTouchX, eventX);
dirtyRect.top = Math.min(lastTouchY, eventY);
dirtyRect.bottom = Math.max(lastTouchY, eventY);
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
this.initialize();
}
public Matrix getImageMatrix() {
return mMatrix;
}
public Bitmap getBitmap() {
ScaleImageViewActivity.imageview.setImageMatrix(null);
this.setDrawingCacheEnabled(true);
this.buildDrawingCache();
Bitmap bmp = Bitmap.createBitmap(this.getDrawingCache());
this.setDrawingCacheEnabled(false);
return bmp;
}
@Override
public void setImageResource(int resId) {
super.setImageResource(resId);
this.initialize();
}
private void initialize() {
this.setScaleType(ScaleType.MATRIX);
this.mMatrix = new Matrix();
Drawable d = getDrawable();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(STROKE_WIDTH);
if (d != null) {
mIntrinsicWidth = d.getIntrinsicWidth();
mIntrinsicHeight = d.getIntrinsicHeight();
setOnTouchListener(this);
}
mDetector = new GestureDetector(mContext,
new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
maxZoomTo((int) e.getX(), (int) e.getY());
cutting();
return super.onDoubleTap(e);
}
});
}
@Override
protected boolean setFrame(int l, int t, int r, int b) {
mWidth = r - l;
mHeight = b - t;
mMatrix.reset();
int r_norm = r - l;
mScale = (float) r_norm / (float) mIntrinsicWidth;
int paddingHeight = 0;
int paddingWidth = 0;
// scaling vertical
if (mScale * mIntrinsicHeight > mHeight) {
mScale = (float) mHeight / (float) mIntrinsicHeight;
mMatrix.postScale(mScale, mScale);
paddingWidth = (r - mWidth) / 2;
paddingHeight = 0;
// scaling horizontal
} else {
mMatrix.postScale(mScale, mScale);
paddingHeight = (b - mHeight) / 2;
paddingWidth = 0;
}
mMatrix.postTranslate(paddingWidth, paddingHeight);
setImageMatrix(mMatrix);
mMinScale = mScale;
zoomTo(mScale, mWidth / 2, mHeight / 2);
cutting();
return super.setFrame(l, t, r, b);
}
protected float getValue(Matrix matrix, int whichValue) {
matrix.getValues(mMatrixValues);
return mMatrixValues[whichValue];
}
protected float getScale() {
return getValue(mMatrix, Matrix.MSCALE_X);
}
public float getTranslateX() {
return getValue(mMatrix, Matrix.MTRANS_X);
}
protected float getTranslateY() {
return getValue(mMatrix, Matrix.MTRANS_Y);
}
protected void maxZoomTo(int x, int y) {
if (mMinScale != getScale() && (getScale() - mMinScale) > 0.1f) {
// threshold 0.1f
float scale = mMinScale / getScale();
zoomTo(scale, x, y);
} else {
float scale = MAX_SCALE / getScale();
zoomTo(scale, x, y);
}
}
public void zoomTo(float scale, int x, int y) {
if (getScale() * scale < mMinScale) {
return;
}
if (scale >= 1 && getScale() * scale > MAX_SCALE) {
return;
}
mMatrix.postScale(scale, scale);
// move to center
mMatrix.postTranslate(-(mWidth * scale - mWidth) / 2,
-(mHeight * scale - mHeight) / 2);
// move x and y distance
mMatrix.postTranslate(-(x - (mWidth / 2)) * scale, 0);
mMatrix.postTranslate(0, -(y - (mHeight / 2)) * scale);
setImageMatrix(mMatrix);
}
public void cutting() {
int width = (int) (mIntrinsicWidth * getScale());
int height = (int) (mIntrinsicHeight * getScale());
imagewidth = width;
imageheight = height;
if (getTranslateX() < -(width - mWidth)) {
mMatrix.postTranslate(-(getTranslateX() + width - mWidth), 0);
}
if (getTranslateX() > 0) {
mMatrix.postTranslate(-getTranslateX(), 0);
}
if (getTranslateY() < -(height - mHeight)) {
mMatrix.postTranslate(0, -(getTranslateY() + height - mHeight));
}
if (getTranslateY() > 0) {
mMatrix.postTranslate(0, -getTranslateY());
}
if (width < mWidth) {
mMatrix.postTranslate((mWidth - width) / 2, 0);
}
if (height < mHeight) {
mMatrix.postTranslate(0, (mHeight - height) / 2);
}
setImageMatrix(mMatrix);
}
private float distance(float x0, float x1, float y0, float y1) {
float x = x0 - x1;
float y = y0 - y1;
return FloatMath.sqrt(x * x + y * y);
}
private float dispDistance() {
return FloatMath.sqrt(mWidth * mWidth + mHeight * mHeight);
}
public void clear() {
path.reset();
invalidate();
}
public static void save() {
Bitmap returnedBitmap = Bitmap.createBitmap(
ScaleImageViewActivity.imageview.getWidth(),
ScaleImageViewActivity.imageview.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
// ScaleImageViewActivity.imageview.draw(canvas);
path.reset();
}
public static Bitmap combineImages(Bitmap c, Bitmap s) {
Bitmap cs = null;
int width, height = 0;
if (c.getWidth() > s.getWidth()) {
width = c.getWidth();
height = c.getHeight() + s.getHeight();
} else {
width = s.getWidth();
height = c.getHeight() + s.getHeight();
}
Log.e("hw :", "X = " + width + " Y = " + height);
cs = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas comboImage = new Canvas(cs);
comboImage.drawBitmap(s, new Matrix(), null);
comboImage.drawBitmap(c, Math.abs(scaledImageOffsetX),
Math.abs(scaledImageOffsetY), null);
return cs;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!ScaleImageViewActivity.flag) {
if (mDetector.onTouchEvent(event)) {
return true;
}
int touchCount = event.getPointerCount();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_1_DOWN:
case MotionEvent.ACTION_POINTER_2_DOWN:
if (touchCount >= 2) {
float distance = distance(event.getX(0), event.getX(1),
event.getY(0), event.getY(1));
mPrevDistance = distance;
isScaling = true;
} else {
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
}
case MotionEvent.ACTION_MOVE:
if (touchCount >= 2 && isScaling) {
float dist = distance(event.getX(0), event.getX(1),
event.getY(0), event.getY(1));
float scale = (dist - mPrevDistance) / dispDistance();
mPrevDistance = dist;
scale += 1;
scale = scale * scale;
zoomTo(scale, mWidth / 2, mHeight / 2);
cutting();
} else if (!isScaling) {
int distanceX = mPrevMoveX - (int) event.getX();
int distanceY = mPrevMoveY - (int) event.getY();
mPrevMoveX = (int) event.getX();
mPrevMoveY = (int) event.getY();
mMatrix.postTranslate(-distanceX, -distanceY);
cutting();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_2_UP:
if (event.getPointerCount() <= 1) {
isScaling = false;
}
break;
}
} else {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
lastTouchX = eventX;
lastTouchY = eventY;
return true;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
resetDirtyRect(eventX, eventY);
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++) {
float historicalX = event.getHistoricalX(i);
float historicalY = event.getHistoricalY(i);
path.lineTo(historicalX, historicalY);
}
path.lineTo(eventX, eventY);
break;
}
invalidate((int) (dirtyRect.left - HALF_STROKE_WIDTH),
(int) (dirtyRect.top - HALF_STROKE_WIDTH),
(int) (dirtyRect.right + HALF_STROKE_WIDTH),
(int) (dirtyRect.bottom + HALF_STROKE_WIDTH));
lastTouchX = eventX;
lastTouchY = eventY;
// finalbitmap = getBitmap();
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (ScaleImageViewActivity.flag) {
canvas.drawPath(path, paint);
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
return super.onTouchEvent(event);
}
}