首页 > 系统 > Android > 正文

android实现图片橡皮擦和快速染色功能

2019-10-21 21:32:38
字体:
来源:转载
供稿:网友

本文为大家分享了android实现图片橡皮擦和快速染色的具体代码,供大家参考,具体内容如下

源码地址:Eraselmg

1.染色

     关于染色部分,可以分别设置调整画笔的大小和画笔的透明度,画笔已经设置了模糊效果。画笔的特效可以调整下面一行代码:

android,图片橡皮擦,快速染色

2.橡皮擦

  橡皮擦的实现用了两个canvas,一个临时的,一个是作用在ImageTouchView上显示的,代码里面有注释,这里不再详细介绍。

3.功能展示:

原图:

android,图片橡皮擦,快速染色

画笔设置界面:

android,图片橡皮擦,快速染色

(1)画笔大小为32,透明度为255(不透明)。如下图:

android,图片橡皮擦,快速染色

(2)画笔大小为32,透明度为10,如下图:

android,图片橡皮擦,快速染色

融合的效果跟画笔的透明度有关系,也跟背景图片的相应区域颜色有关,所以透明度的值自行调整得出满意效果。

(3)擦除

擦除前图像:

android,图片橡皮擦,快速染色

部分擦除后:

android,图片橡皮擦,快速染色

4.Bitmap处理相关的类BitmapUtils:

package com.jiangjie.utils; import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import android.content.Context;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Bitmap.Config;public class BitmapUtils {   /**  * 缩放图片  */ public static void bitmapScale(Bitmap baseBitmap, Paint paint, float x, float y) {  // 因为要将图片放大,所以要根据放大的尺寸重新创建Bitmap  Bitmap scaleBitmap = Bitmap.createBitmap(    (int) (baseBitmap.getWidth() * x),    (int) (baseBitmap.getHeight() * y), baseBitmap.getConfig());  Canvas canvas = new Canvas(scaleBitmap);  // 初始化Matrix对象  Matrix matrix = new Matrix();  // 根据传入的参数设置缩放比例  matrix.setScale(x, y);  // 根据缩放比例,把图片draw到Canvas上  canvas.drawBitmap(baseBitmap, matrix,paint); }  /**  * 图片旋转  */ public static void bitmapRotate(Bitmap baseBitmap, Paint paint,float degrees) {  // 创建一个和原图一样大小的图片  Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap.getWidth(),    baseBitmap.getHeight(), baseBitmap.getConfig());  Canvas canvas = new Canvas(afterBitmap);  Matrix matrix = new Matrix();  // 根据原图的中心位置旋转  matrix.setRotate(degrees, baseBitmap.getWidth() / 2,    baseBitmap.getHeight() / 2);  canvas.drawBitmap(baseBitmap, matrix, paint); }  /**  * 图片移动  */ public static void bitmapTranslate(Bitmap baseBitmap, Paint paint, float dx, float dy) {  // 需要根据移动的距离来创建图片的拷贝图大小  Bitmap afterBitmap = Bitmap.createBitmap(    (int) (baseBitmap.getWidth() + dx),    (int) (baseBitmap.getHeight() + dy), baseBitmap.getConfig());  Canvas canvas = new Canvas(afterBitmap);  Matrix matrix = new Matrix();  // 设置移动的距离  matrix.setTranslate(dx, dy);  canvas.drawBitmap(baseBitmap, matrix, paint); }  /**  * 倾斜图片  */ public static void bitmapSkew(Bitmap baseBitmap, Paint paint, float dx, float dy) {  // 根据图片的倾斜比例,计算变换后图片的大小,  Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap.getWidth()    + (int) (baseBitmap.getWidth() * dx), baseBitmap.getHeight()    + (int) (baseBitmap.getHeight() * dy), baseBitmap.getConfig());  Canvas canvas = new Canvas(afterBitmap);  Matrix matrix = new Matrix();  // 设置图片倾斜的比例  matrix.setSkew(dx, dy);  canvas.drawBitmap(baseBitmap, matrix, paint); }  public static Bitmap decodeFromResource(Context context, int id) {  Resources res = context.getResources();  Bitmap bitmap = BitmapFactory.decodeResource(res,id).copy(Bitmap.Config.ARGB_8888, true);  return bitmap; }   /**  * 保存图片到SD卡  */ public static void saveToSdCard(String path, Bitmap bitmap) { if (null != bitmap && null != path && !path.equalsIgnoreCase("")) { try { File file = new File(path); FileOutputStream outputStream = null; //创建文件,并写入内容 outputStream = new FileOutputStream(new File(path), true); bitmap.compress(Bitmap.CompressFormat.PNG, 30, outputStream); outputStream.flush(); outputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }  /**  * 复制bitmap  */ public static Bitmap duplicateBitmap(Bitmap bmpSrc, int width, int height) { if (null == bmpSrc) { return null; }  int bmpSrcWidth = bmpSrc.getWidth(); int bmpSrcHeight = bmpSrc.getHeight();  Bitmap bmpDest = Bitmap.createBitmap(width, height, Config.ARGB_8888); if (null != bmpDest) { Canvas canvas = new Canvas(bmpDest); Rect viewRect = new Rect(); final Rect rect = new Rect(0, 0, bmpSrcWidth, bmpSrcHeight); if (bmpSrcWidth <= width && bmpSrcHeight <= height) { viewRect.set(rect); } else if (bmpSrcHeight > height && bmpSrcWidth <= width) { viewRect.set(0, 0, bmpSrcWidth, height); } else if (bmpSrcHeight <= height && bmpSrcWidth > width) { viewRect.set(0, 0, width, bmpSrcWidth); } else if (bmpSrcHeight > height && bmpSrcWidth > width) { viewRect.set(0, 0, width, height); } canvas.drawBitmap(bmpSrc, rect, viewRect, null); }  return bmpDest; }  /**  * 复制bitmap  */ public static Bitmap duplicateBitmap(Bitmap bmpSrc) { if (null == bmpSrc) { return null; }  int bmpSrcWidth = bmpSrc.getWidth(); int bmpSrcHeight = bmpSrc.getHeight();  Bitmap bmpDest = Bitmap.createBitmap(bmpSrcWidth, bmpSrcHeight, Config.ARGB_8888); if (null != bmpDest) { Canvas canvas = new Canvas(bmpDest); final Rect rect = new Rect(0, 0, bmpSrcWidth, bmpSrcHeight);  canvas.drawBitmap(bmpSrc, rect, rect, null); }  return bmpDest; }  /**  * bitmap转字节码  */ public static byte[] bitampToByteArray(Bitmap bitmap) { byte[] array = null; try { if (null != bitmap) { ByteArrayOutputStream os = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); array = os.toByteArray(); os.close(); } } catch (IOException e) { e.printStackTrace(); }  return array; }  /**  * 字节码转bitmap  */ public static Bitmap byteArrayToBitmap(byte[] array) { if (null == array) { return null; }  return BitmapFactory.decodeByteArray(array, 0, array.length); } }

5.图像旋转,缩放,橡皮擦和染色功能如下:

package com.jiangjie.ps; import com.jiangjie.utils.PaintConstants; import android.content.Context;import android.graphics.Bitmap;import android.graphics.Bitmap.Config;import android.graphics.BlurMaskFilter;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.Path;import android.graphics.PointF;import android.graphics.PorterDuff.Mode;import android.graphics.PorterDuffXfermode;import android.graphics.RectF;import android.graphics.drawable.BitmapDrawable;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.FloatMath;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView; public class ImageTouchView extends ImageView{ public Matrix matrix = new Matrix();  Matrix savedMatrix = new Matrix(); /** 屏幕的分辨率*/ private DisplayMetrics dm; /** 当前模式*/ int mode = PaintConstants.MODE.NONE;  /** 存储float类型的x,y值,就是你点下的坐标的X和Y*/ PointF prev = new PointF(); PointF curPosition = new PointF(); PointF mid = new PointF(); float dist = 1f;  float oldRotation = 0;  float oldDistX = 1f; float oldDistY = 1f;  /**位图对象*/ private Bitmap bitmap = null; private Paint paint; private Context context;  private Path path; private Path tempPath; //定义一个内存中的图片,该图片将作为缓冲区 Bitmap cacheBitmap = null;  //定义cacheBitmap上的Canvas对象 Canvas cacheCanvas = null; private Paint cachePaint = null;  private String TAG = "APP";  int x = 0;  int y = 0;    public ImageTouchView(Context context) { super(context); }  public ImageTouchView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; Log.i(TAG, "ImageTouchView(Context context, AttributeSet attrs)=>");  setupView(); }  @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  if(mode == PaintConstants.MODE.COLORING){ canvas.drawPath(tempPath, paint); }  }  public void setupView(){  //获取屏幕分辨率,需要根据分辨率来使用图片居中 dm = getContext().getResources().getDisplayMetrics(); //根据MyImageView来获取bitmap对象 BitmapDrawable bd = (BitmapDrawable)this.getDrawable(); if(bd != null){ bitmap = bd.getBitmap(); // bitmap = setBitmapAlpha(bitmap, 100); center(true, true); }  setCoverBitmap(bitmap); this.setImageMatrix(matrix);  this.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Matrix matrixTemp = new Matrix(); matrixTemp.set(matrix); //view的触摸坐标的转换 matrixTemp.invert(matrixTemp); Log.i(TAG, "Touch screen.");  switch (event.getAction() & MotionEvent.ACTION_MASK) { // 主点按下 case MotionEvent.ACTION_DOWN:  savedMatrix.set(matrix);  prev.set(event.getX(), event.getY());   float[] pointPrevInit = new float[]{prev.x, prev.y};  matrixTemp.mapPoints(pointPrevInit);  path.moveTo(pointPrevInit[0], pointPrevInit[1]);  tempPath.moveTo(event.getX(), event.getY());   mode = PaintConstants.MODE.DRAG;  Log.i(TAG, "ACTION_DOWN=>.");  break;  // 副点按下 case MotionEvent.ACTION_POINTER_DOWN:  dist = spacing(event);  oldRotation = rotation(event);   oldDistX = spacingX(event);  oldDistY = spacingY(event);  // 如果连续两点距离大于10,则判定为多点模式  if (spacing(event) > 10f) {  savedMatrix.set(matrix);  midPoint(mid, event);  mode = PaintConstants.MODE.ZOOM;  }  break; case MotionEvent.ACTION_UP:  Log.i(TAG, "ACTION_UP=>.");  if(mode == PaintConstants.MODE.COLORING){  cachePaint.setColor(PaintConstants.PEN_COLOR);  cachePaint.setStrokeWidth(PaintConstants.PEN_SIZE);  cachePaint.setAlpha(PaintConstants.TRANSPARENT);   cachePaint.setMaskFilter(new BlurMaskFilter(5, PaintConstants.BLUR_TYPE));    cacheCanvas.drawPath(path, cachePaint);  path.reset();  tempPath.reset();  }  break;  case MotionEvent.ACTION_POINTER_UP:  mode = PaintConstants.MODE.NONE;  break;  case MotionEvent.ACTION_MOVE:  if(!PaintConstants.SELECTOR.KEEP_IMAGE){  if (mode == PaintConstants.MODE.DRAG) {  matrix.set(savedMatrix);  matrix.postTranslate(event.getX() - prev.x, event.getY() - prev.y);  } else if (mode == PaintConstants.MODE.ZOOM) {  float rotation = (rotation(event) - oldRotation)/2;   float newDistX = spacingX(event);  float newDistY = spacingY(event);   float scaleX = newDistX-oldDistX;  float scaleY = newDistY-oldDistY;   float newDist = spacing(event);  if (newDist > 10f) {  matrix.set(savedMatrix);  float tScale = newDist / dist;  tScale = tScale>1?1+((tScale-1)/2):1-(1-tScale)/2;  if(PaintConstants.SELECTOR.KEEP_SCALE){   matrix.postScale(tScale, tScale, mid.x, mid.y);// 縮放   }else{   if(Math.abs(scaleX)>=Math.abs(scaleY)){   matrix.postScale(tScale, 1, mid.x, mid.y);// 縮放    }else{   matrix.postScale(1, tScale, mid.x, mid.y);// 縮放   }  }  if(PaintConstants.SELECTOR.HAIR_RURN)   matrix.postRotate(rotation, mid.x, mid.y);// 旋轉   }  }  }else{  float[] pointPrev = new float[]{prev.x, prev.y};  float[] pointStop= new float[]{event.getX(), event.getY()};    //view的触摸坐标的转换  matrixTemp.mapPoints(pointPrev);  matrixTemp.mapPoints(pointStop);    if(PaintConstants.SELECTOR.COLORING){  //染色功能  mode = PaintConstants.MODE.COLORING;  paint.reset();  paint = new Paint(Paint.DITHER_FLAG);  paint.setColor(Color.RED);  //设置画笔风格  paint.setStyle(Paint.Style.STROKE);  paint.setStrokeWidth(1);  //反锯齿  paint.setAntiAlias(true);  paint.setDither(true);   paint.setColor(PaintConstants.PEN_COLOR);  paint.setStrokeWidth(PaintConstants.PEN_SIZE);   path.quadTo(pointPrev[0],pointPrev[1],pointStop[0],pointStop[1]);  tempPath.quadTo(prev.x, prev.y,event.getX(), event.getY());    // 更新开始点的位置  prev.set(event.getX(), event.getY());   ImageTouchView.this.setImageBitmap(cacheBitmap);    }else if(PaintConstants.SELECTOR.ERASE){  //橡皮擦功能   mode = PaintConstants.MODE.ERASE;   paint.reset();  paint.setColor(Color.TRANSPARENT);  paint.setAntiAlias(false);  paint.setStyle(Paint.Style.STROKE);  paint.setStrokeWidth(16);  paint.setStrokeJoin(Paint.Join.ROUND);  paint.setStrokeCap(Paint.Cap.ROUND);  paint.setAlpha(0);   paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));  paint.setStrokeWidth(PaintConstants.ERASE_SIZE);   prev.set(event.getX(), event.getY());    cacheCanvas.drawLine(pointPrev[0],pointPrev[1],pointStop[0],pointStop[1], paint);  ImageTouchView.this.setImageBitmap(cacheBitmap);   }  } } ImageTouchView.this.setImageMatrix(matrix); invalidate();  return true; } }); }  /** * 横向、纵向居中 */ protected void center(boolean horizontal, boolean vertical) { RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());  float height = rect.height(); float width = rect.width();  float deltaX = 0, deltaY = 0;  if (vertical) { // 图片小于屏幕大小,则居中显示。大于屏幕,上方留空则往上移,下方留空则往下移 int screenHeight = dm.heightPixels; if (height < screenHeight) { deltaY = (screenHeight - height) / 2 - rect.top; } else if (rect.top > 0) { deltaY = -rect.top; } else if (rect.bottom < screenHeight) { deltaY = this.getHeight() - rect.bottom; } }  if (horizontal) { int screenWidth = dm.widthPixels; if (width < screenWidth) { deltaX = (screenWidth - width) / 2 - rect.left; } else if (rect.left > 0) { deltaX = -rect.left; } else if (rect.right < screenWidth) { deltaX = screenWidth - rect.right; } } matrix.postTranslate(deltaX, deltaY); }   private float spacingX(MotionEvent event) {  float x = event.getX(0) - event.getX(1);  return x; }  private float spacingY(MotionEvent event) {  float y = event.getY(0) - event.getY(1);  return y;  }   // 取旋转角度  private float rotation(MotionEvent event) {  double delta_x = (event.getX(0) - event.getX(1));  double delta_y = (event.getY(0) - event.getY(1));  double radians = Math.atan2(delta_y, delta_x);  return (float) Math.toDegrees(radians);  }   /** * 两点的距离 */ private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); }  /** * 两点的中点 */ private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); }   /**  *  * @param bm  * @note set cover bitmap , which overlay on background.  */  private void setCoverBitmap(Bitmap bitmap) {  // setting paint  paint = new Paint();   cacheBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);  cacheCanvas = new Canvas(); cacheCanvas.setBitmap(cacheBitmap); cacheCanvas.drawBitmap( bitmap, 0, 0, null);   path = new Path(); tempPath = new Path();  //设置画笔的颜色 cachePaint = new Paint(); //设置画笔风格 cachePaint.setStyle(Paint.Style.STROKE); //反锯齿 cachePaint.setAntiAlias(true); cachePaint.setStrokeJoin(Paint.Join.ROUND); cachePaint.setStrokeCap(Paint.Cap.ROUND); cachePaint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP)); //设置画笔模糊效果 cachePaint.setMaskFilter(new BlurMaskFilter(5, PaintConstants.BLUR_TYPE));  }  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表