74

I have been working on this problem for the last few days. With no luck on trying to display the stream on <embed src> tag, I just tried to display it on a new window.

The new window shows PDF controls only enter image description here)

Any idea why the content of the pdf is not showing?

CODE:

$http.post('/fetchBlobURL',{myParams}).success(function (data) { var file = new Blob([data], {type: 'application/pdf'}); var fileURL = URL.createObjectURL(file); window.open(fileURL); }); 
3

11 Answers 11

181

You need to set the responseType to arraybuffer if you would like to create a blob from your response data:

$http.post('/fetchBlobURL',{myParams}, {responseType: 'arraybuffer'}) .success(function (data) { var file = new Blob([data], {type: 'application/pdf'}); var fileURL = URL.createObjectURL(file); window.open(fileURL); }); 

more information: Sending_and_Receiving_Binary_Data

Sign up to request clarification or add additional context in comments.

7 Comments

Doesn't work for me. When typing the URL in the browser window, it works, but not via the $http.post method. Is there anything else to pay attention to? Security settings? Browser type and version?
It is working now. Seems the arrayBuffer was implemented as of v.1.1 in angularjs. I had v.1.08. When upgrading angularjs, everything worked just fine.
This almost works for me. I need to do the same, but I have to set a user-friendly URL or fileName. The UUID that browser sets it doesn't work for me. Do you know if there is a way to open a PDF in a new tab and set the file name in the URL? Thanks!
URL.createObjectURL() is deprecated from Chrome 71. developers.google.com/web/updates/2018/10/chrome-71-deps-rems You can not use it anymore.
|
32

If you set { responseType: 'blob' }, no need to create Blob on your own. You can simply create url based with response content:

$http({ url: "...", method: "POST", responseType: "blob" }).then(function(response) { var fileURL = URL.createObjectURL(response.data); window.open(fileURL); }); 

7 Comments

Excellent! This worked for me after spending many hours trying to display the pdf content.
ncaught TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided. at Object.success (enquiry.js:68) at j (jquery.js:2) at Object.fireWith [as resolveWith] (jquery.js:2) at x (jquery.js:4) at XMLHttpRequest.<anonymous> (jquery.js:4)
@ThakhaniTharage which browser do you use? Check compatibility table
how about when the response is not there and application/pdf is the response
|
10

I use AngularJS v1.3.4

HTML:

<button ng-click="downloadPdf()" class="btn btn-primary">download PDF</button> 

JS controller:

'use strict'; angular.module('xxxxxxxxApp') .controller('MathController', function ($scope, MathServicePDF) { $scope.downloadPdf = function () { var fileName = "test.pdf"; var a = document.createElement("a"); document.body.appendChild(a); MathServicePDF.downloadPdf().then(function (result) { var file = new Blob([result.data], {type: 'application/pdf'}); var fileURL = window.URL.createObjectURL(file); a.href = fileURL; a.download = fileName; a.click(); }); }; }); 

JS services:

angular.module('xxxxxxxxApp') .factory('MathServicePDF', function ($http) { return { downloadPdf: function () { return $http.get('api/downloadPDF', { responseType: 'arraybuffer' }).then(function (response) { return response; }); } }; }); 

Java REST Web Services - Spring MVC:

@RequestMapping(value = "/downloadPDF", method = RequestMethod.GET, produces = "application/pdf") public ResponseEntity<byte[]> getPDF() { FileInputStream fileStream; try { fileStream = new FileInputStream(new File("C:\\xxxxx\\xxxxxx\\test.pdf")); byte[] contents = IOUtils.toByteArray(fileStream); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/pdf")); String filename = "test.pdf"; headers.setContentDispositionFormData(filename, filename); ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK); return response; } catch (FileNotFoundException e) { System.err.println(e); } catch (IOException e) { System.err.println(e); } return null; } 

Comments

4

You are not required to set the response type if your data is a byte array, make sure you convert it to Uint8Array before passing it to blob.

Example:

let byteArray = new Uint8Array(data) let file = new Blob( [byteArray], {type: 'application/pdf'} ) 

It works for me.

If your data is not byteArray, make sure to convert it to byteArray and follow above-mentioned steps to make it work.

//For example if your data is base-64 encoded string. let byteChars = atob(data); //To decrypt data let dataArray = = new Array(byteChars.length); for(let i=0; i< byteChars.length; i++){ dataArray[i] = byteChars.charCodeAt(i); } let byteArray = new Uint8Array(dataArray) let file = new Blob( [byteArray], {type: 'application/pdf'} ) 

Comments

3
// I used this code with the fpdf library. // Este código lo usé con la libreria fpdf. var datas = json1; var xhr = new XMLHttpRequest(); xhr.open("POST", "carpeta/archivo.php"); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.responseType = "blob"; xhr.onload = function () { if (this.status === 200) { var blob = new Blob([xhr.response], {type: 'application/pdf'}); const url = window.URL.createObjectURL(blob); window.open(url,"_blank"); setTimeout(function () { // For Firefox it is necessary to delay revoking the ObjectURL window.URL.revokeObjectURL(datas) , 100 }) } }; xhr.send("men="+datas); 

Comments

2

I know this is old but since this pointed me in the right direction, I thought I would share what I am doing in case someone else lands here. I am not using Angular btw.

The user can view or download the file. The choice is given with 2 buttons or 2 links

<button type="button" class="btn btn-primary btn-sm show_tooltip download-form" title="Download File" data-formid="{{ @your-id }}" data-forcedownload="1"> <i class="fas fa-file-download"></i> </button> <button type="button" class="btn btn-primary btn-sm show_tooltip download-form" title="View File" data-formid="{{ @your-id }}" data-forcedownload="0"> <i class="fas fa-search"></i> </button> 

I am using jQuery with the native plugin for xhr2. This handles the link/buttons

$('.download-form').click(function(event) { event.preventDefault(); let fid = $(this).data('formid'); let force_download = $(this).data('forcedownload'); $.ajax({ url: '/download', dataType: 'native', type: 'POST', xhrFields: { responseType: 'blob' }, data: { //you can send any parameters via POST here personID: "{{ @personID }}", file_record_id: pfid, file_type: "contract_form", dept: "your-dept", file_category: "fcategory", force_download: force_download }, success: function(blob, status, xhr){ if (xhr.getResponseHeader('Custom-FileError')>1) { alertify.error(xhr.getResponseHeader('Custom-ErrorMsg')); }else{ //I thought this would work when viewing the PDF but it does not. blob.name = xhr.getResponseHeader('Custom-FileName'); var fileURL = URL.createObjectURL(blob); if (xhr.getResponseHeader('Custom-ForceDownload')==1) { window.open(fileURL); var link=document.createElement('a'); link.href=window.URL.createObjectURL(blob); link.download=xhr.getResponseHeader('Custom-FileName'); link.click(); }else{ file_modal(fileURL,'Any Title'); } } } }) }); 

Then, some more javascript for the modal

function file_modal(blob,the_title) { let spinner = "<div class='text-center'><i class='fa fa-spinner fa-spin fa-5x fa-fw'></i></div>"; $("#modal_static_label").html('Loading'); $("#modal_static .modal-body").html(spinner); if (blob.length > 1) { $("#modal_static").modal("show"); $("#modal_static_label").html(the_title); $("#modal_static .modal-body").empty().append('<iframe src='+blob+' width="100%" height="500px" style="border:none;"></iframe>'); }else{ $("#modal_static .modal-body").empty().html('File error'); } $("#modal_static .modal-footer").html('<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>'); } 

On the server side you will need to send custom headers like this [PHP]

 header("Content-length: $file_size"); header("Custom-FileError: 0"); header("Custom-FileName: ".$this->params['original_filename']); header("Custom-ForceDownload: ".$this->params['force_download']); header('Content-Type: '.$web->mime($this->full_path.$this->new_file_name)); readfile($this->full_path.$this->new_file_name); 

If the user clicks "view", a modal will display the PDF if they click "download", the download window will show up with the filename of your choosing. I have tested this with PDF files less than 10mb and it works as expected.

I hope someone finds this useful.

1 Comment

``` xhrFields: { responseType: 'blob' }, ``` fixed it for me.
1

I have been struggling for days finally the solution which worked for me is given below. I had to make the window.print() for PDF in new window needs to work.

 var xhr = new XMLHttpRequest(); xhr.open('GET', pdfUrl, true); xhr.responseType = 'blob'; xhr.onload = function(e) { if (this['status'] == 200) { var blob = new Blob([this['response']], {type: 'application/pdf'}); var url = URL.createObjectURL(blob); var printWindow = window.open(url, '', 'width=800,height=500'); printWindow.print() } }; xhr.send(); 

Some notes on loading PDF & printing in a new window.

  • Loading pdf in a new window via an iframe will work, but the print will not work if url is an external url.
  • Browser pop ups must be allowed, then only it will work.
  • If you try to load iframe from external url and try window.print() you will get empty print or elements which excludes iframe. But you can trigger print manually, which will work.

6 Comments

This did not work for me i got enquiry.js:85 Uncaught TypeError: Cannot read property 'print' of null at XMLHttpRequest.xhr.onload
Does new window opened? This sample has been worked for me earlier.
Nop it does not
pdf URL must be from the same server. Otherwise, it will show CORS error.
See the working sample link pdf-print-pckrishnadas88.c9users.io/hello-world.html. Please note it will be available for few hours as it is a free account.
|
1

problem is, it is not converted to proper format. Use function "printPreview(binaryPDFData)" to get print preview dialog of binary pdf data. you can comment script part if you don't want print dialog open.

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

-1

I ended up just downloading my pdf using below code

function downloadPdfDocument(fileName){ var req = new XMLHttpRequest(); req.open("POST", "/pdf/" + fileName, true); req.responseType = "blob"; fileName += "_" + new Date() + ".pdf"; req.onload = function (event) { var blob = req.response; //for IE if (window.navigator && window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveOrOpenBlob(blob, fileName); } else { var link = document.createElement('a'); link.href = window.URL.createObjectURL(blob); link.download = fileName; link.click(); } }; req.send(); 

}

3 Comments

it starts download.
That's what I wanted, That's why it's in a function so that I can call it when I am ready to do the download. Not sure why you downvoted
that is what i wanted also :-)
-1

Add

responseType: "arraybuffer" 

in API config.
This features make resizing ArrayBuffers more efficient. Otherwise, you have to make a copy of the buffer with a new size.

Comments

-3

let url = "data:application/pdf;base64," + base64PdfFile fetch(url) .then(res => res.blob()) .then(response => { console.log(response); let url = window.URL.createObjectURL(response); let link = document.createElement("a"); link.target = "_blank"; link.href = url; document.body.appendChild(link); link.click(); });

Note: this.file should be you base64 file

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.