如何使用JavaScript拍摄div的屏幕截图?


175

我正在构建一个称为“ HTML测验”的东西。它完全在JavaScript上运行,非常酷。

最后,弹出一个结果框,显示“您的结果:”,它显示了他们花费了多少时间,他们得到了多少百分比以及他们从10个问题中得出了多少个问题。我想有一个按钮,上面写着“捕获结果”,并使其以某种方式截取屏幕截图或div,然后仅在页面上显示捕获的图像即可在其中单击鼠标右键并“将图像另存为”。

我真的很想这样做,以便他们可以与他人分享他们的结果。我不希望他们“复制”结果,因为他们可以轻松更改它。如果他们更改图片中的内容,那就好。

有谁知道做到这一点的方法或类似的方法?


2
看看phantomjs.org。使用它,您可以在服务器端生成HTML页面的完整图像,并为用户提供下载链接。
约书亚

好的文章HTML内容,图像转换和下载codepedia.info/...
Satinder辛格

Answers:


98

不,我不知道“截屏”元素的方法,但是您可以做的是将测验结果绘制到canvas元素中,然后使用HTMLCanvasElement对象的toDataURL函数获取data:包含图像内容的URI。

测验完成后,请执行以下操作:

var c = document.getElementById('the_canvas_element_id');
var t = c.getContext('2d');
/* then use the canvas 2D drawing functions to add text, etc. for the result */

当用户单击“捕获”时,请执行以下操作:

window.open('', document.getElementById('the_canvas_element_id').toDataURL());

这将打开带有“屏幕截图”的新标签或窗口,允许用户保存它。无法调用各种“另存为”对话框,所以我认为这是您可以做的最好的事情。


谢谢!!我对画布一无所知,但我会学习的。我将如何使用Canvas 2D绘图效果?你能帮我吗?非常感谢!:)
内森

5
尝试Mozilla的文档,确实非常容易遵循:developer.mozilla.org/en/canvas_tutorial
Delan Azabani 2011年

可以在嵌入式对话框中打开它,而不是在新窗口/选项卡中打开它?(像Fancybox灯箱插件一样?)
内森

是的,你可以有一个内嵌对话框img,有它src集到data:URI。但是,这并不是真正必要的-您可以将其canvas自身放入内联对话框;用户可以右键单击它并将当前状态另存为图像。
Delan Azabani 2011年

谢谢:)我可能会使用图像版本,因此他们将能够右键单击并单击“将图像另存为”
内森(Nathan)

89

这是@Dathan 答案的扩展,使用了html2canvasFileSaver.js

$(function() { 
    $("#btnSave").click(function() { 
        html2canvas($("#widget"), {
            onrendered: function(canvas) {
                theCanvas = canvas;


                canvas.toBlob(function(blob) {
                    saveAs(blob, "Dashboard.png"); 
                });
            }
        });
    });
});

该代码块等待具有ID的按钮btnSave被单击。widget启用后,它将div转换为canvas元素,然后使用saveAs()FileSaver接口(通过本机不支持它的浏览器中的FileSaver.js)将div保存为名为“ Dashboard.png”的图像。

提琴手提供了此工作的示例。


7
我需要添加对以下内容的引用:html2canvas,filesaver,blob,canvas-toBlob。之后,它起作用了。谢谢!
sirthomas

1
太好了,这应该是公认的答案。直插即用。
rgshenoy

您知道在Three.js中如何使用吗?我有一个div,Three.js渲染器/画布位于(renderer.domElement)中,然后在此之上是div。我想拍摄父级DIV的快照并捕获所有内容吗?这可能吗?谢谢!
Rankinstudio '17

1
您可以避免图片出现在DOM中吗?不能直接下载吗?
kulan

1
第一次尝试对我来说效果很好,甚至看起来像原始的CSS样式等。非常准确。如此精确的程度几乎是虚拟屏幕截图。我将CDN用于必须添加的2个库:<!-html2canvas-> <script src =“ cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/… > <!-filesaver- > <script src =“ cdn.jsdelivr.net/npm/file-saver@2.0.2/dist/… >
OG肖恩

13

经过数小时的研究,我终于找到了一种解决方案,可以对元素进行屏幕截图,即使origin-clean设置了FLAG(以防止XSS),这也是为什么您甚至可以捕获Google Maps(以我为例)的原因。我写了一个通用函数来获取屏幕截图。此外,您唯一需要的就是html2canvas库(https://html2canvas.hertzen.com/)。

例:

getScreenshotOfElement($("div#toBeCaptured").get(0), 0, 0, 100, 100, function(data) {
    // in the data variable there is the base64 image
    // exmaple for displaying the image in an <img>
    $("img#captured").attr("src", "data:image/png;base64,"+data);
});

请记住console.log()alert()如果图像尺寸很大,则不会生成输出。

功能:

function getScreenshotOfElement(element, posX, posY, width, height, callback) {
    html2canvas(element, {
        onrendered: function (canvas) {
            var context = canvas.getContext('2d');
            var imageData = context.getImageData(posX, posY, width, height).data;
            var outputCanvas = document.createElement('canvas');
            var outputContext = outputCanvas.getContext('2d');
            outputCanvas.width = width;
            outputCanvas.height = height;

            var idata = outputContext.createImageData(width, height);
            idata.data.set(imageData);
            outputContext.putImageData(idata, 0, 0);
            callback(outputCanvas.toDataURL().replace("data:image/png;base64,", ""));
        },
        width: width,
        height: height,
        useCORS: true,
        taintTest: false,
        allowTaint: false
    });
}

您在其中定义了html2canvas函数的地方
Bharathi

在到达功能getScreenshotOfElement()之前,我集成了html2canvas库(请参阅我的文章中的链接)。例如,带有<script>标签。只需下载html2canvas并将其复制到您的项目中即可。
orange01年1

@ orange01-我仍然无法捕获Google地图的街道车道。这仅是放大和缩小按钮,地图和卫星文本的屏幕截图。您能帮忙获取完整的地图吗?谢谢
Farhan Sahibole '18 -10-8

7

如果您希望有“另存为”对话框,只需将图像传递到php脚本中,即可添加适当的标题

示例“多合一”脚本 script.php

<?php if(isset($_GET['image'])):
    $image = $_GET['image'];

    if(preg_match('#^data:image/(.*);base64,(.*)$#s', $image, $match)){
        $base64 = $match[2];
        $imageBody = base64_decode($base64);
        $imageFormat = $match[1];

        header('Content-type: application/octet-stream');
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: private", false); // required for certain browsers
        header("Content-Disposition: attachment; filename=\"file.".$imageFormat."\";" ); //png is default for toDataURL
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: ".strlen($imageBody));
        echo $imageBody;
    }
    exit();
endif;?>

<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js?ver=1.7.2'></script>
<canvas id="canvas" width="300" height="150"></canvas>
<button id="btn">Save</button>
<script>
    $(document).ready(function(){
        var canvas = document.getElementById('canvas');
        var oCtx = canvas.getContext("2d");
        oCtx.beginPath();
        oCtx.moveTo(0,0);
        oCtx.lineTo(300,150);
        oCtx.stroke();

        $('#btn').on('click', function(){
            // opens dialog but location doesnt change due to SaveAs Dialog
            document.location.href = '/script.php?image=' + canvas.toDataURL();
        });
    });
</script>

3

您无法进行截屏:让您这样做是不负责任的安全风险。但是,您可以:

  • 在服务器端做事并生成图像
  • 绘制类似于画布的内容并将其渲染到图像(在支持该图像的浏览器中)
  • 使用其他一些图形库直接绘制图像(速度很慢,但是可以在任何浏览器上使用)

谢谢!我将使用画布,因为我不知道任何“绘图库”,也不知道该怎么做。我也不擅长帆布,但我会尽力的。
弥敦道

2
抱歉,我必须对此进行评论,因为它来自Google,但是WTF“不负责任的安全风险”可能会问为什么,如果您让javascript在给定的电源线内进行屏幕截图或快照并将其作为字符串返回BASE64编码的数据,则无安全问题。
Barkermn01,2012年

@MartinBarker我可以(例如)在iframe中拉出某人的Facebook页面,然后对其进行截图。通常,跨站点iframe并不是阻止XSS的可访问DOM的一部分,但在这种情况下,浏览器供应商很难阻止它。
bgw

2
@MartinBarker Javascript可能会在没有用户注意的情况下将数据提供给恶意源,而“打印屏幕”是由用户控制的,而不是某些任意不受信任的网站。
bgw 2012年

2
太棒了 @PiPeep,如果网页可以加载Facebook的iFrame,则已经存在隔离,为什么不使用屏幕截图API扩展这种隔离呢?例如。Div.ToPNG(),前面提到的iFrame在哪里变白了?这不是不负责任的安全风险,它不是内置的,并且没有人在开发这样的内置屏幕快照API时解决“潜在”的隐私/安全问题。对于无数用例(例如对Intranet Web应用程序的支持),它将非常有用。
托德

3
var shot1=imagify($('#widget')[0], (base64) => {
  $('img.screenshot').attr('src', base64);
});

看一下htmlshot包,然后深入检查客户端部分:

npm install htmlshot

这个htmlshot项目是否仍在维护?npm的github链接似乎仍然不存在。是否有其他网站?
whatsTheDiff

@whatsTheDiff::给我您的要求,并且,请确保我会为您提供帮助。因为我是该库的作者。
Abdennour TOUMI 2016年

2
谢谢@ abdennour-toumi。我只是做了一个npm安装来查看代码。看起来它使用的是html2canvas,这是我尝试过的,并且由于SVG和页面的复杂性而在IE中出现问题。因此看来,该库在这方面无济于事。
whatsTheDiff

4
您的客户必须避免IE ..告诉他们!
Abdennour TOUMI

1
<script src="/assets/backend/js/html2canvas.min.js"></script>


<script>
    $("#download").on('click', function(){
        html2canvas($("#printform"), {
            onrendered: function (canvas) {
                var url = canvas.toDataURL();

                var triggerDownload = $("<a>").attr("href", url).attr("download", getNowFormatDate()+"电子签名详细信息.jpeg").appendTo("body");
                triggerDownload[0].click();
                triggerDownload.remove();
            }
        });
    })
</script>

报价单


1

很简单,您可以使用此代码来捕获特定区域的屏幕快照,您必须在html2canvas中定义div ID。我在这里使用2 div-:

div id =“ car”
div id =“ chartContainer”
如果您只想捕获汽车,那么使用car我在这里捕获汽车,只有您可以更改chartContainer来捕获图表 html2canvas($( '#car') 复制并粘贴此代码

<html>
    <head>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css" integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
<script>
    window.onload = function () {
    
    var chart = new CanvasJS.Chart("chartContainer", {
        animationEnabled: true,
        theme: "light2",
        title:{
            text: "Simple Line Chart"
        },
        axisY:{
            includeZero: false
        },
        data: [{        
            type: "line",       
            dataPoints: [
                { y: 450 },
                { y: 414},
                { y: 520, indexLabel: "highest",markerColor: "red", markerType: "triangle" },
                { y: 460 },
                { y: 450 },
                { y: 500 },
                { y: 480 },
                { y: 480 },
                { y: 410 , indexLabel: "lowest",markerColor: "DarkSlateGrey", markerType: "cross" },
                { y: 500 },
                { y: 480 },
                { y: 510 }

            ]
        }]
    });
    chart.render();
    
    }
</script>
</head>

<body bgcolor="black">
<div id="wholebody">  
<a href="javascript:genScreenshotgraph()"><button style="background:aqua; cursor:pointer">Get Screenshot of Cars onl </button> </a>

<div id="car" align="center">
    <i class="fa fa-car" style="font-size:70px;color:red;"></i>
    <i class="fa fa-car" style="font-size:60px;color:red;"></i>
    <i class="fa fa-car" style="font-size:50px;color:red;"></i>
    <i class="fa fa-car" style="font-size:20px;color:red;"></i>
    <i class="fa fa-car" style="font-size:50px;color:red;"></i>
    <i class="fa fa-car" style="font-size:60px;color:red;"></i>
    <i class="fa fa-car" style="font-size:70px;color:red;"></i>
</div>
<br>
<div id="chartContainer" style="height: 370px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>

<div id="box1">
</div>
</div>>
</body>

<script>

function genScreenshotgraph() 
{
    html2canvas($('#car'), {
        
      onrendered: function(canvas) {

        var imgData = canvas.toDataURL("image/jpeg");
        var pdf = new jsPDF();
        pdf.addImage(imgData, 'JPEG', 0, 0, -180, -180);
        pdf.save("download.pdf");
        
      
      
      }
     });

}

</script>

</html>


1
为什么jQuery被两次包含,为什么jQuery UI被包含?老实说,据我所知,这里根本不需要jQuery。document.getElementById('car')document.querySelector('#car')
内森(Nathan)

实际上我在做我的项目。所以我只是忘记删除库而已。
Rudra Pratap Singh,

0

据我所知你做不到,我可能是错的。但是我会用php做到这一点,使用php标准函数生成JPEG,然后显示图像,这不是一件很难的事,但是取决于DIV内容的浮夸度


OP从未暗示过他正在使用服务器端处理,尽管如果这样的话,那会很好。
Delan Azabani 2011年

是的,很遗憾,我不能使用服务器端的东西。我可能会选择上面的答案之一。但是谢谢!:)
内森

-3

据我所知,这是不可能的JavaScript。

您可以对每个结果执行的操作将创建一个屏幕截图,将其保存在某处,并在单击保存结果时指向用户。(我猜没有结果只有10个,因此创建10个jpeg图像结果没什么大不了的)


感谢您的回答:)你是对的!我可以只创建10个结果的JPG图像,然后当它们单击按钮时,它将显示要保存的图像。唯一的问题是,当他们开始测验时,他们必须输入他们的姓名,然后我在整个测验中显示它,并在结果框的最后显示它的姓名,并显示诸如“变得更好”的注释。等等。我将无法在图像中输入它们的名称,或者对吗?
弥敦道
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.