Coder Perfect

How can I use JavaScript to take a screenshot of a div?

Problem

The “HTML Quiz” is something I’m working on. It’s entirely based on JavaScript, and it’s rather impressive.

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’d love to help them with this so they may share their findings with others. Because they can easily manipulate the results, I don’t want them to “copy” them. Oh well, if they update what it says in the graphic.

Is there a method to accomplish this or something similar?

Asked by Nathan

Solution #1

No, I’m not aware of a technique to’screenshot’ an element, however you could draw the quiz results into a canvas element and then use the HTMLCanvasElement object’s toDataURL function to obtain a data: URI with the image’s contents.

After you’ve completed the quiz, perform the following:

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

Do the following when the user clicks “Capture”:

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

The’screenshot’ will appear in a new tab or window, allowing the user to save it. Because there isn’t a method to bring up a’save as’ dialog, this is the best you can do, in my opinion.

Answered by Delan Azabani

Solution #2

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 watches for the btnSave button to be clicked. When it is, it turns the widget div to a canvas element and then saves the div as an image named “Dashboard.png” using the saveAs() FileSaver interface (through FileSaver.js in browsers that don’t support it natively).

This fiddle contains an example of this working.

Answered by Andy

Solution #3

After hours of investigation, I finally discovered a way to capture a screenshot of an element even if the origin-clean FLAG is set (to avoid XSS), which is why you can record Google Maps for example (in my case). To get a screenshot, I created a universal function. The html2canvas library (https://html2canvas.hertzen.com/) is the sole additional requirement.

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 that if the image is too large, console.log() and alert() will not produce any output.

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

Answered by orange01

Solution #4

If you want a “Save as” dialog, simply pass the image through a php script, which will add the necessary headers.

Script.php is an example of a “all-in-one” script.

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

Answered by shukshin.ivan

Solution #5

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
  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();
}

Answered by Pankaj Verma

Post is based on https://stackoverflow.com/questions/6887183/how-to-take-screenshot-of-a-div-with-javascript