微信小程序canvas踩坑录--批量合并生成图片

1,463 阅读2分钟

前言

图片的合并有很广泛的应用,例如活动海报图,需要背景图片和二维码图片。在小程序中,有两种解决方案:

  1. 后端直接合并生成,通过接口获得;
  2. 前段利用canvas实现图片拼接并支持下载。

当批量处理的时候,后端返回的速度可能有些慢,用户体验不好,所以现在介绍下前端利用canvas实现的步骤,如果你当前也在做类似图片合并的功能,通过这篇文章互相交流,希望对你有所帮助,对我也是个提高的方式。

初始化canvas

微信小程序废弃了之前的canvas相关接口,现在设置type="2d"即可使用原生的相关的api。canvas api

<canvas type="2d" id="canvas"></canvas>

注意: 官方文档对于获取canvas实例的方式有所区别,页面和组件内的获取方式不同,以下为页面内的获取方式,其他可查阅微信官方文档(吐槽下,文档嫩不嫩写的再好点哇=。=)

const query = wx.createSelectorQuery()
query.select('#canvas').fields({ node: true, size: true }).exec((res) => {
      const canvas = res[0].node
      const ctx = canvas.getContext('2d')
      // canvas实例和其context
      this.setData({ canvas, ctx })
})

批量图片合并

从后端获得背景图片列表imageList数组和二维码图片链接qrcodeUrl字符串。

onLoad() {
    // 通过接口获得的imageList, qrcodeUrl
    this.setData({ imageList, qrcodeUrl },this.getMergeImgaes)
}
async getMergeImgaes() {
    const finalImages = await Promise.all(this.drawImage())
    // 获得批量合并生成后的图片数组,可以进行接下来的操作
    // ...
}

注意: canvas的drawImage需要在图片对象的onload异步中使用,那对于批量来说,就需要思考,我首先要拿到二维码的图片对象,然后再遍历背景图片数组,与每一张图片合并后再返回新的图片,我们使用promise处理。

drawImage() {
    const { imageList, qrcodeUrl, canvas, ctx } = this.data
    const qrcodeImage = new Promise((resolve, reject) => {
        // 小程序中使用createImage获得图片实例,而不是new Image()
        const image = canvas.createImage()
        image.src = qrcodeurl
        image.onload = () => {
            resolve(image)
        }
    })
    // 接下来异步处理下图片的合并
    let promiseList = []
    for (let item of imageList) { // 为什么用for of,可以想想
        let p = new Promise((resolve, reject) => {
            qrcodeImage.then(qrcode => {
                const image = canvas.createImage()
                image.src = item
                image.onload = () => {
                    canvas.width = image.width
                    canvas.height = image.height
                    // 批量处理,首先需要清除下画布再重新绘制
                    ctx.clearRect(0, 0, canvas.width, canvas.height)
                    ctx.drawImage(image, 0, 0, canvas.width, canvas.height)
                    // 关于二维码或其他需要拼接的图片,首先确定下x,y的坐标
                    ctx.drawImage(qrcode, x, y, qrcode.width, qrcode.height)
                    // 将canvas的画布转为图片
                    resolve(canvas.toDataURL())
                    //wx.canvasToTempFilePath获得的是本地临时路径,在批量状态下可能会显示重复
                }
            })
        })
        promiseList.push(p)
    } 
    return promiseList
}

后记

将多张图片合并成一张也是如此,很简单,本文主要考虑微信小程序环境中对图片进行批量合并处理的情况。另外值得一提的是,若是图片需要提高精度以减少锯齿感,可依据微信文档的处理方法即可。谢谢!