以图形图像界经典的实验例图Lenna为例,当手指在图片上滑过后,形成马赛克的:

写一个MosaicView继承自AppCompatImageView:

package com.zhangphil;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.MotionEvent;import java.util.ArrayList;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(true);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(32);
//        //抖动效果
//        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();}}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;}@Overridepublic void setImageDrawable(Drawable drawable) {super.setImageDrawable(drawable);if (drawable != null && drawable instanceof BitmapDrawable) {scaleBitmap(((BitmapDrawable) drawable).getBitmap());}}@Overridepublic 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);}@Overrideprotected 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);}}@Overrideprotected 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);}}@Overridepublic 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);}}}
}

使用很简单,因为MosaicView继承自AppCompatImagView,可以把它当做普通的ImageView直接放在布局里面,提供一个src指定的图片即可开始马赛克效果:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"><com.zhangphil.MosaicViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:src="@mipmap/lenna" />
</RelativeLayout>

Android图形图像处理:马赛克(Mosaic)效果相关推荐

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

    首先看效果 然后这是代码 /*** Create by Mazhanzhu on 2020/9/25* Android图形图像处理:马赛克(Mosaic)效果*/ public class Mosai ...

  2. Android图形图像处理:添加涂鸦文字

    先看运行效果: 关键的PaintView: package com.zhangphil;import android.content.Context; import android.graphics. ...

  3. Android移动开发--对图形图像处理的介绍与应用

    前言 随着移动设备的不断普及与发展,相关的软件开发技术也越来越受到人们所重视.Android作为全球最受欢迎的移动智能终端平台.图形图像处理技术在Android中非常重要,特别是在开发益智类游戏或者2 ...

  4. 图形图像处理 - 手写 QQ 说说图片处理效果

    OpenCv 的基础学习目前先告一段落了,后面我们要开始手写一些常用的效果,且都是基于 Android 平台的.希望我们有一定的 C++ 和 JNI 基础,如果我们对这块知识有所欠缺,大家不妨看看这个 ...

  5. android马赛克代码,android图片马赛克 mosaic

    android图片马赛克 mosaic https://github.com/shenkaige/andtools/blob/master/src/com/phodev/andtools/utils/ ...

  6. 【Android】图形图像处理

    1.简单图片 <1>Bitmap <2>BitmapFactory [Android]图形图像处理之"简单图片" (这里包含一个图片放大器实例) 2.逐帧动 ...

  7. android 马赛克 代码,Android_Android 马赛克(Mosaics)效果,前几天看见开源项目效果好赞 - phpStudy...

    Android 马赛克(Mosaics)效果 前几天看见开源项目效果好赞,看了下代码,实现大致就是在原界面之上覆盖一成自定义的View,获取到点击的那个View的内容(Bitmap),然后在覆盖的那个 ...

  8. ImageGear for .NET扫描打印等图形图像处理控件介绍使用手册

    ImageGear for .NET是一款图形图像处理控件,具有扫描,压缩,浏览.添加注释,打印,图像编辑,OCR以及PDF和矢量图像支持,使开发人员可以快速地开发出图像处理程序,可用于.NET Fr ...

  9. 图形图像处理-之-高质量的快速的图像缩放 中篇 二次线性插值和三次卷积插值

    from:http://blog.csdn.net/housisong/article/details/1452249 图形图像处理-之-高质量的快速的图像缩放 中篇 二次线性插值和三次卷积插值    ...

最新文章

  1. 北京大学吴华君课题组多组学数据分析方向博士后和技术员招聘启示
  2. codeforces#597 C. Constanze's Machine(简单dp)
  3. SQLServer 客户端远程访问配置
  4. oracle模拟试题
  5. 韦冬雪计算机应用,捕获效应下RFID防碰撞算法的研究与应用
  6. cglib动态代理导致注解丢失问题及如何修改注解允许被继承
  7. MountFlags of reg
  8. C ++ 类 | 类的辅助函数(Helper Functions) ,类与数组_3
  9. 中小微企业房抵贷业务场景介绍
  10. jquery实现无刷新分页,跳转
  11. 看似简单的hashCode和equals面试题,竟然有这么多坑!
  12. bzoj1997 [Hnoi2010]Planar——2-SAT
  13. java 怎么调用clojure_从java调用Clojure时Clojure状态的范围
  14. 加州大学戴维斯分校 计算机科学,美国王牌专业!加州大学戴维斯分校计算机科学专业等你来...
  15. 快门(曝光时间)、光圈、感光度(ISO)的关系
  16. 标题您的主机不满足在启用 Hyper-V 或 Device/Credential Guard 的情况下运行 VMware Workstation 的最低要求
  17. 局域网即时通讯Active Messenger 完美破解版本 最新版本破解
  18. 2.2磁盘IO网络IO工作机制
  19. 《人类简史》个人读书笔记
  20. 程序员恭喜了!11月起逼自己拿下这个证,年薪68万起!

热门文章

  1. 【java】java 实现 将 字符串 第一个字符 大写 或者 小写
  2. [转]20150617-让程序员跳槽的非钱原因
  3. 1月29日服务器例行维护公告,7月29日服务器例行维护公告 升至1.1.7.5
  4. python两个for循环顺序_python两个for循环顺序_Python编程基础2——顺序、循环、选择...
  5. 云上就医 无接触式问诊!海信电视上线“小聚健康”
  6. 广告再营销之前,你需要了解哪些信息?
  7. 利用指针输出数组元素的三种方法:
  8. IDEA个性化设置注释模板(详细版)
  9. python中地址路径的间隔符在字符中的表示
  10. python四种占位符例子_Python 占位符格式化的简单示例