作者 | 张鹏
Android 程序员,关注大前端各种新兴技术。
相信大家都用过微信的图片编辑功能,非常有用,例如发送图片前可以画上一些标记,或者把隐私信息涂上马赛克。最近在杏仁医生 APP 上,我们也添加了类似功能。今天就来讲讲其中的涂鸦和马赛克的原理与实现。下图就是我们最终的实现效果。
基本概念
在讲具体的实现之前,先来看一下图片编辑功能中用到的一些基本概念。了解这些对后续一些复杂计算的理解有一定的帮助。
坐标系
触屏坐标系 这里一般会使用
MotionEvent
中的getX()
和getY()
,这里的坐标值就是相对于当前控件显示区域的相对坐标,不论当前控件如何显示,如scrollX
和scrollY
的值发生变化后,也不会影响触屏坐标。不过有一点就是控件如果旋转(setRotation
)或者平移(setTranslation
)后,坐标原点位置也是会跟着变化的。画布坐标系 画布坐标可以简单计算得到,当前的坐标原点就是
(-scrollX, -scrollY)
,这样可以通过 View 的scrollTo
和scrollBy
方便地实现平移效果。
图片位置
图片的位置是基于画布坐标系的,并使用一个 RectF
对象表示(下面使用 mFrame
表示),它可以表示出图片的左上角和右下角坐标,因此 mFrame
不仅表示了图片的坐标位置,还表示的图片的缩放程度。关于图片展示,缩放以及平移等操作,可以参考我写过的一个大图预览的库:IntensifyImageView (地址:https://github.com/kareluo/IntensifyImageView)
// 当前图片矩形
RectF mFrame;
// 原始图片矩形
RectF mOriginalFrame;
// 当前图片的缩放值float
scale = mFrame.getWidth() / mOriginalFrame.getWidth();
绘制的时候只需要将Bitmap对象绘制到mFrame
矩形中即可,对图像的缩放及平移操作全部转化到了对mFrame
矩形的操作。
// 绘制图像
canvas.drawBitmap(bitmap, null, mFrame, null);
图像的缩放
图片缩放会涉及到两个坐标系,手势触摸得到缩放值及缩放中心,如 (focusX, focusY, factor)
,然后转换成画布坐标 (focusX + scrollX, focusY + scrollY, factor)
,再根据这个坐标及缩放值计算 mFrame
,如下:
Matrix m = new Matrix();