How to take print (screenshot) from a web page?

Asked

Viewed 7,944 times

13

I would like to know how to print a page, and save in image.

Follow example for understanding:

inserir a descrição da imagem aqui

  • I had forgotten to add the save part, I believe your need is to save on the server. If you do not let me know.

  • @Guilhermenascimento, if you could put that part in, I’d be grateful ;)

  • Save to server? Or save to desktop?

  • @Guilhermenascimento can leave, I saw that you put how to save canvas on the server.

  • All right, thank you!

4 answers

13


You can use html2canvas, note that it does not take a real photo, but yes tries to redraw the page elements, note that the other answers are correct, but the examples are probably not will work in the current version of html2canvas, as several functions have been modified and passed the use es6-promise

Using the html2canvas

I recommend downloading the version 0.5.0-Alpha2 in https://github.com/niklasvh/html2canvas/releases and include on the page that will need to take the "photo", should look something like:

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

html2canvas(document.getElementById("id-do-meu-elemento"), {
    "logging": true //Habilita os logs
}).then(function(canvas) {
    var img = new Image();
    img.onload = function () {
        img.onload = null;
        document.getElementById("output").appendChild(img);
    };
    img.src = canvas.toDataURL("image/png");
});

However there may be cases that the images are from different domains, it will be necessary to use CORS, then we’ll have to use proxy.

Proxy in this case is not the technology to use a different ip on your machine, but rather a script that runs on the server and displays the image of the external domain as if I’ve been in your domain, or even if it’s three domains seu-site.com, maps.google.com and proxy.seu-site.com he makes use of CORS or of data URI scheme.

Proxy for html2canvas

I developed four proxys in different languages:

The use would be something like (example with aspx):

html2canvas(document.getElementById("ID-DO-ELEMENTO"), {
    "logging": true, //Habilita os logs
    "proxy":"html2canvasproxy.ashx"
}).then(function(canvas) {
    var img = new Image();
    img.onload = function () {
        img.onload = null;
        document.getElementById("output").appendChild(img);
    };
    img.src = canvas.toDataURL("image/png");
});

List of options to use in html2canvas(..., {opções}).then(...)

Option Type pattern Description
allowTaint boolean false Allows to cause Taint when there are cross-origin images
background string #fff Change the background color of the canvas, if not specific in the gift use undefined for transparent
height number null Limits the height of the in pixels. If null will render with the full height of the window
letterRendering boolean false Used to render each letter separately. Required if using letter-spacing
logging boolean false When true shows log in browser console
proxy string undefined The proxy url is used to load cross-origin images. If not set or empty images will not be loaded
taintTest boolean true Test each image for before drawing, to see if it will stain the <canvas>
timeout number 0 Waiting time for loading images in mileseconds. If 0 there will be no waiting
width number null Limits the width of the in pixels. If null will render with the full width of the window
useCORS boolean false If true tries to load cross-source images if you do not try to use the proxy

Drawing DOM with SVG inside the Canvas

It is possible to draw the Svgs within the Canvas, but the moment we use <foreignObject>, the browsers WebKit and Blink/Chromium have security blocks when using this, ie you can draw, but can not use toDataURI (in Firefox works if you use CORS).

The following example is simple, taken from MDN, to use <link> (style sheets) and CSS properties will need to convert them to <style> and convert the url(...) to the Data URI Scheme and even then text sources will not be supported (as amazing as it seems I’m working for a few months on a library that does all this, takes "photo" of the page using SVG, only stopped because of the issue of web-sources, which is very difficult to embed in SVG)so you can try, but it will only work in browsers with the Gecko engine (used Firefox) and it will still be a bit of a hassle to import, but CSS and HTML effects will probably all work, follow simple example:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
           '<foreignObject width="100%" height="100%">' +
           '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
             '<em>I</em> like' + 
             '<span style="color:white; text-shadow:0 0 2px blue;">' +
             'cheese</span>' +
           '</div>' +
           '</foreignObject>' +
           '</svg>';

var DOMURL = window.URL || window.webkitURL || window;

var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svg);

img.onload = function () {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
}

img.src = url;

Note that to use SVG you need a valid HTML (or better XHTML), for this use this script:

var doc = document.implementation.createHTMLDocument("");

//Adicione o seu html, como por exemplo document.documentElement.innerHTML
doc.write(STRING DO CONTEUDO HTML);

doc.documentElement.setAttribute("xmlns", doc.documentElement.namespaceURI);

var html = (new XMLSerializer).serializeToString(doc);

var docWidth  = Math.max(document.documentElement.clientWidth,
                         document.body.scrollWidth,
                         document.documentElement.scrollWidth,
                         document.body.offsetWidth,
                         document.documentElement.offsetWidth);

var docHeight = Math.max(document.documentElement.clientHeight,
                         document.body.scrollHeight,
                         document.documentElement.scrollHeight,
                         document.body.offsetHeight,
                         document.documentElement.offsetHeight);

var data = '<svg xmlns="http://www.w3.org/2000/svg" ' +
           'width="' + docWidth + '" height="' + docHeight + '">' +
           '<foreignObject width="100%" height="100%">' +
             html +
           '</foreignObject>' +
           '</svg>';

Conclusion about taking a picture of the page

With the exception of SVG + Canvas, no library has sufficient support yet to simulate the HTML and CSS effects of browsers yet and even if you get this, you’ll still be subject to Bugs or you won’t be able to follow the engines of web browsers in real time, as it’s all "simulated".

Saving canvas on the server

As is my answer in /a/63018/3635 to upload an image to canvas, do the following process:

function uploadAjax(data, fileName, success, error)
{
    var oReq = new XMLHttpRequest();

    oReq.open("POST", "upload.php?filename=" + fileName, true);
    oReq.onreadystatechange = function() {
        if (oReq.readyState === 4) {
            if (oReq.status === 200) {
                success(oReq.responseText);
            } else {
                error(oReq.status);
            }
        }
    };
    oReq.send(data);
}

html2canvas(document.getElementById("id-do-meu-elemento"), {
    "logging": true //Habilita os logs
}).then(function(canvas) {
    uploadAjax(
        canvas.toDataURL("image/jpeg").replace(/^data[:]image\/(.*);base64,/, ""),
        "photo.jpg", function(response) {
            if (response === "OK") {
                alert("sucesso");
            } else {
                alert("Ajax: " + response);
            }
        }, function(errStatus) {
            alert("erro: " + errStatus);
        });
});

Change image/jpeg by the format you want, for example image/gif or image/png, so for example:

canvas.toDataURL("image/png")

PHP to upload:

<?php
define('PASTA_UPLOAD', '/home/user/projeto/data');

if (isset($_GET['filename']) && $_SERVER['REQUEST_METHOD'] === 'POST') {
    $cl = (int) $_SERVER['CONTENT_LENGTH'];

    $tmpFile = tempnam(sys_get_temp_dir(), '~upload-');

    $file = fopen($tmpFile, 'w');
    $fh   = fopen('php://input', 'r');
    if ($file && $fh) {
        $data = '';
        while (FALSE === feof($fh)) {
            $data .= fgets($fh, 256);
        }
        fwrite($file, base64_decode($data));
    }

    if ($file) {
        fclose($file);
    }

    if ($fh) {
        fclose($fh);
    }

    echo 'OK';
    copy($tmpFile, PASTA_UPLOAD . '/' . $_GET['filename']);
} else {
    echo 'Requisição inválida';
}

Saving on Desktop User Machine

To save to the Desktop, the user’s browser will need to have support for the attribute download on the tag <a> (all modern Desktop browsers have), example:

function canvasDownload(canvas, filename, formato) {
    var a = document.createElement("a");
    a.href = canvas.toDataURL("image/" + (formato ? formato : "jpeg") );
    a.download = filename;
    a.click();
}

Note that you need to add the event downloadHtml2canvas in an action of the user, as click, mouseover, etc, because if not the script is locked. Example of use:

<button id="gerar">Gerar</button>
<button id="salvar" disabled>Salvar</button>

<script>
(function() {
    var gerar  = document.getElementById("gerar"),
        salvar = document.getElementById("salvar"),
        currentCanvas = null;

    gerar.onclick = function() {
        salvar.disabled = true;
        html2canvas(document.getElementById("id-do-meu-elemento"), {
            "logging": true //Habilita os logs
        }).then(function(canvas) {
            currentCanvas = canvas;
            salvar.disabled = false;
        });
    };

    salvar.onclick = function() {
         if (currentCanvas !== null && salvar.disabled === false) {
             canvasDownload(currentCanvas, "foto.jpg");
         }
    };
})();
</script>

Note: if you want to save in another format just adjust so:

  • canvasDownload(currentCanvas, "foto.png", "png")
  • canvasDownload(currentCanvas, "foto.gif", "gif")
  • William Nascimento could tell me if your solution does the print page after CSS/JS be applied and implemented?

  • 1

    It depends on the time of execution, if you apply CSS by Javascript and then run html2canvas, yes it will work. But if you are talking about static elements it is necessary to window.onload to release the html2canvas. @Ricardohenrique Note: Read the part of the answer that is written Conclusion about taking a picture of the page.

  • Guilhermenasicimento I read this part, you misunderstood my pergunnta did not mean the CSS applied by javascript, I meant the css applied to the html elements and the execution of the Javascripts scripts (to render images that are in Base64 and/or make AJAX requests to search them)

  • 1

    If I understand, yes @Ricardohenrique html2canvas tries to render in the current state, regardless of whether the DOM was manipulated manually or by javascript.

  • Guilhermenascimento OK got it.

5

You can use the library html2canvas that fits exactly what you want, because it "print" any division of an html page.

Here you can find the examples of use, but I’ll leave a snippet of code below to illustrate:

$("#PrintTrigger").on("click", function (e) {
    e.preventDefault();
    
    html2canvas($("#Print"), {
      onrendered: function(canvas) {
        document.body.appendChild(canvas);
      }
    });
});
#Print {
    width: 300px;
    height: 300px;
    background: #00FF00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://github.com/niklasvh/html2canvas/releases/download/0.4.1/html2canvas.js"></script>
<div id="Print">
    <h1>Vai printar esta div e repetí-la abaixo:</h1>
</div>
<button id="PrintTrigger">Tirar Print</button>

Functioning

The JS code is very simple:

html2canvas(elemento, {
  onrendered: function(canvas) {
    // Ação à realizar, ao renderizar a imagem (print)
  }
});

element - Corresponds to the division of the html page to which you want to "printar" (Can without a DOM Element, an ID or a Class)
onrendered - Function that will be executed once "print" is rendered. In this function you can use AJAX to send to the server without reloading the page, anyway, the possibilities are numerous.

3

With PHP I believe that can not be done, but with Javascript and canvas (HTML5) yes.

With the advent of HTML5, new tags have been implemented, one of them is the canvas, that makes it possible to accomplish this task.

With the element canvas you can create graphics, photo compositions, animations, 2D, 3D images and there are several Apis that provide you with numerous features such as html2canvas, and it is this API that we will work on.

First we will enter the site and download the file. I imagine you have already downloaded the file jquery.js.

The html2canvas has an initial method called Preload, that receives two parameters.

  • Element: It is the element you want to be rendering, by default it is Document.body
  • Options: Are the render options.
  • Complete: callback function that will be called after Preloading
  • Logging: Log events into the console
  • Proxy: Url of the page that will be used as a proxy
  • Timeout: Time for image loading

The script performs the following behavior:

  1. Run the page Preload
  2. Run Parse of Widgets
  3. Execute Render From Object

Let’s go to the code:

<script>
    $(window).ready(function () {
        html2canvas.Preload(document.body, {
            complete: function (images) {
                var queue = html2canvas.Parse();
                var canvas = html2canvas.Renderer(queue, { elements: { length: 1} });
                var img = canvas.toDataURL();
                openConsole("<img src='" + img + "'><p>");
            }
        });
        function openConsole(content) {
            top.console = window.open('', 'myconsole',
              'width=350,height=250'
               + ',menubar=0'
               + ',toolbar=1'
               + ',status=0'
               + ',scrollbars=1'
               + ',resizable=1')
            top.console.document.writeln(
              '<html><head><title>Console</title></head>'
               + '<body bgcolor=white onLoad="self.focus()">'
               + content
               + '</body></html>'
             )
            top.console.document.close()
        };
    });
</script>

Remembering that the browsers that accept canvas are Chrome, FF, Opera and IE7+

For more information, take a look at this article:

http://imasters.com.br/artigo/24443/javascript/screenshot-com-canvas-e-javascript/

  • While this link may answer the question, it is best to include the essential parts of the answer here and provide the link for reference. Replies per link only can be invalidated if the page with the link is changed.

  • 1

    @williamhk2 was worth the hint, I put the code in my reply.

  • 3

    The version provided in the example has been in disuse for a long time, I follow and eventually collaborate with the html2canvas project, the current version is 0.5.0-rc. In the link it says it has support for IE7, but this was when there was the "html2canvas-flash-fallback", this part of the project was discontinued. Links in Sopt: http://answall.com/a/57155/3635 and http://answall.com/a/55522/3635

2

I already make use of the Headless Browser Phantomjs to download COMPLETE WEB pages FAITHFULLY rendered to displayed in the common browser (it interprets JS and CSS) but with it it is also possible to perform a print screen of the desired page of the shape sequinte:

  • Create a file with extension . js
  • Paste and save the following content:

Command that accesses a given page and saves the contents of it in a . png (but can save as PDF):

var page = require('webpage').create();
page.open('http://stackoverflow.com/', function() {
  page.render('stackoverflow.png');
  phantom.exit();
});
  • call it from the following foma at the command line: program name (if it has been inserted in the path) plus npath of the javascript file created in the above item so it is as follows:

    phantomjs test.js

With it it is also possible to establish the dimensions of the window where the site is displayed (this is useful if you want to see how a responsive site is being rendered) as follows (this setting should be done before the page.open()):

var webPage = require('webpage');
var page = webPage.create();

page.viewportSize = {
  width: 480,
  height: 800
};

You can call it using the shell_exec command in this way:

    $pathToPhantomJS = 'C:\phantomjs-2.0.0-windows\bin\phantomjs';
    $pathToJSScript = 'GetPage.js';
    $comand = $pathToPhantomJS . ' ' . $pathToJSScript . ' ' . $site;
    shell_exec($comand);

Note: step a third variable that represents the site to have its page printada the site is picked up by the vector of args that are passed to the shell.

It is possible to create a CRON JOB to execute the command phantomjs teste.js at a certain time.

Phantomjs was very useful to me and is very configurable and I could not describe all the possibilities here so I am pasting some links Official and not Official that may be useful:

Note: A relevant point raised by the user @Guilhermenascimento is that this solution only works on the side Servidor or in his Desktop.

Download

Link: http://phantomjs.org/download.html

Documentation

Screen Capture: Link

viewportSize: Link

shell_exec (PHP): Link

  • I just read about it, only problem is that this lib uses the Webkit engine so it will not render in the same way as it is viewed by the user, but to create a system of portfolios, galleries, etc. really is an amazing solution. A cool note is to leave something like "this only works on the server side"

  • @Guilhermenascimento looks I’ve already made several prints and always came in a similar way to the one displayed on Chrome/firefox is likely (and already happened to me) is that some sites identify that it does not have certain complements like the flash player and do not return the content that should be returned.

  • @Guilhermenascimento some servers identify that it is not a browser like firefox /ie/Chrome and do not send the full HTML (only the head), send an anti-robot javascript code or leave in infinite loop.

  • I understand, although rendering very similar, the engines (Gecko, Webkit and Blink (Fork from the Webkit)) still can have differences, especially if the developer of the page that will be "photographed" has done something that conflicts with the rendering engine, but apart from these possible problems, the tip is very good and I am seriously thinking of using on my server.

  • 1

    @Guilhermenascimento Use, I like it a lot and has MANY other features if it were not for the obstacles highlighted in the comment above would be almost perfect. for the purpose of printing out another question where I also gave the same answer: http://answall.com/questions/714/como-exportar-umap%C3%A1gina-html-php-para-pdf/60104#60104

  • 1

    +1 there too, thank you

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.