Im trying to run in-browser encryption application which uses jQuery 1.10.2 and CryptoJS 3.2.1
the problem that I face starts at around 2mb files. File can be encrypted just fine, but when a data URI is created for the file it crashes the browser.
I would like a way around this to make it possible to encrypt files up-to 50mb's without browser crashing.
Here is the current snippt responsible for file saving via FileReader API
var reader = new FileReader();
if(body.hasClass('encrypt')){
// Encrypt the file!
reader.onload = function(e){
// Use the CryptoJS library and the AES cypher to encrypt the
// contents of the file, held in e.target.result, with the password
var encrypted = CryptoJS.AES.encrypt(e.target.result, password);
// The download attribute will cause the contents of the href
// attribute to be downloaded when clicked. The download attribute
// also holds the name of the file that is offered for download.
a.attr('href', 'data:application/octet-stream,' + encrypted);
a.attr('download', file.name + '.encrypted');
step(4);
};
// This will encode the contents of the file into a data-uri.
// It will trigger the onload handler above, with the result
reader.readAsDataURL(file);
}
else {
// Decrypt it!
reader.onload = function(e){
var decrypted = CryptoJS.AES.decrypt(e.target.result, password)
.toString(CryptoJS.enc.Latin1);
if(!/^data:/.test(decrypted)){
alert("Invalid pass phrase or file! Please try again.");
return false;
}
a.attr('href', decrypted);
a.attr('download', file.name.replace('.encrypted',''));
step(4);
};
reader.readAsText(file);
}
What can I change in above code to allow for larger files to be encrypted and decrypted?
Live site: droplet.so (currently capped at 1.5mb otherwise browser crash is guaranteed)
Kindly thanks in advance.
With a little research I found out that 1.99MB is the maximum the can be saved in the data url in chrome.
Your problem can be done by converting your data url to blob
You can find more information here:
Blob from DataURL?
Chrome crashes when URI is too long is here a similar post ( see second answer ).
EDIT:
Possible solution
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var bb = new BlobBuilder();
bb.append(ab);
return bb.getBlob(mimeString);
}
function download(dataURI) {
var blob = dataURItoBlob(dataURI);
var url = window.URL.createObjectURL(blob);
window.location.assign(url);
}
And you can use this code by calling download(dataURI).
Related
I'm working on a REST web application that manages documents between users and uploaders. The backend is written in Java and my Document entity contains, besides various attributes, a byte[] content. I was able to send a file created at server side by
#GET
...
document.setContent(Files.readAllBytes(Paths.get("WEB-INF/testFile.txt")));
return Response.ok(document).build();
and retrieve it at front-end (vueJs) through
async function download(file) {
const fileURL = window.URL.createObjectURL(new Blob([atob(file.content)]));
const fileLink = document.createElement("a");
fileLink.href = fileURL;
fileLink.setAttribute("download",`${file.name}.${file.type}`);
document.body.appendChild(fileLink);
fileLink.click();
fileLink.remove;
window.URL.revokeObjectURL(fileURL);
}
the problem is that when I try to upload a file and then download it, its content is not parsed correctly (is shown undefined, string in Base64 or numbers depending on how I try to solve it). The file is sent by a post request and is retrieved through an input form bound to an onFileSelected function.
function onFileSelected(e) {
var reader = new FileReader();
reader.readAsArrayBuffer(e.target.files[0]);
reader.onloadend = (evt) => {
if (evt.target.readyState === FileReader.DONE) {
var arrayBuffer = evt.target.result;
this.file.content = new Uint8Array(arrayBuffer);
//this.file.content = arrayBuffer;
}
};
}
axios.post(...,document,...)
and I have tried using atob and btoa as well before assigning the value to this.file.content. If I print the file on server Welcome.txt it gives B#ae3b74d and if I use Arrays.toString(welcome.getContent()) it gives an array of numbers but as soon as it passed to the frontend its content become in Base64 welcome: { ... content: IFRoaXMgaXMgYSB0ZXN0IGZpbGUhIAo...}. Any idea? Thank you a lot!
I need to read a file, which has no extension, in a web page and then encode this file in a QR code in binary mode.
In order to encode binary I found this library and I think is good: https://github.com/nayuki/QR-Code-generator/blob/master/javascript/qrcodegen.js
But for the first part, read a file and don't modify it or encode it as a text or something else, I am unable to understand how to do it.
What is the best choice? A success could be just read that file and allow the page to download the file I had read in order to check that is the same file.
ok, i handled correctly:
$("#pwbutton").click(function(e) {
e.preventDefault();
var file = document.getElementById('customFile').files[0];
var fr = new FileReader();
fr.onloadend = function(e) {
console.log(e.target.result);
var readed = e.target.result;
var QRC = qrcodegen.QrCode;
var segs = qrcodegen.QrSegment.makeSegments(String.fromCharCode.apply(null, new Uint8Array(e.target.result)));
var qr = QRC.encodeSegments(segs, QRC.Ecc.LOW, 19, 19, -1, true);
var canvas = document.getElementById("qrcode-canvas");
qr.drawCanvas(3, 0, canvas);
$('#qresult').show();
};
fr.readAsArrayBuffer(file);
});
I have a function that currently downloads multiple images and saves them to a users "download" folder (Only works in Chrome)
I want to take this function to the next step and put these images in a single zip file.
Below is an example of my current code. I want to merge my code with the JSZip API I found online here.
I have done the bower install for this JSZip API already and included the script in my html.
Here is my code that works perfectly downloading multiple SINGLE images at once:
$scope.downloadPhotos = function() {
var photoUrls = [];
for (var x = 0; x < $scope.$parent.photos.length; x++) {
var p = $scope.$parent.photos[x];
if (p.isChecked) {
photoUrls.push($scope.bucketUrl() + p.photoUrl);
}
}
saveImage(photoUrls);
};
/*----this function saveImage works great (only Chrome)-----*/
function saveImage(urls) {
var link = document.createElement('a');
link.setAttribute('download', null);
link.style.display = 'none';
document.body.appendChild(link);
for (var i = 0; i < urls.length; i++) {
link.setAttribute('href', urls[i]);
link.click();
}
document.body.removeChild(link);
}
And here is the JSZip API code example to create a zip file with content in it:
function create_zip() {
var zip = new JSZip();
zip.add("hello1.txt", "Hello First World\n");
zip.add("hello2.txt", "Hello Second World\n");
content = zip.generate();
location.href = "data:application/zip;base64," + content;
}
Now I'm just wondering how to combine the two to put my images into a zipfile.
Thanks for your help!
I put this together that will let you zip an array of image urls.
https://jsfiddle.net/jaitsujin/zrdgsjht/
You can manage zip folder structure by modifying this line
filename = filename.replace(/[\/\*\|\:\<\>\?\"\\]/gi, '').replace("httpsi.imgur.com","");
To Download multiple files in Zip format we can use jsZip and FileSaver.js or if we are using Web API and Angularjs then we can create an API method to create zip archieve file at server and then in angularjs we can use $http post or get api call to download the file as zip file (We have to use filesaver to save the file in zip format). for example -
api call in angularjs -
function downloadFiles(files) {
return $http.post(baseUrl + 'api/download/files', files, { responseType: 'arraybuffer' });
}
call above function and on response use fileSaver.js method saveAs to save file in zip format for example -
//files - array input of files like http://www.example.com/file1.png', 'http://www.example.com/file2.jpeg', 'http://www.example.com/file3.jpg'];
downloadFiles(files).then(function (response) {
//on success
var file = new Blob([response.data], { type: 'application/zip' });
saveAs(file, 'example.zip');
}, function (error) {
//on error
//write your code to handle error
});
You should see this example. Currently, you just ask the browser to trigger the download of a file. If you want to create a zip file client side, your js code needs to access the content of the files with ajax calls (you will get CORS issues if they aren't stored on the same server).
Without copy/pasting the whole code, the example:
triggers ajax calls (with JSZipUtils but you can easily only use a responseType = "arraybuffer" if you only supports recent browsers)
wrap them into promises (jQuery promises here but you can use your own)
add the result into a zip object
wait for all promises to complete before triggering a download
function downloadImageAsZip(imageUrl){
var zip = new JSZip();
var img = new Image();
img.crossOrigin = 'Anonymous';
img.src = imageUrl;
img.onload = function() {
$scope.count2++;
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(this, 0, 0);
ctx.enabled = false;
dataURL = canvas.toDataURL("Canvas");
canvas = null;
//var base64String = dataURL.replace("/^data:image\/(png|jpg);base64,/", "");
var base64String = dataURL.replace("data:image/png;base64,", "");
zip.file("ImageName", base64String, {base64: true});
zip.generateAsync({type:"blob"}).then(function(content) {
saveAs(content, "ZipFileName.zip");
});
}
}
So I have an interesting question. I have a form where a user draws an image on a canvas (think a signature pad). I then need to send the image to my C# Controller (I am using ASP.NET MVC 5). The code I have functions for shorter strings, but when I try to pass the PNG data, it is too long and I recieve a HTTP Error 414. The request URL is too long error. Here is my code:
Html:
<form id="mainForm" action="submitUserAnswer" method="post">
<input type="hidden" id="userOutput" name="output" value="" />
//...other form elements, signature box, etc.
</form>
Javascript:
function goToNextQuestion() {
var output = $('#signature').jSignature("getData");
$('#userOutput').val(output);
$('#mainForm').submit();
}
C#:
public ActionResult submitUserAnswer()
{
//use the userOutput for whatever
//submit string to the database, do trigger stuff, whatever
//go to next question
System.Collections.Specialized.NameValueCollection nvc = Request.Form;
string userOutput = nvc["output"];
ViewBag.Question = userOutput;
return RedirectToAction("redirectToIndex", new { input = userOutput });
}
public ActionResult redirectToIndex(String input)
{
ViewBag.Answer = input;
return View("Index");
}
My png data is very long, so the error makes sense. My question is how can I get the png data back to my controller?
Maybe you just need to increase allowed GET request URL length.
If that doesn't works I have an aspx WebForm that saves a signature, and I use a WebMethod
[ScriptMethod, WebMethod]
public static string saveSignature(string data)
{
/*..Code..*/
}
and I call it like this:
PageMethods.saveSignature(document.getElementById('canvas').toDataURL(), onSucess, onError);
also I have to increase the length of the JSON request and it works fine, with no problems with the lenght.
In MVC there isn't WebMethods, but JSON and AJAX requests do the job, just save the data in a session variable, and then use it when need it.
Hope it helps
You have error because your data is string (base64) and have max limit for send characters, better way is to create blob (png file) from base64 at client side, and send it to server. Edit. All listed code here, exists in stackoverflow posts.
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// 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);
}
var blob = null;
// TypeError old chrome and FF
window.BlobBuilder = window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
if(window.BlobBuilder){
var bb = new BlobBuilder();
bb.append(ab);
blob = bb.getBlob(mimeString);
}else{
blob = new Blob([ab], {type : mimeString});
}
return blob;
}
function sendFileToServer(file, url, onFileSendComplete){
var formData = new FormData()
formData.append("file",file);
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onload = onFileSendComplete;
xhr.send(formData);
}
var base64 = $('#signature').jSignature("getData");
var blob = dataURItoBlob(base64);
var onComplete = function(){alert("file loaded to server");}
sendFileToServer(blob, "/server", onComplete)
I'm working in a little web app that generates an base64 image, I'm using blob to put it back into a file (is a .png but I haven't renamed it yet), now I'm trying to save it on my sever Any ideas or different approaches?
This is the script:
var img = document.getElementById("MyPix");
img.onclick = function() {
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) & 0xff;
}
try {
var blob = new Blob([arraybuffer], {type: 'application/octet-stream'});
} catch (e) {
var bb = new (window.WebKitBlobBuilder || window.MozBlobBuilder);
bb.append(arraybuffer);
var blob = bb.getBlob('application/octet-stream');
}
var url = (window.webkitURL || window.URL).createObjectURL(blob);
valor = (document.getElementById("link").value = url)
location.href = valor;
};
I'm not very good with js so if you want to have a better idea visit the project clicking here its all javascript so just see source code.
you can't save to your server with just client-side JavaScript. Form the data you want to save in Javascript, then POST that to your server with a call to a page that you write that can turn POST data into a file on your filesystem, so in your case a .php file with code that looks for $_POST data and then writes that to file. After making sure it's safe, because anyone will be able to post data to that page, not just people using your webpage.