微信小程序 PC端wx.canvasToTempFilePath显示不全 解决

现象

以下是保存画布到文件的函数:

export function exportcanvas(canvas) {
  wx.canvasToTempFilePath({ //将canvas生成图片
    canvas: canvas,
    x: 0,
    y: 0,
    width: canvas.width,
    height: canvas.height,
    destWidth: canvas.width,
    destHeight: canvas.height,
    success: function (res) {
      wx.saveImageToPhotosAlbum({ //保存图片到相册
        filePath: res.tempFilePath,
        success: function () {
          wx.showToast({
            title: "生成图片成功!",
            duration: 1800
          });
        }
      })
    },
    fail: function (res) {
      console.log(res)
    }
  });
}

在手机端一切正常,但是Windows端出现问题:只截取了原图的一部分进行保存,如下图所示:

为了不占空间我对上图的高度进行了裁剪。但从宽度上明显看出缺了一部分。此外,残缺的图的长宽比和canvas一致(因此后文只提宽度不提高度)。导出的图片的宽度和设置的宽度也不一样,大了不少。

实验 

这个问题n年了微信官方还是没解决。

一开始看到“微信开放社区”内有人的解决办法是除以pixelRatio。但是没有用。于是我把屏幕信息打印了出来:screenWidth=414,pixelRatio=1.4479。

原图的宽度是800像素。然后脑抽以为ctx也有width属性(实际上没有),于是把destWidth和destHeight设置为了ctx.width和ctx.height(为undefined,实际上相当于没传),结果发现也能导出,图片内容和之前一样(相同的残缺),只是图片宽度为599,而之前有1158。我从手机上获取了正常导出的图片,发现本次PC端导出的图片截取的部分,就是正常图片的前599像素(从宽度上来看)。换了别的图片(宽度均超过599),得到的也都是截取前599像素的图片。这个发现告诉我:截取的内容大小相对于canvas固定,都是599像素。

我还是把destWidth和destHeight换成了canvas.width和canvas.height。但是输入不同尺寸的图,导出的大小也不一样,但都比我设置的尺寸大。那有什么共性呢?于是我发现1158=800*1.4479,即:导出的实际宽度=设定宽度*pixelRatio。要让导出的和设定的一样,只要提前除以pixelRatio即可。这样输出就解决了。

我试着改变截取的宽度和高度,小了确实在截取,大了(即使超过画布大小)则锁定截取599像素。那不同的电脑输出的是否相同呢?如果相同,只要缩放画布内容即可;如果不同,那关系是什么?结果是:不同。另一台电脑上,只截取517像素。于是发现了关系:414(屏幕宽度)*1.4479(像素比)=599(实际截取的宽度),这就是实际可以导出的画布的最大宽度。

所以导出前要把内容缩放到这个“最大宽度”内。但是微信小程序不能凭空创建画布,offscreencanvas又是各种bug,所以选择了较为崎岖的一条路:导出为ImageData,转换为我的图片的数据结构,进行缩放,然后转回ImageData,绘制到屏幕上。当然可以直接drawImage在左上角画一个小图,但是这样周围有一圈不好看。

解决

需要注意的是有个延时,因为发现putImageData不会立即更新画布内容。jsPic是我的图片库。代码如下:

async function download() {
    let cW = c.width;
    let cH = c.height;
    let dstW = c.width;
    let dstH = c.height;
    // PC系统要单独处理
    if (wx.getDeviceInfo().system.toLowerCase().startsWith("windows")) {
      const win = wx.getWindowInfo();
      const pixR = win.pixelRatio;
      const realW = win.screenWidth * pixR; // 实际截取的宽度
      // 保证输出的尺寸正确
      dstW /= pixR;
      dstH /= pixR;
      // 保证输入的尺寸正确 对原图进行缩放
      const imgdata = ctx.getImageData(0, 0, c.width, c.height);
      const jspic = (new jsPic().fromImageData(imgdata, 'RGB')).resize(realW);
      data2canvas(jspic.toImageData(), ctx, c);
      // 不延时不会及时反馈
      await new Promise((resolve) => setTimeout(resolve, 100));
    }
    wx.canvasToTempFilePath({ //将canvas生成图片
      canvas: c,
      x: 0,
      y: 0,
      width: cW,
      height: cH,
      destWidth: dstW,
      destHeight: dstH,
      success: function (res) {
        wx.saveImageToPhotosAlbum({ //保存图片到相册
          filePath: res.tempFilePath,
          success: function () {
            wx.showToast({
              title: "生成图片成功!",
              duration: 1800
            });
          }
        })
      },
      fail: function (res) {
        console.log(res)
      }
    });
}
function data2canvas(imgdata, ctx, c) {
    c.width = imgdata.width;
    c.height = imgdata.height;
    ctx.putImageData(imgdata, 0, 0);
}

嗯,成一坨屎山了。谢谢你,微信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值