Capturer HTML Canvas au format gif / jpg / png / pdf?

719

Est-il possible de capturer ou d'imprimer ce qui est affiché dans un canevas html en tant qu'image ou pdf?

J'aimerais générer une image via canvas et pouvoir générer un png à partir de cette image.

Parand
la source
Voici une solution pythonique: stackoverflow.com/questions/19395649/… en plus de répondre stackoverflow.com/a/3514404/529442
Eugene Gr. Philippov
Exemple ici freakyjolly.com/…
Code Spy
1
La bibliothèque canvas2image peut vous être utile pour cela: github.com/hongru/canvas2image
noego

Réponses:

737

Oops. La réponse originale était spécifique à une question similaire. Cela a été révisé:

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

avec la valeur dans IMG, vous pouvez l'écrire comme une nouvelle image comme ceci:

document.write('<img src="'+img+'"/>');
donohoe
la source
15
une autre question, comment puis-je enregistrer l'image que j'ai obtenue dans cette balise sur le serveur. Toute proposition??
Surya
7
Mais si j'utilise var img = canvas.toDataURL ("image / jpeg"); je reçois l'arrière-plan en noir complet. Comment y remédier
gauti
181
Oh allez. J'ai répondu à cela en 2009. Qu'attendez-vous?
donohoe
35
@donohoe vous y avez répondu en août 2010 :)
nick
13
Cela utiliserait beaucoup moins de mémoire pour faire quelque chose comme ça var img = new Image(); img.src = canvas.toDataURL(); document.body.appendChild(img);. Le document.writecode crée l'URL des données, les crée une chaîne HTML, puis met une copie de cette chaîne dans le DOM, le navigateur doit ensuite analyser cette chaîne HTML, mettre une autre copie sur l'élément image, puis l'analyser à nouveau pour activer URL de données en données d'image, puis enfin il peut afficher l'image. Pour une image de taille d'écran, c'est une énorme quantité de mémoire / copie / analyse. Juste une suggestion
gman
116

HTML5 fournit Canvas.toDataURL (mimetype) qui est implémenté dans Opera, Firefox et Safari 4 beta. Il existe cependant un certain nombre de restrictions de sécurité (principalement liées au dessin de contenu d'une autre origine sur le canevas).

Vous n'avez donc pas besoin d'une bibliothèque supplémentaire.

par exemple

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

Théoriquement, cela devrait créer puis naviguer vers une image avec un carré vert au milieu, mais je n'ai pas testé.

olliej
la source
2
Où l'image sera enregistrée. Emplacement dans mon local?
chinna_82
5
l'image sera affichée sous forme d'image dans votre navigateur. Vous pouvez ensuite l'enregistrer sur disque ou autre. Voici un bookmarklet générique "Canvas2PNG" rapide et sale qui convertit le premier canevas de la page en PNG et l'affiche dans le navigateur dans une nouvelle fenêtre:javascript:void(window.open().location = document.getElementsByTagName("canvas")[0].toDataURL("image/png"))
Kai Carver
Si l'image fait quelques Mo, préparez-vous à planter votre navigateur (je l'ai fait il y a quelque temps dans FireFox).
jahu
1
Comment cela pourrait-il être modifié pour rendre plusieurs images?
Mentalist
Les URI de données ont une longueur maximale, il y a donc une limite supérieure à la taille d'une image que vous pouvez mettre dans une URL de données.
Juha Syrjälä
44

J'ai pensé étendre un peu la portée de cette question, avec quelques détails utiles sur la question.

Pour obtenir la toile en tant qu'image, vous devez procéder comme suit:

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

Vous pouvez l'utiliser pour écrire l'image sur la page:

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

Où "image / png" est un type mime (png est le seul qui doit être pris en charge). Si vous souhaitez un tableau des types pris en charge, vous pouvez faire quelque chose dans le sens de ceci:

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

Vous n'avez besoin de l'exécuter qu'une fois par page - cela ne devrait jamais changer tout au long du cycle de vie d'une page.

Si vous souhaitez que l'utilisateur télécharge le fichier tel qu'il est enregistré, vous pouvez procéder comme suit:

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;

Si vous l'utilisez avec différents types de mime, assurez-vous de modifier les deux instances de image / png, mais pas le flux image / octet. Il convient également de mentionner que si vous utilisez des ressources interdomaines pour le rendu de votre canevas, vous rencontrerez une erreur de sécurité lorsque vous essayez d'utiliser la méthode toDataUrl.

meiamsome
la source
1
Avec votre solution de téléchargement du fichier, je dois choisir le logiciel que je souhaite utiliser, c'est un peu gênant ... Existe-t-il un moyen de remplacer le mime en png une fois téléchargé?
So4ne
1
@ So4ne Je ne pense pas, ce doit être une image / un flux d'octets pour inviter l'utilisateur à télécharger. Si vous vous débarrassez de cette ligne, vous vous retrouverez avec la page redirigée vers l'image. J'aimerais bien savoir si quelqu'un d'autre connaît un moyen de le faire bien.
meiamsome
2
en utilisant target = "_ blank" sur le lien <a> et .click () cela devrait aussi fonctionner pour déclencher le téléchargement (testé avec FF data-urls et download = "filename" pour text / csv et text / plain)
Ax3l
C'est bien. Merci! Mais que se passe-t-il si je souhaite enregistrer sur le serveur et non local? Une entrée de fichier de formulaire acceptera-t-elle l'img src comme quelque chose qui peut être téléchargé?
Chief Alchemist
Oops. Je viens de trouver la réponse. Laissant la question précédente au cas où quelqu'un d'autre regarderait aussi 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
la source
Le fichier enregistré reste au format .svg. Comment l'enregistrer au format png?
nullpointer
C'est une bonne solution, sauf qu'elle peut ne pas fonctionner sur IE. Erreur "La zone de données transmise à un appel système est trop petite"
Jose Cherian
Dans Chrome, il indique "Erreur réseau", tandis que dans Firefox, cela fonctionne très bien. (Sous Linux)
Ecker00
20

J'utiliserais " wkhtmltopdf ". Cela fonctionne très bien. Il utilise le moteur webkit (utilisé dans Chrome, Safari, etc.), et il est très facile à utiliser:

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

C'est ça!

Essayez-le

lepe
la source
1
Je suis aussi dans le camp wkhtmltopdf. Nous l'avons utilisé pour l'archivage et son incroyable.
Daniel Szabo
Comment utiliser WKHTMLtoPDF dans une page nécessitant des informations de connexion? J'utilise Jsreport pour convertir au format PDF mais je capture mon contenu avec HTML2Canvas, j'ai des problèmes avec l'envoi du canevas en tant que paramètre à JSreport
khaled Dehia
@khaledDehia check: stackoverflow.com/questions/10287386/…
lepe
15

Voici une aide si vous effectuez le téléchargement via un serveur (de cette façon, vous pouvez nommer / convertir / post-traiter / etc votre fichier):

-Publier des données en utilisant toDataURL

-Réglez les en-têtes

$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");

-créer une image

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

-exporter l'image au format JPEG

$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();

-ou en PNG transparent

imagesavealpha($img, true);
imagepng($img);
die($img);
Communauté
la source
9

Une autre solution intéressante est PhantomJS . C'est un WebKit sans tête scriptable avec JavaScript ou CoffeeScript.

L'un des cas d'utilisation est la capture d'écran: vous pouvez capturer par programme des contenus Web, y compris SVG et Canvas et / ou créer des captures d'écran de sites Web avec aperçu des vignettes.

Le meilleur point d'entrée est la page wiki de capture d'écran .

Voici un bon exemple pour l'horloge polaire (de RaphaelJS):

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

Voulez-vous rendre une page au format PDF?

> phantomjs rasterize.js 'http://en.wikipedia.org/w/index.php?title=Jakarta&printable=yes' jakarta.pdf
Cybermaxs
la source
2
+1: PhantomJS est un système simple, bien documenté et bien pensé, parfait pour ce travail. Il permet bien plus que de simplement saisir une toile - par exemple, vous pouvez modifier la page ou une partie de celle-ci (via JS) avant de la saisir, alors faites-la ressembler exactement à ce que vous voulez. Parfait!
johndodo
1
PhantomJs est désormais obsolète
Merc
3

Si vous utilisez jQuery, ce que font beaucoup de gens, alors vous implémenteriez la réponse acceptée comme suit:

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

$("#elememt-to-write-to").html('<img src="'+img+'"/>');
Pattle
la source
12
Notez que le seul usage de jQuery ici est la sélection du canevas. .toDataURLest natif JS.
j6m8
J'ai un problème de sauvegarde, quelqu'un peut m'aider à voir ce lien: stackoverflow.com/questions/25131763/…
Ramesh S
2
La solution jQuery pure (100%) est la suivante: $('<img>').attr('src',$('#mycanvas')[0].toDataURL('image/png')).appendTo($('#element-to-write-to').empty());Exactement une ligne.
Naeel Maqsudov
1

Vous pouvez utiliser jspdf pour capturer un canevas dans une image ou pdf comme ceci:

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

Plus d'informations: https://github.com/MrRio/jsPDF

ferralucho
la source
1

C'est l'inverse, sans cordes même si je ne sais pas vraiment si c'est plus rapide ou non. Au lieu de toDataURL (comme toutes les questions proposées ici). Dans mon cas, je veux empêcher dataUrl / base64 car j'ai besoin d'un tampon ou d'une vue de tableau. Donc, l'autre méthode dans HTMLCanvasElement est toBlob. (Fonction TypeScript):

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

Un autre avantage des blobs est que vous pouvez créer des ObjectUrls pour représenter les données sous forme de fichiers, similaire au membre «files» de HTMLInputFile. Plus d'informations:

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

cancerbero
la source
-1

Sur certaines versions de Chrome, vous pouvez:

  1. Utilisez la fonction de dessin d'image ctx.drawImage(image1, 0, 0, w, h);
  2. Faites un clic droit sur la toile
Peter
la source