html2canvas图片模糊解决方案

html2canvas官方的配置介绍

ViewPort布局方案

页面采用ViewPort方案,解决iOS上的1px的边框问题,采用这个方案,在iOS上渲染出来的Dom会自动乘以devicePixelRatio,因此iOS上的Canvas相当于被直接放大了,没有出现模糊的情况。

var viewport = document.querySelector("meta[name=viewport]");
var deviceRatio = window.devicePixelRatio || 1;
var scale = 1.0/deviceRatio;
viewport.setAttribute('content', 'width=device-width,initial-scale='+scale + ', maximum-scale='+scale+', minimum-scale='+ scale +', user-scalable=no');

发现#id锚点异常,是因为CSS的属性text-size-adjust在作怪,导致,关掉即可。

-webkit-text-size-adjust: 100%;

安卓也想采用ViewPort方案,发现会引入更多的问题,首先是text-size-adjust导致的布局异常问题,可以通过关闭所有设备上的text-size-adjust解决

 -ms-text-size-adjust: 100%;
 -webkit-text-size-adjust: 100%;
 text-size-adjust: 100%;

但是依旧会发现在某些设备上有布局问题,还有因为这个text-size-adjust导致的闪动问题,以及滑动卡顿问题(devicePixelRatio太大了导致原始dom的尺寸太大渲染不流畅)。找了一圈后发现手淘的使用Flexible实现手淘H5页面的终端适配在安卓上的这个值始终认为是0,看来是不好走通了。

其中initial-dpr会把dpr强制设置为给定的值。如果手动设置了dpr之后,不管设备是多少的dpr,都会强制认为其dpr是你设置的值。在此不建议手动强制设置dpr,因为在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1。

到这里iOS不用任何配置直接使用Html2Canvas就可以画出清晰的图了。

安卓还需要另外适配。

图片模糊问题

html2canvas一开始用的最新版本,发现dom在屏幕之外的部分始终无法绘制,调了半天最后换了个版本(往下降了一个版本)直接就好了。目前项目中使用的是1.0.0-alpha.12

"html2canvas": "^1.0.0-alpha.12"
  1. 设置html2canvas的选项
const html2canvasOpts = {
  backgroundColor: null,
  useCORS: $fn.isDev(),
  allowTaint: $fn.isDev(),
  scale: window.devicePixelRatio || 1,
  ignoreElements: (element) => {
    if(element.className.indexOf('no-share-element') > -1){
      return true;
    }
    return false;
  },
  copyStyles: true,
  removeContainer: true
}

主要是scale,需要引入devicePixelRatio,即可保证canvas清晰。

  1. 不要使用background-image:url()属性,实验发现用这个属性渲染出来的图片都很糊,用img标签就好了。

其他问题

跨域问题

由于涉及到外源图片,目前是通过后台写了一个接口做图片下载后pipe()来解决的,在开发环境的时候直接打开跨域和允许污染Canvas的属性

useCORS: $fn.isDev(), //允许跨域
allowTaint: $fn.isDev(), //允许污染画布

这样在开发环境只能看到Canvas却无法调用canvas.toDataURL("image/png");函数。

正式环境将所有的图片替换成接口调用,使之同源

if(!isDev()){
    coverUrl = '/api/fetchImage?src='+encodeURIComponent(coverUrl);
}

接口层代码,express侧

//使用http或者https或者request库直接请求,然后直接
response.pipe(res)

注意需要白名单和各种过滤规则,否则就是典型的ssrf了。