当前位置:主页 > 移动开发 > Android代码 >

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

时间:2021-12-24 11:07:29 | 栏目:Android代码 | 点击:

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

源码地址:Eraselmg

1.染色

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

2.橡皮擦

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

3.功能展示:

原图:

画笔设置界面:

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

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

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

(3)擦除

擦除前图像:

部分擦除后:

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);// ?s放 
  }else{
   if(Math.abs(scaleX)>=Math.abs(scaleY)){
   matrix.postScale(tScale, 1, mid.x, mid.y);// ?s放 
   }else{
   matrix.postScale(1, tScale, mid.x, mid.y);// ?s放
   }
  }
  if(PaintConstants.SELECTOR.HAIR_RURN)
   matrix.postRotate(rotation, mid.x, mid.y);// 旋?D 
  }
  }
  }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));
 
 } 
 
}

您可能感兴趣的文章:

相关文章