9

I have a function that allows me to pass file content, name, and type and the function will automatically save it. It works great for text based documents, but now I'm trying to have it save other files, like an image file. Somewhere along the line its getting corrupted and isn't working.

function write(text, filename, mime){
    var file = new Blob([text], {type:mime}), a = document.createElement('a');

    // Download in IE
    if(window.navigator.msSaveBlob) window.navigator.msSaveBlob(file, filename);

    // Download in compliant browsers
    else{
        var url = URL.createObjectURL(file);
        a.href = url, a.download = filename;
        document.body.appendChild(a);
        a.click();
        setTimeout(function(){
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url);}, 0);}}

write('Plain text', 'demo.txt', 'text/plain');

write(atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAAdCAIAAADkY5E+AAAAD0lEQVR42mNg0AthoDMGAE1BDruZMRqXAAAAAElFTkSuQmCC'), 'demo.png', 'image/png');
GFL
  • 1,278
  • 2
  • 15
  • 24

2 Answers2

8

FileSaver.js a very powerful js script to save any type of blob file.

Import it then use it like this:

saveAs(new Blob([file], {type:mime}),filename);
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
m.nachury
  • 972
  • 8
  • 23
  • 1
    Thanks, I didn't think about the filesize limit of blobs. I was able to get the text to work, but not the image: saveAs(new Blob(["Hello, world!"], {type: "text/plain;charset=utf-8"}), "hello world.txt"); var img = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAAdCAIAAADkY5E+AAAAD0lEQVR42mNg0AthoDMGAE1BDruZMRqXAAAAAElFTkSuQmCC'); saveAs(new Blob([img], {type: "image/png"}), "test.png"); – GFL Jul 21 '17 at 14:09
  • Edited it to add mime type – m.nachury Jul 21 '17 at 14:53
5

Are you fetching the file using ajax? if so, you should set XmlHttpRequest.responseType to 'arraybuffer' or 'blob' (default is '' and that will not work with binaries or blob data).

Working example (using arraybuffer) (Fiddle):

var xhr = new XMLHttpRequest();

var url = 'https://upload.wikimedia.org/wikipedia/commons/d/da/Internet2.jpg';

xhr.responseType = 'arraybuffer'; //Set the response type to arraybuffer so xhr.response returns ArrayBuffer
xhr.open('GET', url , true);

xhr.onreadystatechange = function () {
    if (xhr.readyState == xhr.DONE) {
        //When request is done
        //xhr.response will be an ArrayBuffer
        var file = new Blob([xhr.response], {type:'image/jpeg'});
        saveAs(file, 'image.jpeg');
    }
};

xhr.send(); //Request is sent

Working example 2 (using blob) (Fiddle):

var xhr = new XMLHttpRequest();

var url = 'https://upload.wikimedia.org/wikipedia/commons/d/da/Internet2.jpg';

xhr.responseType = 'blob'; //Set the response type to blob so xhr.response returns a blob
xhr.open('GET', url , true);

xhr.onreadystatechange = function () {
    if (xhr.readyState == xhr.DONE) {
        //When request is done
        //xhr.response will be a Blob ready to save
        saveAs(xhr.response, 'image.jpeg');
    }
};

xhr.send(); //Request is sent

I recommend FileSaver.js to save the blobs as files.

Useful links:

XmlHttpRequest Standard

XmlHttpRequest Standard (responseType attribute)

MDN Docs (XmlHttpRequest)

MDN Docs (ArrayBuffer)

Cheloide
  • 793
  • 6
  • 21