浏览器截图计划剖析

页面截屏是前端常常遇到的需要,比方页面生成海报,弹窗图片分享等。

以下是我整顿三种截图计划:

  1. html2canvas
  2. dom-to-image
  3. webRTC

html2canvas

html2canvas 用的比拟宽泛的前端截图计划,先将 DOM 一个个 转为 Canvas 而后导出图片(应用 canvas 自带的 toDataUrl、toBobl)即可。应用起来应该是兼容性比拟好的计划了,能解决大部分的需要,然而也有一写小问题,如:

  1. 图片跨域,开启
  2. CSS 属性错乱
  3. 遇到 canvas 元素导出后为通明色。

大部分问题还是能够通过配置和百度解决的

const getDomImg = (eleId) => {    html2canvas(document.getElementById(eleId), {        //superMap整个页面的节点        backgroundColor: null, //画进去的图片有红色的边框,不要可设置背景为通明色(null)        allowTaint: true,        useCORS: true, //反对图片跨域        scale: 1, //设置放大的倍数    })        .then((canvas) => {            //截图用img元素承装,显示在页面的上            let img = new Image();            img.src = canvas.toDataURL("image/jpg"); // toDataURL :图片格式转成 base64            // 间接下载            let a = document.createElement("a");            a.href = canvas.toDataURL("image/jpeg");            a.download = "test";            a.click();        })        .catch((err) => {            console.log("html2canvas err", err);        });};

dom-to-image

应用 svg,通过 createObjectURL 或 encodeURIComponent 解决 svg 失去图像资源,能够把 svg 绘制到 canvas。

dom-to-image-more 是dom-to-image的升级版 将 HTMl 放到 SVG 里,而后创立一个以 SVG 作为源的 Image 元素

然而也有一些问题如: svg 中不容许内部资源(js,css,img 的 url 等),svg 中不反对执行 js,须要通过解决,也不能齐全还原

const getDomImg = (eleId) => {    domtoimage        .toPng(document.getElementById(eleId))        .then(function (dataUrl) {            let a = document.createElement("a");            a.href = dataUrl;            a.download = "test";            a.click();        })        .catch(function (error) {            console.error("生成失败", error);        });};

webRTC

应用浏览器原生 API——webERT中的getDisplayMedia能够将窗口中的资源以录屏形式从其中拿出一帧,然而须要用户受权和做一些窗口抉择,相比于前两种计划做不到默认截图。

然而劣势也很显著,就是不会有什么款式错乱、图片跨域等问题。因为应用的浏览器原生办法,基本上用户看到是什么样子,截图进去就是什么样子,1: 1 还原。

function getDomImg(videoId: string) {    const videoElem: any = document.getElementById(videoId);    const displayMediaOptions = {        audio: false,        video: { width: window.screen.width, height: window.screen.height }, // cursor: "always"    };    navigator.mediaDevices        .getDisplayMedia(displayMediaOptions)        .then((stream) => {            videoElem.srcObject = stream;            setTimeout(() => {                var canvas = document.createElement("canvas");                canvas.width = videoElem.clientWidth;                canvas.height = videoElem.clientHeight;                canvas                    .getContext("2d")                    .drawImage(                        videoElem,                        0,                        0,                        window.screen.width,                        window.screen.height,                        0,                        0,                        canvas.width,                        canvas.height                    );                var dataURL = canvas.toDataURL("image/webp");                let a = document.createElement("a");                a.href = dataURL;                a.download = "test";                a.click();                let tracks = videoElem.srcObject.getTracks();                tracks.forEach((track) => track.stop());                videoElem.srcObject = null;            }, 200);        })        .finally(() => {});}

须要在代码中放入一个 Video 标签

<video id="video"></video>

截图后上传

如果有将截图上传的需要,能够转换一个格局在上传。

canvas 导出的 base64 是不能够间接上传到服务器的,所以须要转一下格局,我这边找了转换 Blob 和 file 两种格局的办法。我用的将图片转为 Blob后上传的。

  1. base64转化为Blob对象
// function convertBase64ToBlob(imageEditorBase64) {    var base64Arr = imageEditorBase64.split(",");    var imgtype = "";    var base64String = "";    if (base64Arr.length > 1) {        //如果是图片base64,去掉头信息        base64String = base64Arr[1];        imgtype = base64Arr[0].substring(            base64Arr[0].indexOf(":") + 1,            base64Arr[0].indexOf(";")        );    }    // 将base64解码    var bytes = atob(base64String);    //var bytes = base64;    var bytesCode = new ArrayBuffer(bytes.length);    // 转换为类型化数组    var byteArray = new Uint8Array(bytesCode);    // 将base64转换为ascii码    for (var i = 0; i < bytes.length; i++) {        byteArray[i] = bytes.charCodeAt(i);    }    // 生成Blob对象(文件对象)    return new Blob([bytesCode], { type: imgtype });}
  1. base64 转 formData
function base64ToFile(data, fileName) {    const dataArr = data.split(",");    const byteString = atob(dataArr[1]);    const options: any = {        type: "image/jpeg",        endings: "native",    };    const u8Arr = new Uint8Array(byteString.length);    for (let i = 0; i < byteString.length; i++) {        u8Arr[i] = byteString.charCodeAt(i);    }    let formData = new FormData();    let fileOfBlob = new File([u8Arr], fileName + ".jpg", options); //返回文件流    formData.append("file", fileOfBlob);    console.log("file", formData);    debugger;    return formData;}

示例

GitHub:https://github.com/AnsonZnl/w...

代码基于 Create React App 演示三种截图办法的根本应用形式。

参考

  • 史上最具体浏览器端网页截图计划解析
  • 一款实用的前端截图工具