HTML2canvas
该脚本通过读取 DOM 以及应用于元素的不同样式,将当前页面呈现为 canvas 图像。
它不需要来自服务器的任何渲染,因为整个图像是在客户端上创建的。但是,由于它太依赖于浏览器,因此该库不适合在 nodejs 中使用。它也不会神奇地规避任何浏览器内容策略限制,因此呈现跨域内容将需要代理来将内容提供给相同的源。
该脚本仍然处理非常实验状态,因此不建议在生产环境中使用它,也不建议使用它来构建应用程序,因为仍然会有重大更改。
该库应该可以在以下浏览器上正常工作
● Firefox 3.5+
● Google Chrome
● Opera 12+
● IE9+
● Edge
● Safari 6+
由于需要手动构建每一个 CSS 属性以支持,因此还有许多尚不支持的属性。
使用方法
// 安装
npm install html2canvas
// 引入
import html2canvas from 'html2canvas'
// 使用
html2canvas(document.body).then(function(canvas) {
document.body.appnedChild(canvas)
})
中文文档
https://allenchinese.github.io/html2canvas-docs-zh-cn/
缺陷
会有dom样式还原和img的同源策略的问题
dom-to-image与dom-to-image-more
dom-to-image-more是dom-to-image的升级版
dom-to-image-more是一个库,它可以将任意 DOM 节点(包括同源和 blob iframe)转换为用 JavaScript 编写的矢量(SVG)或光栅(PNG 或 JPEG)图像。
使用方法
// 安装
npm install dom-to-image-more
// 引入
/* in ES 6 */
import domtoimage from "dom-to-image-more";
/* in ES 5 */
var domtoimage = require("dom-to-image-more");
// 使用
var node = document.getElementById("my-node");
domtoimage
.toPng(node)
.then(function (dataUrl) {
var img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
})
.catch(function (error) {
console.error("oops, something went wrong!", error);
});
文档
https://www.npmjs.com/package/dom-to-image-more
缺陷
也有样式还原不完全或者不正确问题,但是比html2canvas优一些
使用 navigator.mediaDevices.getDisplayMedia() API
-
这个 MediaDevices 接口的 getDisplayMedia()方法提示用户去选择和授权捕获展示的内容或部分内容(如一个 窗口)在一个MediaStream 里。 然后,这个媒体流可以通过使用 MediaStream Recording API 被记录或者作为WebRTC 会话的一部分被传输。
-
这个api返回的屏幕视频流可以被用于video标签来进行播放,然后video又可以通过canvas的context的drawImage方法绘制一帧作为canvas的页面。
-
随后使用canvas.toDataURL绘制成base64的图像数据。 这个数据可以通过种种方式进行使用。
-
下面还提供了将base64转变为File对象的方法,以及保存到浏览器临时url的办法
使用方法
// 容器
let imgFile,imgUrl
// 点击进行截图
function leaderHandler() {
// 创建标签
const video = document.createElement('video')
// 自动播放
video.setAttribute('autoplay', 'autoplay')
// 静音
video.setAttribute('muted', 'muted')
startCapture(function (screen) {
video.srcObject = screen
})
video.addEventListener('loadeddata', function () {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
// 设置一个宽高
canvas.width = 1280
canvas.height = 773
if (!ctx) return
setTimeout(() => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
let base64 = canvas.toDataURL('image/png')
// 转为File对象
imgFile = base64ImgtoFile(base64)
// HACK 创建的地址 可以通过revokeObjectURL()清除以释放内存 是个优化点
imgUrl = window.webkitURL.createObjectURL(img) || window.URL.createObjectURL(img)
// 停止以释放内存和停止分享流
let tracks = video.srcObject.getTracks()
tracks.forEach((track) => track.stop())
video.srcObject = null
}, 250)
})
}
// 开启视频流截屏
async function startCapture(success) {
var constraints = {
audio: false,
video: true,
width: 1280,
height: 773
}
if (navigator.mediaDevices?.getDisplayMedia) {
navigator.mediaDevices.getDisplayMedia(constraints).then(success)
} else {
;navigator.getDisplayMedia(constraints).then(success)
}
}
// base64 转file对象
function base64ImgtoFile(data, filename = 'file') {
const arr = data.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const suffix = mime.split('/')[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], `${filename}.${suffix}`, {
type: mime
})
}
缺陷
需要用户同意权限,部分设备需要做兼容性处理
有模糊的问题,不能做到完全清晰,但是也有对应缓解方案。
缓解不太清晰的方案
canvas标签,将width和height标签属性扩大一倍,然后通过css将样式上的width和height规定成正确的样式。