Come fare uno screenshot di un div con JavaScript?


175

Sto costruendo qualcosa chiamato "HTML Quiz". È completamente eseguito su JavaScript ed è piuttosto interessante.

Alla fine, viene visualizzata una finestra di risultati che dice "I tuoi risultati:" e mostra quanto tempo hanno impiegato, quale percentuale hanno ottenuto e quante domande hanno ricevuto subito su 10. Vorrei avere un pulsante che dice "Acquisisci risultati" e in qualche modo fai uno screenshot o qualcosa del div, quindi mostra semplicemente l'immagine catturata sulla pagina in cui possono fare clic con il tasto destro e "Salva immagine con nome".

Mi piacerebbe davvero farlo in modo che possano condividere i loro risultati con gli altri. Non voglio che "copino" i risultati perché possono facilmente cambiarlo. Se cambiano ciò che dice nell'immagine, vabbè.

Qualcuno sa un modo per fare questo o qualcosa di simile?


2
Dai un'occhiata a phantomjs.org . Usandolo puoi generare un'immagine completa della pagina HTML sul lato server e dare all'utente un link per il download.
Giosuè,


Risposte:


99

No, non conosco un modo per "screenshot" di un elemento, ma quello che potresti fare è disegnare i risultati del quiz in un elemento canvas, quindi utilizzare la funzione HTMLCanvasElementdell'oggetto toDataURLper ottenere un data:URI con il contenuto dell'immagine.

Al termine del quiz, procedere come segue:

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

Quando l'utente fa clic su "Cattura", procedere come segue:

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

Questo aprirà una nuova scheda o finestra con lo 'screenshot', permettendo all'utente di salvarlo. Non c'è modo di invocare una sorta di finestra di dialogo 'Salva con nome', quindi questo è il meglio che puoi fare secondo me.


Grazie!! Non so nulla della tela, ma la imparerò. Come dovrei usare gli effetti di disegno 2D Canvas? Potresti aiutarmi con questo? Grazie mille! :)
Nathan,

5
Prova la documentazione di Mozilla, è davvero abbastanza facile da seguire: developer.mozilla.org/en/canvas_tutorial
Delan Azabani

Invece di aprirlo in una nuova finestra / scheda, posso aprirlo in una finestra di dialogo incorporata? (Come il plug-in lightbox Fancybox?)
Nathan

Sì, puoi avere una finestra di dialogo incorporata con una imgche è srcimpostata data:sull'URI. Tuttavia, ciò non è davvero necessario: puoi semplicemente inserire lo canvasstesso nella finestra di dialogo in linea; gli utenti possono fare clic con il pulsante destro del mouse e salvare lo stato corrente come immagine.
Delan Azabani,

Grazie :) Potrei usare la versione dell'immagine in modo che possano fare clic con il tasto destro e fare clic su "salva immagine con nome"
Nathan

89

Questa è un'espansione della risposta di @ Dathan , usando html2canvas e FileSaver.js .

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


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

Questo blocco di codice attende btnSaveche si faccia clic sul pulsante con l'id . Quando lo è, converte il widgetdiv in un elemento canvas e quindi utilizza l'interfaccia FileSaver saveAs () (tramite FileSaver.js nei browser che non lo supportano nativamente) per salvare il div come immagine denominata "Dashboard.png".

Un esempio di questo lavoro è disponibile in questo violino .


7
Avevo bisogno di aggiungere riferimenti a: html2canvas, filesaver, blob, canvas-toBlob. Dopodiché ha funzionato. Grazie!
sirthomas,

1
Fantastico, questa dovrebbe essere la risposta accettata. Plug and play semplice.
rgshenoy,

Sai come funzionerebbe con three.js? Ho un div in cui si trova il renderer / canvas three.js (renderer.domElement), e poi ci div. Vorrei fare un'istantanea del DIV principale e catturare tutto? È possibile? Grazie!
Rankinstudio,

1
Puoi evitare che l'immagine appaia nel tuo DOM? Non è possibile scaricare subito?
kulan,

1
Questo ha funzionato benissimo per me al primo tentativo, e sembra persino lo stile CSS originale ecc. Incredibilmente preciso. Praticamente una schermata virtuale con questo livello di precisione. Ho usato CDN per le 2 librerie che ho dovuto aggiungere: <! - 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 Sean

13

Dopo ore di ricerca, ho finalmente trovato una soluzione per fare uno screenshot di un elemento, anche se il origin-cleanFLAG è impostato (per prevenire XSS), ecco perché puoi persino catturare, ad esempio, Google Maps (nel mio caso). Ho scritto una funzione universale per ottenere uno screenshot. L'unica cosa di cui hai bisogno è inoltre la libreria html2canvas ( https://html2canvas.hertzen.com/ ).

Esempio:

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

Tieni presente console.log()che alert()non genererà output se la dimensione dell'immagine è ottima.

Funzione:

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

dove hai definito la funzione html2canvas
Bharathi

Ho integrato la libreria html2canvas (vedi link nel mio post) prima di raggiungere la funzione getScreenshotOfElement (). Ad esempio con <script> -tag. Basta scaricare html2canvas e copiarlo nel progetto.
orange01

@ orange01 - Non riesco ancora a catturare le stradine di Google Map. Questo solo screenshot del pulsante Zoom avanti e indietro, Mappa e testo satellitare. puoi per favore aiutare a catturare la mappa completa. Grazie
Farhan Sahibole,

7

Se desideri avere la finestra di dialogo "Salva con nome", passa l'immagine nello script php, che aggiunge le intestazioni appropriate

Esempio di script "tutto in uno" 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

Non puoi fare uno screenshot: sarebbe un rischio irresponsabile per la sicurezza lasciarti fare. Tuttavia, puoi:

  • Fai cose sul lato server e genera un'immagine
  • Disegna qualcosa di simile a una tela e rendila a un'immagine (in un browser che la supporta)
  • Usa qualche altra libreria di disegni per disegnare direttamente sull'immagine (lento, ma funzionerebbe su qualsiasi browser)

Grazie! Andrò con la tela, poiché non conosco alcuna "libreria di disegni" né so come farlo. Nemmeno io sono bravo in tela ma ci proverò.
Nathan,

2
Mi dispiace, devo commentare questo dato che proviene da Google, ma WTF "rischio di sicurezza irresponsabile" potrei chiedermi perché, se lasci che javascript prenda uno screenshot o uno scatto all'interno di determinati cavi e restituisca i dati codificati BASE64 come una stringa, nessun problema di sicurezza
Barkermn01,

@MartinBarker Potrei (ad esempio) visualizzare la pagina Facebook di qualcuno in un iframe e poi catturarlo come immagine. Normalmente un iframe tra siti non fa parte del DOM accessibile per impedire XSS, ma sarebbe molto più difficile per il fornitore del browser fermarlo in questo caso.
bgw,

2
@MartinBarker Javascript potrebbe fornire i dati a una fonte malevola senza che l'utente se ne accorga, mentre "schermo di stampa" è controllato dall'utente e non alcuni siti Web arbitrari non attendibili.
bgw,

2
Che picchiata. @PiPeep, se una pagina web può caricare un iFrame di Facebook, c'è già isolamento, perché non estenderlo con un'API per screenshot? per esempio. Div.ToPNG (), dove l'iFrame di cui sopra è sbiancato? Non è un irresponsabile rischio per la sicurezza, semplicemente non è integrato e nessuno ha elaborato "potenziali" problemi di privacy / sicurezza nello sviluppo di un'API di screenshot integrata. Sarebbe estremamente utile per una miriade di casi d'uso, come ad esempio il supporto di applicazioni Web Intranet.
Todd,

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

Dai un'occhiata al pacchetto htmlshot , quindi controlla attentamente la sezione lato client :

npm install htmlshot

questo progetto htmlshot è ancora mantenuto? Il collegamento github da npm non sembra esistere ancora. C'è un altro sito web per questo?
whatsTheDiff,

@whatsTheDiff:: dammi le tue esigenze e, assicurati che ti aiuterò. Dal momento che sono l'autore di questa libreria.
Abdennour TOUMI,

2
Grazie @ abdennour-toumi. Ho appena fatto un'installazione npm per consultare il codice. Sembra che stia usando html2canvas che ho provato e sto riscontrando problemi in IE e a causa della SVG e della complessità della mia pagina. Sembra quindi che questa biblioteca non mi aiuti in tal senso.
whatsTheDiff, il

4
Il tuo cliente deve evitare IE .. diglielo!
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>

Quotazione


1

È così semplice che puoi usare questo codice per catturare lo screenshot di un'area particolare che devi definire l'id div in html2canvas. Sto usando qui 2 div-:

div id = "car"
div id = "chartContainer"
se vuoi catturare solo auto quindi usa auto sto catturando qui auto solo tu puoi cambiare chartContainer per catturare il grafico html2canvas ($ ( '#car') copia e incolla questo codice

<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
Perché jQuery è incluso due volte e perché è inclusa l'interfaccia utente di jQuery? Onestamente, jQuery non è affatto necessario qui da quello che posso dire. document.getElementById('car')oppuredocument.querySelector('#car')
Nathan,

in realtà sto lavorando al mio progetto. quindi dimentico solo di rimuovere la libreria e niente.
Rudra Pratap Singh,

0

Per quanto so che non puoi farlo, potrei sbagliarmi. Comunque lo farei con php, genererei un JPEG usando le funzioni standard di php e quindi visualizzerei l'immagine, non dovrebbe essere un lavoro molto difficile, comunque dipende da quanto appariscenti sono i contenuti del DIV


L'OP non ha mai suggerito di utilizzare l'elaborazione lato server, anche se in tal caso andrebbe bene.
Delan Azabani,

Sì, sfortunatamente non posso usare roba sul lato server. Probabilmente andrò con una delle risposte sopra. Ma grazie! :)
Nathan,

-3

Per quanto ne so non è possibile con JavaScript.

Cosa puoi fare per ogni risultato crea uno screenshot, salvalo da qualche parte e punta l'utente quando fai clic sul risultato del salvataggio. (Suppongo che il risultato non sia solo 10, quindi non è un grosso problema per creare 10 jpeg di risultati)


Grazie per aver risposto :) Hai ragione! Potrei semplicemente creare 10 immagini JPG dei risultati e quindi una volta che fanno clic sul pulsante, mostrerà l'immagine per loro da salvare. L'unico problema è che quando iniziano il quiz, devono inserire il loro nome e lo visualizzo attraverso il quiz, e alla fine nella casella dei risultati, mostra il loro nome e dice un commento come "Come migliorare" ecc. Non sarei in grado di mettere il loro nome nell'immagine o no?
Nathan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.