微信小程序 canvas裁图

256 阅读1分钟

小程序分享给朋友的图片默认是5:4的尺寸, 实际业务中提供的图片尺寸不一定恰是这个比例,微信默认从左上角进行裁图,而一般图片主要信息都是在中间,所以默认裁图方式,易丢失图片主要信息

我们采用canvas手动进行裁图,生成分享图片

// index.wxml 采用canvas2D接口,使裁剪支持gif图
<canvas id="j-clip" type="2d" style="{{clipStyle}} {{customStyle}}"></canvas>


// index.js
import canvasClip from './lib/clip.js'
Component({
    properties: {
        customStyle: {
            type: String
        },
        src: {
            type: String
        }
    },
    
    data: {
        clipStyle: 'width: 500rpx; height: 400rpx; position: absolute; z-index: 999;top: 9999rpx; left: 9999rpx;'
    },
    
    lifetimes: {
        ready() {
            // 裁剪成功之前,先使页面不可操作,防止用户此时操作,拿不到裁剪后的图片 
            wx.showLoading({
                title: '',
                mask: true
            })
        }
    },
    observers: {
        src(val) {
            val && canvasClip('#j-clip', val, this).then(path => {
                this.triggerEvent('done', path)
                setTimeout(function() {
                    wx.hideLoading()
                })
            }).catch(err => {
                this.triggerEvent('fail', err)
                wx.hideLoading()
            })
        }
    }

})

// ./lib/clip.js
const canvasClip = (canvasId, url, self, cw = 500, ch = 400, ratio = 5 / 4) => {
  return new Promise((resolve, reject) => {
    wx.createSelectorQuery().in(self)
      .select(canvasId)
      .fields({
        node: true
      })
      .exec(res => {
        const canvas = res[0].node
        canvas.width = cw
        canvas.height = ch
        const ctx = canvas.getContext('2d')
        const img = canvas.createImage()

        img.onload = () => {
          let x = 0
          let y = 0
          let imgWidth = img.width // 图片宽
          let imgHeight = img.height // 图片高
          let sImgWidth
          let sImgHeight

          if ((imgWidth / imgHeight) > ratio) {
            sImgHeight = ch
            sImgWidth = (sImgHeight * imgWidth) / imgHeight
            x = -(sImgWidth - cw) / 2
          } else {
            sImgWidth = cw
            sImgHeight = (sImgWidth * imgHeight) / imgWidth
            y = -(sImgHeight - ch) / 2
          }
          ctx.drawImage(img, x, y, sImgWidth, sImgHeight)

          wx.canvasToTempFilePath({
            canvasId: canvasId,
            canvas: canvas,
            success: res => {
              const path = res.tempFilePath
              resolve(path)
              console.log('************* path', path)
            },
            fail: (err) => {
              reject('裁图:存储canvas到临时路径失败', err)
            }
          })
        }
        img.src = url
      })
  })
}

export default canvasClip