Uploading html5 canvas content using ajax on IOS - javascript

For a webbased application we want to be able to let people sign on an Ipad.running IOS
We use a canvas element to draw on and then upload it to an IBM I Service.running net.data
It works fine on chrome and firefox on a pc.
on an ipad in safari or chrome though the request seems to be empty.
I am searching for hours and don’t seem to be able to find out what is wrong with this code.
Does anybody Know Who I Could Fix this?
We are not using jquery by the way.
belowe is part of the code we use
thanks!
j.v.
GUI.Signature.dataURItoBlob = function(dataURI) {
var binary = atob(dataURI.split(',')[1]);;
var array = [];
var content = null;
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
content= new Uint8Array(array);
return new Blob([content], {type: 'image/jpeg'});
};
GUI.Signature.send = function(){
if(!GUI.Signature.isEnabled()){return;}
var request = new XMLHttpRequest();
var dataURL = GUI.Signature.canvas.toDataURL('image/jpeg', 0.8);
var blob = GUI.Signature.dataURItoBlob(dataURL);
var fd = new FormData(GLOBAL.activeForm);
var fsUri = GLOBAL.activeForm.action.replace("MAIN","UPLOAD");
fd.append("signature", blob);
fd.append("blobName","signature" );
request.open('POST', fsUri, false);
request.send(fd);
};

the problem is indeed appending the Uint8Array tot the Blob object.
Wrapping the Uint8Array in an ArrayBuffer solves the problem
it was answerd here

Related

Upload file to AWS S3 using REST API Javascript

I am trying to retrieve a file from the user's file system and upload it to AWS S3. However, I have had no success thus far doing so. To be more specific, I have been working with trying to upload images. So far the images won't render properly whenever I upload them. I am really only familiar with uploading images as Blobs, but since SHA256 function can't read a Blob I'm unsure what to do. Below is my code:
var grabFile = new XMLHttpRequest();
grabFile.open("GET", 'https://s3.amazonaws.com/'+bucketName+'/asd.jpeg', true);
grabFile.responseType = "arraybuffer";
grabFile.onload = function( e ) {
var grabbedFile = this.response;
var arrayBufferView = new Uint8Array( this.response );
var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
var base64data = '';
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
//var readData = reader.result;
var readData = blob;
//readData = readData.split(',').pop();
console.log(readData);
console.log(readData.toString());
var shaString = CryptoJS.SHA256(readData.toString()).toString();
var request = new XMLHttpRequest();
var signingKey = getSigningKey(dateStamp, secretKey, regionName, serviceName);
var headersList = "content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date";
var time = new Date();
time = time.toISOString();
time = time.replace(/:/g, '').replace(/-/g,'');
time = time.substring(0,time.indexOf('.'))+"Z";
var canonString = "PUT\n"+
"/asd5.jpeg\n"+
"\n"+
//"content-encoding:base64\n"+
"content-type:image/jpeg\n"+
"host:"+bucketName+".s3.amazonaws.com\n"+
'x-amz-acl:public-read\n'+
'x-amz-content-sha256:'+shaString+"\n"+
'x-amz-date:'+time+'\n'+
'\n'+
headersList+'\n'+
shaString;
var stringToSign = "AWS4-HMAC-SHA256\n"+
time+"\n"+
dateStamp+"/us-east-1/s3/aws4_request\n"+
CryptoJS.SHA256(canonString);
var authString = CryptoJS.HmacSHA256(stringToSign, signingKey).toString();
var auth = "AWS4-HMAC-SHA256 "+
"Credential="+accessKey+"/"+dateStamp+"/"+regionName+"/"+serviceName+"/aws4_request, "+
"SignedHeaders="+headersList+", "+
"Signature="+authString;
request.open("PUT", "https://"+bucketName+".s3.amazonaws.com/asd5.jpeg", true);
request.setRequestHeader("Authorization", auth);
//request.setRequestHeader("content-encoding", "base64");
request.setRequestHeader("content-type", "image/jpeg");
request.setRequestHeader('x-amz-acl', 'public-read');
request.setRequestHeader("x-amz-content-sha256", shaString);
request.setRequestHeader("x-amz-date", time);
request.send(readData.toString());
console.log(request);
How do I go about doing this? The code above just uploads something that's just a few Bytes because blob.toString() comes out as [Object Blob] and that's what gets uploaded. If I don't toString() it, I get an error from my SHA256 function.
As you can see, I tried reading it as Base64 before uploading it, but that did not resolve my problem either. This problem has been bugging me for close to a week now and I would love to get this solved. I've tried changing content-type, changed the body of what I'm uploading, etc. but nothing has worked.
EDIT: Forgot to mention (even though the title should imply it) but I cannot use the SDK for this. I was using it at one point, and with it I was able to upload images as Blobs. So I know this is possible, it's just that I don't know what crafty thing the SDK is doing to upload it.
EDIT2: I found the solution just in case someone stumbles across this in the future. Try setting replace every place I have shaString with 'UNSIGNED PAYLOAD' and send the blob and it will work! Here's where I found it: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html

Problems downloading big file(max 15 mb) on google chrome

I have a downloading problem in Google Chrome.
I am using Ruby 2.2, Rails 4.2, AngularJS 1.2.
We dont have a database here. Everything we are getting through API. The file which we are trying to download is around 7 mb. It gives us "Failed: Network Error". Though it works fine on Firefox.
From the API we are getting binary data in JSON. We are parsing it. And then:
send_data response_fields["attachment"], type: response_fields["mimeType"], disposition: 'attachment', filename: params[:filename]
As we are using AngularJS, we are catching that value in AngularJS Controller and then converting it as:
var str = data;
var uri = "data:" + mimeType + ";base64," + str;
var downloadLink = document.createElement("a");
downloadLink.href = uri;
downloadLink.download = filename;
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
This works in Firefox & even Chrome for smaller file size. Not sure why it is giving error for bigger size on Chrome.
Any suggestions?
Thanks.
This is an almost duplicate of these questions 1 and 2, but since they do deal particularly with the canvas element, I'll rewrite a more global solution here.
This problem is due to a size limit chrome has set in the anchor (<a>) download attribute. I'm not quite sure why they did it, but the solution is pretty easy.
Convert your dataURI to a Blob, then create an ObjectURL from this Blob, and pass this ObjectURL as the anchor's download attribute.
// edited from https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill
function dataURIToBlob(dataURI) {
var binStr = atob(dataURI.split(',')[1]),
len = binStr.length,
arr = new Uint8Array(len),
mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
for (var i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
return new Blob([arr], {
type: mimeString
});
}
var dataURI_DL = function() {
var dataURI = this.result;
var blob = dataURIToBlob(dataURI);
var url = URL.createObjectURL(blob);
var blobAnchor = document.getElementById('blob');
var dataURIAnchor = document.getElementById('dataURI');
blobAnchor.download = dataURIAnchor.download = 'yourFile.mp4';
blobAnchor.href = url;
dataURIAnchor.href = dataURI;
stat_.textContent = '';
blobAnchor.onclick = function() {
requestAnimationFrame(function() {
URL.revokeObjectURL(url);
})
};
};
// That may seem stupid, but for the sake of the example, we'll first convert a blob to a dataURI...
var start = function() {
stat_.textContent = 'Please wait while loading...';
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
status.textContent = 'converting';
var fr = new FileReader();
fr.onload = dataURI_DL;
fr.readAsDataURL(this.response);
};
xhr.open('GET', 'https://dl.dropboxusercontent.com/s/bch2j17v6ny4ako/movie720p.mp4?dl=0');
xhr.send();
confirm_btn.parentNode.removeChild(confirm_btn);
};
confirm_btn.onclick = start;
<button id="confirm_btn">Start the loading of this 45Mb video</button>
<span id="stat_"></span>
<br>
<a id="blob">blob</a>
<a id="dataURI">dataURI</a>
And a jsfiddle version for FF, since they don't allow the downloadattribute from stack-snippets...

Illegal Constructor error: convert Base64 to Blob fails on cordova

I want to convert my Base64 image to a blob in my cordova app project using AngularJS but i keep getting Illegal constructor error. I have tried a lot of the solutions given online but none seems to be working. Any help is appreciated.
var imageElement = angular.element(document.querySelector('#profileImg'));
var imageURI = dataURIToBlobURI(imageElement.attr('src'));
function dataURIToBlobURI(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 bb = new Blob([ab], {type: 'image/png'});
return bb;
}
I keep getting an error over here new Blob([ab], {type: 'image/png'}) and dont seem to knw how to make it work. Only happens when the app is in Android or iOS not when viewed in Chrome.
I have tried the following but all to no avail.
var bb = new Blob(ab);
var bb = new Blob([ab]);
var bb = new Blob(dataURI);
Thanks
Kingsley! Possible, device where you could reproduce the error doesn't support Blob actually. Actually you could use two ways:
Firstly, check
polyfill or smth similar to fix your problem. It will allow you to use Blob as a constructor.
Secondly, you could use BlobBuilder except of Blob. Small exmaple below,
var bb = new BlobBuilder();
bb.append('blob content');
var blob = bb.getBlob('text/plain');
I used this to solve my problem. Just incase anyone runs into this problem. All solutions didnt work for me on my device. Just follow instructions and add the javascript file and you shud be fine. https://github.com/blueimp/JavaScript-Canvas-to-Blob
var b64Data = 'R0lGODdhUAA8AIABAAAAAP///ywAAAAAUAA8AAACS4SPqcvtD6' +
'OctNqLs968+w+G4kiW5omm6sq27gvH8kzX9o3n+s73/g8MCofE' +
'ovGITCqXzKbzCY1Kp9Sq9YrNarfcrvcLDovH5PKsAAA7',
imageUrl = 'data:image/gif;base64,' + b64Data,
blob = window.dataURLtoBlob && window.dataURLtoBlob(imageUrl);

HTML Rename download link

I have a mp3 link like this :
http://example.com/932937293723.mp3
but i want to rename it when user downloads the file to be like this
http://example.com/Artist - Title.mp3
My code :
DOWNLOAD
The mp3 file stored in remote server. And i'm not the owner of that server.
HTML download attribute seem not good solution. because it's not cross-browser. Any cross-browser solution to solve this ? Javascript maybe :D
If you insist on working from the front end, try working with the following code. The getblob method is depreciated, but you need to update that side. Let me know.
function getBinary(file){
var xhr = new XMLHttpRequest();
xhr.open("GET", file, false);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.send(null);
return xhr.responseText;
}
function sendBinary(data, url){
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
if (typeof XMLHttpRequest.prototype.sendAsBinary == "function") { // Firefox 3 & 4
var tmp = '';
for (var i = 0; i < data.length; i++) tmp += String.fromCharCode(data.charCodeAt(i) & 0xff);
data = tmp;
}
else { // Chrome 9
// http://javascript0.org/wiki/Portable_sendAsBinary
XMLHttpRequest.prototype.sendAsBinary = function(text){
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0);
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
var bb = new BlobBuilder(); // doesn't exist in Firefox 4
bb.append(data);
var blob = bb.getBlob();
this.send(blob);
}
}
xhr.sendAsBinary(data);
}
var data = getBinary("My music.mp3");
sendBinary(data,'http://www.tonycuffe.com/mp3/tailtoddle_lo.mp3');
In your back end code, you can fetch the file to your server, store it to a variable, rename it from there, define the corresponding headers, and return it. this could happen as an ajax call initiated on the javascript click.
Post further details about your backed and i can help you more.
You can use something like below (ASP.NET)
In ASPX
Download
In ASP.NET
Response.ContentType = "audio/mpeg3";
Response.AddHeader("content-disposition", "attachment;filename=New_file_name.mp3");
Server.Transfer(decoded_URL_of_MP3_file);
Look here for other MIME types
Update#1 - Using Javascript alone, you can try something like this, though I've not tested in different browsers
function Download(url, fancyFileName)
{
var file = document.createElement('a');
file.href = url;
file.target = '_blank';
file.download = fancyFileName;
var event = document.createEvent('Event');
event.initEvent('click', true, true);
file.dispatchEvent(event);
window.URL.revokeObjectURL(file.href);
}
Download('http://server.com/file.mp3','Artist_file.mp3');

Pdf.js and viewer.js. Pass a stream or blob to the viewer

I'm having troubles in finding a solution for this:
I retrieve a PDF blob from a SQL filestream field using Javascript in this way (it's a lightswitch project)
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
I have the blob and I can even convert it in a filestream or to base64("JVBERi0....." or "%PDF 1.6 ......", etc.)
No problem so far.
Now I need to display it in a viewer. I prefer the viewer to open in a new window but i'm open to embed it into my page somehow.
I'm wondering if I can directly pass the blob or the stream to the viewer and display the document. I've tried something like
PDFView.open(pdfAsArray, 0)
Nothing happens in the embedded viewer in this case.
The pdfAsArray is good since I can display it appending the stream to a canvas within the same page. I just want to display the viewer, not embed the PDF in a canvas, possibly in a new window.
Can anyone provide few lines of code on how to achieve that in Javascript?
I'm using PDFJS.version = '1.0.1040'; PDFJS.build = '997096f';
The code that worked for me to get base64 pdf data loaded was this:
function (base64Data) {
var pdfData = base64ToUint8Array(base64Data);
PDFJS.getDocument(pdfData).then(function (pdf) {
pdf.getPage(1).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({ canvasContext: context, viewport: viewport });
});
});
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
}
This function could be the success function of an api call promise. What I'm doing here is rendering the pdf onto a canvas element myCanvas.
<canvas id="myCanvas"></canvas>
This shows the first page of the pdf but has no functionality. I can see why the viewer is desirable. If I get this hooked up to the viewer (viewer.html / viewer.js) I will edit my answer.
EDIT: How to hook up the viewer
1 In bower.json, add "pdfjs-viewer": "1.0.1040"
2 Html:
<iframe id="pdfViewer" src="lib/pdfjs-viewer/web/viewer.html" style="width: 100%; height: 700px;" allowfullscreen="" webkitallowfullscreen=""></iframe>
3 Change the stupid default document in the viewer.js file:
var DEFAULT_URL = '';
4 Controller:
var pdfjsframe = document.getElementById('pdfViewer');
pdfjsframe.onload = function() {
LoadPdfDocument();
};
$scope.myApiCallThatReturnsBase64PdfData.then(
function(base64Data) {
$scope.base64Data = base64Data;
LoadPdfDocument();
},
function(failure) {
//NotificationService.error(failure.Message);
});
function LoadPdfDocument() {
if ($scope.PdfDocumentLoaded)
return;
if (!$scope.base64Data)
return;
var pdfData = base64ToUint8Array($scope.base64Data);
pdfjsframe.contentWindow.PDFViewerApplication.open(pdfData);
$scope.PdfDocumentLoaded = true;
}
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
If you've got an typed array (e.g. an Uint8Array), then the file can be opened using PDFView.open(typedarray, 0);.
If you've got a Blob or File object, then the data has to be converted to a typed array before you can view it:
var fr = new FileReader();
fr.onload = function() {
var arraybuffer = this.result;
var uint8array = new Uint8Array(arraybuffer);
PDFView.open(uint8array, 0);
};
fr.readAsArrayBuffer(blob);
Another method is to create a URL for the Blob/File object:
var url = URL.createObjectURL(blob);
PDFView.open(url, 0);
If the PDF Viewer is hosted at the same origin as your website that embeds the frame, then you can also view the PDF by passing the blob URL to the viewer:
var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.
I finally made the PDFView.open method working. Now if I embed the viewer into my page and call the open function as Rob suggested in the first 2 examples it works.
For those who are looking for this kind of solution I provide some lines of code here:
This is the code in my Lightswitch mainPage.lsml.js. The js scripts (pdf.js, viewer and Others) are referenced in the main html page of the Lightswitch project (Default.html); I assume it should work with any other html page not Lightswitch based.
myapp.MainPage.ShowPdf_execute = function (screen) {
// Write code here.
// Getting the stream from sql
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
// Pass the stream to an aspx page that makes some manipulations and returns a response
var formData = new FormData();
formData.tagName = pdfName;
formData.append(pdfName, blob);
var xhr = new XMLHttpRequest();
var url = "../OpenPdf.aspx";
xhr.open('POST', url, false);
xhr.onload = function (e) {
var response = e.target.response;
var pdfAsArray = convertDataURIToBinary("data:application/pdf;base64, " + response);
var pdfDocument;
// Use PDFJS to render a pdfDocument from pdf array
PDFJS.getDocument(pdfAsArray).then(function (pdf) {
pdfDocument = pdf;
var url = URL.createObjectURL(blob);
PDFView.load(pdfDocument, 1.5)
})
};
xhr.send(formData); // multipart/form-data
};
This is the convertDataURIToBinary function
function convertDataURIToBinary(dataURI) {
var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
What is still missed is the possibility to pass the stream directly to the viewer.html page in order to open it in a new window and have a separate ui where make the rendering.
This code is still not working since I got an empty viewer with no document inside:
var blob = new Blob([screen.WebReportsPdfFilesStream.selectedItem.Pdf], { type: "application/pdf;base64" });
var url = URL.createObjectURL(blob);
var viewerUrl = 'Scripts/pdfViewer/web/viewer.html?file=' + encodeURIComponent(url);
window.open(viewerUrl);
Looks like the encodeURIComponent(url) is not passing to the viewer a good object to load into the viewer.
Any idea or suggestion?
var url = URL.createObjectURL(blob);
var viewerUrl = 'web/viewer.html?file=' + encodeURIComponent(url);
// TODO: Load the PDF.js viewer in a frame or new tab/window.
//-- Abobe code opens a new window but with errors : 'Missing PDF
// blob://http://server-addr:port/converted-blob'
I am using viewer in an iframe;
<iframe
id="pdfIframe"
src="pdfjs/web/viewer.html"
style="width: 100%; height: 100%;"
>
</iframe>
And fetch API used as follows;
fetch(pdfSourceUrl).then((response: Response) => {
response.blob().then((blob) => {
var url = URL.createObjectURL(blob);
pdfIframe.src = `pdfjs/web/viewer.html?file=${url}`;
});
});
Eventually iframe src created as follows;
http://localhost:9000/pdfjs/web/viewer.html?file=blob:http://localhost:9000/14f6a2ec-ad25-40ab-9db8-560c15e90f6e

Categories

Resources