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
Related
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.
I am trying to save image canvas to disk as .png in chrome extension with file name reflecting MD5 hash. For this I use something like this:
var img = document.createElement("img");
img.src=canvas.toDataURL("image/png");
var image_data = atob(img.src.split(',')[1]);
var arraybuffer = new ArrayBuffer(image_data.length);
var view = new Uint8Array(arraybuffer);
for (var i=0; i<image_data.length; i++) {
view[i] = image_data.charCodeAt(i);
}
var blob = new Blob([view], {type: 'image/png'});
var url = (window.webkitURL || window.URL).createObjectURL(blob);
var b = new FileReader;
b.readAsDataURL(blob);
b.onloadend = function () {
filename = SparkMD5.hash(b.result);
}
// ....some code
chrome.downloads.download ({ url, filename+'.png', saveAs: false });
The file is saved correctly, but MD5 hash that I get in code via SparkMD5 is different from the one I see in Windows after the file is saved. I cannot understand why. Experimented a bit with different approaches to saving (directly XMLHttpRequest, etc), but no luck yet. Probably I misunderstand some basic concept, as far as I am a bit of newbee to web programming.
I have also saved files via chrome.pageCapture.saveAsMHTML with the use of FileReader and in that case MD5 are equal.
What is wrong and is there a way to get equal MD5 for filename and final file while saving .png from Chrome extension?
I want to send an image the user selected from their machine along with form data all wrapped up in a JSON object and sent to server. I am using Node for the server. Is it possible to place the image in the JSON object along with the other form elements and read in Node?
The common ways I encountered are using the Base64 string approach: you encode your image into a Base64 string and set it as part of the JSON Object that you send over to your server.
Another approach seems to be using the Binary Data in JSON but I'd never tried this before so not much info from me.
Here's a code sample to do a Base64 encoding in Javascript. Specifically look for the method below
function getBase64Image(imgElem) {
// imgElem must be on the same server otherwise a cross-origin error will be thrown "SECURITY_ERR: DOM Exception 18"
var canvas = document.createElement("canvas");
canvas.width = imgElem.clientWidth;
canvas.height = imgElem.clientHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(imgElem, 0, 0);
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
There is a way to achieve this: use image data.
In Javascript, on client side, the FileReader will allow you to read binary image data, and get them into a base64 encoded string.
On client side:
var file = $('.file-upload > input')[0].files[0];
function upload(file) {
var reader = new FileReader();
// when image data was read
reader.onload = function(event) {
// I usually remove the prefix to only keep data, but it depends on your server
var data = event.target.result.replace("data:"+ file.type +";base64,", '');
// make here your ajax call
$.ajax({
url: 'and_so_on',
json: {
data: data
}
});
// read data from file
reader.readAsDataURL(file);
}
On server side, you will received base64 encoded image that you can easilly translate into binary with the Buffer constructor
var buffer = new Buffer(data, 'base64');
Be warned that FileReader is not supported by all browsers
I am reading a base64 encoded file from indexedDB and trying to link to it as a blob url. The code below works fine in Chrome but when I click the link in ie10 nothing happens. I can see on the properties of the link that the href is blob:66A3E18D-BAD6-44A4-A35A-75B3469E392B which seems right. Anyone see what I'm doing wrong?
Download Attachment
//convert the base64 encoded attachment string back into a binary array
var binary = atob(attachment.data);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
//create a blob from the binary array
var myBlob=new Blob([new Uint8Array(array)], {type: attachment.content_type});
//create a url hooked to the blob
downloadURL = (window.webkitURL ? webkitURL : URL).createObjectURL(myBlob);
//set the attachment link to the url
$('#attachmentLink').attr("href", downloadURL);
$("#attachmentLink").text(fileName);
Figured it out. IE10 does not want to open a blob url in a new window, as my code above is trying to do. I could only make this work when I set the blob url as the src of an img tag to display my file, which luckily is an image anyway.
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);
}
}