Flowjs file upload - Ionic and ngCordova - javascript

I'm trying to upload an image from my app to the server, I wanted to use the ngCordova file transfer plugin but I'm not happy with the progress informations that this plugin gives you, so I decided to go with Flowjs, but I can't manage to create a proper HTML5 File object from the file url I have.
This is my code
window.resolveLocalFileSystemURL(photo, function(fileEntry){
fileEntry.file(function(file){
$scope.flow.addFile(file);
$scope.flow.upload();
$scope.flow.on('fileProgress', function (file, chunk){
console.log(file);
console.log(chunk);
});
$scope.flow.on('error', function(a,b){
console.log(a);
console.log(b);
});
});
}, function(err){
console.log(err);
});
Where photo is the path to the fileSystem for the file.
I get a 400(bad Request) error when I try doing this upload, I'm sure the server side is correct because I use it with many other Flowjs applications.
I think that the object returned by fileEntry.file() is not a proper HTML5 file object, maybe creating a Blob from the file url could solve the problem, but I haven't understand how to create it.
I'd like to get my code to work though, before trying to create a Blob, but if that's the only solution, well...

Ok, I've found a solution that works, dunno if it's the best possibile, any improvment is well appreciated.
window.resolveLocalFileSystemURL(photo, function(fileEntry){
fileEntry.file(function(file){
var reader = new FileReader();
reader.onload = function(){
var blob = new Blob([reader.result], {type: 'application/octet-stream'});
blob.name = 'image.jpg';
$scope.flow.addFile(blob);
$scope.flow.upload();
$scope.flow.on('fileProgress', function (file, chunk){
console.log(file);
console.log(chunk);
});
$scope.flow.on('error', function(a,b){
console.log(a);
console.log(b);
});
};
reader.readAsArrayBuffer(file);
});
}, function(err){
console.log(err);
});

Related

Download the image returned by an API

I am working with the sportradar api. The api call that I am making, returns a png image. Till now I have done this.
const apiCall = (url) => {
return axios.get(url).then((data) => {
if(data){
return Promise.resolve(data);
}
else{
return Promise.reject();
}
});
}
//all data in data.assetlist
for(let i=0; i<data.assetlist.length; i++){
let imageLink = data.assetlist[i].links[12].href;
let url = `https://api.sportradar.us/nfl-images-p3/ap_premium${imageLink}?api_key=${api_key}`;
apiCall(url).then((data) => {
console.log(data);
let blob = new Blob(data, {type: "image/png"}); // didn't compile with this line
});
}
The above code is working fine and is returning the data. But the data are weird character, which if I am understanding it correctly, is because of the fact that image is a blob type and I am getting a stream of data.
I took reference from here and wrote this line
let blob = new Blob(data, {type: "image/png"});
I didn't try this, because I am afraid that the data is so big that it might crash my system (old laptop). If I am doing this right, I wanna know, how to save this blob file into my system as a png file and if not then I wanna know how can i convert this stream of data into an image and can download and save it in a local directory.
If the image you get is already a blob you can download it using this library :
https://github.com/eligrey/FileSaver.js
let FileSaver = require('file-saver');
FileSaver.saveAs(blob, "my_image.png");
I think you shouldn't be so worried about the size and just go for it.
After a lot of research, I found this solution and it worked.
apiCall(url).then((response) => {
response.data.pipe(fs.createWriteStream('test.jpg'));
});

How to Upload Audio/Videos using AngularJS

I'm working on Audio/Video upload and Task. Can somebody help me show to achieve this functionality in Angular JS?
We would need more details, what hae you tried, what type of backend (REST, SOAP, Web Service in general) you are using, in which language...
I did it with a Java RESTful server by, probably, not the smarter solution.
$scope.uploadVideo = function(){
// Obtaining the selected file. In case of many, the others will be from the position 1 of the array
var f = document.getElementById("videoInput").files[0];
console.log("====================>SIZE: "+f.size);
var name = f.name;
//Getting the file name and its extension
}
//Loading the file and passing the callback as a parameter
loadFile(f, function(data){
// The file consist on its name and bytes
var file={
name:name,
data:data
}
//Sending the video
servicioRest.postFile(file)
.then(function(){
//Whatever
})
.catch(function(err){
console.log("ERROR");
alert("ERROR: "+err);
});
});
};
//---------------------------------------------------- UTILS ----------------------------------------------
function loadFile(source, callBack){;
var r = new FileReader();
//Event that will be triggered when FileReader finish reading the file
r.onloadend = function(e){
var data = e.target.result;
// some chars cannot be sent through http requests. So we encode them in base64 to ensure we send the correct bytes
data=btoa(data);
console.log(data.length);
callBack(data);
//send you binary data via $http or $resource or do anything else with it
}
//Reading the file. When it ends, the event "onloadend", previously declared, will be triggered
r.readAsBinaryString(source);
}
Then, in the server, I decoded the bytes and create a file with them and that bytes... or save them in the database.. Whatever you want.
But I insist, we need more details to answer you correctly. It's impossible, at list for me, to answer you correctly with only that information

Append image file to form data - Cordova/Angular

I am using Anuglar, Ionic and Cordova in my current project, and I'm trying to POST FormData containing an image file to my server. Right now I'm using the cordova camera plugin to return a file path to the image on the device (ex: file://path/to/img). Once I have the file path I want to append the image file to a FormData object using the images file path. Here is my code right now.
var fd = new FormData();
fd.append('attachment', file);
fd.append('uuid', uuid);
fd.append('userRoleId', userRole);
The code above works when appending a file that is taken from an <input type='file'> but doesn't work when just given the file path on the device.
Basically the FormData is showing like this right now:
------WebKitFormBoundaryasdf
Content-Disposition: form-data; name="attachment";
file://path/to/img
and I want it to look like this
------WebKitFormBoundaryasdf
Content-Disposition: form-data; name="attachment"; filename="jesus-quintana.jpg"
Content-Type: image/jpeg
I found many different ways to upload the image using cordova FileTransfer and by converting the image to a base64 and then uploading it. But I couldn't find any simple ways of just grabbing the file by using the path and posting it within a form. I'm not very familiar with the File Api so any help would be appreciated
After some fiddling around I manage to figure out a pretty simple solution.
First I added the cordova file plugin then I use the code below
var fd = new FormData();
window.resolveLocalFileSystemURL(attachment.img, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var imgBlob = new Blob([ this.result ], { type: "image/jpeg" } );
fd.append('attachment', imgBlob);
fd.append('uuid', attachment.uuid);
fd.append('userRoleId', 12345);
console.log(fd);
//post form call here
};
reader.readAsArrayBuffer(file);
}, function(e){$scope.errorHandler(e)});
}, function(e){$scope.errorHandler(e)});
So I'm just creating a form and using FileReader to insert an ArrayBuffer to the Blob object and then append that to the form data. Hopefully this helps someone else looking for an easy way to do this.
You do need to send file content. With the HTML5 FileAPI you need to create a FileReader object.
Some time ago, I developed an application with cordova and I had to read some files, and I made a library called CoFS (first, by Cordova FileSystem, but it's working in some browsers).
It's on beta state, but I use it and works well. You can try to do some like this:
var errHandler = function (err) {
console.log("Error getting picture.", err);
};
var sendPicture = function (file) {
var fs = new CoFS();
fs.readFile(file, function (err, data) {
if (err) {
return errHandler(err);
}
var fd = new FormData();
fd.append('attachment', new Blob(data));
fd.append('uuid', uuid);
fd.append('userRoleId', userRole);
console.log("Data of file:" + data.toString('base64'));
// Send fd...
});
};
navigator.camera.getPicture(sendPicture, errHandler);
Sorry my poor english.
Your post was extremly helpful to fix my problem. I'm using Ionic 4 and trying to upload an image using standard http and file client. The key code for reference is here:
return this.file.readAsArrayBuffer(path, file).
then(blob => {
const imgBlob = new Blob([blob], { type: 'image/jpeg' } );
formData.append('image[file]', imgBlob);
return this.http.post(url, formData, headers).subscribe();
});
Hope it helps someone out there as it did for me.

Uploading Images via JQuery AJAX

I looked around and just couldn't find what I'm looking for without additional plugins/libraries. I want to upload an image and process it serverside via JQuery AJAX, but I can't figure out how to pass and process it. Any help is much appreciated!
Though Diodeus is correct, it isn't quite that difficult. Just maddening.
HTML5 does expose what is called the FileReader API, which is still relatively new and unsupported on legacy browsers, but which will make your job easier. I have a small app which accepts images on the client side and, using the FileReader API, converts them to base-64 for uploading to the server.
The following is the function I call upon a user's uploading an image. App.FileReader is an instantiation of the HTML5 FileReader, which is declared simply like:
App.FileReader = window.FileReader ? new FileReader : null;
Upon upload, I read the image as a dataURL using the FileReader, and push the data into an unused tag. The FileReader itself retains the read data, which is why it is a good idea to only instantiate one FileReader at a time.
if (input.files && input.files[0]) {
if (App.FileReader) {
App.FileReader.onload = function (e) {
$('#createMomentImagePreview').attr('src', e.target.result);
}
App.FileReader.readAsDataURL(input.files[0]);
$this.uploadedImage = true
}
else {
$('#createMomentImagePreview').attr('src', 'http://d33w6ffaa49e6z.cloudfront.net/media/ImageLoaded.png');
$this.uploadedImage = true
}
}
This is the AJAX call for uploading to the server, where data represents the read file, or "App.FileReader.result":
$.ajax({
url: '/image',
type: 'POST',
data: {
image: App.FileReader.result
}
}).done(function(data){
callback(data);
}).fail(function() {
console.log("Image upload failed!")
alert("Sorry, there was an error uploading your image to the database.")
})
Server-side (and I'm using Node with Express, so this might not apply), I can convert the base64 string to a Buffer (Blob) and send that up to S3 using Knox's putBuffer. This is waaaaaay simpler than actually authenticating with S3 AND trying to get it to play nice with your binary data.
if (req.body.image.match(/^data:image\/png;base64,/)) {
var image = new Buffer(req.body.image.replace(/^data:image\/png;base64,/,""), "base64");
}
else if (req.body.image.match(/^data:image\/jpeg;base64,/)) {
var image = new Buffer(req.body.image.replace(/^data:image\/jpeg;base64,/,""), "base64");
}
awsClient.putBuffer(image, '/' + imagePath + '.jpg', headers, function(err, stream) {
if (err) {
console.log(err);
return false
}
res.send(200, imagePath + '.jpg')
image = null;
});
In either case, once you have the base64 data on your server you've made significant progress. You could use ImageMagick to handle processing as well. For what it's worth, I hope this helps you out in some way!

overwrite a file with HTML5 FileWriter

I'm using HTML5 FileWriter API to save the state of my webapp. I have bit of JS that periodically calls FileWriter.write to do that (so , over time, the write method is called several times). By default FileWriter API use an 'append' approach to writing files which does not suits my needs since I wan't to overwrite the file content.
I first tried this:
this._writer.seek(0);
this._writer.write(content);
This is not working when you are writing a text shorter than the file content. I then tried this:
this._writer.truncate(0);
this._writer.write(content);
This code is supposed to clear the file and then write my new content but I'm getting the following error when write method is called:
Uncaught InvalidStateError: An operation that depends on state cached in an interface object was made but the state had changed since it was read from disk.
Odd thing: when I debug the code (with a breakpoint), the error does not occur, as if FileWriter.truncate was an asynchronous method...
I am stuck here, any ideas?
I am using Chrome 30.0.1599.69
Here is a correct code that won't waste 500ms on waiting
fileWriter.onwriteend = function() {
if (fileWriter.length === 0) {
//fileWriter has been reset, write file
fileWriter.write(blob);
} else {
//file has been overwritten with blob
//use callback or resolve promise
}
};
fileWriter.truncate(0);
You can truncate and then write with two different FileWriter objects.
fileEntry.createWriter(function (fileWriter) {
fileWriter.truncate(0);
}, errorHandler);
fileEntry.createWriter(function (fileWriter) {
var blob = new Blob(["New text"], { type: 'text/plain' });
fileWriter.write(blob);
}, errorHandler);
If you want to always override it, you can use this method
function save(path,data){
window.resolveLocalFileSystemURL(dataDirectory, function(dir){
dir.getFile(path, {create:true}, function(file){
file.createWriter(function(fileWriter){
fileWriter.seek(0);
fileWriter.truncate(0);
var blob = new Blob([data], {type:'text/plain'});
fileWriter.write(blob);
}, function(e){
console.log(e);
});
});
});
};
A workaround is the following code:
this._writer.truncate(0);
window.setTimeout(function(){
this._writer.write(content);
}.bind(this),500)
This simply wait 500 milliseconds before writing. Not great but it works...
This is the simplest way how i use to delete the content of a file with syncFileSystem in my Chrome App.
Two createWriter, the first one truncates then the second one overwrites with nothing (you can change with your new value) :
file.createWriter((fileWriter)=>fileWriter.truncate(0));
file.createWriter((fileWriter)=> {
fileWriter.onwriteend = function() {
console.log('New Actions!');
};
var blob = new Blob([''], {type: 'text/plain'});
fileWriter.write(blob);
});

Categories