Declaration of VAR

and some other stuff

Screenshot of an HTML page with JavaScript

2018-07-23 18:50:01 +0200

2018-07-23 18:50:01 +0200 | Comments

Yes, it is possible to make a screenshot (create a canvas replica) of an HTML page (or rather of a selected node) on client-side using JavaScript.

And like everything in JS world, it is done via some library. This time it’s html2canvas.

Download the file and put it in your project folder:

├── html2canvas.min.js
└── index.html

Include it into index.html:

<head>
  ...
  <script src="html2canvas.min.js"></script>
  ...
</head>

Now, let’s say, you want to make a screenshot (generate a raster image) of some <div id="screenshot"> from your page. Here’s how you do it:

...
<script>
function makeScreenshot() {
    html2canvas(document.getElementById("screenshot"), {scale: 1}).then(canvas => {
        document.body.appendChild(canvas);
    });
}
</script>
</body>

You’ll get a canvas element at the end of your page. This canvas can then be saved as a regular image file.

To make it more interesting, here’s what we will do:

  1. Create a rather complex <div id="screenshot"> node inside some <div id="main">;
  2. Assign onclick="makeScreenshot();" to the <div id="screenshot">;
  3. Generate a <canvas> with twice the size (scale to 200%), replacing the original <div>.

Here’s the code:

<script>
    function makeScreenshot() {
        html2canvas(document.getElementById("screenshot"), {scale: 2}).then(canvas => {
            var main = document.getElementById("main");
            while (main.firstChild) {
              main.removeChild(main.firstChild);
            }

            // for Firefox
            main.appendChild(canvas);

            // for Safari
            //canvas.toBlob(function(blob) {
            //  var newImg = document.createElement('img'),
            //      url = URL.createObjectURL(blob);
              
            //  newImg.onload = function() {
            //    URL.revokeObjectURL(url);
            //  };

            //  newImg.src = url;
            //  newImg.title = "some title";
            //  newImg.alt = "some alternative text";
            //  main.appendChild(newImg);
            //});
        });
    }
</script>

Note the commented section for Safari. Apparently, canvas element is still not really cross-browser yet, because what’s okay for Firefox is not okay for Safari and vice versa, so if you need it for this or that browser, then comment/uncomment the corresponding section.

And here’s a demo:

Pay attention to the bottom part, where the Inspector is - you’ll see how <div> is replaced by <canvas>.



[24.07.2018] Update: More universal solution

A bit later I found an universal solution that works in both Firefox and Safari:

<div>
    <a id="a-make" href="#">Make a screenshot</a>
    <a id="a-download" href="#" style="display:none;">Download a screenshot</a>
</div>

<div id="main">
    <div id="screenshot">
        ...
    </div>
</div>

<script>
    function makeScreenshot()
    {
        html2canvas(document.getElementById("screenshot"), {scale: 2}).then(canvas =>
        {
            canvas.id = "canvasID";
            var main = document.getElementById("main");
            while (main.firstChild) { main.removeChild(main.firstChild); }
            main.appendChild(canvas);
        });
    }

    document.getElementById("a-make").addEventListener('click', function()
    {
        document.getElementById("a-make").style.display = "none";
        makeScreenshot();
        document.getElementById("a-download").style.display = "inline";
    }, false);

    document.getElementById("a-download").addEventListener('click', function()
    {
        this.href = document.getElementById("canvasID").toDataURL();
        this.download = "canvas-image.png";
    }, false);
</script>

That way you’ll get a proper Save File dialog in your browser:

Full source code and a live demo are available in this repository.



[29.07.2018] Update: More about cross-browser support

As usual in the web-world, you can get all sorts of results in different browsers.

First of all, even before getting to canvas, custom fonts are not picked up in some browsers. Hilarious enough, even the same browser (Safari) on one Mac shows fonts as it should, and on another Mac it just doesn’t.

But forget about fonts, take a look how different browser create the canvas.

Firefox moves the content down a bit:

Vivaldi messes up the font a bit:

And only Safari works fine (at least on my Mac):

So I can conclude that creating a screenshot (canvas) of a web-page is not reliable (or cross-browser enough) at the moment.