Android图形图像处理:马赛克(Mosaic)效果【直接可用】

首先看效果


然后这是代码

/**
 * Create by Mazhanzhu on 2020/9/25
 * Android图形图像处理:马赛克(Mosaic)效果
 */
public class MosaicView extends AppCompatImageView {
    private Bitmap mMosaicBmp;
    private Paint mPaint;
    private ArrayList<DrawPath> 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文件了,那不是想干啥就干啥嘛~完事了,该吃饭了

猜你喜欢

转载自blog.csdn.net/fengyeNom1/article/details/114691646