1:activity代码
public class MosaicActivity extends Activity implements View.OnClickListener {
private DrawMosaicView mosaic;
private int mWidth, mHeight;
Bitmap srcBitmap = null;
private Button button1, button2, button3, button4, button5;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_mosaic);
initView();
mosaic.setMosaicBackgroundResource(TietieEditImageService.getInstance().getEditBitmap());
srcBitmap = TietieEditImageService.getInstance().getEditBitmap();
mWidth = srcBitmap.getWidth();
mHeight = srcBitmap.getHeight();
Bitmap bit = MosaicUtil.getMosaic(srcBitmap);
mosaic.setMosaicResource(bit);
mosaic.setMosaicBrushWidth(10);
}
private void initView() {
mosaic = (DrawMosaicView) findViewById(R.id.mosaic);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);
button4 = (Button) findViewById(R.id.button4);
button5 = (Button) findViewById(R.id.button5);
button1.setOnClickListener(this);
button2.setOnClickListener(this);
button3.setOnClickListener(this);
button4.setOnClickListener(this);
button5.setOnClickListener(this);
}
int size = 5;
public static Bitmap ResizeBitmap(Bitmap bitmap, int newWidth, int newHeight) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height,
matrix, true);
bitmap.recycle();
return resizedBitmap;
}
@Override
public void onClick(View v) {
if (v == button1) {
Bitmap bit = BitmapFactory.decodeResource(this.getResources(),
R.drawable.hi4);
bit = ResizeBitmap(bit, mWidth, mHeight);
mosaic.setMosaicResource(bit);
} else if (v == button2) {
Bitmap bitmapMosaic = MosaicUtil.getMosaic(srcBitmap);
mosaic.setMosaicResource(bitmapMosaic);
} else if (v == button3) {
Bitmap bitmapBlur = MosaicUtil.getBlur(srcBitmap);
mosaic.setMosaicResource(bitmapBlur);
} else if (v == button4) {
if (size >= 30) {
size = 5;
} else {
size += 5;
}
mosaic.setMosaicBrushWidth(size);
} else if (v == button5) {
mosaic.setMosaicType(MosaicType.ERASER);
}
}
}
2布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="花色" />
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="马赛克" />
<Button
android:id="@+id/button3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="毛玻璃" />
<Button
android:id="@+id/button4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="大小" />
<Button
android:id="@+id/button5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="橡皮擦" />
</LinearLayout>
<com.picturesedit.view.DrawMosaicView
android:id="@+id/mosaic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/app_name" />
</LinearLayout>
3:绘制马赛克样式view
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,
Bitmap.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,
Bitmap.Config.ARGB_8888);
Bitmap bmTouchLayer = Bitmap.createBitmap(mImageWidth, mImageHeight,
Bitmap.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,
Bitmap.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;
}
public class MosaicPath {
/**
* 绘画路径
*/
public Path drawPath;
/**
* 绘画粗细
*/
public int paintWidth;
}
}
马赛克样式工具类
public class MosaicUtil {
public static enum Effect {
MOSAIC, BLUR,
}
;
public static enum MosaicType {
MOSAIC, ERASER
}
/**
* 马赛克效果(Native)
*
* @param bitmap 原图
* @return 马赛克图片
*/
public static Bitmap getMosaic(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int radius = 20;
Bitmap mosaicBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mosaicBitmap);
int horCount = (int) Math.ceil(width / (float) radius);
int verCount = (int) Math.ceil(height / (float) radius);
Paint paint = new Paint();
paint.setAntiAlias(true);
for (int horIndex = 0; horIndex < horCount; ++horIndex) {
for (int verIndex = 0; verIndex < verCount; ++verIndex) {
int l = radius * horIndex;
int t = radius * verIndex;
int r = l + radius;
if (r > width) {
r = width;
}
int b = t + radius;
if (b > height) {
b = height;
}
int color = bitmap.getPixel(l, t);
Rect rect = new Rect(l, t, r, b);
paint.setColor(color);
canvas.drawRect(rect, paint);
}
}
canvas.save();
return mosaicBitmap;
}
/**
* 马赛克效果
*
* @param pixels
* @param width
* @param height
* @param radius
* @return
*/
private static int[] mosatic(int[] pixels, int width, int height, int radius) {
int a = radius;
int b = a * height / width;
int size = width * height;
int[] result = new int[size];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int x = i - i % a + a / 2;
x = x > width ? width : x;
int y = j - j % b + b / 2;
y = y > height ? height : y;
int curentColor = pixels[x + y * width];
result[i + j * width] = curentColor;
}
}
return result;
}
/**
* 模糊效果(毛玻璃)
*
* @param bitmap 原图像
* @return 模糊图像
*/
public static Bitmap getBlur(Bitmap bitmap) {
int iterations = 1;
int radius = 8;
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] inPixels = new int[width * height];
int[] outPixels = new int[width * height];
Bitmap blured = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
bitmap.getPixels(inPixels, 0, width, 0, 0, width, height);
for (int i = 0; i < iterations; i++) {
blur(inPixels, outPixels, width, height, radius);
blur(outPixels, inPixels, height, width, radius);
}
blured.setPixels(inPixels, 0, width, 0, 0, width, height);
return blured;
}
private static void blur(int[] in, int[] out, int width, int height,
int radius) {
int widthMinus = width - 1;
int tableSize = 2 * radius + 1;
int divide[] = new int[256 * tableSize];
for (int index = 0; index < 256 * tableSize; index++) {
divide[index] = index / tableSize;
}
int inIndex = 0;
for (int y = 0; y < height; y++) {
int outIndex = y;
int ta = 0, tr = 0, tg = 0, tb = 0;
for (int i = -radius; i <= radius; i++) {
int rgb = in[inIndex + clamp(i, 0, width - 1)];
ta += (rgb >> 24) & 0xff;
tr += (rgb >> 16) & 0xff;
tg += (rgb >> 8) & 0xff;
tb += rgb & 0xff;
}
for (int x = 0; x < width; x++) {
out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16)
| (divide[tg] << 8) | divide[tb];
int i1 = x + radius + 1;
if (i1 > widthMinus)
i1 = widthMinus;
int i2 = x - radius;
if (i2 < 0)
i2 = 0;
int rgb1 = in[inIndex + i1];
int rgb2 = in[inIndex + i2];
ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);
tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;
tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;
tb += (rgb1 & 0xff) - (rgb2 & 0xff);
outIndex += height;
}
inIndex += width;
}
}
private static int clamp(int x, int a, int b) {
return (x < a) ? a : (x > b) ? b : x;
}
}