首先看效果
然后这是代码
/**
* Create by Mazhanzhu on 2020/9/25
* Android图形图像处理:马赛克(Mosaic)效果
*/
public class MosaicView extends AppCompatImageView {
private Bitmap mMosaicBmp;
private Paint mPaint;
private ArrayList mPaths;
private DrawPath mLastPath;
private RectF mBitmapRectF;
private PorterDuffXfermode mDuffXfermode;//马赛克专用画笔
private float tempX, tempY;
private final float mTargetWidth = 20.0f;
public MosaicView(Context context) {
super(context);
init();
}
public MosaicView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MosaicView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setAntiAlias(false);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);//描边
mPaint.setTextAlign(Paint.Align.CENTER);//居中
mPaint.setStrokeCap(Paint.Cap.ROUND);//圆角
mPaint.setStrokeJoin(Paint.Join.ROUND);//拐点圆角
mPaint.setStrokeWidth(60);//宽度
// //抖动效果
// mPaint.setStrokeWidth(2f);
// mPaint.setPathEffect(new DiscretePathEffect(0.35f, 40));
mPaths = new ArrayList<>();
mBitmapRectF = new RectF();
//叠加效果
mDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
}
/**
* 清除操作
*/
public void clear() {
mPaths.clear();
invalidate();
}
/**
* 撤销
*/
public void undo() {
int size = mPaths.size();
if (size > 0) {
mPaths.remove(size - 1);
invalidate();
}
}
/**
* 添加马赛克涂抹监听
*/
public void addListener(MosaicListener mosaicListener) {
int size = mPaths.size();
if (size > 0) {
mosaicListener.isMosaic(true);
} else {
mosaicListener.isMosaic(false);
}
}
private float mScale;
/**
* 获取处理后的图片
*/
public Bitmap getImageBitmap() {
Bitmap bitmap;
if ((getDrawable() instanceof BitmapDrawable)) {
BitmapDrawable drawable = (BitmapDrawable) getDrawable();
bitmap = drawable.getBitmap().copy(Bitmap.Config.ARGB_8888, true);
} else {
bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
}
int width = bitmap.getWidth();
mScale = (float) width / mMosaicBmp.getWidth();
Canvas canvas = new Canvas(bitmap);
canvas.save();
canvas.scale(mScale, mScale);
drawOnLayer(canvas);
canvas.restore();
return bitmap;
}
private int drawOnLayer(Canvas canvas) {
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
//新图层
int layerId;
layerId = canvas.saveLayer(0, 0, canvasWidth / mScale, canvasHeight / mScale, null, Canvas.ALL_SAVE_FLAG);
canvas.save();
canvas.translate(-mBitmapRectF.left, -mBitmapRectF.top);
for (DrawPath drawPath : mPaths) {
//滑过的区域
drawPath.draw(canvas);
}
mPaint.setXfermode(mDuffXfermode);//设置叠加模式
canvas.drawBitmap(mMosaicBmp, mBitmapRectF.left, mBitmapRectF.top, mPaint);//画出重叠区域
canvas.restore();
mPaint.setXfermode(null);
return layerId;
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if (drawable != null && drawable instanceof BitmapDrawable) {
scaleBitmap(((BitmapDrawable) drawable).getBitmap());
}
}
@Override
public void setImageBitmap(Bitmap bm) {
super.setImageBitmap(bm);
scaleBitmap(bm);
}
// 生成小图
private void scaleBitmap(Bitmap bm) {
int width = bm.getWidth();
float scale = mTargetWidth / width;
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
mMosaicBmp = Bitmap.createBitmap(bm, 0, 0, width, bm.getHeight(), matrix, true);
}
/**
* 得到图片展示区域
*/
private RectF getBitmapRect() {
final Drawable drawable = getDrawable();
if (drawable == null) {
return new RectF();
}
// Get image matrix values and place them in an array.
final float[] matrixValues = new float[9];
getImageMatrix().getValues(matrixValues);
// Extract the scale and translation values from the matrix.
final float scaleX = matrixValues[Matrix.MSCALE_X];
final float scaleY = matrixValues[Matrix.MSCALE_Y];
final float transX = matrixValues[Matrix.MTRANS_X] + getPaddingLeft();
final float transY = matrixValues[Matrix.MTRANS_Y] + getPaddingTop();
// Get the width and height of the original bitmap.
final int drawableIntrinsicWidth = drawable.getIntrinsicWidth();
final int drawableIntrinsicHeight = drawable.getIntrinsicHeight();
// Calculate the dimensions as seen on screen.
final int drawableDisplayWidth = Math.round(drawableIntrinsicWidth * scaleX);
final int drawableDisplayHeight = Math.round(drawableIntrinsicHeight * scaleY);
// Get the Rect of the displayed image within the ImageView.
final float left = Math.max(transX, 0);
final float top = Math.max(transY, 0);
final float right = Math.min(left + drawableDisplayWidth, getWidth());
final float bottom = Math.min(top + drawableDisplayHeight, getHeight());
return new RectF(left, top, right, bottom);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mMosaicBmp != null) {
mBitmapRectF = getBitmapRect();
Matrix mosaicMatrix = new Matrix();
mosaicMatrix.setTranslate(mBitmapRectF.left, mBitmapRectF.top);
float scaleX = (mBitmapRectF.right - mBitmapRectF.left) / mMosaicBmp.getWidth();
float scaleY = (mBitmapRectF.bottom - mBitmapRectF.top) / mMosaicBmp.getHeight();
mosaicMatrix.postScale(scaleX, scaleY);
// 生成整张模糊图片
mMosaicBmp = Bitmap.createBitmap(mMosaicBmp, 0, 0, mMosaicBmp.getWidth(), mMosaicBmp.getHeight(),
mosaicMatrix, true);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!mPaths.isEmpty()) {
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
//新图层
int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG);
canvas.clipRect(mBitmapRectF); //限定区域
for (DrawPath drawPath : mPaths) {
//滑过的区域
drawPath.draw(canvas);
}
mPaint.setXfermode(mDuffXfermode);//设置叠加模式
canvas.drawBitmap(mMosaicBmp, mBitmapRectF.left, mBitmapRectF.top, mPaint);//画出重叠区域
mPaint.setXfermode(null);
canvas.restoreToCount(layerId);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
float downX = event.getX();
float downY = event.getY();
mLastPath = new DrawPath();//每次手指下去都是一条新的路径
mLastPath.moveTo(downX, downY);
mPaths.add(mLastPath);
invalidate();
tempX = downX;
tempY = downY;
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX();
float moveY = event.getY();
if (Math.abs(moveX - tempX) > 5 || Math.abs(moveY - tempY) > 5) {
mLastPath.quadTo(tempX, tempY, moveX, moveY);
invalidate();
}
tempX = moveX;
tempY = moveY;
break;
case MotionEvent.ACTION_UP:
mLastPath.up();
break;
}
return true;
}
/**
* 封装一条路径
*/
public class DrawPath {
Path path;
float downX;
float downY;
boolean quaded;
DrawPath() {
path = new Path();
}
void moveTo(float x, float y) {
downX = x;
downY = y;
path.moveTo(x, y);
}
void quadTo(float x1, float y1, float x2, float y2) {
quaded = true;
path.quadTo(x1, y1, x2, y2);
}
void up() {
if (!quaded) {
//画点
path.lineTo(downX, downY + 0.1f);
invalidate();
}
}
void draw(Canvas canvas) {
if (path != null) {
canvas.drawPath(path, mPaint);
}
}
}
public interface MosaicListener {
void isMosaic(boolean b);
}
}
1-首先在布局文件中引用:
2-设置图像
ImageUtils.loadImage_FitCenter(mosaicview, mImg_url);
3-获取涂抹之后的马赛克的图像bitmap
mosaicview.addListener(new MosaicView.MosaicListener() {
@Override
public void isMosaic(boolean b) {
if (b) {
Bitmap bitmap = mosaicview.getImageBitmap();
mFile = Base64Util.bitmapToFile(bitmap);
if (mType == 0) {
startOCR_Token();
} else {
startJiaMi_IMG("");
}
} else {
shuazi.setVisibility(View.VISIBLE);
shuazi.postDelayed(new Runnable() {
@Override
public void run() {
shuazi.setVisibility(View.GONE);
}
}, 6000);
}
}
});
其中这里面有有一个Bitmap 转 文件的方法也发出来吧
/**
* Bitmap 转 文件
*/
public static File bitmapToFile(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//第二个参数是压缩比重,图片存储在磁盘上的大小会根据这个值变化。值越小存储在磁盘的图片文件越小,
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
File fileDir = new File(Base64Util.Mzz_NB);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
File file = new File(Mzz_NB, System.currentTimeMillis() + "_Mzz.jpg");
try {
FileOutputStream fos = new FileOutputStream(file);
InputStream is = new ByteArrayInputStream(baos.toByteArray());
int x = 0;
byte[] b = new byte[1024 * 100];
while ((x = is.read(b)) != -1) {
fos.write(b, 0, x);
}
fos.close();
} catch (Exception e) {
Log_Ma.e("ss", e.toString());
e.printStackTrace();
}
return file;
}
剩下的,拿到了涂抹之后的file文件了,那不是想干啥就干啥嘛~完事了,该吃饭了