base64 string to pdf download - javascript

I am facing issue to download pdf in SAPUI5 application. Issue is Getting base64 string from backend system but not able to convert it and display as PDF.
I am able to convert the base64 and download also but only small size.
Not able to download for larger PDF file its downloading but shows download failed.
kindly help me out
var data =" JVBERi0xLjQNJeLjz9MNCjc1MDEgMCBvYmogPDwvTGluZWFyaXplZCAxL0wgOTM2NDM1Mi9PIDc1MDMvRSAxMjE3ODgvTiA1MjIvVCA5MjE0MjgzL0ggWyA2..";
var uri = 'data:application/pdf;base64,' + atob(data);
var link = document.createElement("a");
link.href = uri;
link.style = "visibility:hidden";
link.download = object.FileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

Saving the data as a blob and setting the download link to get the data from the blog may solve your problem for large files. The most effective way in this mechanism is to get the data from your server as binary instead of Base64. It works with base64 too - but it is just a resource over kill in the blob scenario.
var data = Uint8Array.from(atob(base64_string), c => c.charCodeAt(0));
var blob = new Blob([data], {type: "octet/stream"});
var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
...
...

As per you current solution, a hyperlink will be created with href contains data:application/pdf;base64,' + base64Data. When the hyperlink is clicked the complete URL will be opened in the browser new tab, which makes the browser to download the PFD file.
If the base64 data is bulk then the browser will take time to download PDF. Sometimes browser will be crashed OR leads to download failed error as it takes too much of time to download.
Alternative Options
Using GET_STEAM method you can download the pdf from the backend only.
Using download plugins like downloadjs, FileSaver.js, StreamSaver.js.
As per you requirement you can get different available plugins for file downloading using client-side JavaScript

Here is a sap blog entry solving your problem.
TLDR:
var base64EncodedPDF = "JVBERi0xLjcNCiW..."; // the encoded string
var decodedPdfContent = atob(base64EncodedPDF);
var byteArray = new Uint8Array(decodedPdfContent.length)
for(var i=0; i<decodedPdfContent.length; i++){
byteArray[i] = decodedPdfContent.charCodeAt(i);
}
var blob = new Blob([byteArray.buffer], { type: 'application/pdf' });
var _pdfurl = URL.createObjectURL(blob);
this._PDFViewer.setSource(_pdfurl);

Related

Downloading image in Javascript creates corrupted file

I'm trying to download an image and write it to the disk in Javascript. The image will be delivered base64 encoded by the server. I'm then trying to decode the image, create a blob with that data and create a new URL object. The download itself works, but the output file will be corrupted and unusable. My code looks as follows:
jsonObject = JSON.parse(requestObject.getReturnData());
decoded = atob(jsonObject['DownloadFile']);
url = window.URL.createObjectURL(new Blob([decoded], { type: "image/png" }));
aElement = document.createElement('a');
aElement.style.display = 'none';
aElement.href = url;
aElement.download = 'download.' + jsonObject['DownloadType'];
document.body.appendChild(aElement);
aElement.click();
window.URL.revokeObjectURL(url);
I verified that jsonObject['DownloadFile'] contains the correct base64 representation of the image. However, it seems that there's an error when creating the blob, since its size is too big when looking at the debug console.

How to create a download button in React

I am trying to create a button that triggers a download of a JSON file. (And please i don't want to use any libraries to achieve this). Thank you.
import Data from '../Data';
let data = Data;
<Button>Download</Button>
Triggering browser download from front-end is not reliable.
What you should do is, create an endpoint that when called, will provide the correct response headers, thus triggering the browser download.
Front-end code can only do so much. The 'download' attribute for example, might just open the file in a new tab depending on the browser.
Take a look at this solution: How to create a file in memory for user to download, but not through server? I have rewritten their code a bit, but basically for your case, you'd want...
// Set globals
var mimetype = 'application/json';
var filename = 'yourfile.json';
// Create Dummy A Element
var a = window.document.createElement('a');
// createObjectURL for local data as a Blob type
a.href = window.URL.createObjectURL(new Blob([data], {
encoding: "UTF-8",
type: mimetype + ";charset=UTF-8",
}));
a.download = filename;
// Download file and remove dummy element
document.body.appendChild(a);
a.click();
a.remove();
You would need to create a file using your data and then create a downloadable link
and append it in whichever part of your application you would like to.
const fileName = "file";
const json = JSON.stringify(data);
const blob = new Blob([json],{type:'application/json'});
const href = await URL.createObjectURL(blob); // Create a downloadable link
const link = document.createElement('a');
link.href = href;
link.download = fileName + ".json";
document.body.appendChild(link); // This can any part of your website
link.click();
document.body.removeChild(link);

Opening a file with C# as a BLOB, and downloading with JS as a BLOB

I have a PDF on my .NET Core server, which I need to somehow send across the wire as a BLOB, so that my JS AJAX request can convert it back to a PDF so it can be downloaded.
The reason for the indirection is because the file comes from my API, which is only accessed through AJAX. Due to the need for a Bearer token, I can't just use a form behind the scenes, as there's no cookie for the site created. (Weird, I know, but that's how it is presently, and I'm not looking to change that part)
So, on my C# side, I've tried several variations, shown below. ApiResponse is just a container I use that holds a bool and a string (named message) so I can tell if the request was good or not.
These are what I've been trying
return new ApiResponse(true, File.ReadAllText(path));
return new ApiResponse(true, Convert.ToBase64String(File.ReadAllBytes(path)));
return new ApiResponse(true, JsonConvert.SerializeObject(File.ReadAllBytes(path)));
And on the JS side, in the same order to parse it back out, I have:
// Get the response in object form, since it's sent as an ApiResponse
const response = JSON.parse(xmlhttp.response);
const text = response.message;
const text = atob(response.message)
const text = JSON.parse(response.message)
I've also tried things like
const text = atob(JSON.parse(response.message))
Then, with the text I'm doing this:
const blob = new Blob([text], {type: "application/pdf"});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "file.pdf";
document.body.appendChild(a);
a.click();
And this does correctly generate a file that's downloaded. However, that file is not valid: it's corrupted.
I'm pretty much stuck at this point, and I haven't been able to find something that goes from start to finish using this method to download files with Javascript. It's either the back side, or the front side, but never tied together.
So, how can I successfully send a PDF BLOB across the wire, and recreate it on the front end so it can be downloaded?
The easy answer to how to do the convert is don't.
Every modern browser supports base64 encoding natively, so there's no need to convert the data back to a BLOB before putting it into download.
Thus, the end code is:
const a = document.createElement("a");
a.href = "data:application/pdf;base64," + response.message;
a.download = "file.pdf";
document.body.appendChild(a);
a.click();

Javascript Blob document with html tags to be saved with formatting

I am having some text like below to be saved in a downloadable doc format using javascript blob.
<p style='font-size:18px'>Hello</p>
Once the download happens I want the doc to show just show formatted 'Hello' without any html tags. In ubuntu this works very well.
But when I open the same doc in windows or google docs, I still see html tags.
Is there a way where I can do this formatting at Blob level itself. Below is the way Iam creating blob object.
var file = new Blob([val], {type: "octet/stream"});
Appreciate your help on this.
Try adjusting type of Blob to "text/html" , using URL.objectCreateURL() as file object reference for download
var val = "<div>abc</div>";
var file = new Blob([val], {
type: "text/html"
});
// file object reference
var download = URL.createObjectURL(file);
var a = document.createElement("a");
a.href = download;
a.download = "file-" + new Date().getTime();
document.body.appendChild(a);
a.click()

encodeURI file download - crashing browser

I created a web application to clean up CSV/TSV data. The app allows me to upload a CSV file, read it, fix data, and then download a new CSV file with the correct data. One challenge I have run into is downloading files with more than ~ 2500 lines. The browser crashes with the following error message:
"Aw, Snap! Something went wrong while displaying this webpage..."
To work around this I have changed the programming to download multiple CSV files not exceeding 2500 lines until all the data is downloaded. I would then put together the downloaded CSV files into a final file. That's not the solution I am looking for. Working with files of well over 100,000 lines, I need to download all contents in 1 file, and not 40. I also need a front-end solution.
Following is the code for downloading the CSV file. I am creating a hidden link, encoding the contents of data array (each element has 1000 lines) and creating the path for the hidden link. I then trigger a click on the link to start the download.
var startDownload = function (data){
var hiddenElement = document.createElement('a');
var path = 'data:attachment/tsv,';
for (i=0;i<data.length;i++){
path += encodeURI(data[i]);
}
hiddenElement.href = path;
hiddenElement.target = '_blank';
hiddenElement.download = 'result.tsv';
hiddenElement.click();
}
In my case the above process works for ~ 2500 lines at a time. If I attempt to download bigger files, the browser crashes. What am I doing wrong, and how can I download bigger files without crashing the browser? The file that is crashing the browser has (12,000 rows by 48 columns)
p.s. I am doing all of this in Google Chrome, which allows for file upload. So the solution should work in Chrome.
I've experienced this problem before and the solution I found was to use Blobs to download the CSV. Essentially, you turn the csv data into a Blob, then use the URL API to create a URL to use in the link, eg:
var blob = new Blob([data], { type: 'text/csv' });
var hiddenElement = document.createElement('a');
hiddenElement.href = window.URL.createObjectURL(blob);
Blobs aren't supported in IE9, but if you just need Chrome support you should be fine.
I also faced same problem. I used this code,it will works fine. You can also try this.
if (window.navigator.msSaveBlob) {
window.navigator.msSaveBlob(new Blob([base64toBlob($.base64.encode(excelFile), 'text/csv')]),'data.csv');
} else {
var link = document.createElement('a');
link.download = 'data.csv';
// If u use chrome u can use webkitURL in place of URL
link.href = window.URL.createObjectURL(new Blob([base64toBlob($.base64.encode(excelFile), 'text/csv')]));
link.click();
}

Categories