如何使用JavaScript在浏览器中截取屏幕截图
[删除(380066935@qq.com或微信通知)]
更好的阅读体验请查看原文:https://hackernoon.com/how-to-take-screenshots-in-the-browser-using-javascript-l92k3xq7
在浏览器(或“客户端”)中截取屏幕截图就是权衡 - 没有针对每种情况的完美解决方案。让我们看一下拍摄屏幕截图的三种不同方法,然后如何通过将它们发送到服务器或让用户下载图像来使用它们。
屏幕截图可能是 JavaScript 应用程序中非常有价值和重要的部分。像谷歌这样的公司使用它们来获取用户的反馈,像BugHerd这样的产品使用屏幕截图作为其产品的核心部分,它们非常适合生成数据导出(如图表)。
要求用户截取他们正在查看的内容的屏幕截图会引入很多摩擦。首先,他们需要知道键盘快捷键(这与macOS到Windows不同)。
然后他们需要知道如何处理它。例如,他们可以将其上传到Dropbox等地方或通过电子邮件发送给您。大多数用户可能也不知道如何调整大小或优化屏幕截图的质量。如果您自己托管屏幕截图,则需要确保它们占用尽可能少的空间,从而确保您花费尽可能少的时间。
您可以通过以下三种方式为用户自动捕获屏幕截图:
1. 使用 html2canvas 进行客户端屏幕截图
Niklas von Hertzen在2011年回答了StackOverflow的问题,称可以将页面的DOM放入HTML画布中,并使用它来生成屏幕截图。在他将代码公开后,他用html2canvas的原始想法更新了他的答案。后来的调查显示,谷歌使用一种非常类似的技术来自动生成用户提供反馈的屏幕截图,证明实施规模,并且对于大型产品来说足够强大。
如何使用 html2canvas
这个想法很简单 - 当你想要生成屏幕截图时,你捕获DOM(页面的HTML),并将该DOM传递到HTML画布中。在某些限制下,canvas 元素可以生成内部内容的数据 URI(作为 base64 字符串)。下面的示例生成一个屏幕截图,并将其作为图像在窗口中打开。
const screenshotTarget = document.body;
html2canvas(screenshotTarget).then((canvas) => {
const base64image = canvas.toDataURL("image/png");
window.location.href = base64image;
});
画布方法的优缺点
优点
快速 - 您无需等待任何外部服务,这一切都是在客户端上完成的定期更新 - 虽然html2cavnas不是每天更新,但它每隔几个月就会定期看到更新和修复非常流行 - 社区强大而活跃,有超过40个拉取请求打开,记录了600个问题(截至2020年7月)。Stack Overflow上也有定期的问题(和答案!)。良好的浏览器支持 - html2canvas已有9年的历史,并且仍然保持着出色的浏览器支持。
缺点
不支持Shadow DOM或Web Components - 有一个拉取请求打开以添加支持,看起来维护者热衷于将其合并。跨源限制 - 当您向画布添加包含请求的元素(如图像、样式表等)时,它们受普通请求相同的 COR 策略的约束。
不支持每个 CSS 属性 - 属性是手动添加和配置的,因此很难实现 100% 的覆盖率。文档指出“html2canvas永远不会有完整的CSS支持”。易更新 - html2canvas对浏览器更新来说可能很脆弱,偶尔会破坏现有功能。
2. 使用 getDisplayMedia 生成屏幕截图
大约在html2canvas发布的同时,网络可以支持原生视频通话的想法得到了很大的牵引力。2011年,谷歌发布了Hangouts,一个实时视频和音频平台。为了支持Hangouts,Google提出了实时通信(RTC)的想法(和一些实现),后来被开发成WebRTC。WebRTC已成为所有现代浏览器的标准,它是为Web提供实时视频,音频和数据通信的基础设施。
WebRTC的一部分是getDisplayMedia-它被用作屏幕共享API。您可以从视频中捕获静止图像,例如屏幕共享,这实质上就是屏幕截图。让我们看一个基本示例:
const capture = async () => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const video = document.createElement("video");
try {
const captureStream = await navigator.mediaDevices.getDisplayMedia();
video.srcObject = captureStream;
context.drawImage(video, 0, 0, window.width, window.height);
const frame = canvas.toDataURL("image/png");
captureStream.getTracks().forEach(track => track.stop());
window.location.href = frame;
} catch (err) {
console.error("Error: " + err);
}
};
capture();
getDisplayMedia API 的优缺点
优点
良好的现代浏览器支持 - 它是一个本机API,这意味着它内置于现代浏览器,不需要任何第三方脚本或代码。
可扩展 - 您可以使用相同的APIPixel完美地使用相同的APIPixel轻松添加对视频录制的支持 - 这正是用户所看到的
桌面或选项卡 - getDisplayMedia API可以记录桌面或浏览器窗口 - 非常适合拍摄应用程序以外的其他内容的屏幕截图。
缺点
权限 - 您需要从用户处获取要记录的权限。根据浏览器的不同,权限对话框可能看起来不同,有时可能会令人困惑。
慢 - 因为您需要获得权限,所以用户可能需要一段时间才能单击“接受”并了解正在发生的事情。如果用户需要即时截图,这个小小的UI交互冷延迟捕获一些时间敏感的内容。
3. 屏幕截图即服务
屏幕截图服务越来越受欢迎,因为它们提供了一种将屏幕截图集成到现有应用程序中的简单方法。虽然它不是客户端,但使用像url2png,Stillio或Urlbox这样的屏幕截图服务意味着你不需要管理任何截取屏幕截图的基础设施。
虽然每个服务的实现可能不同,但总体思路是相同的。将 URL(以及维度、格式和质量等可自定义参数)发送到外部服务,然后等待响应,或侦听其他位置的响应。这通常是用后端服务来处理的,所以让我们看看使用url2png和NodeJS和express:
const url2png = require('url2png')('API_KEY', 'PRIVATE_KEY');
const fs = require('fs');
app.get('/screenshot', (req, res) => {
url2png.readURL(req.query.url, {}).pipe(fs.createWriteStream('screenshot.png'));
res.json({success: true})
});
使用屏幕截图服务的利弊
优点
后处理 - 服务也可以处理后处理,从而可以灵活地生成不同文件类型,大小,质量等的图像。
健壮的API - 这些服务被许多人使用,并促进了大量的请求。基础结构 - 您无需维护基础结构即可管理截取屏幕截图的过程。如果您愿意,像PhantomJS这样的项目和像SauceLabs这样的服务是一个很好的起点。
缺点
非有状态 - 屏幕截图可能不是用户看到的内容。例如,如果用户已与页面交互,或者他们已通过身份验证,则屏幕截图服务将无法为屏幕截图呈现同一页面。
成本 - 在三个选项中,这是唯一一个带有成本的选项。尽管它非常便宜,但如果您正在处理大量屏幕截图,则可能会很昂贵。
时间 - 屏幕截图服务可能需要几分钟才能生成和返回图像。
综述
无论您是要集成屏幕截图以获取反馈,还是要针对应用程序中的关键功能,都需要权衡每种解决方案的优缺点。
使用客户端解决方案,如html2canvas或getDisplayMedia API,意味着您不必管理任何服务器基础架构,并且通常图像的生成速度非常快。
如果您需要用户正在查看的内容的像素完美表示,并且不介意有时过时的权限弹出窗口,那么getDisplayMedia API是一个很好的起点。
如果您想在没有外部服务依赖的情况下快速拍摄半准确的屏幕截图,html2canvas可能是您的正确选择。
最后,如果您同意外包技术实施以及与之相关的成本,那么屏幕截图服务可能是最佳选择。