iOS 小程序 2d canvas drawImage 结果是空的问题

作者: 科技微讯

日期:

我写了一段大概是下面这样的代码, 把图片 draw 在一个 canvas 上, 然后再把 canvas 导出成图片. canvas 的尺寸有两种, 分别是 canvas.width 和 canvas.style.width, 其中 canvas.width 我在 query 执行后的回调函数中设置, 而 canvas.style.width 我通过数据绑定的方式动态设置, 具体也是在 query 执行后的回调函数中设置.

wxml

<canvas
  type="2d"
  id="canvas"
  style="width: {{canvasSize.cssWidth}}px; height: {{canvasSize.cssHeight}}px"
></canvas>
<image
  src="{{outputImage}}"
  style="width: {{canvasSize.cssWidth}}px; height: {{canvasSize.cssHeight}}px"
></image>

js

const image = {
  path: "",
  width: 100,
  height: 100,
}
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.width = 100
    canvas.height = 100
    const img = canvas.createImage()
    img.src = image.path
    img.onload = function() {
      this.setData({
        canvasSize: {
          cssWidth: 50,
          cssHeight: 50,
        },
      })
      ctx.drawImage(img, 0, 0, image.width, image.height)
      wx.canvasToTempFilePath({
        canvas: canvas,
        destWidth: 100,
        destHeight: 100,
        success: res => {
          this.setData({
            outputImage: res.tempFilePath,
          })
        },
      })
    }
  })

这样的代码可以在开发者工具以及 android 端正常运行, 即 <image> 组件可以成功显示通过 canvas 导出的图片, 但是 iOS 端不能, iOS 显示为空.

解决方法是在 query 之前, 就应该设置好 <canvas> 的 css 尺寸, 即把下面这段代码移至 query 之前:

this.setData({
  canvasSize: {
    cssWidth: 50,
    cssHeight: 50,
  },
})

如果不设置 canvas 的 css 尺寸, 那小程序会默认它是 300 x 150, 所以并不会出错.

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

更改 canvas 的 css 尺寸之后, 如果需要用到新尺寸的画布, 那都需要重新 query 一次这个 canvas, 如果使用修改尺寸之前 query 到的 ctx 去画图, 画出来的图片可能会变形. 修改 canvas 的尺寸之前, 最好 clear 一次画布, 这样在画布尺寸修改时可以避免画面的短暂变形.