Android图片编辑马赛克效果

在这里插入图片描述
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;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值