web端

使用 html2canvas

html2canvas 能够实现在用户浏览器端直接对整个或部分页面进行截屏。这个html2canvas脚本将当页面渲染成一个Canvas图片,通过读取DOM并将不同的样式应用到这些元素上实现

基本用法

  1. <div id="capture" style="padding: 10px; background: #f5da55">
  2. <h4 style="color: #000; ">Hello world!</h4>
  3. </div>
  1. html2canvas(document.querySelector("#capture")).then(canvas => {
  2. var url = canvas.toDataURL()
  3. document.body.appendChild(canvas)
  4. });

通过调用canvas.toDataURL()可得到base64编码的图片地址

注意点

  • 生成的图片有空白原因

大多数原因是html的dom元素还没加载完就进行转换图片,最好加上setTimeout延时或者再dom的onload回调函数中处理

  • html与转换后图片不一致

html2canvas没有全部支持css属性,需要取舍

Unsupported CSS properties

These CSS properties are NOT currently supported

  • 生成的图片模糊不清且有锯齿瑕疵

设置scale参数

  • ios9 会有较多bug
  • 图片跨域,生成图片空白

    解决方案

  1. 设置代理Proxy,接口返回图片的base64编码字符串.例子:node.js ```javascript const express = require(‘express’); const url = require(‘url’); const cors = require(‘cors’); const request = require(‘request’);

function validUrl(req, res, next) { if (!req.query.url) { next(new Error(‘No url specified’)); } else if (typeof req.query.url !== ‘string’ || url.parse(req.query.url).host === null) { next(new Error(Invalid url specified: ${req.query.url})); } else { next(); } }

module.exports = () => { const app = express.Router(); app.get(‘/‘, cors(), validUrl, (req, res, next) => { switch (req.query.responseType) { case ‘blob’: req.pipe(request(req.query.url).on(‘error’, next)).pipe(res); break; case ‘text’: default: request({url: req.query.url, encoding: ‘binary’}, (error, response, body) => { if (error) { return next(error); } res.send( data:${response.headers['content-type']};base64,${Buffer.from( body, 'binary' ).toString('base64')} ); }); } });

return app;

};


2. 配置项中配置 `allowTaint:true`, 但不能调用`toDataURL`方法<br />
3. 配置项中配置 `useCORS:true`(与`allowTaint:true`互斥),直接跟文档只添加这个属性是不行的

1、添加useCORS:true属性; 2、给要生成canvas的DOM中包含的每一个web端 小程序生成海报图片 - 图1标签添加crossorigin=”anonymous”属性;给要生成canvas的dom中的所有web端 小程序生成海报图片 - 图2标签的src添加一个任意的字符串,只要能起到重新发起图片读取请求,从而避免读取到浏览器缓存数据即可,如:’http://h0.hucdn.com/open/201819/9404b56f97e7df8a_750x1334.png?any_string_is_ok‘ 3、确保你的图片CDN服务器支持CORS访问,也就是会返回Access-Control-Allow-Origin等响应头;需再阿里云CDN后台设置

解释:<br />`useCORS:true`的作用`img.crossOrigin = 'anonymous'` [源码地址](https://github.com/niklasvh/html2canvas/blob/cae44a6f0a6649bd8a7c4250a20792bb5c2e5b42/src/core/cache-storage.ts)
```javascript
            const img = new Image();
            img.onload = () => resolve(img);
            img.onerror = reject;
            //ios safari 10.3 taints canvas with data urls unless crossOrigin is set to anonymous
            if (isInlineBase64Image(src) || useCORS) {
                img.crossOrigin = 'anonymous';
            }
            img.src = src;
            if (img.complete === true) {
                // Inline XML images may fail to parse, throwing an Error later on
                setTimeout(() => resolve(img), 500);
            }
            if (this._options.imageTimeout > 0) {
                setTimeout(
                    () => reject(`Timed out (${this._options.imageTimeout}ms) loading image`),
                    this._options.imageTimeout
                );
            }

crossorigin=’anonymous’就可以触发带跨域请求头Origin的HTTP请求了,除了请求头要添加Origin之外,服务器的响应头中也必须要包含正确的Access-Control-Allow-Origin才行,否则就说明服务器并不接受客户端的跨域请求
html2canvas库需要我们先提供一段DOM节点,然后它再读取并解析这一段DOM节点生成canvas对象。如果DOM节点中已经使用了web端 小程序生成海报图片 - 图3标签的话,它也会解析这个web端 小程序生成海报图片 - 图4标签的src属性,然后重新创建一个Image对象,给它添加crossOrigin=”anonymous”属性后尝试以跨域的方式重新读取图片数据。需要注意的是,一般CDN上的图片都是带有缓存响应头并且会在浏览器端缓存的,而且缓存的不仅仅是图片数据,还有HTTP响应头。所以问题的根本原因我们就找到了,当html2canvas尝试以跨域的方式去读取图片数据时,它读取到的是浏览器的缓存数据,而且因为我们没有给DOM节点中的web端 小程序生成海报图片 - 图5标签添加crossorigin=”anonymous”属性,所以缓存数据是不带Access-Control-Allow-Origin响应头的,进而导致html2canvas库读取到的图片数据污染了生成的canvas对象,最终致使canvas导出数据报错

安全性和“被污染”的 canvas

由于在 [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 位图中的像素可能来自多种来源,包括从其他主机检索的图像或视频,因此不可避免的会出现安全问题。 尽管不通过 CORS 就可以在 [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 中使用其他来源的图片,但是这会污染画布,并且不再认为是安全的画布,这将可能在 [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 检索数据过程中引发异常。 如果从外部引入的 HTML [web端 小程序生成海报图片 - 图6](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img)或 SVG [](https://developer.mozilla.org/zh-CN/docs/Web/SVG/Element/svg) ,并且图像源不符合规则,将会被阻止从 [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 中读取数据。 在”被污染”的画布中调用以下方法将会抛出安全错误:

  • [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 的上下文上调用[getImageData()](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/getImageData)
  • [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 上调用 [toBlob()](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toBlob)
  • [](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas) 上调用 [toDataURL()](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL)

这种机制可以避免未经许可拉取远程网站信息而导致的用户隐私泄露。

资料

  1. Cross-Origin Resource Sharing (CORS)
  2. html2canvas: Screenshots with JavaScript
  3. HTMLCanvasElement.toDataURL()

小程序

由于小程序没有DOM,故不能使用html2canvas库, 我们采用封装Canvas API来作图,因为使用小程序的downloadFileapi,故没有跨域问题,但需要配置download域名白名单

基本用法

小程序端中采用了自行封装了一套方法用于绘制文本、图像、矩形、线段等,通过对象配置形式实现画图

资料

  1. CanvasRenderingContext2D