HTML-Canvas als gif / jpg / png / pdf erfassen?

719

Ist es möglich, das, was auf einer HTML-Leinwand angezeigt wird, als Bild oder PDF zu erfassen oder zu drucken?

Ich möchte ein Bild über Leinwand erzeugen und aus diesem Bild ein PNG generieren können.

Parand
quelle
Hier ist eine pythonische Lösung: stackoverflow.com/questions/19395649/… zusätzlich zur Antwort stackoverflow.com/a/3514404/529442
Eugene Gr. Philippov
Beispiel hier freakyjolly.com/…
Code Spy
1
Möglicherweise finden Sie die canvas2image-Bibliothek dafür nützlich: github.com/hongru/canvas2image
noego

Antworten:

737

Hoppla. Die ursprüngliche Antwort war spezifisch für eine ähnliche Frage. Dies wurde überarbeitet:

var canvas = document.getElementById("mycanvas");
var img    = canvas.toDataURL("image/png");

Mit dem Wert in IMG können Sie es wie folgt als neues Bild ausschreiben:

document.write('<img src="'+img+'"/>');
Donohoe
quelle
15
Noch eine Frage: Wie kann ich das Bild, das ich in diesem Tag erhalten habe, auf dem Server speichern? Irgendwelche Ideen??
Surya
7
Aber wenn ich var img = canvas.toDataURL ("image / jpeg") benutze; bekomme den Hintergrund als komplett schwarz. Wie man das korrigiert
Gauti
181
Ach komm schon. Ich habe dies 2009 beantwortet. Was erwarten Sie?
Donohoe
35
@donohoe eigentlich hast du es im August 2010 beantwortet :)
Nick
13
Es würde viel weniger Speicher benötigen, um so etwas zu tun var img = new Image(); img.src = canvas.toDataURL(); document.body.appendChild(img);. Der document.writeCode erstellt die Daten-URL, erstellt eine HTML-Zeichenfolge und fügt dann eine Kopie dieser Zeichenfolge in das DOM ein. Der Browser muss dann diese HTML-Zeichenfolge analysieren, eine weitere Kopie in das Bildelement einfügen und sie dann erneut analysieren, um die zu ändern Daten-URL in Bilddaten, dann kann es endlich das Bild anzeigen. Für ein Bild in Bildschirmgröße ist das eine große Menge an Speicher / Kopieren / Parsen. Nur ein Vorschlag
Gman
116

HTML5 bietet Canvas.toDataURL (Mimetyp), das in der Beta von Opera, Firefox und Safari 4 implementiert ist. Es gibt jedoch eine Reihe von Sicherheitsbeschränkungen (hauptsächlich im Zusammenhang mit dem Zeichnen von Inhalten eines anderen Ursprungs auf die Leinwand).

Sie benötigen also keine zusätzliche Bibliothek.

z.B

 <canvas id=canvas width=200 height=200></canvas>
 <script>
      window.onload = function() {
          var canvas = document.getElementById("canvas");
          var context = canvas.getContext("2d");
          context.fillStyle = "green";
          context.fillRect(50, 50, 100, 100);
          // no argument defaults to image/png; image/jpeg, etc also work on some
          // implementations -- image/png is the only one that must be supported per spec.
          window.location = canvas.toDataURL("image/png");
      }
 </script>

Theoretisch sollte dies ein Bild mit einem grünen Quadrat in der Mitte erstellen und dann zu diesem navigieren, aber ich habe es nicht getestet.

olliej
quelle
2
Wo das Bild gespeichert wird. Lage in meiner Nähe?
Chinna_82
5
Das Bild wird in Ihrem Browser als Bild angezeigt. Sie können es dann auf der Festplatte oder was auch immer speichern. Hier ist ein schnelles und schmutziges generisches "Canvas2PNG" -Lesezeichen, das die erste Zeichenfläche auf der Seite in PNG konvertiert und im Browser in einem neuen Fenster anzeigt:javascript:void(window.open().location = document.getElementsByTagName("canvas")[0].toDataURL("image/png"))
Kai Carver
Wenn das Bild einige MB groß ist, bereiten Sie den Absturz Ihres Browsers vor (das habe ich vor einiger Zeit in FireFox getan).
Jahu
1
Wie kann dies geändert werden, um mehrere Bilder zu rendern?
Mentalist
Daten-URIs haben eine maximale Länge, daher gibt es eine Obergrenze für die Größe eines Bildes, das Sie einer Daten-URL hinzufügen können.
Juha Syrjälä
44

Ich dachte, ich würde den Umfang dieser Frage ein wenig erweitern, mit einigen nützlichen Details zu diesem Thema.

Um die Leinwand als Bild zu erhalten, sollten Sie Folgendes tun:

var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png");

Sie können dies verwenden, um das Bild auf die Seite zu schreiben:

document.write('<img src="'+image+'"/>');

Wobei "image / png" ein MIME-Typ ist (PNG ist der einzige, der unterstützt werden muss). Wenn Sie ein Array der unterstützten Typen möchten, können Sie Folgendes tun:

var imageMimes = ['image/png', 'image/bmp', 'image/gif', 'image/jpeg', 'image/tiff']; //Extend as necessary 
var acceptedMimes = new Array();
for(i = 0; i < imageMimes.length; i++) {
    if(canvas.toDataURL(imageMimes[i]).search(imageMimes[i])>=0) {
        acceptedMimes[acceptedMimes.length] = imageMimes[i];
    }
}

Sie müssen dies nur einmal pro Seite ausführen - es sollte sich niemals während des Lebenszyklus einer Seite ändern.

Wenn Sie möchten, dass der Benutzer die Datei beim Speichern herunterlädt, können Sie Folgendes tun:

var canvas = document.getElementById("mycanvas");
var image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); //Convert image to 'octet-stream' (Just a download, really)
window.location.href = image;

Wenn Sie dies mit verschiedenen MIME-Typen verwenden, müssen Sie beide Instanzen von image / png ändern, nicht jedoch den image / octet-Stream. Erwähnenswert ist auch, dass bei der Verwendung der toDataUrl-Methode ein Sicherheitsfehler auftritt, wenn Sie beim Rendern Ihrer Zeichenfläche domänenübergreifende Ressourcen verwenden.

meiamsome
quelle
1
Bei Ihrer Lösung zum Herunterladen der Datei muss ich die Software auswählen, die ich verwenden möchte. Dies ist etwas unpraktisch. Gibt es eine Möglichkeit, die MIME als PNG nach dem Herunterladen wieder zu ersetzen?
So4ne
1
@ So4ne Ich glaube nicht, es muss ein Bild- / Oktett-Stream sein, um den Benutzer zum Herunterladen aufzufordern. Wenn Sie diese Zeile entfernen, wird die Seite zum Bild umgeleitet. Ich würde gerne wissen, ob jemand anderes einen Weg kennt, dies gut zu machen.
Meiamsome
2
Mit target = "_ blank" auf <a> link und .click () sollte es auch funktionieren, um den Download auszulösen (getestet mit FF-Daten-URLs und download = "filename" für text / csv und text / plain)
Ax3l
Das ist toll. Vielen Dank! Aber was ist, wenn ich auf dem Server und nicht lokal speichern möchte? Akzeptiert eine Formulardateieingabe das img src als etwas, das hochgeladen werden kann?
Chef Alchemist
Hoppla. Habe gerade die Antwort gefunden. Lassen Sie die vorherige Frage für den Fall, dass jemand anderes ebenfalls nach stackoverflow.com/questions/13198131/…
Chief Alchemist
34
function exportCanvasAsPNG(id, fileName) {

    var canvasElement = document.getElementById(id);

    var MIME_TYPE = "image/png";

    var imgURL = canvasElement.toDataURL(MIME_TYPE);

    var dlLink = document.createElement('a');
    dlLink.download = fileName;
    dlLink.href = imgURL;
    dlLink.dataset.downloadurl = [MIME_TYPE, dlLink.download, dlLink.href].join(':');

    document.body.appendChild(dlLink);
    dlLink.click();
    document.body.removeChild(dlLink);
}
david.barkhuizen
quelle
Die gespeicherte Datei bleibt im SVG-Format. Wie speichere ich es als PNG?
Nullzeiger
Dies ist eine nette Lösung, außer dass sie im IE möglicherweise nicht funktioniert. Fehler "Der an einen Systemaufruf übergebene Datenbereich ist zu klein"
Jose Cherian
In Chrome heißt es "Netzwerkfehler", während es in Firefox hervorragend funktioniert. (Unter Linux)
Ecker00
20

Ich würde " wkhtmltopdf " verwenden. Es funktioniert einfach großartig. Es verwendet die Webkit-Engine (in Chrome, Safari usw. verwendet) und ist sehr einfach zu verwenden:

wkhtmltopdf stackoverflow.com/questions/923885/ this_question.pdf

Das ist es!

Versuch es

Lepe
quelle
1
Ich bin auch im wkhtmltopdf-Lager. Wir haben es für die Archivierung und seine erstaunliche verwendet.
Daniel Szabo
Wie verwende ich WKHTMLtoPDF auf einer Seite, für die Anmeldeinformationen erforderlich sind? Ich verwende Jsreport zum Konvertieren in PDF, aber ich erfasse meinen Inhalt mit HTML2Canvas. Ich habe Probleme beim Senden des Canvas als Parameter an JSreport
khaled Dehia
@ KhaledDehia überprüfen: stackoverflow.com/questions/10287386/…
Lepe
15

Hier ist eine Hilfe, wenn Sie den Download über einen Server durchführen (auf diese Weise können Sie Ihre Datei benennen / konvertieren / nachbearbeiten / usw.):

-Postdaten mit toDataURL

-Stellen Sie die Header

$filename = "test.jpg"; //or png
header('Content-Description: File Transfer');
if($msie = !strstr($_SERVER["HTTP_USER_AGENT"],"MSIE")==false)      
  header("Content-type: application/force-download");else       
  header("Content-type: application/octet-stream"); 
header("Content-Disposition: attachment; filename=\"$filename\"");   
header("Content-Transfer-Encoding: binary"); 
header("Expires: 0"); header("Cache-Control: must-revalidate"); 
header("Pragma: public");

-Bild erstellen

$data = $_POST['data'];
$img = imagecreatefromstring(base64_decode(substr($data,strpos($data,',')+1)));

-Bild als JPEG exportieren

$width = imagesx($img);
$height = imagesy($img);
$output = imagecreatetruecolor($width, $height);
$white = imagecolorallocate($output,  255, 255, 255);
imagefilledrectangle($output, 0, 0, $width, $height, $white);
imagecopy($output, $img, 0, 0, 0, 0, $width, $height);
imagejpeg($output);
exit();

-oder als transparentes PNG

imagesavealpha($img, true);
imagepng($img);
die($img);
Gemeinschaft
quelle
9

Eine weitere interessante Lösung ist PhantomJS . Es ist ein kopfloses WebKit, das mit JavaScript oder CoffeeScript geschrieben werden kann.

Einer der Anwendungsfälle ist die Bildschirmaufnahme: Sie können programmgesteuert Webinhalte wie SVG und Canvas erfassen und / oder Website-Screenshots mit Miniaturansicht erstellen.

Der beste Einstiegspunkt ist die Bildschirmaufnahme- Wiki-Seite.

Hier ist ein gutes Beispiel für die Polaruhr (von RaphaelJS):

>phantomjs rasterize.js http://raphaeljs.com/polar-clock.html clock.png

Möchten Sie eine Seite als PDF rendern?

> phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf
Cybermaxs
quelle
2
+1: PhantomJS ist ein einfaches, gut dokumentiertes und durchdachtes System, perfekt für diesen Job. Es ermöglicht viel mehr als nur das Greifen einer Leinwand. Sie können beispielsweise die Seite oder einen Teil davon (über JS) vor dem Greifen ändern, damit sie genau so aussieht, wie Sie es möchten. Perfekt!
Johndodo
1
PhantomJs ist jetzt veraltet
Merc
3

Wenn Sie jQuery verwenden, was ziemlich viele Leute tun, würden Sie die akzeptierte Antwort folgendermaßen implementieren:

var canvas = $("#mycanvas")[0];
var img = canvas.toDataURL("image/png");

$("#elememt-to-write-to").html('<img src="'+img+'"/>');
Vieh
quelle
12
Beachten Sie, dass die einzige Verwendung von jQuery hier die Auswahl der Zeichenfläche ist. .toDataURList native JS.
j6m8
Ich habe ein Problem gespeichert. Jemand
Ramesh S
2
Die reine (100%) jQuery-Lösung lautet wie folgt: $('<img>').attr('src',$('#mycanvas')[0].toDataURL('image/png')).appendTo($('#element-to-write-to').empty());Genau eine Zeile.
Naeel Maqsudov
1

Sie können jspdf verwenden, um eine Leinwand in ein Bild oder PDF wie folgt aufzunehmen:

var imgData = canvas.toDataURL('image/png');              
var doc = new jsPDF('p', 'mm');
doc.addImage(imgData, 'PNG', 10, 10);
doc.save('sample-file.pdf');

Weitere Informationen: https://github.com/MrRio/jsPDF

Ferralucho
quelle
1

Dies ist der andere Weg, ohne Zeichenfolgen, obwohl ich nicht wirklich weiß, ob es schneller ist oder nicht. Anstelle von toDataURL (wie alle Fragen hier vorschlagen). In meinem Fall möchte ich dataUrl / base64 verhindern, da ich einen Array-Puffer oder eine Ansicht benötige. Die andere Methode in HTMLCanvasElement ist also toBlob. (TypeScript-Funktion):

    export function canvasToArrayBuffer(canvas: HTMLCanvasElement, mime: string): Promise<ArrayBuffer> {
  return new Promise((resolve, reject) => canvas.toBlob(async (d) => {
    if (d) {
      const r = new FileReader();
      r.addEventListener('loadend', e => {
        const ab = r.result;
        if (ab) {
          resolve(ab as ArrayBuffer);
        }
        else {
           reject(new Error('Expected FileReader result'));
        }
      }); r.addEventListener('error', e => {
        reject(e)
      });
      r.readAsArrayBuffer(d);
    }
    else {
      reject(new Error('Expected toBlob() to be defined'));
    }
  }, mime));
}

Ein weiterer Vorteil von Blobs besteht darin, dass Sie ObjectUrls erstellen können, um Daten als Dateien darzustellen, ähnlich wie bei HTMLInputFiles 'files'-Mitglied. Mehr Info:

https://developer.mozilla.org/es/docs/Web/API/HTMLCanvasElement/toBlob

Cancerbero
quelle
-1

Bei einigen Chrome-Versionen können Sie:

  1. Verwenden Sie die Funktion zum Zeichnen von Bildern ctx.drawImage(image1, 0, 0, w, h);
  2. Klicken Sie mit der rechten Maustaste auf die Leinwand
Peter
quelle