翻译小白,哈哈哈哈
当我们使用浏览器(或“客户端”)进行屏幕截图开发时,需要权衡所选方案,没有完美的解决方案,能够解决每种情况。让我们看一下,可以用于屏幕截图的三种不同方式,以及如何通过将它们发送到服务器或让用户下载图像来使用它们。
屏幕截图 是 JavaScript 应用中非常有价值且重要的一部分。像 Google 这样的公司使用它们来从用户那里获得反馈,Bugherd ,类似的产品将屏幕截图用作其产品的核心部分,并且非常适合数据导出(例如图表)。
如果要求用户对他们所看的内容进行屏幕截图,会给用户带来很多麻烦。首先,他们需要知道键盘快捷键( MACOS 和 Windows 是不同的)。
然后他们需要知道接下来该怎么做。例如,他们可以将其上传到诸如 Dropbox 之类的某个地方或将其通过邮件发送给您。大多数用户可能也不知道如何调整或优化屏幕截图的质量。如果您自己存储屏幕截图,则要确保它们占用尽可能少的空间,从而确保您的花费尽可能少。
接下来,介绍三种自动为用户捕获屏幕截图的方法。
1、使用html2canvas进行客户端屏幕截图
2011年 Niklas von Hertzen 在Stackoverflow回答了一个问题,称可以将页面的DOM放入HTML Canvas中,并使用它来生成屏幕截图。随后他公开了代码,并更新了答案,即HTML2Canvas。后来的调查显示,Google使用一种非常相似的技术来自动生成屏幕截图,去提供用户反馈,来作为证据,并且对大型产品也足够健壮。
如何使用html2canvas
这个非常简单,当你要生成屏幕截图时,你只需要获取DOM(页面的HTML),然后将DOM传递到HTML Canvas中。在某些限制下,canvas元素可以生成一个data URI(作为base64字符串)。下面的示例生成屏幕截图,并将其作为图像在窗口中打开。
const screenshotTarget = document.body;
html2canvas(screenshotTarget).then((canvas) => {
const base64image = canvas.toDataURL("image/png");
window.location.href = base64image;
});
使用canvas的优缺点
优点
快
。你不需要等待任何外部服务,这一切都是在客户端上完成的。虽然 html2canvas 并未每天更新,但通常每隔几个月,都会定期看到它的更新和修复。社区很强大且活跃,在那里超过40个 pull request 是开放的,并记录了600多个问题(截至2020年7月)。在 Stack Overflow 也有很多的问题(和答案!)。良好的浏览器兼容性
,html2canvas 已有9年的历史,并且仍然保持出色的浏览器兼容性。
缺点
不支持Shadow DOM(或Web Component)
。这里有一个开放的 pull request 去增加了支持,维护者看起来非常渴望去合并这个分支。
跨域限制
。当你往Canvas中增加包含请求的元素,比如图片或者css样式等,他们会因为跨域策略而被拒绝。
并不是所有的CSS属性都能支持
。文档中明确提到了 “html2canvas 将不会提供完整的CSS能力” 。
示例
2. 使用 getDisplayMedia 生成截图
在 html2canvas 发布的同一时间,关于Web应该支持原生视频通话的想法也获得了众人的追捧。在 2011 年,Google 发布了 Hangouts,一个实时视频和音频平台。为了支持 Hangouts,Google 提出并实现了实时通讯(RTC)的想法,RTC 随后也发展为了 WebRTC。WebRTC 已经变为了所有现代浏览器的标准,它是 Web 实时视频、音频和数据传输的基础设施。
getDisplayMedia 是 WebRTC 中用来做屏幕分享的一个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();
虽然以上的例子没有第一个例子那么简洁,它依然很容易理解。首先,在内存中创建了canvas和video元素,然后 getDisplayMedia
API用来请求访问用户的桌面或选项卡。在用户授权之后,屏幕流被设置到video元素,然后绘制到canvas上。从canvas中导出图片,可以使用和html2canvas示例中相同的方法。
getDisplayMedia API的优缺点
优点
良好的现代浏览器支持 - 是原生API,也就是内建在浏览器中,意味着它不需要依赖任何第三方的脚本和代码。
可扩展性 - 正如你所看到的,使用相同的API,在未来你可以很容易的增加视频录制的功能。
桌面 || 标签页 - getDisplayMedia API 可以录制其他的桌面或浏览器的窗口,这使它变得强大,可以给你的应用之外的东西截图。
缺点
权限 - 你需要获取用户的权限。因为依赖于浏览器,权限对话框可能看起来不一样,有时候让人有点困扰。
慢 - 因为你需要获取权限,这需要花费用户一些时间去点击和理解发生了什么。如果用户需要立刻获取截图,这个小UI交互对于截取时间敏感的内容,会有一些延迟。
示例
3. 截图服务
截图服务正在变得流行,它提供了一个容易的方式将截图功能集成到你的应用中。然而它不在客户端执行,需要使用类似 url2png, Stillio or 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})
});
以上的例子,我们可以使用下面这种形式来请求:
/screenshot?url=http://google.com.au
实际上,我们是使用url2png库来生成一个截图。截图会被保存在本地文件系统,或者你可以通过接口返回,举例。
截图服务的优缺点
优点
后处理 - 可以提供更多后处理的功能,比如灵活的设置图片格式,尺寸,质量,等等;
健壮性 - 可以提供给很多用户使用,容易处理大量的请求。你不需要去维护截图过程相关的基础设施,如果你高兴,像 PhantomJS项目 和 SauceLabs 服务,都是一个好的开始。
缺点
无状态 - 截图可能不是用户看到的那样子,例如,如果用户已经在页面中做过了一些交互,或者页面需要登录,截图服务可能无法截图相同的页面。
成本 - 以上三个选择中,这是唯一一个需要成本的。虽然它相当便宜,如果你要处理大量的截图需求,它就会比较昂贵。
时间 - 截图服务可能会花费几分钟去生成和返回一张图片。
综上所述
如果你正在将截图作为一个重要的功能集成到你的应用中,你需要好好衡量一下每个方案的优缺点。
使用客户端方案,例如html2canvas 或 getDisplayMedia API,意味着你不需要管理任何服务端设施,而且能够快速的生成截图。
如果你需要像素级的还原用户看到的画面,同时对于偶尔出现的授权弹框不介意,那么 getDisplayMedia API 将是好的开始。
如果你希望快速获取一个不太精确的截图,同时没有额外的服务依赖,html2canvas 可能是一个更好的选择。
最终,如果你能接受使用外包的技术实现,也能接受对应的成本,截图服务 也许是最好的选项。