Convertir URI de données en Fichier, puis Ajouter à FormData
j'ai essayé de ré-implémenter un téléchargement d'image HTML5 comme celui sur le site Mozilla Hacks , mais cela fonctionne avec les navigateurs WebKit. Une partie de la tâche consiste à extraire un fichier image de l'objet canvas
et de l'ajouter à un FormData objet à télécharger.
le problème est que tandis que canvas
a la fonction toDataURL
pour retourner une représentation du fichier image, L'objet FormData accepte seulement Les objets File ou Blob de "File API .
la solution Mozilla utilisait la fonction Firefox suivante sur canvas
:
var file = canvas.mozGetAsFile("foo.png");
...qui n'est pas disponible sur les navigateurs WebKit. La meilleure solution que je puisse imaginer est de trouver un moyen de convertir un URI de données en un objet de fichier, qui je pensais pourrait faire partie de L'API de fichier, mais je ne peux pas pour la vie de moi trouver quelque chose à faire.
est-il possible? Si non, des alternatives?
Merci.
14 réponses
après avoir joué avec quelques trucs, j'ai réussi à le découvrir moi-même.
tout D'abord, cela convertira un dataURI en 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é comme un 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);
BlobBuilder et ArrayBuffer sont maintenant dépréciés, voici le code du Commentaire du Haut mis à jour avec Blob constructor:
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'});
}
celui-ci travaille à iOS et Safari.
vous devez utiliser la solution ArrayBuffer de Stoive mais vous ne pouvez pas utiliser BlobBuilder, comme vava720 indique, donc 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' });
}
Firefox a de la toile.toBlob () et canvas.méthodes mozGetAsFile ().
mais pas les autres navigateurs.
on peut obtenir des données à partir de canvas et ensuite convertir des données en objet blob.
voici ma fonction dataURLtoBlob (). C'est très court.
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
utilisez cette fonction avec FormData pour manipuler votre toile ou votre dataurl.
par exemple:
var dataurl = canvas.toDataURL('image/jpeg',0.8);
var blob = dataURLtoBlob(dataurl);
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");
vous pouvez aussi créer un HTMLCanvasElement.prototype.méthode toBlob pour navigateur moteur non gecko.
if(!HTMLCanvasElement.prototype.toBlob){
HTMLCanvasElement.prototype.toBlob = function(callback, type, encoderOptions){
var dataurl = this.toDataURL(type, encoderOptions);
var bstr = atob(dataurl.split(',')[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
var blob = new Blob([u8arr], {type: type});
callback.call(this, blob);
};
}
maintenant toile.toBlob () fonctionne pour tous les navigateurs modernes non seulement firefox. par exemple:
canvas.toBlob(
function(blob){
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");
//continue do something...
},
'image/jpeg',
0.8
);
grâce à @Stoive et @vava720 j'ai combiné les deux de cette façon, en évitant d'utiliser l'obsolète BlobBuilder et ArrayBuffer
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});
}
Ma voie préférée est toile.toBlob ()
mais en tout cas voici une autre façon de convertir base64 en blob en utilisant fetch ^^,
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
fetch(url)
.then(res => res.blob())
.then(blob => {
var fd = new FormData()
fd.append('image', blob, 'filename')
console.log(blob)
// Upload
// fetch('upload', {method: 'POST', body: fd})
})
le standard évolutif semble être toile.toBlob() pas de toile.getAsFile() comme Mozilla exposé à deviner.
Je ne vois pas encore de navigateur le supportant: (
Merci pour ce grand fil!
aussi, quiconque essaie la réponse acceptée devrait faire attention avec BlobBuilder car je trouve le support pour être limité (et namespaced):
var bb;
try {
bb = new BlobBuilder();
} catch(e) {
try {
bb = new WebKitBlobBuilder();
} catch(e) {
bb = new MozBlobBuilder();
}
}
utilisiez-vous un autre le polyfill de la bibliothèque pour BlobBuilder?
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);
peut être utilisé sans le try catch.
merci à check_ca. Un excellent travail.
la réponse originale de Stoive est facilement fixable en changeant la dernière ligne pour accommoder Blob:
function dataURItoBlob (dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
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 an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
return new Blob([ab],{type: mimeString});
}
Voici une version ES6 de réponse de Stoive :
export class ImageDataConverter {
constructor(dataURI) {
this.dataURI = dataURI;
}
getByteString() {
let byteString;
if (this.dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(this.dataURI.split(',')[1]);
} else {
byteString = decodeURI(this.dataURI.split(',')[1]);
}
return byteString;
}
getMimeString() {
return this.dataURI.split(',')[0].split(':')[1].split(';')[0];
}
convertToTypedArray() {
let byteString = this.getByteString();
let ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return ia;
}
dataURItoBlob() {
let mimeString = this.getMimeString();
let intArray = this.convertToTypedArray();
return new Blob([intArray], {type: mimeString});
}
}
Utilisation:
const dataURL = canvas.toDataURL('image/jpeg', 0.5);
const blob = new ImageDataConverter(dataURL).dataURItoBlob();
let fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
faire simple :D
function dataURItoBlob(dataURI,mime) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString = window.atob(dataURI);
// separate out the mime component
// write the bytes of the string to an ArrayBuffer
//var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
var blob = new Blob([ia], { type: mime });
return blob;
}
Merci! @steovi pour cette solution.
j'ai ajouté le support à la version ES6 et j'ai changé de unescape à dataURI(unescape est déprécié).
converterDataURItoBlob(dataURI) {
let byteString;
let mimeString;
let ia;
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(dataURI.split(',')[1]);
} else {
byteString = encodeURI(dataURI.split(',')[1]);
}
// separate out the mime component
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
toDataURL vous donne une chaîne et vous pouvez mettre cette chaîne à une entrée cachée.
j'ai eu exactement le même problème que Ravinder Payal, et j'ai trouvé la réponse. Essayez ceci:
var dataURL = canvas.toDataURL("image/jpeg");
var name = "image.jpg";
var parseFile = new Parse.File(name, {base64: dataURL.substring(23)});