Navegador / HTML Força o download da imagem de src = “data: image / jpeg; base64…”

86

Estou gerando uma imagem no lado do cliente e a exibo com HTML assim:

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

Quero oferecer a possibilidade de baixar a imagem gerada.

Como posso perceber que o navegador está abrindo uma caixa de diálogo para salvar o arquivo (ou apenas baixar a imagem como o chrome ou firefox para a pasta de download faria) que permite ao usuário salvar a imagem sem clicar com o botão direito e salvar como na imagem?

Eu preferiria uma solução sem interação com o servidor. Portanto, estou ciente de que seria possível se eu primeiro carregasse a imagem e depois iniciasse o download.

Muito obrigado!

alex
fonte

Respostas:

120

Basta substituir image/jpegpor application/octet-stream. O cliente não reconheceria o URL como um recurso habilitado em linha e solicitaria uma caixa de diálogo de download.

Uma solução JavaScript simples seria:

//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, 

Outro método é usar um 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!
};

Documentação relevante

Rob W
fonte
1
por algum motivo, parece estar quebrado no Chrome 19.0 beta, mas funciona no Chrome 18 e no Firefox, então estou bem. Existe a possibilidade de definir um nome de arquivo?
alex
Não há como definir o nome do arquivo em um URI de dados. Mesmo quando um canvas / Blob é usado para exportar os dados, o nome do arquivo não pode ser definido. Eu adicionei outro método à minha resposta (acho que este funcionará no Chrome 19).
Rob W
2
Você acha que o primeiro método será descontinuado porque não está mais funcionando no Chrome 19?
alex
1
Não consigo encontrar uma fonte relevante sobre isso. Também encontrei esta resposta , a propósito, que sugere como definir um nome padrão no Chrome (apenas âncoras, o usuário precisa clicar nele)
Rob W
Também encontrei esta solução - parece ser cromada apenas por enquanto. Obrigado por seu apoio!
alex
98

você pode usar o atributo de download em uma tag ...

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

veja mais: https://developer.mozilla.org/en/HTML/element/a#attr-download

Bruce Aldridge
fonte
1
Como posso usar essa solução ao gerar a fonte da imagem dinamicamente? Quer dizer, eu tenho o botão Download, quando o usuário clica nele, eu faço alguns cálculos, gero imagem base64 e ... como posso forçar o download?
Mikhail de
No chrome, não consigo definir o nome do arquivo usando este método. O nome do arquivo baixado permanece "download", não importa o quê. Isso só acontece ao usar dados: imagem ...
cmaduro
5
Eu sei que esta é uma postagem antiga, mas de acordo com o atributo 'download' do site W3Schools não é compatível com IE, Safari e Opera v. <12 w3schools.com/tags/tryit.asp?filename=tryhtml5_a_download2 na verdade eu tentei com IE e não funciona .... :(
Mirko Lugano
6
No momento deste comentário, o downloadatributo ainda não era compatível com Safari e IE.
TheCarver
1
ele tem limitação de comprimento de base64, você não pode baixar imagens maiores usando essa abordagem.
Kiran Chenna
15

Eu acho que um img tag é necessária como uma criança de um a tag, da seguinte forma:

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

ou

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

Apenas usando a um tag como explicado no # 15 não funcionou para mim com a mais recente versão do Firefox e Chrome, mas colocando os mesmos dados de imagem em ambos os a.href e img.src etiquetas funcionou para mim.

A partir de JavaScript, ele pode ser gerado assim:

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);
user3521208
fonte
não é que ele precise de uma tag img dentro, os documentos do MSDN afirmam que apenas os recursos já baixados podem ser usados ​​- deve funcionar, desde que você tenha a imagem com os mesmos dados: base64 em qualquer lugar. msdn.microsoft.com/en-us/library/cc848897.aspx - "Por razões de segurança, URIs de dados são restritos a recursos baixados. URIs de dados não podem ser usados ​​para navegação, para script ou para preencher elementos de frame ou iframe."
Dimitar Christoff de
5

Dê uma olhada em FileSaver.js . Ele fornece uma saveAsfunção útil que cuida da maioria das peculiaridades específicas do navegador.

Jesal
fonte