92

I have a formatted PDF string that looks like

%PDF-1.73 0 obj<<< /Type /Group /S /Transparency /CS /DeviceRGB >> /Resources 2 0 R/Contents 4 0 R>> endobj4 0 obj<> streamx��R=o�0��+��=|vL�R���l�-��ځ,���Ge�JK����{���Y5�����Z˯k�vf�a��`G֢ۢ��Asf�z�ͼ��`%��aI#�!;�t���GD?!���<�����B�b��

...

00000 n 0000000703 00000 n 0000000820 00000 n 0000000926 00000 n 0000001206 00000 n 0000001649 00000 n trailer << /Size 11 /Root 10 0 R /Info 9 0 R >>startxref2015%%EOF

I am trying to open up this string in a new window as a PDF file. Whenever I use window.open() and write the string to the new tab it thinks that the text should be the contents of an HTML document. I want it to recognize that this is a PDF file.

8
  • 2
    How are you "writing" this string? Do you mean it's returned by the backend (if so, what platform?). If the PDF data is being generated by the backend, make sure you set the correct Content-Type header. Commented May 10, 2010 at 18:37
  • Best answer: You should not be using AJAX in this situation. Commented May 10, 2010 at 18:43
  • @Josh - He never mentioned AJAX. It could be a standalone HTML page on a CD dynamically generating customised strings for all we know. I doubt that this is possible though. Commented May 10, 2010 at 18:52
  • 1
    It is being created on the backend but it will not be possible/elegant to save on the server. Furthermore, content is already being written to the page before the pdf is being generated.... thus setting a header to pdf will not work. Commented May 10, 2010 at 18:53
  • 2
    @Josh Stodola why one should not be using AJAX in this situation Commented Jun 29, 2017 at 15:22

17 Answers 17

135

Just for information, the below

window.open("data:application/pdf," + encodeURI(pdfString)); 

does not work anymore in Chrome. Yesterday, I came across with the same issue and tried this solution, but did not work (it is 'Not allowed to navigate top frame to data URL'). You cannot open the data URL directly in a new window anymore. But, you can wrap it in iframe and make it open in a new window like below. =)

let pdfWindow = window.open("")
pdfWindow.document.write(
    "<iframe width='100%' height='100%' src='data:application/pdf;base64, " +
    encodeURI(yourDocumentBase64VarHere) + "'></iframe>"
)
Sign up to request clarification or add additional context in comments.

9 Comments

Works in Chrome but once loaded it consumes CPU and GPU and the tab says it is still loading. Tried with iframe, embed and object.
@SivaKiran setTimeout-0 solve my problem like this setTimeout(() => { pdfWindow.document.write(<iframe width='100%' height='100%' src='${url}'></iframe>); pdfWindow.document.title = ${title}; }, 0);
this work great, the document opened in new tab. But, when I click the download icon on the right corner, nothing happen. How to make it downloadable?
The tab still loading issue is very odd. 4 of our team members used the same button to open the pdf, and for 2 people it shows loading in the favicon, but for 2 of us it doesnt show the loading animation.... everyone is using the same version of chrome...
setTimeout(function(){ pdfWindow.stop() }, 1000); at the end stops the loading issue
|
80
var byteCharacters = atob(response.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' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);

You return a base64 string from the API or another source. You can also download it.

12 Comments

This seems like by far the best solution. Ever other solution seemed to work sporadically at best. I kept trying to encode the string responses from the server, but this seemed to be the only sure fire way. Thanks!
I m getting error "failed to execute atob to window.any help
Is there a way to obfuscate the url. I want to be the name of the file. Right now it shows as encoded base 64 value?
Wish I could upvote this a hundred times! I've been struggling to get larger files to open for days. Thank you ever so much!
@himanshu-chawla awseome answer! As a side question - is there a way to define the default file name when clicking download button, so it doesn't look like 6a5e4cd0-2db4-4c8c-80b8-15b77f911700.pdf but myFile.pdf?
|
25

You might want to explore using the data URI. It would look something like.

window.open("data:application/pdf," + escape(pdfString));

I wasn't immediately able to get this to work, possible because formating of the binary string provided. I also usually use base64 encoded data when using the data URI. If you are able to pass the content from the backend encoded you can use..

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

Hopefully this is the right direction for what you need. Also note this will not work at all in IE6/7 because they do not support Data URIs.

4 Comments

won't work in IE 8+ either, because the URL size will most likely be > 2048 character limit that IE imposes on URLs
I believe this restriction does not apply to Data URIs, only URLs. IE8 has a 32KB Data URI limit that was removed in IE9.
That's great but window.open(url) takes a URL, not a URI. IE chops off anything after 2048 chars, even if you use a data URI. Try this jsfiddle in IE, you'll see it doesn't work: jsfiddle.net/bpdj7ksv
This doesn't work for me window.open('data:application/pdf;base64,' + btoa(unescape(encodeURIComponent(resp))), "_blank", "toolbar=yes, scrollbars=yes, resizable=yes");
21

This one worked for me.

window.open("data:application/octet-stream;charset=utf-16le;base64,"+data64);

This one worked too

 let a = document.createElement("a");
 a.href = "data:application/octet-stream;base64,"+data64;
 a.download = "documentName.pdf"
 a.click();

1 Comment

I put the second part of code in a javascript function and called it onclick function of buttom and get answer very well.
18
window.open("data:application/pdf," + escape(pdfString)); 

The above one pasting the encoded content in URL. That makes restriction of the content length in URL and hence PDF file loading failed (because of incomplete content).

5 Comments

warning: chrome detects this as pop-up and blocks
This will not work in MSIE due to the 2048 max character URL length MS decided to impose.
This limit does not apply to Data URIs, only normal navigational URLs. Reference: msdn.microsoft.com/en-us/library/cc848897(v=vs.85).aspx
does anyone know why you wouldn't be able to interact with this window after opening it? like this var wdw = window.open("data:application/pdf," + escape(pdfString)); wdw.print(); The print function doesn't do anything. And I've even tried using a setTimeout to delay the print, but that doesn't work either. It's like it loses the reference to the window object. If I do the same thing but pass in an actual web url it works.
how you solved such issue when the length of the content is too large ?
17

I realize this is a pretty old question, but I had the same thing come up today and came up with the following solution:

doSomethingToRequestData().then(function(downloadedFile) {
  // create a download anchor tag
  var downloadLink      = document.createElement('a');
  downloadLink.target   = '_blank';
  downloadLink.download = 'name_to_give_saved_file.pdf';

  // convert downloaded data to a Blob
  var blob = new Blob([downloadedFile.data], { type: 'application/pdf' });

  // create an object URL from the Blob
  var URL = window.URL || window.webkitURL;
  var downloadUrl = URL.createObjectURL(blob);

  // set object URL as the anchor's href
  downloadLink.href = downloadUrl;

  // append the anchor to document body
  document.body.appendChild(downloadLink);

  // fire a click event on the anchor
  downloadLink.click();

  // cleanup: remove element and revoke object URL
  document.body.removeChild(downloadLink);
  URL.revokeObjectURL(downloadUrl);
});

7 Comments

This is a good solution! Works only in IE10+ though, according to MDN
on chrome I get document.body.append is not a function and so I used: document.getElementsByTagName('body')[0].appendChild(downloadLink);
Thanks @manuel-84, you found a typo. It should have been appendChild from the start.
Note that adding download property (as in the example) will cause the file to download instead to open in a new window/tab. And it's not supported in Safari.
Hi @ChrisCashwell, I have the same problem. I want to know what is parameter downloadedFile. Why does it contains data property? Is data string or blob?
|
12

An updated version of answer by @Noby Fujioka:

function showPdfInNewTab(base64Data, fileName) {  
  let pdfWindow = window.open("");
  pdfWindow.document.write("<html<head><title>"+fileName+"</title><style>body{margin: 0px;}</style></head>");
  pdfWindow.document.write("<body><embed width='100%' height='100%' src='data:application/pdf;base64, " + encodeURI(base64Data)+"#toolbar=0&navpanes=0&scrollbar=0'></embed></body></html>");
  pdfWindow.document.close();
}

Comments

4

I just want to add with @Noby Fujioka's response, Edge will not support following

window.open("data:application/pdf," + encodeURI(pdfString));

For Edge we need to convert it to blob and this is something like following

//If Browser is Edge
            if (window.navigator && window.navigator.msSaveOrOpenBlob) {
                var byteCharacters = atob(<Your_base64_Report 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, "myreport.pdf");
            } else {
                var pdfWindow = window.open("", '_blank');
                pdfWindow.document.write("<iframe width='100%' style='margin: -8px;border: none;' height='100%' src='data:application/pdf;base64, " + encodeURI(<Your_base64_Report Data>) + "'></iframe>");
            }

Comments

3

Based off other old answers:

escape() function is now deprecated,

Use encodeURI() or encodeURIComponent() instead.

Example that worked in my situation:

window.open("data:application/pdf," + encodeURI(pdfString)); 

2 Comments

Because this open a new tab where in the url are the PDF content, there is a PDF limit size? I did tried many solusions and only this works but... if i have a PDF that is 2 MB ?
@Mistre83 - Not entirely sure I understand your question, but I have used it numerous times on some rather large PDF's and it worked, can't test right now, try it on a large PDF and see, it should work though, if there is a size limit I would assume it to be quite large like 2-4GB (pure guesstimates)
2

I had this problem working with a FedEx shipment request. I perform the request with AJAX. The response includes tracking #, cost, as well as pdf string containing the shipping label.

Here's what I did:

Add a form:

<form id='getlabel' name='getlabel' action='getlabel.php' method='post' target='_blank'>
<input type='hidden' id='pdf' name='pdf'>
</form>

Use javascript to populate the hidden field's value with the pdf string and post the form.

Where getlabel.php:

<?
header('Content-Type: application/pdf');
header('Content-Length: '.strlen($_POST["pdf"]));
header('Content-Disposition: inline;');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
print $_POST["pdf"];
?>

2 Comments

Problem with this method is there is no way to inform the user when the document has downloaded.
I believe target='_blank' will inform the user?
1

In my case, I was receiving a pdf string from the backend and I had to set the responseType in Axios

{
    responseType: 'blob',
} 

and then like this, you can open a pdf file in a new tab

const file = new Blob([file], { type: 'application/pdf' });
const url = URL.createObjectURL(file);
window.open(url, '_blank');

Comments

0

//for pdf view

let pdfWindow = window.open("");
pdfWindow.document.write("<iframe width='100%' height='100%' src='data:application/pdf;base64," + data.data +"'></iframe>");

Comments

0

I just got stuck in 'opening pdf in new page on clicking the name of pdfFile' and this worked for me:

Js-

fileName = '';
    fileUrl = '';

    handleFileUpload(event) {
        const file = event.target.files[0];
        this.fileName = file.name;
        this.fileUrl = URL.createObjectURL(file);
    }

Html-

<div class="slds-form-element">
        <lightning-input
            type="file"
            label="Upload PDF File"
            onchange={handleFileUpload}>
        </lightning-input>
    </div>
    <div class="slds-form-element">
        <a href={fileUrl}  target="_blank">{fileName}</a>
    </div>

Comments

-1

One suggestion is that use a pdf library like PDFJS.

Yo have to append, the following "data:application/pdf;base64" + your pdf String, and set the src of your element to that.

Try with this example:

var pdfsrc = "data:application/pdf;base64" + "67987yiujkhkyktgiyuyhjhgkhgyi...n"

<pdf-element id="pdfOpen" elevation="5" downloadable src="pdfsrc" ></pdf-element>

1 Comment

Life saver, my client has an aversion to pdfs automatically being downloaded to the pc, they just want to be able to print from browser.
-2

Just encode your formatted PDF string in base 64. Then you should do:

$pdf = 'data:application/pdf;base64,'.$base64EncodedString;

return this to javascript and open in a new window:

window.open(return);

Comments

-2

use function "printPreview(binaryPDFData)" to get print preview dialog of binary pdf data.

printPreview = (data, type = 'application/pdf') => {
    let blob = null;
    blob = this.b64toBlob(data, type);
    const blobURL = URL.createObjectURL(blob);
    const theWindow = window.open(blobURL);
    const theDoc = theWindow.document;
    const theScript = document.createElement('script');
    function injectThis() {
        window.print();
    }
    theScript.innerHTML = `window.onload = ${injectThis.toString()};`;
    theDoc.body.appendChild(theScript);
};

b64toBlob = (content, contentType) => {
    contentType = contentType || '';
    const sliceSize = 512;
     // method which converts base64 to binary
    const byteCharacters = window.atob(content); 

    const byteArrays = [];
    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        const slice = byteCharacters.slice(offset, offset + sliceSize);
        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }
        const byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
    }
    const blob = new Blob(byteArrays, {
        type: contentType
    }); // statement which creates the blob
    return blob;
};

Comments

-2

for the latest Chrome version, this works for me :

var win = window.open("", "Title", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=200,top="+(screen.height-400)+",left="+(screen.width-840));
win.document.body.innerHTML = 'iframe width="100%" height="100%" src="data:application/pdf;base64,"+base64+"></iframe>';

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.