Canvas DrawImage变形问题

先来看段代码:

wx.createSelectorQuery().in(this).select('#output')
        .fields({
          node: true,
          size: true
        })
        .exec((res2) => {
          var canvas = res2[0].node;
          const output = canvas.getContext('2d')
          let img = canvas.createImage(); //创建img对象
            img.onload = () => {
              output.clearRect(0, 0, canvas._width, canvas._height)
              output.drawImage(img, 0, 0, canvas._width, canvas._height); //drawImage(要绘画的元素, x轴, y轴)
            };
            img.src = remoteSrc;
        });

其中这个图片的宽高跟canvas的宽高是完全一致的,但是通过上面的输出后,图片呈现出被裁剪以及变形的情况

DrawImage的文档地址

CanvasContext.drawImage(string imageResource, number sx, number sy, number sWidth, number sHeight, number dx, number dy, number dWidth, number dHeight) | 微信开放文档 (qq.com)

DrawImage的参数主要包含两部分,一是从图中的截取哪一部分,二是将截取的部分粘贴到canvas的哪个位置

其中第一部分可以不要,表达截取整个图片,形如上面代码中写的

找遍全网都没有找到解决办法,后来在canvas的示例中看到一段代码

canvas | 微信开放文档 (qq.com)

// canvas.js
Page({
  onReady() {
    const query = wx.createSelectorQuery()
    query.select('#myCanvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')

        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)

        ctx.fillRect(0, 0, 100, 100)
      })
  }
})

依样画葫芦试了下,图片不再变形,大小也正确

我理解的如下:

scale 缩放,缩放画布,缩放完画布后,新画到画布的图,也会随着缩放。

设备像素比Dpr=物理像素/css像素 ,假如dpr为2,那么手机一般是2个像素当1个像素进行显示,假如图片尺寸是200px,实际上你看到的是100px

微信小程序默认canvas的width,height分别为300,150

回到最初,显示会变大变形的问题,

  1. 虽然canvas通过css控制为 300,300,但是这个只是css的,实际的canvas宽高还是300,150
  2. 现在将300px*300px的图片画到canvas中,由于使用了canvas的_height,也就是css的高度300,但实际上canvas只有150的高,那么将图将被切掉一半高度
  3. canvas只有一半的图片,再通过canvas的css进行展示,有就是将300*150的图片展示为300*300,最终呈现的效果如下

既然知道了变形的原因,也就是canvas实际宽高的问题,那么就知道如何解决

  1. 将canvas的实际宽高进行重置,这样300*300的图片画到了300*300的canvas上,图片不再被裁剪
  2. const dpr = wx.getSystemInfoSync().pixelRatio canvas.width = res[0].width * dpr canvas.height = res[0].height * dpr
  3. 上面的代码有一个细节,canvas宽高都乘上了dpr值,假如dpr值是2,那么300的图,扩大为600的图,画在600的canvas上,为什么要这样做?这里有一个二倍图的概念,假如css使用的是rpx,那么这个图会根据屏幕自动缩小,为了能够匹配这种缩小,就需要将原图扩大,也就是乘上dpr