283 votes

Comment enregistrer un Canvas HTML5 en tant qu'image sur un serveur ?

Je travaille sur un projet d'art génératif dans lequel j'aimerais permettre aux utilisateurs d'enregistrer les images résultant d'un algorithme. L'idée générale est la suivante :

  • Créer une image sur un Canvas HTML5 en utilisant un algorithme génératif
  • Lorsque l'image est terminée, permettez aux utilisateurs d'enregistrer le canevas en tant que fichier image sur le serveur.
  • Permettez à l'utilisateur de télécharger l'image ou de l'ajouter à une galerie de pièces produites à l'aide de l'algorithme.

Cependant, je suis bloqué à la deuxième étape. Après un peu d'aide de Google, j'ai trouvé ceci article de blog ce qui semblait être exactement ce que je voulais :

Ce qui a conduit au code JavaScript :

function saveImage() {
  var canvasData = canvas.toDataURL("image/png");
  var ajax = new XMLHttpRequest();

  ajax.open("POST", "testSave.php", false);
  ajax.onreadystatechange = function() {
    console.log(ajax.responseText);
  }
  ajax.setRequestHeader("Content-Type", "application/upload");
  ajax.send("imgData=" + canvasData);
}

et le PHP correspondant (testSave.php) :

<?php
if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) {
  $imageData = $GLOBALS['HTTP_RAW_POST_DATA'];
  $filteredData = substr($imageData, strpos($imageData, ",") + 1);
  $unencodedData = base64_decode($filteredData);
  $fp = fopen('/path/to/file.png', 'wb');

  fwrite($fp, $unencodedData);
  fclose($fp);
}
?>

Mais cela ne semble rien faire du tout.

En cherchant sur Google, on trouve ceci article de blog qui est basé sur le tutoriel précédent. Ce n'est pas très différent, mais cela vaut peut-être la peine d'essayer :

$data = $_POST['imgData'];
$file = "/path/to/file.png";
$uri = substr($data,strpos($data, ",") + 1);

file_put_contents($file, base64_decode($uri));
echo $file;

Celui-ci crée un fichier (yay) mais il est corrompu et ne semble pas contenir quoi que ce soit. Il semble également être vide (taille de fichier de 0).

Y a-t-il quelque chose de vraiment évident que je fais mal ? Le chemin où je stocke mon fichier est accessible en écriture, donc ce n'est pas un problème, mais rien ne semble se produire et je ne sais pas vraiment comment déboguer cela.

Editar

En suivant le lien de Salvidor Dali, j'ai modifié la requête AJAX comme suit :

function saveImage() {
  var canvasData = canvas.toDataURL("image/png");
  var xmlHttpReq = false;

  if (window.XMLHttpRequest) {
    ajax = new XMLHttpRequest();
  }
  else if (window.ActiveXObject) {
    ajax = new ActiveXObject("Microsoft.XMLHTTP");
  }

  ajax.open("POST", "testSave.php", false);
  ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  ajax.onreadystatechange = function() {
    console.log(ajax.responseText);
  }
  ajax.send("imgData=" + canvasData);
}

Et maintenant le fichier image est créé et n'est pas vide ! Il semble que le type de contenu soit important et que le fait de le changer en x-www-form-urlencoded a permis d'envoyer les données de l'image.

La console renvoie la chaîne (assez grande) de code base64 et le fichier de données fait ~140 kB. Cependant, je ne peux toujours pas l'ouvrir et il semble ne pas être formaté comme une image.

0 votes

Le premier article de blog que vous avez fourni utilise ajax.send(canvasData ); alors que vous l'utilisez comme ajax.send("imgData="+canvasData); . Par conséquent, $GLOBALS["HTTP_RAW_POST_DATA"] ne sera pas ce que vous attendez, vous devriez probablement utiliser $_POST['imgData'] .

0 votes

0 votes

Diodeus : J'utilise déjà la technique qui a été suggérée dans ce fil de discussion ; cependant, ils n'ont pas fourni de détails supplémentaires sur la mise en œuvre et c'est là que je suis bloqué.

262voto

Salvador Dali Points 11667

Voici un exemple de la façon d'obtenir ce dont vous avez besoin :

  1. Dessinez quelque chose (extrait de tutoriel sur la toile )

    <canvas id="myCanvas" width="578" height="200"></canvas> <script> var canvas = document.getElementById('myCanvas'); var context = canvas.getContext('2d');

    // begin custom shape context.beginPath(); context.moveTo(170, 80); context.bezierCurveTo(130, 100, 130, 150, 230, 150); context.bezierCurveTo(250, 180, 320, 180, 340, 150); context.bezierCurveTo(420, 150, 420, 120, 390, 100); context.bezierCurveTo(430, 40, 370, 30, 340, 50); context.bezierCurveTo(320, 5, 250, 20, 250, 50); context.bezierCurveTo(200, 5, 150, 20, 170, 80);

    // complete custom shape context.closePath(); context.lineWidth = 5; context.fillStyle = '#8ED6FF'; context.fill(); context.strokeStyle = 'blue'; context.stroke(); </script>

  2. Convertir l'image du canevas au format URL (base64)

    var dataURL = canvas.toDataURL() ;

  3. Envoyez-le à votre serveur via Ajax

    $.ajax({
      type: "POST",
      url: "script.php",
      data: { 
         imgBase64: dataURL
      }
    }).done(function(o) {
      console.log('saved'); 
      // If you want the file to be visible in the browser 
      // - please modify the callback in javascript. All you
      // need is to return the url to the file, you just saved 
      // and than put the image in your browser.
    });
  4. Enregistrez base64 sur votre serveur comme une image (voici comment faire cela en PHP les mêmes idées se retrouvent dans toutes les langues. Le côté serveur en PHP peut être trouvé ici ):

1 votes

Je veux dire que le fichier est là mais qu'il ne s'ouvre pas dans mon navigateur ou dans une visionneuse d'images si je le télécharge.

0 votes

You send it to your server as an ajax request Cette méthode nécessite-t-elle la confirmation de l'utilisateur ? Ou puis-je envoyer silencieusement l'image du canevas au serveur ?

0 votes

J'obtiens une erreur dans la console Web. [16:53:43.227] SecurityError : L'opération n'est pas sécurisée. @ sharevi.com/staging/canvas.html:43 Cette connexion n'est pas sécurisée. Y a-t-il quelque chose à faire ? /// MISE À JOUR Je pense savoir pourquoi, j'utilisais des images inter-domaines.

72voto

user568021 Points 429

J'ai joué avec ça deux semainesIs palgaoy,e di tw'ist hv etrhyi ss itmwpol ew.e eTkhse aognol,y iptr'osb lveemr yi ss itmIhp alptel . aa ylTelhd e t whoient lhty u ttphorirosib altlewsmo jiwuses ettk hsta atal gkao l,al b iottuh'tes stvauevtrioynr gis aitlmhspe l jeiu. ms atTg hete a llooknc laaylb lopyur.to bTslhaeivmsi niigss tthhoeaw t i Ima aldglie d t lhioetc :atlultyo.r iTahliss jiuss th otwa lIk daibdo uitt :saving the image locally. Voici comment j'ai procédé : j'ai joué avec ça il y a deux semaines, c'est très simple. Le seul problème est que tous les tutoriels ne parlent que de sauvegarder l'image localement. Voici comment j'ai procédé :

1) J'ai configuré un formulaire pour pouvoir utiliser la méthode POST.

2) Lorsque l'utilisateur a fini de dessiner, il peut cliquer sur le bouton "Enregistrer".

3) Lorsque le bouton est cliqué, je prends les données de l'image et les place dans un champ caché. Après cela, je soumets le formulaire.

document.getElementById('my_hidden').value = canvas.toDataURL('image/png');
document.forms["form1"].submit();

4) Lorsque le formulaire est soumis, j'ai ce petit php script :

<?php 
$upload_dir = somehow_get_upload_dir();  //implement this function yourself
$img = $_POST['my_hidden'];
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = $upload_dir."image_name.png";
$success = file_put_contents($file, $data);
header('Location: '.$_POST['return_url']);
?>

1 votes

Est-ce que je peux utiliser canvas.toDataURL() ? J'ai une extension de fichier dynamique, comme jpeg, png, gif. J'ai essayé canvas.toDataURL('image/jpg') mais cela ne fonctionne pas. Quel est le problème ?

0 votes

J'obtenais l'erreur 413 (request too large) en essayant d'envoyer une image depuis le canevas par AJAX. Cette approche m'a permis de faire passer les images.

1 votes

Pourquoi celui-ci me donne-t-il un fichier png de 0kb ?

9voto

MaloMax Points 1

Si vous voulez sauvegarder des données qui sont dérivées d'un Javascript canvas.toDataURL() vous devez convertir les blancs en positifs. Si vous ne le faites pas, les données décodées sont corrompues :

<?php
  $encodedData = str_replace(' ','+',$encodedData);
  $decocedData = base64_decode($encodedData);
?>

http://php.net/manual/ro/function.base64-decode.php

4voto

Ardine Points 24

En plus de la réponse de Salvador Dali :

du côté du serveur, n'oubliez pas que les données sont en base64. chaîne de caractères format. C'est important car, dans certains langages de programmation, il faut dire explicitement que cette chaîne doit être considérée comme octets pas une simple chaîne Unicode.

Sinon, le décodage ne fonctionnera pas : l'image sera enregistrée mais ce sera un fichier illisible.

1voto

anonymoushelper Points 11

Ça a marché pour moi. C'est une approche différente mais ça marche. En gros, il utilise javascript pour créer une "capture d'écran" ou une recréation en pixels du contenu d'un div cible, puis l'enregistre sur votre serveur avec un formulaire et un fichier php.

Il n'est pas toujours précis et ne capture pas les iframes mais est utile pour les toiles et d'autres éléments.

http://www.kubilayerdogan.net/?p=304

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X