238

I am building something called the "HTML Quiz". It's completely ran on JavaScript and it's pretty cool.

At the end, a results box pops up that says "Your Results:" and it shows how much time they took, what percentage they got, and how many questions they got right out of 10. I would like to have a button that says "Capture results" and have it somehow take a screenshot or something of the div, and then just show the image captured on the page where they can right click and "Save image as."

I really would love to do this so they can share their results with others. I don't want them to "copy" the results because they can easily change that. If they change what it says in the image, oh well.

Does anyone know a way to do this or something similar?

2

13 Answers 13

130

No, I don't know of a way to 'screenshot' an element, but what you could do, is draw the quiz results into a canvas element, then use the HTMLCanvasElement object's toDataURL function to get a data: URI with the image's contents.

When the quiz is finished, do this:

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 */

When the user clicks "Capture", do this:

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

This will open a new tab or window with the 'screenshot', allowing the user to save it. There is no way to invoke a 'save as' dialog of sorts, so this is the best you can do in my opinion.

10
  • 1
    Thanks!! I don't know anything about canvas, but I will learn it. How would I use the Canvas 2D drawing effects? Could you assist me with this? Thanks so much! :)
    – Nathan
    Commented Jul 31, 2011 at 3:35
  • 6
    Try Mozilla's documentation, it's really quite easy to follow: developer.mozilla.org/en/canvas_tutorial Commented Jul 31, 2011 at 3:41
  • Instead of opening it in a new window/tab, can I open it in a inline dialog box? (Like the Fancybox lightbox plugin?)
    – Nathan
    Commented Jul 31, 2011 at 4:16
  • Yep, you can have an inline dialog box with an img that has its src set to the data: URI. However, that isn't really necessary -- you can just put the canvas itself in the inline dialog box; users can right click it and save the current state as an image. Commented Jul 31, 2011 at 4:18
  • 5
    The link to the canvas tutorial has changed: developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial
    – Fabricio
    Commented Feb 25, 2021 at 20:09
125

This is an expansion of @Dathan's answer, using html2canvas and FileSaver.js.

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


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

This code block waits for the button with the id btnSave to be clicked. When it is, it converts the widget div to a canvas element and then uses the saveAs() FileSaver interface (via FileSaver.js in browsers that don't support it natively) to save the div as an image named "Dashboard.png".

An example of this working is available at this fiddle.

13
  • 7
    I needed to add references to: html2canvas, filesaver, blob, canvas-toBlob. After that it worked. Thanks!
    – sirthomas
    Commented Sep 5, 2014 at 17:08
  • 1
    Awesome, this should be the accepted answer. Straightforward plug n play.
    – rgshenoy
    Commented Nov 20, 2016 at 17:35
  • 1
    Can you avoid image appearing in your DOM? Can't it just go to download straight away?
    – kulan
    Commented Sep 27, 2018 at 10:49
  • 2
    The fiddle does not do anything! Commented May 27, 2019 at 15:10
  • 2
    This worked great for me on the first try, and even looks like the original CSS styling etc. Amazingly accurate. Pretty much a virtual screen-shot with this level of accuracy. I used CDN for the 2 libraries I had to add: <!-- html2canvas --> <script src="cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/…> <!-- filesaver --> <script src="cdn.jsdelivr.net/npm/[email protected]/dist/…>
    – OG Sean
    Commented Feb 6, 2020 at 20:16
28

After hours of research, I finally found a solution to take a screenshot of an element, even if the origin-clean FLAG is set (to prevent XSS), that´s why you can even capture for example Google Maps (in my case). I wrote a universal function to get a screenshot. The only thing you need in addition is the html2canvas library (https://html2canvas.hertzen.com/).

Example:

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);
});

Keep in mind console.log() and alert() won´t generate output if the size of the image is great.

Function:

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
    });
}
4
  • where you have defined html2canvas function
    – Bharathi
    Commented Apr 6, 2017 at 6:31
  • I integrated the library html2canvas (see link in my post) before the function getScreenshotOfElement() is reached. For example with the <script>-tag. Just download html2canvas and copy it to your project.
    – orange01
    Commented Apr 8, 2017 at 6:12
  • @orange01 - I am still not able to capture street lanes of google map. This only screenshot the zoom In and out button, Map and satellite text. can you please help to capture full map. Thanks Commented Oct 8, 2018 at 12:12
  • 1
    FYI, the syntax has changed since this was posted. "onrendered" is no longer a property and the function should be moved to a "then" call: html2canvas(element, { width, height, ...}).then(function (canvas) { ... }) Commented May 8, 2023 at 4:19
7

If you wish to have "Save as" dialog, just pass image into php script, which adds appropriate headers

Example "all-in-one" script 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>
6

Add this Script in your index.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>

Use this function to get screenshot of div tag

  getScreenShot(){
    let c = this.elem.nativeElement.querySelector('.chartContainer'); // or document.getElementById('canvas');
    html2canvas(c).then((canvas:any)=>{
      var t = canvas.toDataURL().replace("data:image/png;base64,", "");
      this.downloadBase64File('image/png',t,'image');
    })
  }

downloadBase64File(contentType:any, base64Data:any, fileName:any) {
  const linkSource = `data:${contentType};base64,${base64Data}`;
  const downloadLink = document.createElement("a");
  downloadLink.href = linkSource;
  downloadLink.download = fileName;
  downloadLink.click();
}
1
  • Hi, do you have any resource how this can be opened in camera roll or google photos please? Need image to be shared on social media.
    – Dgloria
    Commented Jul 26, 2021 at 10:09
4

You can't take a screen-shot: it would be an irresponsible security risk to let you do so. However, you can:

  • Do things server-side and generate an image
  • Draw something similar to a Canvas and render that to an image (in a browser that supports it)
  • Use some other drawing library to draw directly to the image (slow, but would work on any browser)
7
  • Thanks! I will go with the canvas, as I don't know of any "drawing libraries" nor do I know how to do that. I'm not that good at canvas either but I'll try.
    – Nathan
    Commented Jul 31, 2011 at 3:34
  • 4
    Sorry i have to comment this as it comes from google but WTF "irresponsible security risk" might i ask why, if you let javascript take a screenshot or a shot within given cords and return the BASE64 encoded data of it as a string no Security problem
    – Barkermn01
    Commented Dec 27, 2012 at 19:56
  • 1
    whats wrong with that there not going to see any thing still the same as it currently is if a user was to Print screen the browser with facebook in it
    – Barkermn01
    Commented Dec 27, 2012 at 22:15
  • 2
    @MartinBarker The Javascript could give the data to a malicious source without the user even noticing, whereas "print screen" is controlled by the user, and not some some arbitrary untrusted website.
    – bgw
    Commented Dec 28, 2012 at 0:45
  • 2
    What a beat up. @PiPeep, If a webpage can load up an iFrame of Facebook, there is already isolation, why not extend such isolation with a screenshot API? eg. Div.ToPNG(), where the aforementioned iFrame is whited out? It's not an irresponsible security risk, it just not there built-in and no one has worked through "potential" privacy/security issues in developing such a built in screenshot API. It would be immensely useful for a myriad of use-cases, such as support of intranet web applications for example. Commented Nov 25, 2013 at 5:37
4
var shot1=imagify($('#widget')[0], (base64) => {
  $('img.screenshot').attr('src', base64);
});

Take a look at htmlshot package , then, check deeply the client side section:

npm install htmlshot
4
  • is this htmlshot project still maintained? The github link from npm doesn't look to still exist. Is there another website for it? Commented Jul 22, 2016 at 16:21
  • 1
    @whatsTheDiff: : give me your requirements , and , be sure that i will help you .since i am the author of this library. Commented Jul 22, 2016 at 16:38
  • 2
    Thanks @abdennour-toumi. I just did an npm install to look through the code. Looks like it's using html2canvas which I've tried and am having issues with in IE and due to the SVG's and complexity of my page. So appears that this library won't help me in that regards. Commented Jul 25, 2016 at 14:29
  • 4
    Your customer has to avoid IE.. tell them that! Commented Jul 25, 2016 at 14:43
4
<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>

quotation

2

It's to simple you can use this code for capture the screenshot of particular area you have to define the div id in html2canvas. I'm using here 2 div-:

div id="car"
div id ="chartContainer"
if you want to capture only cars then use car i'm capture here car only you can change chartContainer for capture the graph html2canvas($('#car') copy and paste this code

<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>

2
  • 1
    Why is jQuery included twice, and why is jQuery UI included? Honestly, jQuery is not needed here at all from what I can tell. document.getElementById('car') or document.querySelector('#car')
    – Nathan
    Commented Aug 20, 2018 at 14:02
  • actually i'm working on my project. so i just forget about to remove the library and nothing. Commented Aug 21, 2018 at 11:34
0

As far as I know you can't do that, I may be wrong. However I'd do this with php, generate a JPEG using php standard functions and then display the image, should not be a very hard job, however depends on how flashy the contents of the DIV are

2
  • The OP never suggested that he is using server-side processing, though if he was, this would be fine. Commented Jul 31, 2011 at 2:37
  • Yeah, I can't use server-side stuff unfortunately. I will probably go with one of the answers above. But thanks! :)
    – Nathan
    Commented Jul 31, 2011 at 3:32
0

Add to your html file and id="capture" to the div you want to take screenshot

<a id="btn-Convert-Html2Image" href="#">Download</a>
<script src="capture.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js" type="text/javascript"></script> 

In capture.js add:

document.getElementById("btn-Convert-Html2Image").addEventListener("click", function() {
  html2canvas(document.getElementById("capture")).then(function (canvas) {
    var anchorTag = document.createElement("a");
    anchorTag.download = "filename.jpg";
    anchorTag.href = canvas.toDataURL();
    anchorTag.target = '_blank';
    anchorTag.click();
  });
});

Then, just press download and it will download the screenshot

Or you can view screenshot img by add

<div id="previewImg"></div>

in html code is where you want to view that img and js code will be

document.getElementById("btn-Convert-Html2Image").addEventListener("click", function() {
  html2canvas(document.getElementById("capture")).then(function (canvas) {
    var anchorTag = document.createElement("a");
    document.body.appendChild(anchorTag);
    document.getElementById("previewImg").appendChild(canvas);
    anchorTag.click();
  });
});
0

first you need include html2canvas:

HTML

<div id="toBeCaptured">
<p><b>Note:</b> The download attribute is not supported in IE or Edge (prior version 18), or in Safari (prior version 10.1).</p>
</div>
<img id="captured" src="">

Javascript

async function x(){
  const data = await    html2canvas(document.querySelector("#toBeCaptured"));
  document.querySelector("#captured").src = data.toDataURL();
  document.innerHTML = data.toDataURL();
}
x();
-7

This is an ~11 year old answer. Please ignore this answer and check other recent answers here

As far as I know its not possible with javascript.

What you can do for every result create a screenshot, save it somewhere and point the user when clicked on save result. (I guess no of result is only 10 so not a big deal to create 10 jpeg image of results)

1
  • 1
    Thanks for answering :) You're right! I could just create 10 JPG images of the results and then once they click the button, it'll show the image for them to save. The only problem is that when they start the quiz, they have to enter their name, and I display it through out the quiz, and at the end in the results box, it shows their name and it says a comment like "Getting Better" etc. I wouldn't be able to put the name of them in the image or would I?
    – Nathan
    Commented Jul 31, 2011 at 3:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.