源码github地址:https://github.com/zhouguangfu09/EraseImg.git

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) {// 因为要将图片放大,所以要根据放大的尺寸重新创建BitmapBitmap 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();}@Overrideprotected 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() {@Overridepublic 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图片橡皮擦功能和快速染色相关推荐

  1. Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪)

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://mzh3344258.blog.51cto.com/1823534/808837 ...

  2. android图片浏览功能,怎么在Android应用中实现一个网页图片浏览功能

    怎么在Android应用中实现一个网页图片浏览功能 发布时间:2020-12-05 17:28:31 来源:亿速云 阅读:80 作者:Leah 本篇文章给大家分享的是有关怎么在Android应用中实现 ...

  3. android方法中添加 N,Android N 新功能 - 添加快速设定

    Android N version 其中一个功能,就是允许三方app可以添加自己的快速设定,到系统的下拉设定中,方便用户快速打开关闭某些功能. 废话不多说,直接上代码来讲解. 创建一个class,继承 ...

  4. Android 图片浏览功能简单实现(画廊效果实现,支持放大缩小)

    前言 APP日常小功能整理,别小瞧小功能的实现和积累,万一哪天使用到了,直接Ctrl+C和Ctrl+V轻松实现是不是节约了时间呢?同事也是日常Andro基础知识的复习点,哈哈哈! 首先上一波gif动态 ...

  5. android 图片查看功能吗,Android仿百度图片查看功能

    我们知道,进入百度图片后,输入一个关键字后,首先看到的是很多缩略图,当我们点击某张缩略图时,我们就可以进入到大图显示页面,在大图显示页面,中包含了一个图片画廊,同时当前大图为刚刚我们点击的那张图片.现 ...

  6. Android图片涂鸦功能,Android之给图片添加涂鸦(文字)

    原图: 效果图: 代码如下: public class GraffitiView extends View { private Paint paint = null; /* * 源图 */ priva ...

  7. android将图片宽高定死,Android 图片裁剪功能实现详解(类似QQ自定义头像裁剪) - 酷_莫名简单、KNothing - 51CTO技术博客...

    packagecom.xiaoma.piccut.demo; /** * 下面这些注释是下载这个类的时候本来就有的,本来要删除的,但看了下竟然是license,吼吼, * 好东西,留在注释里,以备不时 ...

  8. java 渐变橡皮擦_android实现图片橡皮擦和快速染色功能

    本文为大家分享了android实现图片橡皮擦和快速染色的具体代码,供大家参考,具体内容如下 1.染色 关于染色部分,可以分别设置调整画笔的大小和画笔的透明度,画笔已经设置了模糊效果.画笔的特效可以调整 ...

  9. android 橡皮擦功能吗,android,安卓开发_Android 图片涂鸦橡皮擦功能,android,安卓开发 - phpStudy...

    Android 图片涂鸦橡皮擦功能 最近在做一个画板功能,大致的不同颜色画笔.不同粗细已经实现. 参照的是该教程:android-drawing-app 现在要做的功能是,从相册或者相机导入图像,然后 ...

最新文章

  1. Callgrind--函数调用分析工具以及可视化方法
  2. anaconda中查看python的版本
  3. linux png pdf,将多页PDF转换为PNG并返回(Linux)
  4. AsyncTask与多任务
  5. 亚信科技笔试面试2019届
  6. 前端学习(1355) 子模板
  7. 数据库查询字段为空时,返回0
  8. python判断对错题_可以在线答题,并且能判断对错,将错题保存起来
  9. vSphere 故障排错:针对 Virtual Machine 的故障排查
  10. Windows 8实例教程系列 - 开篇
  11. 斐波那契java编写_请编写一个Java程序的斐波那契数
  12. Vue:安装Vue Devtools调试工具简便方法解决Cannot find module webpack-cli,@vue-devtools/build-tools等
  13. jquery 操作表格实例
  14. DP转HDMI音视频数据转换器普瑞PS176方案设计
  15. select * from a,b用法
  16. python爬取微博评论点赞数_python 爬虫 爬微博 分析 数据
  17. js日历多选(在表单中显示)
  18. 在STM32上对EV1527等无线编码格式的C程序编码实现
  19. 2019企业发布会最新震撼大气开场舞蹈 《全息未来已来》全息投影舞蹈 创意3D科技互动视频秀 企业舞蹈编排
  20. android 行车记录仪分析,基于Android架构行车记录仪的异常掉电可播放视频方法与流程...

热门文章

  1. Java——双向map BiMap
  2. 深度学习: pooling (池化 / 降采样)
  3. 玩转AI(Adobe illustrator)——小西瓜(2)
  4. 一位私企老板的真心话
  5. 虚拟机安装redhat 9.0后,解决屏幕不能全屏以及避免鼠标来回切换的方法
  6. Flutter 项目在iPhone/苹果手机启动页/闪屏页黑屏问题
  7. Vue开发登录组件(附下载)
  8. 脱脂剂非硅消泡剂怎能成为厂家们口中的除泡方案之一!
  9. Foamdoctor®A10FG 聚二甲基硅氧烷消泡剂 好又多海外进口
  10. Google技术分享