Saving a PDF returned by service - javascript

I'm using FileSaver.js and Blob.js into an Angular JS application to save a PDF returned by a REST service (which returns an array of bytes representing the file).
var headers = {headers: {"Authorization":"Bearer "+token, "Accept":"application/pdf"}};
$http.get(URL, headers)
.success(function (data) {
var blob = new Blob([data], {type: 'application/pdf'});
saveAs(blob, 'contract.pdf');
});
the file gets saved with the right type and the number of pages is correct, but it's totally blank.
Opening it with an editor, it turned out the it contains only the first part of the data returned by the server, like it's truncated.
Thank everyone for helping out!

$http.get probably isn't handling binary data correctly. Try $http({method: "GET", url: URL, responseType: "arraybuffer", ...}) (see angularjs) to get a binary object you can put in for data.
You can also use responseType: "blob" so you don't even have to create var blob, but I think that responseType has less browser support.

Adding a response type to the config argument worked for me. Try:
var config = { responseType: 'blob', headers: {"Authorization":"Bearer "+token,
"Accept":"application/pdf"}};
$http.get(URL, config)
.success(function (data) {
var blob = new Blob([data], {type: 'application/pdf'});
saveAs(blob, 'contract.pdf');
});

Related

google script create file from external blob

I'm getting a PDF file from an external web resource using ajax.
I want to store this PDF in the google drive using google script API from within google docs.
Sample of that ajax call:
$.ajax({
url: "<fancyurl>",
contentType: 'application/octet-stream',
responsetype: 'blob',
type: 'GET',
success: function(response) {
// or converted response.. etc..
google.script.run.withSuccessHandler(yay).withUserObject(this).createFile(response);
});
The response from the webresource is an octet-stream:
I've tried to import the original response, the response converted to blob, a uint8 blob and the base64string. All end up in errors or corrupt files.
var blob = Utilities.newBlob(data, 'application/pdf' ,'asdf.pdf');
// blob.setName('asdf.pdf');
// blob.setContentTypeFromExtension();
DriveApp.createFile(blob);
Where data is the response or converted response.
Does anybody know how to solve this or what google script expects as a valid input?
In my experience, when the binary data is retrieved using ajax, the binary data is converted to the text data. By this, I'm worried that responsetype of blob and arraybuffer might not be able to be used. I thought that this might be the reason of your issue. So, in this answer, I would like to propose using "XMLHttpRequest" instead of "ajax".
The modified script is as follows.
Modified script:
From:
$.ajax({
url: "<fancyurl>",
contentType: 'application/octet-stream',
responsetype: 'blob',
type: 'GET',
success: function(response) {
// or converted response.. etc..
google.script.run.withSuccessHandler(yay).withUserObject(this).createFile(response);
});
To:
const xhr = new XMLHttpRequest();
xhr.open('GET', "<fancyurl>", true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
google.script.run.withSuccessHandler(yay).withUserObject(this).createFile([...new Int8Array(this.response)]);
};
xhr.send();
In this modification, the binary data is converted to the array buffer and converted it to int8 array. By this, this data can be used as the byte array with Google Apps Script.
In this case, although I cannot see your whole script of Google Apps Script, you can use your Google Apps Script as follows.
function createFile(data) {
var blob = Utilities.newBlob(data, 'application/pdf', 'asdf.pdf');
DriveApp.createFile(blob);
}

PDF Blob is showing nothing in new tab, using stream from backend

I used https://github.com/barryvdh/laravel-dompdf
stream method for sending a response to front-end.
Here is my code which I wrote for opening pdf in a new tab.I'm calling stream from backend API in result it gives a response but when I try to create blob it shows nothing in PDF.
APICaller({
method: 'get',
responseType: "arraybuffer",
headers: {
'Accept': 'application/pdf'
},
endpoint: gep('generate/certificate?path=certificate.pdf', 'v3'),
}).then( (data) => {
var file = new Blob([data.data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
});
here is Empty PDF
I had a similar issue with axios, it doesn't work for downloading files using Blob. Use XMLHttpRequest and do the similar response handler in its on('load') event to achieve file download.

Generating PDF from wkhtml using PHP wrapper, when sent back to Angular 4, opens only in Chrome

I generate a html in Angular 4, send it to PHP wrapper for wkhtmltopdf, after that it is returned to Angular, and this works fine in Chrome, the PDF is displayed. I need it to be displayed also in Firefox. This is the code that sends the PDF to PHP:
public getPdf() {
const html = this.pdfEl.innerHTML;
alert(html);
this.rest.post(
'/pdf',
{ html },
{
headers: new Headers(),
responseType: ResponseContentType.Blob
}
).subscribe(
(value) => {
//alert('subscribe receiver in pdf button directive');
this.url = URL.createObjectURL(value.blob());
open(this.url);
});
}
Things that I have tried so far, but none worked are:
1. Setting this.url = URL.createObjectURL(new Blob([value.blob()], {type: 'application/pdf'})); instead of this.url = URL.createObjectURL(value.blob());
2. Setting this as headers instead of new Headers() :
new Headers({
'Content-Type': 'application/json',
'Accept': 'application/pdf'
}),
any suggestions to resolve this, guys? Thanks.
If value.blob() returns a Blob you have also set the blob type to application/pdf. That has to be done on the response side, because the property is read only.
Blob Documentation
Blob.type Read only A string indicating the MIME type of the data
contained in the Blob. If the type is unknown, this string is empty.
Or if you value.blob() returns only an array buffer you have to create a new Blob on your own.
new Blob([value.blob()], {type: 'application/pdf'});

Posting a base64 encoded PDF file with AJAX

I'm trying to post a base64-encoded PDF file to a Zendesk file upload API endpoint but the file URL returned from the API shows that the file is corrupted.
First I receive the PDF as a base64-encoded string from a separate API call. Let's call it base64String.
If I do window.open("data:application/pdf;base64," + base64String) I can view the PDF in my browser.
Now I am trying to follow the documentation here for uploading files via the API. I can successfully complete a cURL call as shown in the example. However, the jQuery AJAX call will corrupt the PDF file.
client.request({
url: '/api/v2/uploads.json?filename=test.pdf',
type: 'POST',
data: atob(base64String),
contentType: 'application/binary'
}).then(function(data) {
window.open(data.upload.attachment.content_url); // corrupt file
}, function(response) {
console.log("Failed to upload file to Zendesk.");
console.log(response);
});
Like I said, this will succeed but when I visit the content_url the PDF does not display. I am quite sure the file is being corrupt in the POST request.
I have tried uploading the file as a base64 string (without decoding with atob()) with no luck among other things.
UPDATE
I'm still not able to view the PDF after converting the base64 string to blob.
var blob = base64ToBlob(base64String);
console.log(blob); // Blob {size:39574, type: "application/pdf"}
client.request({
url: '/api/v2/uploads.json?filename=test.pdf',
type: 'POST',
data: blob,
processData: false,
contentType: 'application/pdf'
}).then(function(data) {
window.open(data.upload.attachment.content_url); // corrupt file
}, function(response) {
console.log("Failed to upload file to Zendesk.");
console.log(response);
});
function base64ToBlob(byteString) {
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
var blob = new Blob([ab], {type: 'application/pdf'});
return blob;
};
I learned that the Zendesk app framework uses a jQuery AJAX wrapper for requests and the arraybuffer type is unsupported, so the file was getting corrupted. The app framework team has fixed the issue.

Angular form uploading not working in Safari, working in Chrome

I try upload file using angular $http.
It works properly in Chrome, and Even send a request in Safari (and have 200 response from server), but not file not uploaded to server.
I also try to use ngUpload library, but with the same result - file has not been uploaded to the server.
Source code:
var formData = new FormData();
formData.append('userid', Users.getCurrentId());
formData.append('avatar', myFile); // this is File() size abput 100K
$http({
url: AppState.getApiHost()+AppState.getApiPrefix() + '/setavatar',
method: "POST",
data: formData,
headers: {'Content-Type': undefined}
})
.then(function (res) {
console.log('Success', res);
})
.catch(function (err) {
console.log('Error',err)
});
I've just found an answer. The problem was with File() object was created using File() constructor:
return new File([u8arr], filename, {type:mime});
But it not working properly with Safari. It creates File object with size equal size of file but actual file was empty. And if I try to send it after append to form - form has sent empty file (even if it looks as a not empty file).
I've replaced it to this code:
var the_blob = new Blob([u8arr]);
the_blob.lastModifiedDate = new Date();
the_blob.name = 'avatar.png'
return the_blob;
This is work for me

Categories