309 votes

Convertir l'URI de données en fichier puis ajouter à FormData

J'ai essayé de ré-implémenter un HTML5 image uploader comme celui sur la Mozilla Hacks site, mais qui fonctionne avec les navigateurs WebKit. Une partie de la tâche consiste à extraire d'un fichier image à partir de l' canvas objet et l'ajouter à un FormData objet pour le téléchargement.

Le problème est que tout canvas a toDataURL fonction pour renvoyer une représentation de l'image du fichier, l'objet FormData n'accepte que des Fichiers ou des objets Blob à partir du Fichier de l'API.

La Mozilla solution utilisé Firefox ne fonctionne que sur canvas:

var file = canvas.mozGetAsFile("foo.png");

...ce qui n'est pas disponible sur les navigateurs WebKit. La meilleure solution je pense est de trouver le moyen de convertir un URI dans un Fichier objet, j'ai pensé que peut-être partie du Fichier de l'API, mais je ne peux pas pour la vie de me trouver quelque chose à faire.

Est-il possible? Si non, des alternatives?

Merci.

514voto

Stoive Points 3723

Après avoir joué avec quelques trucs, j'ai réussi à comprendre cela moi-même.

Tout d'abord, cela va convertir un dataURI en un blob:

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

De là, ajouter les données à un formulaire tel qu'il sera téléchargé en tant que fichier est facile:

 var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
 

149voto

vava720 Points 791

BlobBuilder et ArrayBuffer sont maintenant obsolètes, voici le code du commentaire le plus haut mis à jour avec le constructeur Blob:

 function dataURItoBlob(dataURI) {
    var binary = atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}
 

54voto

William T. Points 1879

Celui-ci fonctionne dans iOS et Safari.

Vous devez utiliser la solution ArrayBuffer de Stoive, mais vous ne pouvez pas utiliser BlobBuilder, comme l'indique vava720, alors voici le mashup des deux.

 function dataURItoBlob(dataURI) {
    var byteString = atob(dataURI.split(',')[1]);
    var ab = new ArrayBuffer(byteString.length);
    var ia = new Uint8Array(ab);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ab], { type: 'image/jpeg' });
}
 

20voto

john locke Points 1666

Grâce à @Stoive et @ vava720, j'ai combiné les deux de cette façon, évitant d'utiliser les BlobBuilder et ArrayBuffer obsolètes

 function dataURItoBlob(dataURI) {
    'use strict'
    var byteString, 
        mimestring 

    if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
        byteString = atob(dataURI.split(',')[1])
    } else {
        byteString = decodeURI(dataURI.split(',')[1])
    }

    mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]

    var content = new Array();
    for (var i = 0; i < byteString.length; i++) {
        content[i] = byteString.charCodeAt(i)
    }

    return new Blob([new Uint8Array(content)], {type: mimestring});
}
 

12voto

Chris Bosco Points 469

L'évolution de la norme semble être la toile.toBlob() pas de toile.getAsFile() comme Mozilla exposé à deviner.

Je ne vois pas de n'importe quel navigateur encore le soutien :(

Merci pour ce grand fil!

Aussi, toute personne essayant accepté la réponse devrait être prudent avec BlobBuilder comme je suis la recherche de soutien à limiter (et des espaces):

    var bb;
    try {
        bb = new BlobBuilder();
    } catch(e) {
        try {
            bb = new WebKitBlobBuilder();
        } catch(e) {
            bb = new MozBlobBuilder();
        }
    }

Avez-vous été à l'aide d'une autre bibliothèque du polyfill pour BlobBuilder?

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