Problems downloading base64 as pdf JavaScript - javascript

I'm writing a Google Apps Script Web App, I'm facing a problem.
From server side I return the base64 encoded html code of a page:
function getRAW() {
var formText = 'https://www.google.com/';
var response = UrlFetchApp.fetch(formText);
var pdf1 = response.getAs('application/pdf');
//var myNewFile = DriveApp.createFile(pdf1);
var blob = response.getBlob()
var bytes = blob.getBytes();
var encoded = Utilities.base64Encode(bytes);
return encoded
}
And that works well.
Now, from client side, I want to download the base64 (is an html RAW content) as a pdf file (or .html if it is possible), but If I try to do like this I obtain a blank pdf page
function downloadRAW() {
var encoded = window.value;
var element = document.createElement('a');
element.setAttribute('href', 'data:application/pdf;base64,' + encoded);
element.setAttribute('download', 'prova');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
Note that If I try to obtain a text/plain;base64, works perfectly (return a .txt) file; but this is not what I want.
How can I achieve it?

I believe your goal and your current situation as follows.
You want to convert the HTML data to a PDF data as the raw HTML code.
From I want to download the base64 (is an html RAW content) as a pdf file, I thought that the PDF data has the raw HTML code.
You want to make users download the HTML data as a PDF file.
var encoded = window.value; of your Javascript side is the value of encoded from the function of getRAW() of Google Apps Script.
Modification points:
In this case, in order to convert the raw HTML code (text data) to a PDF data, I would like to propose to use the Google Document. When Google Document is used, the text data can be converted to the PDF data.
When above points are reflected to your script, it becomes as follows.
Modified script:
In this case, please modify getRAW() at Google Apps Script side as follows.
function downloadRAW() {
var formText = 'https://www.google.com/';
var html = UrlFetchApp.fetch(formText).getContentText();
var doc = DocumentApp.create("temp");
doc.getBody().editAsText().setText(html);
doc.saveAndClose();
var file = DriveApp.getFileById(doc.getId());
var blob = file.getBlob();
var bytes = blob.getBytes();
var encoded = Utilities.base64Encode(bytes);
file.setTrashed(true);
return encoded
}
In this modification, at first, the retrieved HTML data is put to the Google Document created as a temporal document, and then, the Google Document is converted to the PDF data and converted to the base64 data, and return the data. And, the temporal Document is removed.
Note:
From (or .html if it is possible), if you want to export it as the text file, how about the following modification?
Google Apps Script side:
function downloadRAW() {
var formText = 'https://www.google.com/';
var blob = UrlFetchApp.fetch(formText).getBlob().setContentType("text/html");
var bytes = blob.getBytes();
var encoded = Utilities.base64Encode(bytes);
return encoded
}
Javascript side:
In this case, please modify element.setAttribute('href', 'data:application/pdf;base64,' + encoded); as follows.
element.setAttribute('href', 'data:text/html;base64,' + encoded);
From your question, I couldn't understand about the method for giving the value of encoded of Google Apps Script side to var encoded = window.value; of Javascript side. So if you want to see the sample script for this. I thought that this thread might be useful. Ref
When the blob of HTML is converted to application/json, the raw HTML code cannot be retrieved. The rendered result is obtained. Please be careful this.
References:
create(name) of Class DocumentApp
saveAndClose()
getFileById(id)

Even if the proposed solution by #Tanaike is very good, I do not want to use additional permission on writing file in the Google Drive of the user (since my script is executed as "Run as user"), so I decided to use JsPDF.
Client-side code:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js"></script>
function downloadRAWPDF() {
// window.value is a global variable that contains base64 encoded content (passed from server)
var encoded = window.value;
var decoded = atob(encoded);
var doc = new jsPDF();
// Resize text to fit in an A4 page
var splitTitle = doc.splitTextToSize(decoded, 270);
var pageHeight = doc.internal.pageSize.height;
doc.setFontType("normal");
doc.setFontSize("11");
var y = 7;
for (var i = 0; i < splitTitle.length; i++) {
if (y > 280) {
y = 10;
doc.addPage();
}
doc.text(15, y, splitTitle[i]);
y = y + 7;
}
doc.save('myPDF.pdf');
}
Server-side code (Google Apps Script):
// #return RAW Response base64 encoded (without response headers)
function getRAW(formObject) {
// contains the value of an Input Field
var formText = formObject.myInput;
var response = UrlFetchApp.fetch(formText);
var blob = response.getBlob()
var bytes = blob.getBytes();
var encoded = Utilities.base64Encode(bytes);
return encoded
}
To convert the file in a html file the approach suggested by #Tanaike is perfect: data:text/html;base64, + encoded

Related

How to lift inline files/images from an email using Google App Script?

I would like to gather the name, content type and byes of all inline files in an email using Google App Script. Message object's have a getAttachments() function in App Script however this only returns an array of Gmail Attachments that are not inline.
When I look at the raw content of the email I can see that the data for an inline image is there but parsing it is difficult and I wanted to check it there was any Google utilities that I'm not aware of?
This was a rather fun one to crack, so here goes.
Get your email's raw contents with .getRawContent(). This contains all the content, included base64 encoded attachments like images.
Parse the email content to narrow it down to an image/gif attachment type
Narrow it down more to the base64 encoded string that is your image
Use the Utilities.base64Decode() utility to get your Byte array
Here is what I came up with:
Note: This will just get the first image, I'm sure you can take this concept and adapt to your own needs.
function myFunction() {
var emails = GmailApp.getThreadById(myThreadID).getMessages();
var contents = emails[0].getRawContent();
var firstImageStart = contents.substring(contents.indexOf('Content-Type: image/gif;'), contents.length); //Finds the image/gif type
var name = firstImageStart.substring(firstImageStart.indexOf('name=') + 5, firstImageStart.indexOf('\r\n')); //get name from raw data
var attachmentStringStart = firstImageStart.substring(firstImageStart.indexOf('X-Attachment-Id:'), firstImageStart.length); //Finds where the attachment ID line is
var startOfBase64 = attachmentStringStart.substring(attachmentStringStart.indexOf('\r\n\r\n') + 4, attachmentStringStart.length); //Finds the end of that line and the start of the base64 encoded attachment
var base64String = startOfBase64.substring(0, startOfBase64.indexOf('\r\n--')); //Finds the end of the base64 encoded attachment
var byteArray = Utilities.base64Decode(base64String); //Retrieves a byteArray of the base64 encoded image
var blob = Utilities.newBlob(byteArray, 'image/gif', name.substring(1, name.length - 1)); //Create blob
var newfile = DriveApp.createFile(blob);
DriveApp.getRootFolder().addFile(newfile); //Write new file to drive root
}
This works, and wrote the image to my drive, which shows as a proper image.
I just followed the pattern the raw content has it's data laid out in, you can view this by clicking the Show Original link in gmail on the dropdown beside the reply button.

Getting image file size transferred with socket.io

in a Node.js with Socket.io project, i get an image via Socket.io like this:
socket.on('newImage', function (data) {
var desc = data.description;
var image = data.img; //i want file size of this
}
in this code, image variable contains image binary data, i want to detect file size of that image. how?
Depending on how the data is encoded you can retrieve the byte length by using the byteLength method:
var encoding = 'binary';
var data = new Buffer('hello world', encoding);
Buffer.byteLength(data, encoding); // 11

Decode Base64 encoded PDF content in browser

We transform HTML to PDF in the backend (PHP) using dompdf. The generated output from dompdf is Base64 encoded with
$output = $dompdf->output();
base64_encode($output);
This Base64 encoded content is saved as a file on the server. When we decode this file content like this:
cat /tmp/55acbaa9600f4 | base64 -D > test.pdf
we get a proper PDF file.
But when we transfer the Base64 content to the client as a string value inside a JSON object (the server provides a RESTful API...):
{
"file_data": "...the base64 string..."
}
And decode it with atob() and then create a Blob object to download the file later on, the PDF is always "empty"/broken.
$scope.downloadFileData = function(doc) {
DocumentService.getFileData(doc).then(function(data) {
var decodedFileData = atob(data.file_data);
var file = new Blob([decodedFileData], { type: doc.file_type });
saveAs(file, doc.title + '.' + doc.extension);
});
};
When we log the decoded content, it seems that the content is "broken", because several symbols are not the same as when we decode the content on the server using base64 -D.
When we encode/decode the content of simple text/plain documents, it's working as expected. But all binary (or not ASCII formats) are not working.
We have searched the web for many hours, but didn't find a solution for this that works for us. Does anyone have the same problem and can provide us with a working solution? Thanks in advance!
This is a example for a on the server Base64 encoded content of a PDF document:
JVBERi0xLjMKMSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZwovT3V0bGluZXMgMiAwIFIKL1BhZ2VzIDMgMCBSID4+CmVuZG9iagoyIDAgb2JqCjw8IC9UeXBlIC9PdXRsaW5lcyAvQ291bnQgMCA+PgplbmRvYmoKMyAwIG9iago8PCAvVHlwZSAvUGFnZXMKL0tpZHMgWzYgMCBSCl0KL0NvdW50IDEKL1Jlc291cmNlcyA8PAovUHJvY1NldCA0IDAgUgovRm9udCA8PCAKL0YxIDggMCBSCj4+Cj4+Ci9NZWRpYUJveCBbMC4wMDAgMC4wMDAgNjEyLjAwMCA3OTIuMDAwXQogPj4KZW5kb2JqCjQgMCBvYmoKWy9QREYgL1RleHQgXQplbmRvYmoKNSAwIG9iago8PAovQ3JlYXRvciAoRE9NUERGKQovQ3JlYXRpb25EYXRlIChEOjIwMTUwNzIwMTMzMzIzKzAyJzAwJykKL01vZERhdGUgKEQ6MjAxNTA3MjAxMzMzMjMrMDInMDAnKQo+PgplbmRvYmoKNiAwIG9iago8PCAvVHlwZSAvUGFnZQovUGFyZW50IDMgMCBSCi9Db250ZW50cyA3IDAgUgo+PgplbmRvYmoKNyAwIG9iago8PCAvRmlsdGVyIC9GbGF0ZURlY29kZQovTGVuZ3RoIDY2ID4+CnN0cmVhbQp4nOMy0DMwMFBAJovSuZxCFIxN9AwMzRTMDS31DCxNFUJSFPTdDBWMgKIKIWkKCtEaIanFJZqxCiFeCq4hAO4PD0MKZW5kc3RyZWFtCmVuZG9iago4IDAgb2JqCjw8IC9UeXBlIC9Gb250Ci9TdWJ0eXBlIC9UeXBlMQovTmFtZSAvRjEKL0Jhc2VGb250IC9UaW1lcy1Cb2xkCi9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nCj4+CmVuZG9iagp4cmVmCjAgOQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMDggMDAwMDAgbiAKMDAwMDAwMDA3MyAwMDAwMCBuIAowMDAwMDAwMTE5IDAwMDAwIG4gCjAwMDAwMDAyNzMgMDAwMDAgbiAKMDAwMDAwMDMwMiAwMDAwMCBuIAowMDAwMDAwNDE2IDAwMDAwIG4gCjAwMDAwMDA0NzkgMDAwMDAgbiAKMDAwMDAwMDYxNiAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDkKL1Jvb3QgMSAwIFIKL0luZm8gNSAwIFIKPj4Kc3RhcnR4cmVmCjcyNQolJUVPRgo=
If you atob() this, you don't get the same result as on the console with base64 -D. Why?
Your issue looks identical to the one I needed to solve recently.
Here is what worked for me:
const binaryImg = atob(base64String);
const length = binaryImg.length;
const arrayBuffer = new ArrayBuffer(length);
const uintArray = new Uint8Array(arrayBuffer);
for (let i = 0; i < length; i++) {
uintArray[i] = binaryImg.charCodeAt(i);
}
const fileBlob = new Blob([uintArray], { type: 'application/pdf' });
saveAs(fileBlob, 'filename.pdf');
It seems that only doing a base64 decode is not enough...you need to put the result into a Uint8Array. Otherwise, the pdf pages appear blank.
I found this solution here:
https://github.com/sayanee/angularjs-pdf/issues/110#issuecomment-579988190
You can use btoa() and atob() work in some browsers:
For Exa.
var enc = btoa("this is some text");
alert(enc);
alert(atob(enc));
To JSON and base64 are completely independent.
Here's a JSON stringifier/parser (and direct GitHub link).
Here's a base64 Q&A. Here's another one.

Oracle Apex Canvas to blob in PNG format saved to item

I am struggling to convert my canvas URL to a blob format, specifically in PNG format. The DataURL is generating quite perfectly when I tested it without the conversion code, the problem comes in when trying to convert it to Blob. I am using an html button that triggers the JavaScript function with the ID buttonTextArea.
I need the Blob file to be linked to my APEX page item, which I use the $s('P9_IMAGE_CODE', Blob) format, which also works when I tested it using text only. Once the page is processed, that item will be sent into a blob column within my table.
Here is my code:
$("#buttonTextArea").click(function(dataURL) {
var BASE64_MARKER = ';base64,';
var canvas = document.getElementById('myCanvas');
var dataURL = canvas.toDataURL();
if (dataURL.indexOf(BASE64_MARKER) == -1) {
var parts = dataURL.split(',');
var contentType = parts[0].split(':')[1];
var raw = decodeURIComponent(parts[1]);
return new Blob([raw], {type: contentType});
}
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {type: contentType});
document.getElementById("textArea").value = dataUrl;
$s('P9_IMAGE_CODE', Blob); --P9_IMAGE_CODE IS THE ITEM ON MY PAGE
});
I have been trying examples from :
https://github.com/blueimp/JavaScript-Canvas-to-Blob/blob/master/README.md
and
https://code.google.com/p/chromium/issues/detail?id=67587
Thank you in advance.
As Jeffrey pointed out, the javasscript "Blob" is not the same as the Oracle BLOB datatype.
The toDataURL function is already returning a base64 encoded string, so what you'd need to do is to save that string and then after submit convert it into a real blob.
Sending it to the database may be a bit of an issue since there is a limit of 32k bytes on an item's content. This means you'll likely have to send the string in chunks to the database. This is then not a VARCHAR2 (which also has a limit of 32k) but a CLOB.
As Wesley points out, there are some workarounds for that. The blog he linked to is one such example. There is also a plugin to facilitate the handling of clobs in apex.
Once you get the base64 string to the database, you'll have to convert it to a real blob. There is no built-in to quickly do this, but once again this is something several people have already solved.
A script is provided here by Tim Hall to convert a CLOB to a BLOB.
So:
In the browser, get the dataURL, which is a base64 encoded string
send it in chunks to the database, where it'll be a CLOB
after everything has been sent, convert the CLOB to a BLOB and save
it in your table

Base64 encode/decode and download content generated in URL

I am generating a string through JavaScript and I need to download it to a text file with a predefined dynamic filename. This way there will be no room for error by employees.
This is obviously not possible in JavaScript due to security issues. However, from what I have read it should be possible with base64 encoding.
I managed to encode the string and open a url with the decoded data. The string has been decoded successfully in this URL. The format is as follows:
var data = 'data:text/plain;base64,'+L_EncodedData;
document.location = data;
I need to open a file dialog with the decoded data so the employees can download the content generated in this URL.
Any help?
Many thanks in advance
If you're still looking for an answer to this, check out my answer here. This is how I would adapt it for your needs.
// Convert the Base64 string back to text.
var txt = atob(data.reportBase64Bytes);
// Blob for saving.
var blob = new Blob([byteString], { type: "text/plain" });
// Tell the browser to save as report.txt.
saveAs(blob, "report.txt");
If you use this, make sure you grab the polyfills that I mention in the other post.
This block is fixed.
window.OpenWindowForBase64 = function(url, callback) {
var image = new Image();
image.src = url;
var w = window.open("");
w.document.write(image.outerHTML);
if (callback) {
callback(url);
}
}

Categories

Resources