web-dev-qa-db-fra.com

Convertir le canevas HTML5 en fichier à télécharger?

Le téléchargement de fichier HTML standard fonctionne comme suit:

<g:form method="post" accept-charset="utf-8" enctype="multipart/form-data"  
     name="form" url="someurl">

    <input type="file" name="file" id="file" />

</form>

Dans mon cas, j'ai chargé une image dans une toile html5 et je souhaite la soumettre sous forme de fichier au serveur. Je peux faire:

var canvas; // some canvas with an image
var url = canvas.toDataURL();

Cela me donne une image/png comme base64.

Comment puis-je envoyer l'image base64 au serveur de la même manière que pour le fichier de type d'entrée?

Le problème est que le fichier base64 n'est pas du même type que le fichier, qui se trouve à l'intérieur du type d'entrée = "fichier".

Puis-je convertir le base64 que les types sont les mêmes pour le serveur?

52
confile

Pour des raisons de sécurité, vous ne pouvez pas définir directement la valeur d'un élément d'entrée de fichier.

Si vous souhaitez utiliser un élément d'entrée de fichier:

  1. Créez une image à partir de la toile (comme vous l'avez fait).
  2. Afficher cette image sur une nouvelle page.
  3. Demandez à l'utilisateur de cliquer avec le bouton droit de la souris sur le lecteur local.
  4. Ils peuvent ensuite utiliser votre élément file-input pour télécharger le fichier nouvellement créé.

Alternativement, vous pouvez utiliser Ajax pour POST les données de la toile:

Vous avez demandé à propos de blob:

var blobBin = atob(dataURL.split(',')[1]);
var array = [];
for(var i = 0; i < blobBin.length; i++) {
    array.Push(blobBin.charCodeAt(i));
}
var file=new Blob([new Uint8Array(array)], {type: 'image/png'});


var formdata = new FormData();
formdata.append("myNewFileName", file);
$.ajax({
   url: "uploadFile.php",
   type: "POST",
   data: formdata,
   processData: false,
   contentType: false,
}).done(function(respond){
  alert(respond);
});

Remarque: le blob est généralement pris en charge par les derniers navigateurs.

51
markE

L'image de la zone de dessin doit être convertie en base64, puis de base64 en binaire. Ceci est fait en utilisant .toDataURL() et dataURItoBlob()

C’était un processus fastidieux qui nécessitait de rassembler plusieurs SO réponses, divers articles de blogues et tutoriels).

J'ai créé un tutoriel que vous pouvez suivre pour vous guider dans le processus .

En réponse au commentaire d'Ateik, voici n violon , qui reproduit le message d'origine au cas où vous auriez du mal à visualiser le lien d'origine. Vous pouvez aussi brancher mon projet ici .

Il y a beaucoup de code, mais l'essentiel de ce que je fais est de prendre un élément canvas:

<canvas id="flatten" width="800" height="600"></canvas>

Définir son contexte en 2D

var snap = document.getElementById('flatten');
var flatten = snap.getContext('2d');

Canvas => Base64 => Binary

function postCanvasToURL() {
  // Convert canvas image to Base64
  var img = snap.toDataURL();
  // Convert Base64 image to binary
  var file = dataURItoBlob(img);
}

function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
    byteString = atob(dataURI.split(',')[1]);
else
    byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}

Vous pouvez vous arrêter en base64 si c'est tout ce dont vous avez besoin. Dans mon cas, j'avais besoin de convertir à nouveau en binaire afin de pouvoir transférer les données sur Twitter (à l'aide de OAuth) sans utiliser de base de données. Il s'avère que vous pouvez tweeter en binaire, ce qui est plutôt cool. Twitter le reconvertira en une image.

25
Pixelomo

Actuellement dans les spécifications (très peu de soutien en avril 17)

Canvas.toBlob();

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob

MODIFIER :

Le lien fournit un polyfill (ce qui semble être plus lent dans la formulation), ce code est très équivalent à la réponse @pixelomo, mais avec le même api que la méthode native toBlob:

Un polyfill basse performance basé sur toDataURL:

if (!HTMLCanvasElement.prototype.toBlob) {
  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value: function (callback, type, quality) {
      var canvas = this;
      setTimeout(function() {

    var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] ),
        len = binStr.length,
        arr = new Uint8Array(len);

    for (var i = 0; i < len; i++ ) {
      arr[i] = binStr.charCodeAt(i);
    }

    callback( new Blob( [arr], {type: type || 'image/png'} ) );

      });
    }
  });
}

Pour être utilisé de cette façon:

canvas.toBlob(function(blob){...}, 'image/jpeg', 0.95); // JPEG at 95% quality

ou

canvas.toBlob(function(blob){...}); // PNG
9
Danie A

Une autre solution: envoyer les données en var url dans un champ caché, les décoder et les sauvegarder sur le serveur.

Exemple dans Python Django:

if form.is_valid():
    url = form.cleaned_data['url']
    url_decoded = b64decode(url.encode())        
    content = ContentFile(url_decoded) 
    your_model.model_field.save('image.png', content)
8
Ardine