Navigateur / HTML Forcer le téléchargement de l'image à partir de src = "data: image / jpeg; base64…"

85

Je génère une image côté client et je l'affiche avec du HTML comme ceci:

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

Je souhaite offrir la possibilité de télécharger l'image générée.

Comment puis-je réaliser que le navigateur ouvre une boîte de dialogue de sauvegarde de fichier (ou simplement télécharger l'image comme le ferait Chrome ou Firefox dans le dossier de téléchargement) qui permet à l'utilisateur d'enregistrer l'image sans faire un clic droit et de l'enregistrer sous l'image?

Je préférerais une solution sans interaction avec le serveur. Je suis donc conscient que ce serait possible si je télécharge d'abord l'image puis que je lance le téléchargement.

Merci beaucoup!

Alex
la source

Réponses:

119

Remplacez simplement image/jpegpar application/octet-stream. Le client ne reconnaîtrait pas l'URL en tant que ressource en ligne et afficherait une boîte de dialogue de téléchargement.

Une solution JavaScript simple serait:

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

Une autre méthode consiste à utiliser 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!
};

Documentation pertinente

Rob W
la source
1
pour une raison quelconque, il semble être cassé dans la version bêta de Chrome 19.0, mais cela fonctionne sur Chrome 18 et Firefox, donc je vais bien. Est-il possible de définir un nom de fichier?
alex
Il n'y a aucun moyen de définir le nom de fichier dans un URI de données. Même lorsqu'un canevas / blob est utilisé pour exporter les données, le nom du fichier ne peut pas être défini. J'ai ajouté une autre méthode à ma réponse (je suppose que celle-ci fonctionnera dans Chrome 19).
Rob W
2
Pensez-vous que la première méthode sera obsolète car elle ne fonctionne plus dans Chrome 19?
alex
1
Je ne trouve pas de source pertinente dessus. J'ai également trouvé cette réponse , en passant, qui suggère comment définir un nom par défaut dans Chrome (ancres uniquement, l'utilisateur doit cliquer dessus)
Rob W
A également trouvé cette solution - semble être chrome uniquement pour le moment. Merci pour votre aide!
alex
96

vous pouvez utiliser l'attribut de téléchargement sur une balise a ...

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

voir plus: https://developer.mozilla.org/en/HTML/element/a#attr-download

Bruce Aldridge
la source
1
Comment puis-je utiliser cette solution lorsque je génère la source d'image de manière dynamique? Je veux dire que j'ai le bouton Télécharger, lorsque l'utilisateur clique dessus, je fais des calculs, je génère une image base64 et ... comment puis-je forcer le téléchargement?
Mikhail
Dans Chrome, je ne peux pas définir le nom de fichier à l'aide de cette méthode. Le nom du fichier téléchargé reste "télécharger" quoi qu'il arrive. Cela ne se produit que lors de l'utilisation de données: image ...
cmaduro
5
Je sais que c'est un ancien message, mais selon l'attribut `` télécharger '' du site Web de W3Schools n'est pas pris en charge par IE, Safari et Opera v. <12 w3schools.com/tags/tryit.asp?filename=tryhtml5_a_download2 en fait, je l'ai essayé avec IE et ça ne marche pas .... :(
Mirko Lugano
6
Au moment de ce commentaire, l' downloadattribut n'est toujours pas pris en charge par Safari et IE.
TheCarver
1
il a une limitation de longueur en base64, vous ne pouvez pas télécharger des images plus grandes en utilisant cette approche.
Kiran Chenna
15

Je suppose qu'une img balise est nécessaire comme un enfant d'une une étiquette, de la façon suivante:

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

Seulement en utilisant l' une balise comme expliqué dans # 15 n'a pas fonctionné pour moi avec la dernière version de Firefox et Chrome, mais mettre les mêmes données d'image dans les deux a.href et img.src balises travaillé pour moi.

À partir de JavaScript, il pourrait être généré comme ceci:

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
la source
ce n'est pas qu'il ait besoin d'une balise img à l'intérieur, les documents MSDN indiquent que seules les ressources déjà téléchargées peuvent être utilisées - devraient fonctionner tant que vous avez l'image avec les mêmes données: base64 n'importe où. msdn.microsoft.com/en-us/library/cc848897.aspx - "Pour des raisons de sécurité, les URI de données sont limités aux ressources téléchargées. Les URI de données ne peuvent pas être utilisés pour la navigation, pour la création de scripts ou pour remplir des éléments frame ou iframe."
Dimitar Christoff
5

Jetez un œil à FileSaver.js . Il fournit une saveAsfonction pratique qui prend en charge la plupart des bizarreries spécifiques au navigateur.

jésal
la source