-
4 埃利奥特·斯普伦 在推文中写道 几天前:>@CatChen那篇stackoverflow帖子不准确。 谷歌反馈的屏幕截图完全由客户端完成。:) – 戈兰·拉基奇 评论 2011年7月11日17:53 -
1 这很符合逻辑,因为他们希望准确捕捉用户浏览器如何呈现页面,而不是如何使用引擎在服务器端呈现页面。 如果只将当前页面DOM发送到服务器,它将忽略浏览器呈现HTML的方式中的任何不一致。 这并不意味着陈的答案是错误的截图,只是看起来谷歌在用不同的方式。 – 戈兰·拉基奇 评论 2011年7月11日18:21 -
Elliott今天提到了Jan Kuča,我在Jan的推文中找到了这个链接: jankuca.tumblr.com/post/7391640769/… – 陈猫 评论 2011年7月12日11:28 -
稍后我将深入研究这一点,看看如何使用客户端渲染引擎实现它,并检查谷歌是否真的这样做。 – 陈猫 评论 2011年7月12日11:30 -
我看到了compareDocumentPosition、getBoxObjectFor、toDataURL、drawImage、跟踪填充等的使用。 尽管如此,仍有数千行模糊代码需要去模糊化和浏览。 我很想看到它的开源授权版本,我已经联系了Elliott Sprehn! – 卢克·斯坦利 评论 2011年7月12日18:18
8个答案
-
1 很酷,Sikuli或Selenium可能适合访问不同的站点,将测试工具中的站点快照与html2canvas.js渲染的图像进行像素相似性比较! 想知道您是否可以使用一个非常简单的公式解算器自动遍历DOM的各个部分,以了解如何解析getBoundingClientRect不可用的浏览器的备用数据源。 如果它是开源的,我可能会使用它,我正在考虑自己玩弄它。 干得好Niklas! – 卢克·斯坦利 评论 2011年7月15日19:25 -
1 @Luke Stanley我很可能会在这个周末在github上发布源代码,在那之前我想做一些小的清理和更改,并消除它目前不必要的jQuery依赖性。 – 尼克拉斯 评论 2011年7月15日19:43 -
54 源代码现在位于 github.com/niklasvh/html2canvas ,正在使用的脚本的一些示例 html2canvas.hertzen.com 那里。 仍然有很多bug需要修复,所以我不建议在实时环境中使用该脚本。 – 尼克拉斯 评论 2011年7月16日1:42 -
2 -
5
-
三 -
8 -
22 @X好吧,请不要这样想。 Web浏览器应该能够做很多事情,但不幸的是,它们与实现不一致。 如果浏览器有这样的功能,只要用户被要求,这是完全可以的。 如果没有你的注意,没有人能拍出截图。 但是太多的恐惧会导致糟糕的实现,比如剪贴板API,它已经被完全禁用,而不是创建确认对话框,比如网络摄像头、麦克风、屏幕截图功能等。 – StanE公司 评论 2017年5月24日17:50 -
4 这已被弃用,将根据 developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia – 阿古斯汀·考廷 评论 2018年2月16日8:10 -
12 @阿古斯汀·考廷 导航器.getUserMedia() 已弃用,但下面写着“……请使用较新的 navigator.mediaDevices.getUserMedia() ”,即它刚刚被更新的API所取代。 – 左旋派 评论 2019年5月3日18:17
//文档: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia //请参见: https://www.webrtc-experiat.com/Pluginfree-Screen-Sharing/#20893521368186473 //请参见: https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Pluginfree-Screen-Sharing/conference.js 函数getDisplayMedia(选项){ if(navigator.mediaDevices&&navigator.mediaDevices.getDisplayMedia){ return navigator.mediaDevices.getDisplayMedia(选项) } if(navigator.getDisplayMedia){ return navigator.getDisplayMedia(选项) } if(导航器.webkitGetDisplayMedia){ return navigator.webkitGetDisplayMedia(选项) } if(navigator.mozGetDisplayMedia){ return navigator.mozGetDisplayMedia(选项) } throw new Error(“getDisplayMedia未定义”) } 函数getUserMedia(选项){ if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){ return navigator.mediaDevices.getUserMedia(选项) } if(导航器.getUserMedia){ return navigator.getUserMedia(选项) } if(导航器.webkitGetUserMedia){ return navigator.webkitGetUserMedia(选项) } if(navigator.mozGetUserMedia){ return navigator.mozGetUserMedia(选项) } 抛出新错误(“未定义getUserMedia”) } 异步函数takeScreenshotStream(){ //请参阅: https://developer.mozilla.org/en-US/docs/Web/API/Window/screen(https://developer.mozilla.org/en-US/docs/Web/API/Window/screen) 常量宽度=屏幕宽度*(window.devicePixelRatio||1) 常量高度=屏幕高度*(window.devicePixelRatio||1) 常量错误=[] 让溪流 尝试{ 流=等待getDisplayMedia({ 音频:假, //请参见: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints/video 视频:{ 宽度, 高度, 帧速率:1, }, }) }捕获(ex){ errors.push(ex) } //对于电子js if(navigator.userAgent.indexOf('Electron')>=0){ 尝试{ 流=等待getUserMedia({ 音频:假, 视频:{ 强制性:{ chromeMediaSource:'桌面', //chromeMediaSourceId:源id, minWidth:宽度, maxWidth:宽度, minHeight:高度, maxHeight:高度, }, }, }) }捕获(ex){ errors.push(ex) } } if(errors.length){ console.debug(…错误) if(!流){ 抛出错误[errors.length-1] } } 回流 } 异步函数takeScreenshotCanvas(){ const stream=等待截图流() //发件人: https://stackoverflow.com/a/57665309/5221762 const-video=document.createElement('video') const result=等待新承诺((resolve,reject)=>{ video.onloadedmetadata=()=>{ video.play() video.pause() //发件人: https://github.com/kasprownik/elecron-screencapture/blob/master/index.js const canvas=document.createElement('canvas') canvas.width=video.videoWidth canvas.height=video.videoHeight const上下文=canvas.getContext('2d') //请参见: https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement网站 context.drawImage(视频,0,0,video.videoWidth,video.jevoHeight) 解析(画布) } video.srcObject=流 }) stream.getTracks().forEach(函数(track)){ track.stop() }) if(结果==空){ throw new Error(“无法拍摄画布屏幕截图”) } 返回结果 } //发件人: https://stackoverflow.com/a/46182044/5221762 函数getJpegBlob(画布){ return new Promise((resolve,reject)=>{ //文档: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob canvas.toBlob(blob=>解析(blob),'image/jpeg',0.95) }) } 异步函数getJpegBytes(画布){ const-blob=等待getJpegBlob(画布) return new Promise((resolve,reject)=>{ const fileReader=新fileReader() fileReader.addEventListener('loadend',函数(){ if(此错误){ 拒绝(this.error) 返回 } 解析(this.result) }) fileReader.readAsArrayBuffer(blob) }) } 异步函数takeScreenshotJpegBlob(){ const canvas=等待截图canvas() return getJpegBlob(画布) } 异步函数takeScreenshotJpegBytes(){ const canvas=等待takeScreenshotCanvas() return getJpegBytes(画布) } 函数blobToCanvas(blob、maxWidth、maxHeight){ return new Promise((resolve,reject)=>{ const img=新图像() img.onload=函数(){ const canvas=document.createElement('canvas') 常数刻度=数学.min( 1, 最大宽度? maxWidth/img.width:1, 最大高度? maxHeight/img.height:1, ) canvas.width=img.width*比例 canvas.height=img.height*比例 const-ctx=canvas.getContext('2d') ctx.drawImage(img,0,0,img.width,img.height,0,O,canvas.width和canvas.height) 解析(画布) } img.onerror=()=>{ 拒绝(新错误(“错误将blob加载到图像”) } img.src=URL.createObjectURL(blob) }) }
document.body.onclick=异步()=>{ //截图 var screenshotJpegBlob=等待take截图Jpegblob() //显示最大尺寸为300 x 300像素的预览 var previewCanvas=等待blobToCanvas(屏幕截图JpegBlob,300,300) previewCanvas.style.position=“已修复” document.body.appendChild(预览画布) //将其发送到服务器 var formdata=新formdata() formdata.append(“屏幕截图”,屏幕截图JpegBlob) 等待获取(' https://your-web-site.com网站/ ', { 方法:“POST”, 正文:表单数据, '内容类型':“multipart/form-data”, }) } //然后单击页面
-
1 -
-
-
1 -
4 我喜欢这个答案,但不幸的是,它在屏幕截图中包含了“选择要共享的屏幕”对话框,并且覆盖了屏幕的很大一部分。 至少对我使用Chrome来说是这样。 评论 2020年11月5日19:51
PoC公司
函数报告(){ let region=document.querySelector(“body”);// 全屏幕 html2画布(地区{ onrendered:函数(画布){ let pngUrl=画布.toDataURL();// dataURL格式的png 让img=document.querySelector(“.screen”); img.src=pngUrl; //在这里,您可以允许用户设置错误区域 //并用“pngUrl”将其发送到服务器 }, }); }
.容器{ 边距:10px; 边框:实心1px黑色; }
<script src=“ https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js “></script> 屏幕截图测试仪 <button onclick=“report()”>截屏 <div class=“container”> <img width=“75%”class=“screen”> </div>
更新
异步函数报告(){ let screenshot=等待makeScreenshot();// png数据URL 设img=q(“.screen”); img.src=屏幕截图; 设c=q(“.bug-container”); c.classList.remove(“隐藏”) let box=等待getBox(); c.classList.add('hide'); 发送(屏幕截图,方框);// 带有错误图像、区域和描述的sed发布请求 alert(“要查看带有图像的POST请求,请转到:chrome控制台>网络选项卡”); } //-----助手功能 让q=s=>document.querySelector;// 查询选择器助手 window.report=报告;// 绑定报表在fiddle html中可见 异步函数makeScreenshot(选择器=“body”) { return new Promise((resolve,reject)=>{ let节点=document.querySelector(选择器); html2canvas(节点,{onrendered:(画布)=>{ 让pngUrl=canvas.toDataURL(); 解析(pngUrl); }}); }); } 异步函数getBox(box){ return new Promise((resolve,reject)=>{ 设b=q(“.bug”); 设r=q(“.region”); 设scr=q(“.screen”); 让send=q(“.send”); 设start=0; 设sx,sy,ex,ey=-1; r.style.width=0; r.style.height=0; 让drawBox=()=>{ r.style.left=(ex>0?sx:sx+ex)+'px'; r.style.top=(ey>0?sy:sy+ey)+'px'; r.style.width=数学.abs(ex)+'px'; r.style.height=数学.abs(ey)+'px'; } //控制台.log({b,r,scr}); b.addEventListener(“点击”,e=>{ if(开始==0){ sx=e.pageX; sy=e.pageY; ex=0; ey=0; drawBox(); } 开始=(开始+1)%3; }); b.addEventListener(“mousemove”,e=>{ //控制台.log(e) if(开始==1){ ex=e.pageX-sx; ey=e.pageY-sy drawBox(); } }); send.addEventListener(“点击”,e=>{ 开始=0; 设a=100/75//缩小img 75% 解决({ x: 数学地板(((ex>0?sx:sx+ex)-scr.offsetLeft)*a), y: 数学地板(((ey>0?sy:sy+ey)-b.offsetTop)*a), 宽度:数学地板(数学abs(ex)*a), 高度:数学地板(数学abs(ex)*a), desc:q('.bug-desc').value }); }); }); } 函数发送(图像、方框){ 让formData=新formData(); 让req=新的XMLHttpRequest(); formData.append(“框”,JSON.stringify(框)); formData.append(“屏幕截图”,图片); req.open(“POST”,“/上传/屏幕截图”); 请求发送(formData); }
.bug容器{background:rgb(255,0,0.1);页边空白顶部:20px;文本对齐:居中;} .send{边框半径:5px;填充:10px;背景:绿色;光标:指针;} .region{位置:绝对;背景:rgba(255,0,0,0.4);} .example{高度:100px;背景:黄色;} .bug{margin-top:10px;光标:十字线;} .hide{显示:无;} .screen{指针事件:无}
<script src=“ https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js “></script> <body> 屏幕截图测试仪 <button onclick=“report()”>报告错误 Lorem ipsum <div class=“bug-container hide”> <div>选择错误区域:单击一次-移动鼠标-再次单击 <div class=“bug”> <img width=“75%”class=“screen”> <div class=“region”> </div> <div> <textarea class=“bug-desc”>在此处描述错误</ 文本区域> </div> 发送BUG </div> </body>
-
2 -
-
1 限制脚本使用的所有图像都需要驻留在同一来源下,以便它能够在没有代理的帮助下读取它们。 类似地,如果页面上有其他画布元素被跨源内容污染,它们将变脏,html2canvas无法再读取。 – 阿拉文3 评论 2019年8月5日8:59 -
在我的网站上使用你的代码,我收到了错误 未捕获(承诺中)错误:元素未附加到文档 →啊,找到了解决方案: stackoverflow.com/q/64716679/1066234 – 阿凡达 评论 2022年11月27日15:17 -
1
//请求媒体 navigator.mediaDevices.getDisplayMedia().then(stream=> { //从流中抓取框架 let track=流.getVideoTracks()[0]; let capture=新图像捕获(曲目); capture.grabFrame().then(位图=> { //停止共享 track.stop(); //将位图绘制到画布 canvas.width=位图宽度; canvas.height=位图高度; canvas.getContext('2d').drawImage(位图,0,0); //从画布抓取水滴 canvas.toBlob(blob=>{ //在这里处理blob console.log('输出blob:',blob); }); }); }) .catch(e=>控制台.log(e));
document.body.innerHTML='<video style=“宽度:100%;高度:100%;边框:1px黑色实心;”/>'; navigator.mediaDevices.getDisplayMedia() .then(媒体流=>{ const-video=document.querySelector('video'); video.srcObject=媒体流; video.onloadedmetadata=e=>{ video.play(); video.pause(); }; }) .catch(err=>console.log(`${err.name}:${err.message}`));
<script src=“ https://raw.githubusercontent.com/amiad/screenshot.js/master/screenshost.js “></script>
新屏幕截图({success:img=>{ //回调函数 myimage=图像; }});
它初始化html2canvas库类并向其提供主体HTML。 生成画布元素并附加到HTML。 它从画布对象获取图像源数据URL。 使用Ajax将图像推送到服务器。
<脚本 src=“ https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js “></script> <script type=“text/javascript” src=“ https://html2canvas.hertzen.com/dist/html2chanvas.min.js “></script> <script type=“text/javascript”> $(“#capture-screenshot”).单击(function(){ const screenshotTarget=文档.body; html2canvas(屏幕截图目标)。然后(画布=>{ //将图像作为png在行下使用 //const base64image=canvas.toDataURL(“image/png”); //在窗口中使用下面的行显示图像 //window.location.href=base64图像; //屏幕截图作为画布附加到正文 document.body.appendChild(画布); dataURL=画布.toDataURL(); //要在控制台中打印屏幕截图,请使用下面的行 //console.log(dataURL); //以下行是可选的,用于保存屏幕截图 //在服务器端。 它启动一个ajax调用 将屏幕截图推送到服务器(dataURL); }); }); 函数pushScreenshotToServer(数据URL){ $.ajax({ url:“push-screenshot.php”, 类型:“POST”, 数据:{ image:dataURL }, dataType:“html”, 成功:function(){ console.log('推送到服务器的屏幕截图'); } }); } </script>