Navegador / HTML Forzar la descarga de la imagen de src = "data: image / jpeg; base64 ..."

85

Estoy generando una imagen en el lado del cliente y la muestro con HTML como este:

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgM...."/>

Quiero ofrecer la posibilidad de descargar la Imagen generada.

¿Cómo puedo darme cuenta de que el navegador está abriendo un diálogo de guardado de archivos (o simplemente descargar la imagen como Chrome o Firefox en la carpeta de descarga sería suficiente) que permite al usuario guardar la imagen sin hacer clic derecho y guardar como en la imagen?

Preferiría una solución sin interacción con el servidor. Entonces soy consciente de que sería posible si primero subo la imagen y luego inicio la descarga.

¡Muchas gracias!

alex
fuente

Respuestas:

119

Simplemente reemplace image/jpegcon application/octet-stream. El cliente no reconocería la URL como un recurso en línea y generaría un cuadro de diálogo de descarga.

Una solución de JavaScript simple sería:

//var img = reference to image
var url = img.src.replace(/^data:image\/[^;]+/, 'data:application/octet-stream');
window.open(url);
// Or perhaps: location.href = url;
// Or even setting the location of an <iframe> element, 

Otro método es usar un blob:URI:

var img = document.images[0];
img.onclick = function() {
    // atob to base64_decode the data-URI
    var image_data = atob(img.src.split(',')[1]);
    // Use typed arrays to convert the binary data to a Blob
    var arraybuffer = new ArrayBuffer(image_data.length);
    var view = new Uint8Array(arraybuffer);
    for (var i=0; i<image_data.length; i++) {
        view[i] = image_data.charCodeAt(i) & 0xff;
    }
    try {
        // This is the recommended method:
        var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
    } catch (e) {
        // The BlobBuilder API has been deprecated in favour of Blob, but older
        // browsers don't know about the Blob constructor
        // IE10 also supports BlobBuilder, but since the `Blob` constructor
        //  also works, there's no need to add `MSBlobBuilder`.
        var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
        bb.append(arraybuffer);
        var blob = bb.getBlob('application/octet-stream'); // <-- Here's the Blob
    }

    // Use the URL object to create a temporary URL
    var url = (window.webkitURL || window.URL).createObjectURL(blob);
    location.href = url; // <-- Download!
};

Documentación relevante

Rob W
fuente
1
por alguna razón, parece estar roto en Chrome 19.0 beta, pero funciona en Chrome 18 y Firefox, así que estoy bien. ¿Existe la posibilidad de establecer un nombre de archivo?
alex
No hay forma de establecer el nombre de archivo en un URI de datos. Incluso cuando se utiliza un lienzo / blob para exportar los datos, no se puede establecer el nombre del archivo. Agregué otro método a mi respuesta (supongo que este funcionará en Chrome 19).
Rob W
2
¿Crees que el primer método va a quedar obsoleto porque ya no funciona en Chrome 19?
alex
1
No puedo encontrar una fuente relevante al respecto. También encontré esta respuesta , por cierto, que sugiere cómo establecer un nombre predeterminado en Chrome (solo anclajes, el usuario debe hacer clic en él)
Rob W
También encontré esta solución: parece ser Chrome solo por ahora. ¡Gracias por su apoyo!
alex
96

puede utilizar el atributo de descarga en una etiqueta a ...

<a href="data:image/jpeg;base64,/9j/4AAQSkZ..." download="filename.jpg"></a>

ver más: https://developer.mozilla.org/en/HTML/element/a#attr-download

Bruce Aldridge
fuente
1
¿Cómo puedo usar esta solución cuando genero la fuente de la imagen de forma dinámica? Quiero decir, tengo el botón Descargar, cuando el usuario hace clic en él, hago algunos cálculos, genero una imagen base64 y ... ¿cómo puedo forzar la descarga?
Mikhail
En Chrome, no puedo establecer el nombre de archivo con este método. El nombre del archivo descargado sigue siendo "descargar" pase lo que pase. Esto solo sucede cuando se usan datos: imagen ...
cmaduro
5
Sé que esta es una publicación antigua, pero según el atributo de 'descarga' del sitio web de W3Schools no es compatible con IE, Safari y Opera v. <12 w3schools.com/tags/tryit.asp?filename=tryhtml5_a_download2 de hecho lo probé con IE y no funciona .... :(
Mirko Lugano
6
En el momento de este comentario, el downloadatributo todavía no es compatible con Safari e IE.
TheCarver
1
tiene una limitación de longitud de base64, no puede descargar imágenes más grandes con este enfoque.
Kiran Chenna
15

Supongo que se necesita una etiqueta img como hijo de una etiqueta a, de la siguiente manera:

<a download="YourFileName.jpeg" href="data:image/jpeg;base64,iVBO...CYII=">
    <img src="data:image/jpeg;base64,iVBO...CYII="></img>
</a>

o

<a download="YourFileName.jpeg" href="/path/to/OtherFile.jpg">
    <img src="/path/to/OtherFile.jpg"></img>
</a>

Sólo mediante el una etiqueta como se explica en el # 15 no funcionó para mí con la última versión de Firefox y Chrome, pero poniendo los mismos datos de imagen tanto en a.href y img.src etiquetas trabajado para mí.

Desde JavaScript se podría generar así:

var data = canvas.toDataURL("image/jpeg");

var img = document.createElement('img');
img.src = data;

var a = document.createElement('a');
a.setAttribute("download", "YourFileName.jpeg");
a.setAttribute("href", data);
a.appendChild(img);

var w = open();
w.document.title = 'Export Image';
w.document.body.innerHTML = 'Left-click on the image to save it.';
w.document.body.appendChild(a);
usuario3521208
fuente
no es que necesite una etiqueta img dentro, los documentos de MSDN establecen que solo se pueden usar los recursos ya descargados; debería funcionar siempre que tenga la imagen con los mismos datos: base64 en cualquier lugar. msdn.microsoft.com/en-us/library/cc848897.aspx - "Por motivos de seguridad, los URI de datos están restringidos a los recursos descargados. Los URI de datos no se pueden usar para navegación, para secuencias de comandos o para completar elementos de marco o iframe".
Dimitar Christoff
5

Eche un vistazo a FileSaver.js . Proporciona una saveAsfunción útil que se encarga de la mayoría de las peculiaridades específicas del navegador.

jesal
fuente