logo科技微讯

小程序 2d canvas 尺寸问题

作者:科技微讯
日期:2020-06-26
📜 文章

这篇文章主要区分 canvas 以下两种尺寸的区别与联系:

  • canvas.widthcanvas.height:device pixel(物理像素)
  • canvas.style.widthcanvas.style.height:css pixel(逻辑像素)

微信小程序 canvas 2d 官方例子是这样的:

<!-- index.wxml -->
<canvas type="2d" id="myCanvas"></canvas>
//index.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");
        // 根据 dpr 做相关设置
        const dpr = wx.getSystemInfoSync().devicePixelRatio;
        canvas.width = res[0].width * dpr;
        canvas.height = res[0].height * dpr;

        ctx.scale(dpr, dpr);
        ctx.fillRect(0, 0, 100, 100);
      });
  },
});

如果 canvas 组件没有设置 style,那默认 style 的就是 width: 300px; height 150px,在 wxml 中的尺寸都是 css pixel,设备会把 css pixel(逻辑像素) 乘以 devicePixelRatio 转换成 device pixel(物理像素) 再显示在屏幕上。iPhone 6 的屏幕分辨率是 375 x 667,这个数字是 css pixel,它的 device pixel 其实是 750 x 1334,大多数产品的参数所标注的屏幕分辨率都是 device pixel。

记住,在 wxml 显示的是 css pixel,但是在 js 写的 canvas 代码是 device pixel 尺寸,所以你会看到上面的例子通过 res[0].width 拿到这个 canvas 组件的 css pixel,然后乘以 dpr 转换成这个 canvas 的 device pixel。如果不转换,那整个图片都会被缩小。

canvas.widthcanvas.style.width 是不同的东西,前者定义了 canvas 的座标体系,而后者定义 canvas 实际显示的尺寸,显示尺寸可以不等于实际尺寸,此时图片可能整体放大或缩小了,甚至被压缩或拉伸了。但通常的做法是 canvas.width = canvas.style.width * dpr,这样可以避免 canvas 上的内容变得模糊。

ctx.scale(dpr,dpr) 的作用是,用微信小程序文档的一句话来说,就是:

在调用后,之后创建的路径其横纵坐标会被缩放。多次调用倍数会相乘。

所以下面这个代码:

ctx.scale(dpr, dpr);
ctx.fillRect(0, 0, 100, 100);

相当于下面这个代码:

ctx.fillRect(0 * dpr, 0 * dpr, 100 * dpr, 100 * dpr);

有时候之所以写 ctx.scale(dpr, dpr),是因为接下来可以用 css pixel 去画这个 canvas,毕竟 css pixel 是设计师采用的尺寸,不用每次都乘以 dpr。

drawImage(imageResource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) 中,sWidth 和 sHeight 都是图片的 css pixel 尺寸,如果不确定可以用 wx.getImageInfo() 获取,后面四个参数都是 canvas 的座标位置,根据 canvas.widthcanvas.height 以及 ctx.scale(dpr, dpr) 确定。

wx.canvasToTempFilePath 可以设置这些选项:

wx.canvasToTempFilePath({
  x: 0,
  y: 0,
  width: 50,
  height: 50,
  destWidth: 100,
  destHeight: 100,
  canvas: "myCanvas",
  success(res) {
    console.log(res.tempFilePath);
  },
});

前面四个参数是 canvas 的 css 座标,destWidth 和 destHeight 是最终输出的图片的 css 尺寸,即 destWidth: 100 其实相当于在输出的图片添加 image.style.width = 100px。destWidth 和 destHeight 要不小于 width 和 height,否则会变模糊。

donation赞赏
thumbsup0
thumbsdown0
暂无评论