UPDATE:
Creating a Blob from a base64 string in JavaScript
I am trying to implement click a button and download file from its DataURL.
Currently, since the Chrome has restricted the old way such as building <a> link which throws error like:
Not allowed to navigate top frame to data URL: ....
The solution I found is open new window with iframe and set the DataURL as its src
let jpgWindow = window.open("", "_blank")
var html = "<html><body><iframe width='100%' height='100%' src='data:application/jpeg;base64, "+ theDataURL+"'></iframe></body></html>";
jpgWindow.document.write(html)
When I click the button, the download works, but the picture is downloaded with filename "download", there is no way I can specify what file name I want it default to.
Any thought?
Look into window.URL.createObjectURL https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
const blob = new Blob(['array of data in your file'], {type : 'text/rtf'});
const anchor = document.createElement('a');
anchor.href = window.URL.createObjectURL(blob);
anchor.download = 'the-file-name.txt';
anchor.click();
I am trying to build a PDF file out of a binary stream which I receive as a response from an Ajax request.
Via XmlHttpRequest I receive the following data:
%PDF-1.4....
.....
....hole data representing the file
....
%% EOF
What I tried so far was to embed my data via data:uri. Now, there's nothing wrong with it and it works fine. Unfortunately, it does not work in IE9 and Firefox. A possible reason may be that FF and IE9 have their problems with this usage of the data-uri.
Now, I'm looking for any solution that works for all browsers. Here's my code:
// responseText encoding
pdfText = $.base64.decode($.trim(pdfText));
// Now pdfText contains %PDF-1.4 ...... data...... %%EOF
var winlogicalname = "detailPDF";
var winparams = 'dependent=yes,locationbar=no,scrollbars=yes,menubar=yes,'+
'resizable,screenX=50,screenY=50,width=850,height=1050';
var htmlText = '<embed width=100% height=100%'
+ ' type="application/pdf"'
+ ' src="data:application/pdf,'
+ escape(pdfText)
+ '"></embed>';
// Open PDF in new browser window
var detailWindow = window.open ("", winlogicalname, winparams);
detailWindow.document.write(htmlText);
detailWindow.document.close();
As I have said, it works fine with Opera and Chrome (Safari hasn't been tested). Using IE or FF will bring up a blank new window.
Is there any solution like building a PDF file on a file system
in order to let the user download it? I need the solution that works in all browsers, at least in IE, FF, Opera, Chrome and Safari.
I have no permission to edit the web-service implementation. So it had to be a solution at client-side. Any ideas?
Is there any solution like building a pdf file on file system in order
to let the user download it?
Try setting responseType of XMLHttpRequest to blob , substituting download attribute at a element for window.open to allow download of response from XMLHttpRequest as .pdf file
var request = new XMLHttpRequest();
request.open("GET", "/path/to/pdf", true);
request.responseType = "blob";
request.onload = function (e) {
if (this.status === 200) {
// `blob` response
console.log(this.response);
// create `objectURL` of `this.response` : `.pdf` as `Blob`
var file = window.URL.createObjectURL(this.response);
var a = document.createElement("a");
a.href = file;
a.download = this.response.name || "detailPDF";
document.body.appendChild(a);
a.click();
// remove `a` following `Save As` dialog,
// `window` regains `focus`
window.onfocus = function () {
document.body.removeChild(a)
}
};
};
request.send();
I realize this is a rather old question, but here's the solution I came up with today:
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.append(downloadLink);
// fire a click event on the anchor
downloadLink.click();
// cleanup: remove element and revoke object URL
document.body.removeChild(downloadLink);
URL.revokeObjectURL(downloadUrl);
}
I changed this:
var htmlText = '<embed width=100% height=100%'
+ ' type="application/pdf"'
+ ' src="data:application/pdf,'
+ escape(pdfText)
+ '"></embed>';
to
var htmlText = '<embed width=100% height=100%'
+ ' type="application/pdf"'
+ ' src="data:application/pdf;base64,'
+ escape(pdfText)
+ '"></embed>';
and it worked for me.
The answer of #alexandre with base64 does the trick.
The explanation why that works for IE is here
https://en.m.wikipedia.org/wiki/Data_URI_scheme
Under header 'format' where it says
Some browsers (Chrome, Opera, Safari, Firefox) accept a non-standard
ordering if both ;base64 and ;charset are supplied, while Internet
Explorer requires that the charset's specification must precede the
base64 token.
I work in PHP and use a function to decode the binary data sent back from the server. I extract the information an input to a simple file.php and view the file through my server and all browser display the pdf artefact.
<?php
$data = 'dfjhdfjhdfjhdfjhjhdfjhdfjhdfjhdfdfjhdf==blah...blah...blah..'
$data = base64_decode($data);
header("Content-type: application/pdf");
header("Content-Length:" . strlen($data ));
header("Content-Disposition: inline; filename=label.pdf");
print $data;
exit(1);
?>
Detect the browser and use Data-URI for Chrome and use PDF.js as below for other browsers.
PDFJS.getDocument(url_of_pdf)
.then(function(pdf) {
return pdf.getPage(1);
})
.then(function(page) {
// get a viewport
var scale = 1.5;
var viewport = page.getViewport(scale);
// get or create a canvas
var canvas = ...;
canvas.width = viewport.width;
canvas.height = viewport.height;
// render a page
page.render({
canvasContext: canvas.getContext('2d'),
viewport: viewport
});
})
.catch(function(err) {
// deal with errors here!
});
I saw another question on just this topic recently (streaming pdf into iframe using dataurl only works in chrome).
I've constructed pdfs in the ast and streamed them to the browser. I was creating them first with fdf, then with a pdf class I wrote myself - in each case the pdf was created from data retrieved from a COM object based on a couple of of GET params passed in via the url.
From looking at your data sent recieved in the ajax call, it looks like you're nearly there. I haven't played with the code for a couple of years now and didn't document it as well as I'd have cared to, but - I think all you need to do is set the target of an iframe to be the url you get the pdf from. Though this may not work - the file that oututs the pdf may also have to outut a html response header first.
In a nutshell, this is the output code I used:
//We send to a browser
header('Content-Type: application/pdf');
if(headers_sent())
$this->Error('Some data has already been output, can\'t send PDF file');
header('Content-Length: '.strlen($this->buffer));
header('Content-Disposition: inline; filename="'.$name.'"');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
ini_set('zlib.output_compression','0');
echo $this->buffer;
So, without seeing the full response text fro the ajax call I can't really be certain what it is, though I'm inclined to think that the code that outputs the pdf you're requesting may only be doig the equivalent of the last line in the above code. If it's code you have control over, I'd try setting the headers - then this way the browser can just deal with the response text - you don't have to bother doing a thing to it.
I simply constructed a url for the pdf I wanted (a timetable) then created a string that represented the html for an iframe of the desired sie, id etc that used the constructed url as it's src. As soon as I set the inner html of a div to the constructed html string, the browser asked for the pdf and then displayed it when it was received.
function showPdfTt(studentId)
{
var url, tgt;
title = byId("popupTitle");
title.innerHTML = "Timetable for " + studentId;
tgt = byId("popupContent");
url = "pdftimetable.php?";
url += "id="+studentId;
url += "&type=Student";
tgt.innerHTML = "<iframe onload=\"centerElem(byId('box'))\" src='"+url+"' width=\"700px\" height=\"500px\"></iframe>";
}
EDIT: forgot to mention - you can send binary pdf's in this manner. The streams they contain don't need to be ascii85 or hex encoded. I used flate on all the streams in the pdf and it worked fine.
You can use PDF.js to create PDF files from javascript... it's easy to code... hope this solve your doubt!!!
Regards!
this is what I want to do:
1) a browser initiates an ajax request to the server, asking for a pdf.
2) the server downloads the pdf, and returns the pdf for display.
3) the browser displays the downloaded pdf in a pre-existing iframe.
Below is my code. It appears to stop at the iframe part, but I suspect that its not sending the pdf properly.
Browser index.html file:
var uri = '/viewer/loaddrawing/';
$.getJSON(uri, {key:value}, function(data, jqXHR){
document.getElementById("iframetitle").src = uri;
});
Django server views.py file:
import requests
def loaddrawing(request):
value = request.GET.get('key')
#the key is used to generate a unique url, but for test purposes lets use the url shown below
url = "http://cbmeturkey.com/media/109/test.pdf"
response = urllib2.urlopen(url)
some_data = response.read()
return HttpResponse(some_data, mimetype='application/pdf')
EDIT:
I have one issue remaining: I don't want to use the below code in my index.html file anyway, because I want to actually download the pdf and use it again. The reason for this is that my index.html page uses javascript to display and hide the iframe, and with the below code the pdf is redownloaded each time the iframe is shown.
var uri = '/viewer/loaddrawing/';
document.getElementById('iframetitle').src = uri + '?key=' + value;
SOLVED:
The above issue was solved after directions from Augusto, and the following index.html code, which loads the pdf only once, although notice that now I am now modifying a div (named "divtitle") and not an iframe:
var uri = '/viewer/loaddrawing/' + '?key=' + value;
var htm = '\<iframe src="' + uri +'" onload="downloadComplete()">\</iframe>';
document.getElementById('divtitle').innerHTML = htm;
Probably what you meant was simply:
var uri = '/viewer/loaddrawing/';
document.getElementById('iframetitle').src = uri + '?key=' + value;
There is no JSON involved, so the iframe will get a PDF directly. However, notice that the client must have a PDF-viewer plugin, otherwise the browser will ask for a download prompt.
I have used Blob and URL.createObjectURL() to get an "object URL" (blob:) to some binary PDF data.
In FireFox and Chrome, if I include an <A/> link HTML element, with its href programmatically set to the object URL, that link is clickable and causes the PDF to be shown.
In IE10, I get the object URL OK. The link HTML element shows OK and has a blob: target. But clicking on it does not result in the PDF being shown. Instead, I get a blank window and the IE icon spinning forever.
Yet, even in IE10, right-click save-target-as on the link does save a PDF file containing the correct data. This file can be opened successfully outside of the browser.
Anyone know why IE isn't showing me the PDF file? Any suggestions how I can cause it to do so? Alternatively, any suggestions for persuading it only to offer to save the link, rather than trying and failing to open it.
Here is a page and script to reproduce the issue: -
Click this link
<script type="text/javascript">
var TEST_PDF_DATA = "JVBERi0xLjYNJeLjz9MNMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvUGFnZXMgMiAwIFIgPj4KZW5kb2JqCjIgMCBvYmoKPDwgL1R5cGUgL1BhZ2VzIC9LaWRzIFsgNyAwIFIgXSAvUmVzb3VyY2VzIDQgMCBSIC9Db3VudCAxIC9NZWRpYUJveCAzIDAgUiA+PgplbmRvYmoKMyAwIG9iagpbIDAgMCA1OTUgODQyIF0KZW5kb2JqCjQgMCBvYmoKPDwgL0ZvbnQgNSAwIFIgPj4KZW5kb2JqCjUgMCBvYmoKPDwgL2RlZmF1bHQgNiAwIFIgPj4KZW5kb2JqCjYgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL0Jhc2VGb250IC9Db3VyaWVyLUJvbGQgL1N1YnR5cGUgL1R5cGUxID4+CmVuZG9iago3IDAgb2JqCjw8IC9QYXJlbnQgMiAwIFIgL1R5cGUgL1BhZ2UgL0NvbnRlbnRzIFsgOCAwIFIgXSAvUmVzb3VyY2VzIDQgMCBSIC9NZWRpYUJveCAzIDAgUiA+PgplbmRvYmoKOCAwIG9iago8PCAvRmlsdGVyIC9GbGF0ZURlY29kZSAvTGVuZ3RoIDY4ID4+DXN0cmVhbQ14nDNQSOd1CuHVT0lNSyzNKVEwNlIISeM1VDAAQkMQz9zcWM/CHCiay6vhkZqTk68Qnl+Uk6KoqRCSxesawgsADSoQLA1lbmRzdHJlYW0KZW5kb2JqCnhyZWYNMCA5DTAwMDAwMDAwMDAgNjU1MzUgZg0KMDAwMDAwMDAxNSAwMDAwMCBuDQowMDAwMDAwMDY0IDAwMDAwIG4NCjAwMDAwMDAxNTYgMDAwMDAgbg0KMDAwMDAwMDE4NyAwMDAwMCBuDQowMDAwMDAwMjIwIDAwMDAwIG4NCjAwMDAwMDAyNTYgMDAwMDAgbg0KMDAwMDAwMDMyOSAwMDAwMCBuDQowMDAwMDAwNDI5IDAwMDAwIG4NCnRyYWlsZXINPDwgL1NpemUgOSAvUm9vdCAxIDAgUiA+Pg1zdGFydHhyZWYNNTY4DSUlRU9G";
var byteCharacters = atob(TEST_PDF_DATA);
var charCodeFromCharacter = function(c) { return c.charCodeAt(0); }
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += 1000)
{
var slice = byteCharacters.slice(offset, offset + 1000);
var byteNumbers = Array.prototype.map.call(slice, charCodeFromCharacter);
byteArrays.push(new Uint8Array(byteNumbers));
}
var blob = new Blob(byteArrays, { type: "application/pdf" });
var url = URL.createObjectURL(blob);
document.getElementById("theLink").href = url;
document.getElementById("theLink").innerHTML = url;
</script>
Take a look at the following url
https://superuser.com/questions/560647/ie10-unexpectedly-sends-a-head-request-for-pdf-what-has-changed
Looks like IE10 is sending a head request
You should open the url first as user action then populate pdf
Check this one:
how to bypass pop-up blocker in angular 6?
In javascript I have a string, containing an SpreadsheetML file (excel xml)
I want to open a new window, and write this data to it, but have it open as excel.
Can I do that from javascript?
Yes, you can do that with a data URL,. First, encode the document as base64. Then, use the following URL as source of your window:
var mtype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
var url = 'data:' + mtype + ';base64,' + base64data;
window.open(url);
This will require a modern browser.