iOS多边形马赛克的实现(下)

上一篇里我们详述了多边形马赛克的实现步骤,末尾提出了一个思考:如何在涂抹时让马赛克逐块显示呢?

再回顾一下多边形马赛克的实现。首先进行图片预处理,将原图转成bitmap后生成铺满马赛克的全图。手指移动的时候从touch回调里获取坐标点,在这些点之间进行插值,然后以插值之后的路径点为圆心将马赛克图层里对应的区域贴过去,这样就完成了对图像的特定区域打码的处理。

试想一下,如果上述步骤不变,要想让多边形马赛克一块一块的显示出来,首先得计算手指移动时经过了哪些马赛克块。具体来说,也就是在每一次touchMove的回调都需要计算若干个圆形与哪些多边形马赛克相交。多边形相交的运算是十分复杂的,考虑到我们的马赛克模块还是在cpu上计算,如何让整个过程的复杂度降低成为必须要考虑的问题。

第一步:计算手指移动所覆盖到的马赛克单元

为了解决这个问题,我给每一个马赛克素材图片加入“重心”的概念。所谓的重心,指的是图片有效区域的中心,而不是整张图的中心点。以拼图马赛克为例

给左图设置的重心是(0.25, 0.5),右图的重心是(0.75, 0.5)。考虑到素材会缩放以调整单位马赛克大小,这里的x, y分别以素材的宽高为基准。

在这样的定义下,我们可以将前面的问题简化为:找到手指移动过的区域包含了哪些马赛克块的重心,然后将这些马赛克显示出来。具体来说,则是遍历插值之后的坐标点,找到距离该点在特定半径之内的马赛克重心,然后绘制这些马赛克块。这里的半径是根据用户所选笔触大小计算出的一个数值,笔触越粗则半径越大,手指移动绘制出的马赛克块也更多一些。比如下图范围内的4块马赛克应该显示出来。

之前预处理的时候,我们需要根据马赛克素材的各种规则定义生成铺满马赛克的全图。而现在我们是将马赛克逐块绘制,显而易见生成全图已经没必要了。这里我们需要初始化马赛克行数、列数、横向间距、纵向间距等参数,以便手指移动的时候计算经过了哪些马赛克块。初始化的代码如下

在这样的设定下,我们将多边形相交的运算简化为点与点之间的距离计算,复杂度大大降低。

第二步:绘制

前面详述了如何找出手指移动区域所覆盖的马赛克块,那么如何给这些马赛克块上色呢?上一篇里我们讲到,通过遍历maskImage对应的有效颜色区域,求出该区域的rgb平均值即可。试想一下,在大多数机型上touch事件的回调频率可高达60Hz。也就是说,在1/60秒的时间里,我们需要完成插值、找到马赛克块、以及绘制马赛克块等步骤,如果在绘制的时候还需要计算平均rgb值,有可能会因为计算量太大而造成UI卡顿。因此这里我们将求平均rgb值改为直接取该马赛克区域重心的颜色,以简化整个绘制的过程。以正方形马赛克为例,下面两图分别是取平均值和重心(正方形的中心点)颜色所生成的全图马赛克效果。

可以看到取中心点生成的马赛克图片似乎更鲜活一些。当然如果一定要取马赛克区域的平均rgb值也是可以的,在预处理的时候事先计算好每个马赛克块的平均颜色即可。

现在看看我们用新方案实现的涂抹绘制多边形马赛克效果吧。

大功告成!看起来可还行?事实上在实现过程中也是遇到了各种坑,接下来说一下主要遇到的问题。

边界问题

以六边形马赛克为例,放大图片的边缘区域如下。

可以看到,由于列间距只有单元格高度的0.5倍,因此我们在计算单元格行数和列数的时候最好是在首尾各预留一行/列以免边缘地方出现遮盖不到的情况(考虑一下行/列间距如果小于0.5是否会有问题?)

另外在计算马赛克重心的时候,可以看到边缘地方的马赛克块重心很有可能不在图片范围内。所以这里一定要做好预防,否则涂抹到边缘时候很有可能crash(CLAMP函数第二、三个参数分别对应最小、最大值)。

叠加顺序问题

我们来看一下这种类型的马赛克。

这是一种正方形内嵌圆形的马赛克,其素材由4个角以及中间的圆形一共5张图构成。

设计师期望的是,在手指移动过程中,这种素材能以正方形单元格为整体一起显示出来。而且他们的叠加顺序也是固定的:先绘制4个角,最后再绘制中间的圆形以免圆形区域被遮挡。对于这样的素材,我给它额外添加了一个subType来做区分处理。在手指移动时用前面的方法判断移动区域是否包含该单元格中心,如包含,将该单元格的马赛克块按顺序依次绘制出来即可。

实现出来的效果如下图所示。

总结

回顾上下两篇iOS多边形马赛克实现,主要研究和探讨了以下几个问题:针对各种形状的多边形找到通用平铺规则;手指移动时判断经过了哪些马赛克块;计算颜色及绘制;消除锯齿问题、边界问题以及叠加顺序问题。有兴趣的朋友可以试用一下天天P图的马赛克模块哦~


作者简介:jennysluo(罗爽),天天P图iOS工程师

原文发布于微信公众号 - 天天P图攻城狮(ttpic_dev)

原文发表时间:2017-01-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏哈雷彗星撞地球

iOS动画三板斧(三)--UIDynamic动画介绍实战

终于到了动画三板斧第三篇了,这里用UIDynamic来实现动画。 UIDynamic是iOS 7之后新添加的一些物理仿真动画库,包含在UIKit框架中。

944
来自专栏Android机动车

开发中的动效设计与实现 —— 贝塞尔曲线动画的插值法

一个动画一般有这些参数 —— 动画时间、属性变化量、以及贝塞尔插值曲线。在动效标注的时候,也只需要标注这些参数就可以完整的给UI研发写动效了。一个动效所涉及的元...

1962
来自专栏数据小魔方

R语言信息可视化——文字云

这一篇跟大家分享R语言信息可视化——文字云。 R语言可以轻松处理信息可视化,并且很早就有专用的信息可视化包——WordCloud。 可是这个第一版的文字云工具,...

3988
来自专栏落影的专栏

OpenGL ES实践教程(八)blend混合与shader混合

教程 OpenGL ES实践教程1-Demo01-AVPlayer OpenGL ES实践教程2-Demo02-摄像头采集数据和渲染 OpenGL ES实践...

5865
来自专栏Material Design组件

Human Interface Guidelines — Sliders

982
来自专栏腾讯NEXT学位

这个CSS问题屏幕前的你是否熟悉,然后懵逼,最后放弃

3716
来自专栏我和未来有约会

Silverlight 4 中摄像头的运用—part1

入的视频 摄像头经过一个Video对象就能让你看到视频,而这个对象是一个显示对象,所以显示对象能做得事情,它都能做,比如滤镜,变形,混合模式等等。当然最强大的还...

1895
来自专栏逍遥剑客的游戏开发

简单的运动模糊效果实现

1864
来自专栏编程之旅

Rem布局的原理探究

在用前端给移动端页面写布局时,我接触到了Rem布局,但是老实说我也看了几篇手淘适配的文章,并且主要的目的是拿到代码写出demo,所以对于Rem我还是停留在只会使...

4012
来自专栏企鹅号快讯

技术干货:前端图形化技术简介(上)

Canvas与SVG 前端图形化技术,主要包括Canvas绘图和SVG绘图两类。 ? Canvas早在十几年前就被火狐浏览器引入。Canvas通过Canvas....

2387

扫码关注云+社区

领取腾讯云代金券