package com.js.photosdk.mosaic;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ViewGroup;
import com.js.photosdk.mosaic.MosaicUtil.MosaicType;
import com.js.photosdk.utils.FileUtils;
/**
* 马赛克
*
* @author jarlen
*
* 2014/12/28
*
* 使用说明:
*
* 1. 布局中引用view mosaic = (DrawMosaicView) findViewById(R.id.mosaic);
*
* 2. 设置所要打马赛克的图片
*
* mosaic.setMosaicBackgroundResource(mBitmap);
*
* 3.设置马赛克资源样式
*
* mosaic.setMosaicResource(bit);
*
* 4.设置绘画粗细
*
* mosaic.setMosaicBrushWidth(10);
*
* 5.设置马赛克类型(马赛克,橡皮擦)
*
* mosaic.setMosaicType(MosaicType.ERASER);
*
*/
public class DrawMosaicView extends ViewGroup
{
public static final String TAG = "MosaicView";
// default image inner padding, in dip pixels
private static final int INNER_PADDING = 0;
/**
* 马赛克粗细 可以按 5,10,15,20,30
**/
private static final int PATH_WIDTH = 30;
/**
* 绘画板宽度
*/
private int mImageWidth;
/**
* 绘画板高度
*/
private int mImageHeight;
/**
* 绘画底层图片资源
*/
private Bitmap bmBaseLayer;
/**
* 橡皮擦图层
*
*/
private Bitmap bmCoverLayer;
private Bitmap bmMosaicLayer;
/**
* 画笔
*/
private int mBrushWidth;
private Rect mImageRect;
private Paint mPaint;
private int mPadding;
/**
* 触摸路径数据
*/
private List<MosaicPath> touchPaths;
private List<MosaicPath> erasePaths;
private MosaicPath touchPath;
/**
* 马赛克类型 Mosaic: 打码 erase: 橡皮擦
*
*
* */
private MosaicType mMosaicType = MosaicType.MOSAIC;
private Context mContext;
public DrawMosaicView(Context context)
{
super(context);
this.mContext = context;
initDrawView();
}
public DrawMosaicView(Context context, AttributeSet attrs)
{
super(context, attrs);
this.mContext = context;
initDrawView();
}
/**
* 初始化绘画板 默认的情况下是马赛克模式
*
*/
private void initDrawView()
{
touchPaths = new ArrayList<MosaicPath>();
erasePaths = new ArrayList<MosaicPath>();
mPadding = dp2px(INNER_PADDING);
mBrushWidth = dp2px(PATH_WIDTH);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(6);
mPaint.setColor(0xff2a5caa);
mImageRect = new Rect();
setWillNotDraw(false);
setMosaicType(MosaicType.MOSAIC);
}
/**
* 设置画刷的宽度
*
* @param brushWidth
*
* 画刷宽度大小
*
*/
public void setMosaicBrushWidth(int brushWidth)
{
this.mBrushWidth = dp2px(brushWidth);
}
/**
* 设置马赛克类型
*
* @param type
*
* 类型
*/
public void setMosaicType(MosaicType type)
{
this.mMosaicType = type;
}
/**
* 设置所要打码的图片资源
*
* @param imgPath
* 图片路径
*
*/
public void setMosaicBackgroundResource(String imgPath)
{
File file = new File(imgPath);
if (file == null || !file.exists())
{
Log.w(TAG, "setSrcPath invalid file path " + imgPath);
return;
}
reset();
Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
bmBaseLayer = bitmap;
requestLayout();
invalidate();
}
/**
* 设置马赛克样式资源
*
* @param imgPath
* 样式图片路径
*
*/
public void setMosaicResource(String imgPath)
{
File file = new File(imgPath);
if (file == null || !file.exists())
{
Log.w(TAG, "setSrcPath invalid file path " + imgPath);
setMosaicType(MosaicType.ERASER);
return;
}
Bitmap bitmap = BitmapFactory.decodeFile(imgPath);
if (bitmap != null)
{
setMosaicType(MosaicType.MOSAIC);
if (bmCoverLayer != null)
{
bmCoverLayer.recycle();
}
bmCoverLayer = bitmap;
} else
{
Log.i("jarlen", " setMosaicResource bitmap = null ");
return;
}
updatePathMosaic();
invalidate();
}
/**
* 设置所要打码的资源图片
*
* @param bitmap
*
* 资源图片路径
*
*/
public void setMosaicBackgroundResource(Bitmap bitmap)
{
if (bitmap == null)
{
Log.e("jarlen", "setMosaicBackgroundResource : bitmap == null");
return;
}
reset();
mImageWidth = bitmap.getWidth();
mImageHeight = bitmap.getHeight();
bmBaseLayer = bitmap;
requestLayout();
invalidate();
}
/**
* 设置马赛克样式资源
*
* @param bitmap
*
* 样式图片资源
*/
public void setMosaicResource(Bitmap bitmap)
{
setMosaicType(MosaicType.MOSAIC);
if (bmCoverLayer != null)
{
bmCoverLayer.recycle();
}
erasePaths.clear();
touchPaths.clear();
bmCoverLayer = getBitmap(bitmap);
updatePathMosaic();
invalidate();
}
private Bitmap getBitmap(Bitmap bit)
{
Bitmap bitmap = Bitmap.createBitmap(mImageWidth, mImageHeight,
Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(bit, 0, 0, null);
canvas.save();
return bitmap;
}
/**
* 清除绘画数据
*
*/
public void clear()
{
touchPaths.clear();
erasePaths.clear();
if (bmMosaicLayer != null)
{
bmMosaicLayer.recycle();
bmMosaicLayer = null;
}
invalidate();
}
/**
* 重置绘画版
*
* @return
*/
public boolean reset()
{
this.mImageWidth = 0;
this.mImageHeight = 0;
if (bmCoverLayer != null)
{
bmCoverLayer.recycle();
bmCoverLayer = null;
}
if (bmBaseLayer != null)
{
bmBaseLayer.recycle();
bmBaseLayer = null;
}
if (bmMosaicLayer != null)
{
bmMosaicLayer.recycle();
bmMosaicLayer = null;
}
touchPaths.clear();
erasePaths.clear();
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
super.dispatchTouchEvent(event);
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
onPathEvent(action, x, y);
return true;
}
private void onPathEvent(int action, int x, int y)
{
if (mImageWidth <= 0 || mImageHeight <= 0)
{
return;
}
if (x < mImageRect.left || x > mImageRect.right || y < mImageRect.top
|| y > mImageRect.bottom)
{
return;
}
float ratio = (mImageRect.right - mImageRect.left)
/ (float) mImageWidth;
x = (int) ((x - mImageRect.left) / ratio);
y = (int) ((y - mImageRect.top) / ratio);
if (action == MotionEvent.ACTION_DOWN)
{
touchPath = new MosaicPath();
touchPath.drawPath = new Path();
touchPath.drawPath.moveTo(x, y);
touchPath.paintWidth = mBrushWidth;
if (this.mMosaicType == MosaicType.MOSAIC)
{
touchPaths.add(touchPath);
} else
{
erasePaths.add(touchPath);
}
} else if (action == MotionEvent.ACTION_MOVE)
{
touchPath.drawPath.lineTo(x, y);
updatePathMosaic();
invalidate();
}
}
/**
* 刷新绘画板
*/
private void updatePathMosaic()
{
if (mImageWidth <= 0 || mImageHeight <= 0)
{
return;
}
if (bmMosaicLayer != null)
{
bmMosaicLayer.recycle();
}
bmMosaicLayer = Bitmap.createBitmap(mImageWidth, mImageHeight,
Config.ARGB_8888);
Bitmap bmTouchLayer = Bitmap.createBitmap(mImageWidth, mImageHeight,
Config.ARGB_8888);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setPathEffect(new CornerPathEffect(10));
paint.setStrokeWidth(mBrushWidth);
paint.setColor(Color.BLUE);
Canvas canvas = new Canvas(bmTouchLayer);
for (MosaicPath path : touchPaths)
{
Path pathTemp = path.drawPath;
int drawWidth = path.paintWidth;
paint.setStrokeWidth(drawWidth);
canvas.drawPath(pathTemp, paint);
}
paint.setColor(Color.TRANSPARENT);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
for (MosaicPath path : erasePaths)
{
Path pathTemp = path.drawPath;
int drawWidth = path.paintWidth;
paint.setStrokeWidth(drawWidth);
canvas.drawPath(pathTemp, paint);
}
canvas.setBitmap(bmMosaicLayer);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawBitmap(bmCoverLayer, 0, 0, null);
paint.reset();
paint.setAntiAlias(true);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawBitmap(bmTouchLayer, 0, 0, paint);
paint.setXfermode(null);
canvas.save();
bmTouchLayer.recycle();
}
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (bmBaseLayer != null)
{
canvas.drawBitmap(bmBaseLayer, null, mImageRect, null);
}
if (bmMosaicLayer != null)
{
canvas.drawBitmap(bmMosaicLayer, null, mImageRect, null);
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom)
{
if (mImageWidth <= 0 || mImageHeight <= 0)
{
return;
}
int contentWidth = right - left;
int contentHeight = bottom - top;
int viewWidth = contentWidth - mPadding * 2;
int viewHeight = contentHeight - mPadding * 2;
float widthRatio = viewWidth / ((float) mImageWidth);
float heightRatio = viewHeight / ((float) mImageHeight);
float ratio = widthRatio < heightRatio ? widthRatio : heightRatio;
int realWidth = (int) (mImageWidth * ratio);
int realHeight = (int) (mImageHeight * ratio);
int imageLeft = (contentWidth - realWidth) / 2;
int imageTop = (contentHeight - realHeight) / 2;
int imageRight = imageLeft + realWidth;
int imageBottom = imageTop + realHeight;
mImageRect.set(imageLeft, imageTop, imageRight, imageBottom);
}
/**
* 返回马赛克最终结果
*
* @return 马赛克最终结果
*/
public Bitmap getMosaicBitmap()
{
if (bmMosaicLayer == null)
{
return null;
}
Bitmap bitmap = Bitmap.createBitmap(mImageWidth, mImageHeight,
Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawBitmap(bmBaseLayer, 0, 0, null);
canvas.drawBitmap(bmMosaicLayer, 0, 0, null);
canvas.save();
return bitmap;
}
private int dp2px(int dip)
{
Context context = this.getContext();
Resources resources = context.getResources();
int px = Math
.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dip, resources.getDisplayMetrics()));
return px;
}
}