javascript - pgjvzhk - data:image/jpeg;base64
Convierta la URI de datos en un archivo y luego agregue a FormData (14)
He estado intentando volver a implementar un cargador de imágenes HTML5 como el del sitio de Mozilla Hacks , pero eso funciona con los navegadores WebKit. Parte de la tarea es extraer un archivo de imagen del objeto de canvas
y adjuntarlo a un objeto FormData para cargarlo.
El problema es que, si bien el canvas
tiene la función toDataURL
para devolver una representación del archivo de imagen, el objeto FormData solo acepta objetos File o Blob de File API .
La solución Mozilla utilizó la siguiente función solo para Firefox en el canvas
:
var file = canvas.mozGetAsFile("foo.png");
... que no está disponible en los navegadores WebKit. La mejor solución que se me ocurre es encontrar una forma de convertir un URI de datos en un objeto de archivo, que pensé que podría ser parte de la API de archivos, pero no puedo por la vida encontrar algo para hacer eso.
¿Es posible? Si no, ¿alguna alternativa?
Gracias.
Éste funciona en iOS y Safari.
Debe usar la solución ArrayBuffer de Stoive, pero no puede usar BlobBuilder, como indica vava720, así que aquí está el mashup de ambos.
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'' });
}
¡Gracias! @steovi para esta solución.
He añadido soporte a la versión ES6 y he cambiado de unescape a dataURI (unescape está en desuso).
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});
}
Aquí está una versión ES6 de share de share :
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});
}
}
Uso:
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);
BlobBuilder y ArrayBuffer ahora están en desuso, aquí está el código del comentario superior actualizado con el constructor 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''});
}
Después de jugar con algunas cosas, me las arreglé para resolver esto por mí mismo.
En primer lugar, esto 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});
}
A partir de ahí, adjuntar los datos a un formulario para que se carguen como un archivo es fácil:
var dataURL = canvas.toDataURL(''image/jpeg'', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
El estándar en evolución parece ser canvas.toBlob() no canvas.getAsFile () como Mozilla se atrevió a adivinar.
Todavía no veo ningún navegador que lo soporte :(
Gracias por este gran hilo!
Además, cualquier persona que intente la respuesta aceptada debe tener cuidado con BlobBuilder, ya que encuentro que el soporte es limitado (y con nombres):
var bb;
try {
bb = new BlobBuilder();
} catch(e) {
try {
bb = new WebKitBlobBuilder();
} catch(e) {
bb = new MozBlobBuilder();
}
}
¿Estabas usando el polyfill de otra biblioteca para BlobBuilder?
Firefox tiene los canvas.toBlob() y canvas.mozGetAsFile() .
Pero otros navegadores no lo hacen.
Podemos obtener dataurl desde el lienzo y luego convertir dataurl en objeto blob.
Aquí está mi función dataURLtoBlob()
Es muy corto
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});
}
Utilice esta función con FormData para manejar su lienzo o dataurl.
Por ejemplo:
var dataurl = canvas.toDataURL(''image/jpeg'',0.8);
var blob = dataURLtoBlob(dataurl);
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");
Además, puede crear un método HTMLCanvasElement.prototype.toBlob
para el navegador del motor no 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);
};
}
Ahora canvas.toBlob()
funciona para todos los navegadores modernos, no solo para Firefox. Por ejemplo:
canvas.toBlob(
function(blob){
var fd = new FormData();
fd.append("myFile", blob, "thumb.jpg");
//continue do something...
},
''image/jpeg'',
0.8
);
Gracias a @Stoive y @ vava720 combiné los dos de esta manera, evitando usar BlobBuilder y ArrayBuffer en desuso.
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});
}
La respuesta original de Stoive se puede corregir fácilmente cambiando la última línea para acomodar a 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});
}
Mi forma preferida es canvas.toBlob()
Pero de todos modos, aquí hay otra forma de convertir base64 en un blob usando 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})
})
Tuve exactamente el mismo problema que Ravinder Payal, y encontré la respuesta. Prueba esto:
var dataURL = canvas.toDataURL("image/jpeg");
var name = "image.jpg";
var parseFile = new Parse.File(name, {base64: dataURL.substring(23)});
hazlo 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;
}
toDataURL te da una cadena y puedes poner esa cadena en una entrada oculta.
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);
Se puede utilizar sin la captura de prueba.
Gracias a check_ca. Buen trabajo.