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

Posted 爱折腾的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android图片橡皮擦功能和快速染色相关的知识,希望对你有一定的参考价值。

源码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) 
        // 因为要将图片放大,所以要根据放大的尺寸重新创建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图片橡皮擦功能和快速染色的主要内容,如果未能解决你的问题,请参考以下文章

Android 中实现选择图片生成缩略图点击查看大图的功能

snipaste图片标注技巧

PS里图片的锯齿效果怎么做?

Android中获取图片的宽和高

Android 实现ImageView长按显示新图片,松开恢复原图

Android关于创建涂鸦板过程中出现的小问题