33

Based on the question Open PDF in new browser full window, it looks like I can use JavaScript to open a new window with a PDF file with the following code:

window.open('MyPDF.pdf', '_blank');

I'd like to do so on a return trip from the server by adding a byte array instead of the file name to use as the URL location in window.open

I'm currently returning PDF files like this:

Response.Clear();
Response.ContentType = "application/pdf";
Response.BinaryWrite(pdfByteArray);
Response.Flush();

Is there a way to open a new window with a PDF byte array in javascript.

Something like this:

var script = "window.open('" + pdfByteArray + "', '_blank');";
ScriptManager.RegisterClientScriptBlock(Parent.Page, typeof(Page), "pdf", script, true);
Community
  • 1
  • 1
KyleMit
  • 30,350
  • 66
  • 462
  • 664

3 Answers3

33

It looks like window.open will take a Data URI as the location parameter.

So you can open it like this from the question: Opening PDF String in new window with javascript:

window.open("data:application/pdf;base64, " + base64EncodedPDF);

Here's an runnable example in plunker, and sample pdf file that's already base64 encoded.

Then on the server, you can convert the byte array to base64 encoding like this:

string fileName = @"C:\TEMP\TEST.pdf";
byte[] pdfByteArray = System.IO.File.ReadAllBytes(fileName);
string base64EncodedPDF = System.Convert.ToBase64String(pdfByteArray);

NOTE: This seems difficult to implement in IE because the URL length is prohibitively small for sending an entire PDF.

Community
  • 1
  • 1
KyleMit
  • 30,350
  • 66
  • 462
  • 664
  • 1
    After reading various other comments on similar questions, it seems some people claim the limit is somewhere between 2048 bytes and 32KB. Both are too small for me, unfortunately. Looks like there is still no reliable way to tell a user when their PDF download has finished generating short of an ajax polling thread. – crush Mar 11 '15 at 21:39
  • Which library do I need to import to use `System.Convert.ToBase64String`? I am not able to find `Convert` in `System` pkg. – Core_Dumped Feb 01 '16 at 09:20
  • I work with php in the backend, so I made base64_encode(data) before sending the pdf content (skipping the System.Convert.ToBase64String that you wrote there; it wasn't working for me). Thanks! – dani24 Jul 15 '16 at 18:33
  • @KyleMit awesome awesome and amazing solution – 3 rules Oct 06 '16 at 11:37
  • I have a requirement to take this one step further, to automatically trigger the "Print" functionality of the browser. But when I call `window.print()` from the new window object it does nothing. I've even tried to call a `setTimeout` to make sure it's loaded but it doesn't work. Does anyone have any ideas? – jtate Nov 07 '16 at 14:58
  • @kyleMit i am not able to make it work on IE11 , can you please help me out on that. – Viplock Mar 10 '17 at 13:46
  • @Viplock, according to [how to display base64 encoded pdf in IE?](http://stackoverflow.com/a/27957607/1366033), IE might have dropped support for this. According to the MS [data Protocol spec](https://msdn.microsoft.com/en-us/library/cc848897.aspx), "`Data URIs are supported only for the following elements and/or attributes: object (images only), img, input type=image, link, CSS`" – KyleMit Mar 10 '17 at 17:15
  • This does not work anymore on Chrome. I would suggest to go with this approach: https://stackoverflow.com/questions/3749231/download-file-using-javascript-jquery – MonsieurDart Oct 22 '19 at 20:59
  • Hint with encoding to base64 is perfect! In JS worked just like `window.open(fileURL);`. You saved me, many thanks! – Vladislav Ashikhin Nov 22 '20 at 20:12
7

Note: I have verified this in the latest version of IE, and other browsers like Mozilla and Chrome and this works for me. Hope it works for others as well.

if (data == "" || data == undefined) {
    alert("Falied to open PDF.");
} else { //For IE using atob convert base64 encoded data to byte array
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        var byteCharacters = atob(data);
        var byteNumbers = new Array(byteCharacters.length);
        for (var i = 0; i < byteCharacters.length; i++) {
            byteNumbers[i] = byteCharacters.charCodeAt(i);
        }
        var byteArray = new Uint8Array(byteNumbers);
        var blob = new Blob([byteArray], {
            type: 'application/pdf'
        });
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else { // Directly use base 64 encoded data for rest browsers (not IE)
        var base64EncodedPDF = data;
        var dataURI = "data:application/pdf;base64," + base64EncodedPDF;
        window.open(dataURI, '_blank');
    }

}
riQQ
  • 9,878
  • 7
  • 49
  • 66
Dinesh Rajput
  • 161
  • 2
  • 1
  • I finally got things working with a combination of the .NET: Response.Write(System.Convert.ToBase64String(bytearray)); and the javascript block above. Thanks @KyleMit ! – blalond Feb 20 '18 at 19:28
  • 1
    In Chrome, I get `Not allowed to navigate top frame to data URL` when opening the PDF. – Kyle Pollard Apr 16 '20 at 17:53
1

Adding to @Dinesh's answer to handle Not allowed to navigate top frame to data URL error in Chrome and Edge

if (data == "" || data == undefined) {
    // Log Error: PDF data not available
} else {
    var byteCharacters = atob(data);                        
    var byteNumbers = new Array(byteCharacters.length);
    for (var i = 0; i < byteCharacters.length; i++) {
      byteNumbers[i] = byteCharacters.charCodeAt(i);
    }
    var byteArray = new Uint8Array(byteNumbers);
    var file = new Blob([byteArray], { type: 'application/pdf;base64' });
                            
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        // For IE
        window.navigator.msSaveOrOpenBlob(file, 'mypdf.pdf');
    } else {
        // For non-IE
        var fileURL = URL.createObjectURL(file);
        window.open(fileURL);
    }
}
Somebody
  • 2,667
  • 14
  • 60
  • 100