Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem downloading a PDF blob in JavaScript

I've created a function that takes a blob and fileName which is supposed to download that blob implemented as follows:

const blobToBase64 = (blob, callback) => {
  const reader = new FileReader();
  reader.onloadend = () => {
    const base64 = reader.result;
    console.log({ base64 });
    callback(base64);
  };
  reader.readAsDataURL(blob);
};

const downloadFile = (blob, fileName) => () => {
  const link = document.createElement('a');
  blobToBase64(blob, (base64) => {
    link.href = base64;
    link.download = fileName;
    link.click();
  });
};


downloadFile(myBlob, myFileName);

To try debug this I've made a console.log to log out the value of base64 which is created by reader.result.

That base64 value is data:application/octet-stream;base64,Mzc4MDY4...

My PDF file get's downloaded but it's corrupted. What am I doing wrong in my file download implementation?

Let me know if there are any additional details that might help with this? I'm 100% sure that the blob itself is not a corrupted file.

like image 395
Barry Michael Doyle Avatar asked Oct 15 '18 12:10

Barry Michael Doyle


2 Answers

I can't tell for sure why your code doesn't work, but I can tell for sure that what you are doing is useless at best.

Do not convert a Blob to a dataURI, 99%* of the time, what you want to do with this dataURI can be done directly with the original Blob and a blobURI.

*The remaining 1% being when you need to create standalone documents that will include binary data, it happens but not that often.

Here, once again what you want to do (set an anchor to point to your Blob's data) can be done with the Blob directly: simply create a blobURI (which is just a pointer to the data in memory) by calling URL.createObjectURL(blob).

const downloadFile = (blob, fileName) => {
  const link = document.createElement('a');
  // create a blobURI pointing to our Blob
  link.href = URL.createObjectURL(blob);
  link.download = fileName;
  // some browser needs the anchor to be in the doc
  document.body.append(link);
  link.click();
  link.remove();
  // in case the Blob uses a lot of memory
  setTimeout(() => URL.revokeObjectURL(link.href), 7000);
};


downloadFile(new Blob(['random data']), "myfile.txt");
like image 69
Kaiido Avatar answered Oct 04 '22 18:10

Kaiido


I tried using Fetch API to download the PDF file from server which is giving octet-stream content as response. So, if you check the response, you will get characters like these %PDF-1.4

Here is the solution:

function download(pdfUrl) {
        fetch(pdfUrl).then(resp => resp.arrayBuffer()).then(resp => {

            // set the blog type to final pdf
            const file = new Blob([resp], {type: 'application/pdf'});

            // process to auto download it
            const fileURL = URL.createObjectURL(file);
            const link = document.createElement('a');
            link.href = fileURL;
            link.download = "FileName" + new Date() + ".pdf";
            link.click();
        });
    }

You can use the same method and decode the content of the octet-stream before creating the blob.

like image 29
Akansh Avatar answered Oct 04 '22 18:10

Akansh