业务中碰到微信小程序须要生成海报进行朋友圈分享,这个是很是常见的功能,没想到实际操做的时候花了整整一天一晚上才搞好,微信的 canvas 绘图实在是太难用了,官方快点优化一下吧。javascript
业务很是简单,只须要将用到的图片,文案素材拼装到一张图片,保存到本地就能够了。java
首先建立画布,将一张网上的图片画到画布上。git
const ctx = wx.createCanvasContext('shareCanvas');
ctx.drawImage("https://img3.doubanio.com/view/photo/l/public/p2327709524.jpg", 0, 0, 300, 400);
ctx.draw();
复制代码
这时候出现一个问题:在模拟器上没有报错,但是真机测试却什么也没画出来。网上搜索一阵发现微信小程序的 canvas.drawImage 是不支持网络图片的,只支持本地图片。因此,任何的网络图片都须要先缓存到本地,再经过 drawImage 调用存储的本地资源进行绘制,缓存能够经过 wx.getImageInfo 和 wx.downloadFile 实现,此次选用了 wx.getImageInfo, wx.downloadFile 没有试过,不知道可不能够。github
wx.getImageInfo({
src: 'https://img3.doubanio.com/view/photo/l/public/p2327709524.jpg',
success: function (res) {
console.log(res.width)
console.log(res.path)
}
})
复制代码
这个方法能够拿到存储的本地图片地址,长宽以及一些简单的图形变化,将本地缓存的图片地址保存到全局变量或者缓存供 wx.drawImage 调用。canvas
还有一点须要注意的是 draw 方法是异步的,若是图片还没加载成功,有可能画出来的是空的,因此 draw 方法一般都会带有定时器这样的回调。小程序
ctx.draw(true,setTimeout(function(){
wx.canvasToTempFilePath({
canvasId: 'shareCanvas',
success: function(res){
that.data.tmpPath = res.tempFilePath
},
})
},1000));
复制代码
绘图后经过 1 秒的延时将画好的新图片保存到本地,而后经过 wx.saveImageToPhotosAlbum() 保存到手机相册。这一步存在受权问题,须要考虑拒绝受权后的兼容性,也就是若是用户拒接受权之后怎么办?常见的作法是先经过 wx.getSetting() 获取用户的权限设置,若是用户拒绝了访问相册的权限,能够跳转到受权设置页面要求用户更改受权信息。微信小程序
小程序的受权设置 api 已经弃用了,如今只能经过组件形式,将 button 的 open-type 属性设置成 openSetting,自动跳转到设置页面,整体来讲没有以前方便了。若是页面原本已经有 button能够先将 open-type 属性设成 null,当遇到须要跳转的逻辑再经过 setData 设置,这样处理很是复杂,很容易出错,可是能够节省页面或者跳转;另外一种处理方式是,当没有受权时先跳转到说明页面,说明须要受权的信息,在这个页面上添加一个 open-type 的button,点击之后跳转到设置页面,此次咱们采用的是第一种方法:api
下一步是文字编辑的问题,微信画文字是不支持自动换行的,因此只能手动计算每一行可以容纳的文字个数进行手动换行,好比一个文字加间距占 10 px,一行总体可使用 100 px,那就是每行只能容纳 10 个字,第 11 个字另起一行开始画。数组
将文字分割成 10 个字的数组:缓存
function canvasWorkBreak(maxWidth, fontSize, text) {
const maxLength = maxWidth / fontSize
const textLength = text.length
let textRowArr = []
let tmp = 0
while (1) {
textRowArr.push(text.substr(tmp, maxLength))
tmp += maxLength
if (tmp >= textLength) {
return textRowArr
}
}
}
复制代码
将数组一行一行画到画布上:
var height = 200
for (let item of ['个人舍利佛','搜房法拉']) {
if (item !== 'a') {
ctx.setFontSize(16);
ctx.setFillStyle("#484a3d");
ctx.fillText(item, 20, height);
height += 50;
}
}
复制代码
把每一种元素画完之后整个海报制做的流程就已经跑通了,但并不表明在实际业务中就可使用了。首先面对的是海报生成的质量问题,假设咱们的手机像素是 320 * 400 的,若是要将图片展现在手机上用于预览,只有两种选择:
上面的图其实是比较长的,你能够截取一部分显示出来,这样图片看起来就会更协调。在经过正常比例绘制完图片之后,能够经过填充矩形的方式覆盖一部分图片,而后在矩形上输入其余的内容,这样图片的一部分就被隐藏起来了。
因为 canvas 是优先级最高的,老是会覆盖页面上的其余内容,因此「保存图片」的按钮可能会被覆盖掉而显示不出来,能够经过在 button 上套一层 cover-view 来解决。
图片绘制原本应该是一个很是简单也很是成熟的技术,其余的框架都会有对应的组件来处理这些事情,但是微信小程序的 canvas 绘制能够用「很是难用」来形容,但愿微信团队能尽快优化。
你能够点击「阅读原文」获取源码。