77

So here my problem: I have a pdf file as a base64 String that i am getting from the server. I would like to use this string to either display the PDF directly to the browser or give it a option of "Save as..." when clicking on a link. Here the code i am using:

<!doctype>
<html>
<head>
   <title>jsPDF</title>
   <script type="text/javascript" src="../libs/base64.js"></script>
   <script type="text/javascript" src="../libs/sprintf.js"></script>
   <script type="text/javascript" src="../jspdf.js"></script>

       <script type="text/javascript">

        function demo1() {
            jsPDF.init();
            jsPDF.addPage();
            jsPDF.text(20, 20, 'Hello world!');
            jsPDF.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');

            // Making Data URI
            var out = jsPDF.output();
            var url = 'data:application/pdf;base64,' + Base64.encode(out);

            document.location.href = url;
         }
    </script>
</head>
<body>

<a href="javascript:demo1()">Run Code</a>

</body>
</html>

Its working fine with Chrome and Safari. Firefox does recognize the pdf but does not display it as FF requires extensions to be present but the data-URI has none in this case. The reason I'm insisting here, if chrome and safari get it to work, then there has to be a solution for FF and IE

I know there are a few relevant questions to this but not really the exact one and now also a bit old ones. I know a workaround would be to have the pdf generated at server side but I would like to generate it at client side.

So please intelligent folks, is it possible through some hacks or additional JS download plugins?

Kishan Patel
  • 778
  • 11
  • 26
owsata
  • 1,105
  • 1
  • 11
  • 24
  • 1
    hellow ??? isnt there anybody out thr who has some answer to tht .. may be john resig ;-) – owsata Jul 11 '12 at 07:56
  • @owsata, same problem here! It just opens the window! Did you find a solution to your problem? Please let us know. Thanks – Fabio Milheiro Dec 13 '12 at 18:09
  • 1
    @FabioMilheiro Nope didnt find anything useful. The ultimate result was that because the browsers handle the data:application idea differently there wasnt much using it in the first place. So last resort -> send a readymade pdf from the server. – owsata Dec 20 '12 at 13:06
  • Possible duplicate of [Saving Base64 encoded PDF with Internet Explorer 10 and below](http://stackoverflow.com/questions/27154606/saving-base64-encoded-pdf-with-internet-explorer-10-and-below) – SanjiMika Apr 19 '17 at 16:51
  • 1
    https://stackoverflow.com/a/16245768/7282741 This one solved my problem and saved my weekend. – Shubham Jun 05 '17 at 05:30

6 Answers6

66

you can use this function to download file from base64.

function downloadPDF(pdf) {
const linkSource = `data:application/pdf;base64,${pdf}`;
const downloadLink = document.createElement("a");
const fileName = "abc.pdf";
downloadLink.href = linkSource;
downloadLink.download = fileName;
downloadLink.click();}

This code will made an anchor tag with href and download file. if you want to use button then you can call click method on your button click.

i hope this will help of you thanks

adnan javed
  • 1,338
  • 8
  • 10
  • I think it could be useful to mention that this probably does not work nowadays if there is no user interaction activity (like a real click). You still need that the user clicks on something to activate this. – Valerio Bozz Mar 28 '23 at 08:08
46

You can create an anchor like the one showed below to download the base64 pdf:

<a download="PDF Title" href="pdfData">Download PDF document</a>

where pdfData is your base64 encoded pdf like:

data:application/pdf;base64,JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nO1cyY4ktxG911fUWUC3kjsTaBTQ1Ytg32QN4IPgk23JMDQ2LB/0+2YsZAQzmZk1PSPIEB...
Valerio Bozz
  • 1,176
  • 16
  • 32
Gabriel Cerutti
  • 1,347
  • 1
  • 15
  • 17
  • 2
    your this information helped me to accomplished it in Salesforce Lightning, using this string you can make a file download on button click – Subinoy Apr 03 '18 at 11:12
  • 3
    in C# when you return a FileContentResult it keeps the file encoded in base64 however there are no indications of it and no mime type.. so in order to implement it properly in the client side I had to append data:application/pdf;base64, in front of the string and it worked! – Божидар Йовчев Jan 15 '19 at 10:58
  • 2
    this helped me avoid creating an extra backend endpoint just to download the file, thanks!! – EVIL Nov 24 '20 at 16:23
26

You should be able to download the file using

window.open("data:application/pdf;base64," + Base64.encode(out));
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 3
    Nope, Chrome and FF download it directly but dont assign an extension. Safari opens the PDF and displays it in browser wow. IE opens a new tab with the title "application/octet-stream" and nothing else... – owsata Jul 10 '12 at 15:00
  • I did a straight redirect using the data structure, however it needs a container or a mechanism to parse the data into a usable format (for example: an iFrame). I have not however tested this mechanism as prescribed. – Reinhard Behrens Apr 13 '21 at 12:32
18

I know this question is old, but also wanted to accomplish this and came across it while looking. For internet explorer I used code from here to save a Blob. To create a blob from the base64 string there were many results on this site, so its not my code I just can't remember the specific source:

function b64toBlob(b64Data, contentType) {
    contentType = contentType || '';
    var sliceSize = 512;
    b64Data = b64Data.replace(/^[^,]+,/, '');
    b64Data = b64Data.replace(/\s/g, '');
    var byteCharacters = window.atob(b64Data);
    var byteArrays = [];

    for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        var slice = byteCharacters.slice(offset, offset + sliceSize);

        var byteNumbers = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }

        var byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
    }

    var blob = new Blob(byteArrays, {type: contentType});
    return blob;

Using the linked filesaver:

if (window.saveAs) { window.saveAs(blob, name); }
    else { navigator.saveBlob(blob, name); }
RiggsFolly
  • 93,638
  • 21
  • 103
  • 149
Ka0s
  • 398
  • 4
  • 10
  • Filesaver fails in Safari also :( – jrh Dec 08 '15 at 07:48
  • i posted the solution on this link https://stackoverflow.com/questions/34436133/pdf-is-blank-when-downloading-using-javascript/45669785#45669785 which is working fine in IE , CHROME , FF . If this solution helps you , try to vote it up – Sajjad Ali Khan Aug 14 '17 at 07:53
18

function dataURItoBlob(dataURI) {
      const byteString = window.atob(dataURI);
      const arrayBuffer = new ArrayBuffer(byteString.length);
      const int8Array = new Uint8Array(arrayBuffer);
      for (let i = 0; i < byteString.length; i++) {
        int8Array[i] = byteString.charCodeAt(i);
      }
      const blob = new Blob([int8Array], { type: 'application/pdf'});
      return blob;
    }

// data should be your response data in base64 format

const blob = this.dataURItoBlob(data);
const url = URL.createObjectURL(blob);

// to open the PDF in a new window
window.open(url, '_blank');
Jose Rui Santos
  • 15,009
  • 9
  • 58
  • 71
Manas Sahu
  • 779
  • 8
  • 8
2

You will do not need any library for this. JavaScript support this already. Here is my end-to-end solution.

const xhr = new XMLHttpRequest();
xhr.open('GET', 'your-end-point', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
xhr.responseType = 'blob';
xhr.onreadystatechange = function () {
    if (this.readyState == 4 && this.status == 200) {
       if (window.navigator.msSaveOrOpenBlob) {
           window.navigator.msSaveBlob(this.response, "fileName.pdf");
        } else {
           const downloadLink = window.document.createElement('a');
           const contentTypeHeader = xhr.getResponseHeader("Content-Type");
           downloadLink.href = window.URL.createObjectURL(new Blob([this.response], { type: contentTypeHeader }));
           downloadLink.download = "fileName.pdf";
           document.body.appendChild(downloadLink);
           downloadLink.click();
           document.body.removeChild(downloadLink);
        }
    }
};
xhr.send(null);

This also work for .xls or .zip file. You just need to change file name to fileName.xls or fileName.zip. This depends on your case.

Hoang Subin
  • 6,610
  • 6
  • 37
  • 56