时间: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)); } }