Wie mache ich einen Screenshot eines Div mit JavaScript?


174

Ich baue etwas namens "HTML Quiz". Es läuft komplett auf JavaScript und ist ziemlich cool.

Am Ende erscheint ein Ergebnisfeld mit der Aufschrift "Ihre Ergebnisse:" und zeigt an, wie viel Zeit sie gebraucht haben, wie viel Prozent sie bekommen haben und wie viele Fragen sie direkt von 10 bekommen haben. Ich hätte gerne eine Schaltfläche mit der Aufschrift "Ergebnisse erfassen" und irgendwie einen Screenshot oder etwas von der Div machen lassen und dann einfach das auf der Seite aufgenommene Bild anzeigen, auf das sie mit der rechten Maustaste klicken und "Bild speichern unter".

Ich würde das wirklich gerne tun, damit sie ihre Ergebnisse mit anderen teilen können. Ich möchte nicht, dass sie die Ergebnisse "kopieren", weil sie das leicht ändern können. Wenn sie ändern, was auf dem Bild steht, na ja.

Kennt jemand einen Weg, dies oder ähnliches zu tun?


2
Schauen Sie sich phantomjs.org an . Mit dieser Funktion können Sie ein vollständiges Bild der HTML-Seite auf der Serverseite erstellen und dem Benutzer einen Link zum Herunterladen geben.
Joshua

Schöner Artikel HTML-Inhalt zum Bild konvertieren und herunterladen codepedia.info/…
Satinder singh

Antworten:


98

Nein, ich kenne keine Möglichkeit, ein Element als "Screenshot" zu erstellen. Sie können jedoch die Quizergebnisse in ein Canvas-Element zeichnen und dann mithilfe der HTMLCanvasElementObjektfunktion toDataURLeinen data:URI mit dem Bildinhalt abrufen.

Wenn das Quiz beendet ist, gehen Sie folgendermaßen vor:

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

Wenn der Benutzer auf "Erfassen" klickt, gehen Sie wie folgt vor:

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

Dadurch wird eine neue Registerkarte oder ein neues Fenster mit dem "Screenshot" geöffnet, in dem der Benutzer ihn speichern kann. Es gibt keine Möglichkeit, eine Art "Speichern unter" -Dialog aufzurufen. Dies ist meiner Meinung nach das Beste, was Sie tun können.


Vielen Dank!! Ich weiß nichts über Leinwand, aber ich werde es lernen. Wie würde ich die Canvas 2D-Zeichnungseffekte verwenden? Könnten Sie mir dabei helfen? Vielen Dank! :)
Nathan

5
Probieren Sie die Dokumentation von Mozilla aus, es ist wirklich ganz einfach zu folgen: developer.mozilla.org/en/canvas_tutorial
Delan Azabani

Kann ich es in einem Inline-Dialogfeld öffnen, anstatt es in einem neuen Fenster / einer neuen Registerkarte zu öffnen? (Wie das Fancybox Lightbox Plugin?)
Nathan

Yep, können Sie ein Inline - Dialogfeld mit einem haben , imgdas seine hat srcSatz an den data:URI. Dies ist jedoch nicht unbedingt erforderlich. Sie können das canvasselbst einfach in das Inline-Dialogfeld einfügen. Benutzer können mit der rechten Maustaste darauf klicken und den aktuellen Status als Bild speichern.
Delan Azabani

Danke :) Ich könnte die Bildversion verwenden, damit sie mit der rechten Maustaste klicken und auf "Bild speichern unter" klicken können
Nathan

89

Dies ist eine Erweiterung von @ Dathans Antwort unter Verwendung von html2canvas und FileSaver.js .

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


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

Dieser Codeblock wartet darauf, dass auf die Schaltfläche mit der ID btnSavegeklickt wird. Wenn dies widgetder Fall ist, konvertiert es das div in ein Canvas-Element und verwendet dann die Datei saveAs () FileSaver (über FileSaver.js in Browsern, die es nicht nativ unterstützen), um das div als Bild mit dem Namen "Dashboard.png" zu speichern.

Ein Beispiel für diese Arbeit finden Sie in dieser Geige .


7
Ich musste Verweise hinzufügen auf: html2canvas, filesaver, blob, canvas-toBlob. Danach hat es funktioniert. Vielen Dank!
Sirthomas

1
Genial, das sollte die akzeptierte Antwort sein. Einfaches Plug-n-Play.
Rgshenoy

Wissen Sie, wie das mit three.js funktionieren würde? Ich habe ein div, in dem sich der renderer / canvas von three.js befindet (renderer.domElement), und dann divs darüber. Ich möchte einen Schnappschuss des übergeordneten DIV machen und alles erfassen? Ist das möglich? Vielen Dank!
Rankinstudio

1
Können Sie vermeiden, dass Bilder in Ihrem DOM angezeigt werden? Kann es nicht einfach sofort zum Download gehen?
Kulan

1
Dies hat beim ersten Versuch hervorragend funktioniert und sieht sogar aus wie das ursprüngliche CSS-Styling usw. Erstaunlich genau. So ziemlich ein virtueller Screenshot mit dieser Genauigkeit. Ich habe CDN für die 2 Bibliotheken verwendet, die ich hinzufügen musste: <! - 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

Nach stundenlanger Recherche habe ich endlich eine Lösung gefunden, um einen Screenshot eines Elements zu machen, auch wenn die origin-cleanFLAG gesetzt ist (um XSS zu verhindern). Deshalb können Sie beispielsweise auch Google Maps (in meinem Fall) erfassen. Ich habe eine universelle Funktion geschrieben, um einen Screenshot zu erhalten. Das einzige, was Sie zusätzlich benötigen, ist die html2canvas-Bibliothek ( https://html2canvas.hertzen.com/ ).

Beispiel:

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

Denken Sie daran console.log()und alert()generieren Sie keine Ausgabe, wenn die Größe des Bildes groß ist.

Funktion:

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

wo Sie html2canvas Funktion definiert haben
Bharathi

Ich habe die Bibliothek html2canvas (siehe Link in meinem Beitrag) integriert, bevor die Funktion getScreenshotOfElement () erreicht wird. Zum Beispiel mit dem <script> -Tag. Laden Sie einfach html2canvas herunter und kopieren Sie es in Ihr Projekt.
Orange01

@ orange01 - Ich kann immer noch keine Straßenspuren von Google Map erfassen. Dies ist nur ein Screenshot der Schaltfläche zum Vergrößern und Verkleinern, der Karte und des Satellitentextes. Können Sie bitte helfen, die vollständige Karte zu erfassen? Vielen Dank
Farhan Sahibole

7

Wenn Sie das Dialogfeld "Speichern unter" wünschen, übergeben Sie das Bild einfach an das PHP-Skript, das die entsprechenden Überschriften hinzufügt

Beispiel "All-in-One" -Skript 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

Sie können keinen Screenshot machen: Es wäre ein unverantwortliches Sicherheitsrisiko, dies zuzulassen. Sie können jedoch:

  • Machen Sie Dinge serverseitig und generieren Sie ein Image
  • Zeichnen Sie etwas Ähnliches wie eine Leinwand und rendern Sie es in ein Bild (in einem Browser, der dies unterstützt).
  • Verwenden Sie eine andere Zeichenbibliothek, um direkt auf das Bild zu zeichnen (langsam, funktioniert aber in jedem Browser)

Vielen Dank! Ich werde mit der Leinwand gehen, da ich keine "Zeichenbibliotheken" kenne und auch nicht weiß, wie ich das machen soll. Ich bin auch nicht so gut in Leinwand, aber ich werde es versuchen.
Nathan

2
Es tut mir leid, dass ich dies kommentieren muss, da es von Google stammt, aber WTF "unverantwortliches Sicherheitsrisiko" könnte ich fragen, warum, wenn Sie Javascript einen Screenshot oder eine Aufnahme in bestimmten Kabeln machen lassen und die BASE64-codierten Daten davon als Zeichenfolge zurückgeben, kein Sicherheitsproblem
Barkermn01

@MartinBarker Ich könnte (zum Beispiel) jemandes Facebook-Seite in einem Iframe aufrufen und dann einen Screenshot davon machen. Normalerweise ist ein standortübergreifender Iframe nicht Teil des zugänglichen DOM, um XSS zu verhindern, aber in diesem Fall wäre es für den Browserhersteller viel schwieriger, ihn zu stoppen.
Bgw

2
@MartinBarker Das Javascript könnte die Daten an eine böswillige Quelle weitergeben, ohne dass der Benutzer es überhaupt bemerkt, während der "Druckbildschirm" vom Benutzer gesteuert wird und nicht von einer beliebigen nicht vertrauenswürdigen Website.
bgw

2
Was für ein Schlag. @PiPeep, Wenn eine Webseite einen iFrame von Facebook laden kann, gibt es bereits eine Isolation. Warum nicht eine solche Isolation mit einer Screenshot-API erweitern? z.B. Div.ToPNG (), wo der oben genannte iFrame weiß ist? Es ist kein unverantwortliches Sicherheitsrisiko, es ist einfach nicht eingebaut und niemand hat "potenzielle" Datenschutz- / Sicherheitsprobleme bei der Entwicklung einer solchen eingebauten Screenshot-API durchgearbeitet. Es wäre immens nützlich für eine Vielzahl von Anwendungsfällen, wie zum Beispiel die Unterstützung von Intranet-Webanwendungen.
Todd

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

Schauen Sie sich das HTML-Shot- Paket an und überprüfen Sie den clientseitigen Abschnitt gründlich :

npm install htmlshot

Wird dieses HTML-Projekt noch gepflegt? Der Github-Link von npm scheint noch nicht zu existieren. Gibt es eine andere Website dafür?
WhatsTheDiff

@whatsTheDiff :: Geben Sie mir Ihre Anforderungen und stellen Sie sicher, dass ich Ihnen helfen werde, da ich der Autor dieser Bibliothek bin.
Abdennour TOUMI

2
Danke @ abdennour-toumi. Ich habe gerade eine npm-Installation durchgeführt, um den Code durchzusehen. Es sieht so aus, als würde html2canvas verwendet, mit dem ich versucht habe und mit dem ich Probleme im IE habe, und aufgrund der SVGs und der Komplexität meiner Seite. Es scheint also, dass diese Bibliothek mir in dieser Hinsicht nicht helfen wird.
WhatsTheDiff

4
Ihr Kunde muss IE vermeiden .. sagen Sie ihm das!
Abdennour TOUMI

3

Eine andere Alternative ist die Verwendung der JavaScript-API von GrabzIt. Sie müssen lediglich den CSS-Selektor des Divs übergeben, das Sie erfassen möchten. Es wird dann ein Screenshot von nur diesem Div erstellt.

<script type="text/javascript" src="grabzit.min.js"></script>
<script type="text/javascript">
GrabzIt("YOUR APPLICATION KEY").ConvertURL("http://www.example.com/quiz.html",
{"target": "#results", "bheight": -1, "height": -1, "width": -1}).Create();
</script>

Hier finden Sie weitere Beispiele zum Erfassen der Erfassung von HTML-Elementen . Für die vollständige Offenlegung bin ich der API-Ersteller.


Es ist keine Freeware
Amirhossein Tarmast

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>

Zitat


1

Es ist zu einfach, dass Sie diesen Code verwenden können, um den Screenshot eines bestimmten Bereichs zu erfassen, in dem Sie die Div-ID in html2canvas definieren müssen. Ich benutze hier 2 div-:

div id = "Auto"
div id = "chartContainer"
Wenn Sie nur Autos erfassen möchten, dann verwenden Sie Auto. Ich erbebe hier nur Auto. Sie können chartContainer für die Erfassung des Diagramms ändern. Html2canvas ($ ( '#car') Kopieren Sie diesen Code und fügen Sie ihn ein

<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
Warum ist jQuery zweimal enthalten und warum ist die jQuery-Benutzeroberfläche enthalten? Ehrlich gesagt wird jQuery hier überhaupt nicht benötigt, soweit ich das beurteilen kann. document.getElementById('car')oderdocument.querySelector('#car')
Nathan

Eigentlich arbeite ich an meinem Projekt. Also vergesse ich einfach, die Bibliothek zu entfernen und nichts.
Rudra Pratap Singh

0

Soweit ich weiß, können Sie das nicht, ich kann mich irren. Allerdings würde ich dies mit PHP tun, ein JPEG mit PHP-Standardfunktionen erzeugen und dann das Bild anzeigen, sollte keine sehr schwierige Aufgabe sein, hängt jedoch davon ab, wie auffällig der Inhalt des DIV ist


Das OP hat nie vorgeschlagen, dass er serverseitige Verarbeitung verwendet. Wenn dies jedoch der Fall wäre, wäre dies in Ordnung.
Delan Azabani

Ja, ich kann leider keine serverseitigen Inhalte verwenden. Ich werde wahrscheinlich mit einer der obigen Antworten gehen. Aber danke! :)
Nathan

-3

Soweit ich weiß, ist dies mit Javascript nicht möglich.

Was Sie für jedes Ergebnis tun können, erstellen Sie einen Screenshot, speichern Sie ihn irgendwo und zeigen Sie dem Benutzer, wenn Sie auf Ergebnis speichern klicken. (Ich denke, kein Ergebnis ist nur 10, also keine große Sache, um ein 10-JPEG-Bild der Ergebnisse zu erstellen.)


Danke für die Antwort :) Du hast recht! Ich könnte einfach 10 JPG-Bilder der Ergebnisse erstellen und sobald sie auf die Schaltfläche klicken, wird das Bild angezeigt, damit sie es speichern können. Das einzige Problem ist, dass sie beim Starten des Quiz ihren Namen eingeben müssen. Ich zeige ihn während des gesamten Quiz an. Am Ende des Ergebnisfelds wird ihr Name angezeigt und ein Kommentar wie "Getting Better" angezeigt. usw. Ich könnte den Namen nicht ins Bild setzen, oder?
Nathan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.