Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create and Download PDF file from binary string with JS/TS

An Axios request to server response the content of a PDF as a binary string.

export const fetchPDFfile = async (id: string): Promise<string> => {
  const { data } = await http.get<string>(`${baseUrl}/${id}.pdf`);
  return data;
};

The response in Chrome devtools and also console logging the data is like:

%PDF-1.4
%âãÏÓ
2 0 obj <</ColorSpa ......
..........
startxref
10991
%%EOF
  • is defining string as the expected type of Axios response body, correct? or it should be (cast to) Blob?

Now I want to download this as a PDF file in the client-side. There are plenty of questions regarding this but none worked for me and also none had a clear answer.

So what I did so far was (in a React component):

    const data = await fetchPDFfile(props.id);
    const blob = new Blob([data], { type: 'application/pdf' });
    const href = window.URL.createObjectURL(blob);
    const theLink = document.createElement('a');
    theLink.href = href;
    theLink.download = props.id + '.pdf';
    document.body.appendChild(theLink);
    theLink.click();
    document.body.removeChild(theLink);

This downloads a PDF file with 3 blank pages. The number of pages is correct the original doc should bee 3 pages. But I see the white paper.

const href = window.URL.createObjectURL(data); // istead of blob throw Error.

How should I convert and download this PDF file? In general, is the process above needed, or should I directly download it from the server? (something like what cordova-plugin-file-transfer does)

like image 558
Amir-Mousavi Avatar asked Sep 06 '25 03:09

Amir-Mousavi


2 Answers

Scenario

You want the file to be downloaded when the user clicks the link.

Solution 1-

Directly put the link in <a> tag.

Cons- Error message can not be shown on the screen if something went wrong.

So it leads to the next solution.

Solution 2-

Hit the URL as an API and download the file if you get the success message. For this, I use File-server.js

**Don't forget to set the {responseType: 'blob'}, while making the request

http.get<string>(`${baseUrl}/${id}.pdf`, {responseType: 'blob'})

as we don't want the response with Content-Type: application/json

sample code:

import FileSaver from 'file-saver';

downloadPdf() {
    var blob = new Blob([data], {type: "application/pdf"});
    FileSaver.saveAs(blob, "filename");
}
like image 165
LALIT KANTA DIBYADARSHAN Avatar answered Sep 07 '25 21:09

LALIT KANTA DIBYADARSHAN


Firstly use Blob as generic argument for Promise.

I will use fetch API as it can be tested quite easily.

fetch('https://www.jianjunchen.com/papers/CORS-USESEC18.slides.pdf').then(x => x.blob()).then(b => console.log(b.type))

This will log "application/pdf" it the file is trully pdf.

If you got a blob that is not PDF and you will re-wrap it to Blob with pdf type you might break the data. If you got trully a string and you convert it to Blob with pdf type the file will be broken as the PDF would be invalid.

If you want to know if b is trully a blob just console.log(b instanceof Blob) and it should say true. If you have recieved trully a blob you do not have to create new one as you did in new Blob([data]).

This example works just fine:

fetch('https://www.jianjunchen.com/papers/CORS-USESEC18.slides.pdf').then(x => x.blob()).then(b => {
  const url = window.URL.createObjectURL(b);
  var a = document.createElement("a");
  document.body.appendChild(a);
  a.style = "display: none";
  a.href = url;
  a.download = "a.pdf";
  a.click();
  window.URL.revokeObjectURL(url);
})

Sorry for broken code style but I was unable to paste it properly.

like image 30
Luk Deathrage Prochzka Avatar answered Sep 07 '25 22:09

Luk Deathrage Prochzka