Przeglądarka / HTML Wymuś pobranie obrazu z src = „data: image / jpeg; base64…”

85

Generuję obraz po stronie klienta i wyświetlam go w HTML w następujący sposób:

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

Chcę zaoferować możliwość pobrania wygenerowanego obrazu.

Jak mogę zdać sobie sprawę, że przeglądarka otwiera okno dialogowe zapisywania pliku (lub po prostu pobiera obraz, taki jak chrome lub firefox, do folderu pobierania), które pozwala użytkownikowi zapisać obraz bez klikania prawym przyciskiem myszy i zapisywać jak na obrazie?

Wolałbym rozwiązanie bez interakcji z serwerem. Jestem więc świadomy, że byłoby to możliwe, jeśli najpierw załaduję obraz, a następnie rozpocznę pobieranie.

Wielkie dzięki!

Alex
źródło

Odpowiedzi:

119

Wystarczy wymienić image/jpegz application/octet-stream. Klient nie rozpoznałby adresu URL jako zasobu wbudowanego i wyświetliłby okno dialogowe pobierania.

Prostym rozwiązaniem w JavaScript byłoby:

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

Inną metodą jest użycie blob:identyfikatora 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!
};

Odpowiednia dokumentacja

Rob W
źródło
1
z jakiegoś powodu wydaje się, że jest zepsuty w Chrome 19.0 beta, ale działa na Chrome 18 i Firefox, więc wszystko w porządku. Czy istnieje możliwość ustawienia nazwy pliku?
Alex
Nie ma możliwości ustawienia nazwy pliku w identyfikatorze URI danych. Nawet jeśli do wyeksportowania danych jest używany obszar roboczy / obiekt BLOB , nie można ustawić nazwy pliku. Dodałem inną metodę do mojej odpowiedzi (myślę, że ta będzie działać w Chrome 19).
Rob W
2
Czy uważasz, że pierwsza metoda zostanie wycofana, ponieważ nie działa już w Chrome 19?
Alex
1
Nie mogę znaleźć odpowiedniego źródła. Nawiasem mówiąc, znalazłem również tę odpowiedź , która sugeruje, jak ustawić domyślną nazwę w Chrome (tylko kotwice, użytkownik musi ją kliknąć)
Rob W
Znalazłem też to rozwiązanie - na razie wydaje się, że to tylko chrom. Dziękuję za wsparcie!
alex
96

możesz użyć atrybutu download w tagu ...

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

zobacz więcej: https://developer.mozilla.org/en/HTML/element/a#attr-download

Bruce Aldridge
źródło
1
Jak mogę korzystać z tego rozwiązania, gdy dynamicznie generuję źródło obrazu? Mam na myśli przycisk Pobierz, gdy użytkownik go kliknie, wykonuję obliczenia, generuję obraz base64 i ... jak mogę wymusić pobieranie?
Michaił
W chrome nie mogę ustawić nazwy pliku tą metodą. Nazwa pobranego pliku pozostaje „download” bez względu na wszystko. Dzieje się tak tylko wtedy, gdy używasz danych: obraz ...
cmaduro
5
Wiem, że to stary post, ale według strony W3Schools atrybut „download” nie jest obsługiwany przez IE, Safari i Opera v. <12 w3schools.com/tags/tryit.asp?filename=tryhtml5_a_download2 w rzeczywistości wypróbowałem go z IE i to nie działa .... :(
Mirko Lugano
6
W chwili pisania tego komentarza downloadatrybut nadal nie jest obsługiwany przez przeglądarki Safari i IE.
TheCarver
1
ma ograniczenie długości base64, nie można pobrać większych obrazów przy użyciu tej metody.
Kiran Chenna
15

Chyba img tag jest potrzebny jako dziecko wystąpienia w tagu, w następujący sposób:

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

lub

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

Tylko stosując się znacznik, jak wyjaśniono w # 15 nie pracował dla mnie z najnowszej wersji przeglądarki Firefox i Chrome, ale wprowadzanie tych samych danych obrazu zarówno a.href i img.src tagi pracował dla mnie.

Z JavaScript można to wygenerować w następujący sposób:

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
źródło
to nie jest tak, że potrzebuje tagu img w środku, dokumentacja MSDN stwierdza, że ​​można używać tylko już pobranych zasobów - powinno działać, o ile masz obraz z tymi samymi danymi: base64 w dowolnym miejscu. msdn.microsoft.com/en-us/library/cc848897.aspx - „Ze względów bezpieczeństwa identyfikatory URI danych są ograniczone do pobranych zasobów. Identyfikatorów URI danych nie można używać do nawigacji, tworzenia skryptów ani do wypełniania ramek lub elementów iframe.”
Dimitar Christoff
5

Spójrz na FileSaver.js . Zapewnia przydatną saveAsfunkcję, która rozwiązuje większość dziwactw specyficznych dla przeglądarki.

jesal
źródło