小程序Canvas填坑路

        有一个如下的业务场景:后台返回一张图片的ID,前端通过ID拼接出图片的地址,拿到图片之后需要在图片上添加一些额外的文字,在前端显示,然后再将它保存为一张新的图片,并把它以base64格式发送给后台。

        这里我总共遇到了如下几个问题:

                1:在线图片无法在手机端通过canvas绘制显示。

                2:手机端测试,canvas绘制时只绘制了一部分。

                3:在线图片通过canvas绘制完添加完文字后,保存为本地图片时图片清晰度太低。

                4:在小程序里如何将本地图片转换成base64格式。

                5:前端显示的屏幕适配。

        接下来开始进行填坑之路。

        1,2:小程序本身不支持在手机端用canvas绘制在线图片,所以这里我们需要把图片的在线地址换成本地路径,然后再用本地路径去进行canvas绘制就行了。下面把这一操作封装成了一个函数方便在项目中调用。

        这样一来我们就可以把一张在线图片通过本地路径绘制到canvas上,然后canvas绘制完就可以在手机端上显示了。第一点问题就解决了。这里的canvas笔者在一开始的时候把他的宽度和高度进行了动态设置也因为这个引起了第二点问题的出现。但实际上后台返回给我的图片大小是固定的就是一些列的背景图片而已。所以后来我把canvas的长宽设置成固定值就解决了第二点问题。

        3:这个的出现是因为你输出目标图片的时候没有计算屏幕像素密度。要偷懒的话,你可以不用计算,直接不写,小程序会给你自动计算,然后得到一张长宽和你canvas一样而且清晰度不错的图片。下面是小程序官方文档的截图:

        由于小程序wx.canvasToTempFilePath(OBJECT, this)有不少的默认选项,所以笔者也就偷懒了,在实际操作中只写了那些必须的参数比如canvasId。

        4:由于小程序的限制,很多原生JS的方法是不行的,这里的解决思路是用最原始的方法,首先通过wx.canvasGetImageData拿到canvas上的图像数据,然后使用开源库UPNG对原始图像数据进行png编码,png编码后数据用wx.arrayBufferToBase64最终进行base64编码。如下图所示,变量base64就是最后的编码结果,当然首先要引入pako.min.js和UPNG.js这两个JS文件。

        5:这里一开始笔者的思路是canvas绘制完成后可以得到图片的本地路径,然后将这个路径动态的赋值给小程序的image标签,接着使用小程序的API获取屏幕的宽度,再根据canvas的长宽,计算出image最终的高度然后把动态赋值给image,通过position绝对定位占据canvas的位置。然而这里canvas属于小程序原生组件,层级是最高的,在手机端的效果就是你只能看到canvas而看不到image的内容,虽然你对canvas设置了可见性和透明度,但只在开发者工具上有效,真机是无效的。最后的实现是重新定义一个canvas放在原先canvas的前面,把图片的本地路径绘制到新的canvas上去,新的canvas的长宽通过image同样的方式去计算就行了。前面讲过canvas动态设置长宽的时候会出现只绘制部分的情况,后来查明了原因是由于第一次绘制的时候由于文字的处理,图片是由网络图片转化以及其它的操作占用了不少时间,就导致我开始绘制的时候图片只加载了部分。而现在新canvas的情况有所不同,只需要绘制一张本地路径的图片即可,这个速度是跟得上我canvas的渲染的,所以可以使用canvas动态设置长宽。屏幕适配的问题就解决了。这个时候我们是有两个canvas,而初始canvas的长宽是等于原始图片大小的,这样一来屏幕上会有两张图片,解决方案是限定view的长宽,并设置overflow:hidden,这样我们看到的就是,加载时会出现短暂的空白期,然后整张图片开始呈现,在空白期我们可以加一个加载动画,这样就perfect了。

        以上是笔者在开发过程中Canvas里所遇到的一些麻烦和解决方案,欢迎大家留言补充。

猜你喜欢

转载自blog.csdn.net/qq_34295211/article/details/80485148