Encoding a image to base64 and upload to web service in Phonegap - javascript

In my PhoneGap project, I use navigator.device.capture.captureImage(captureSuccess, captureError, {limit : 1}); to take a picture. In captureSucces function, I get de MediaFile, and I encode it to base64 with this:
var file="";
var datafile=mediaFiles[0];
var reader = new FileReader();
reader.onload = function(evt){
file=evt.target.result;
};
reader.readAsDataURL(datafile);
I send this file to a REST Web Service, where I decode the file and save in a folder:
if (files != null) {
FileOutputStream fileOutputStream = null;
try {
byte[] byteFichero = Base64.decodeBase64(files);
System.out.println("ARCHIVO " + byteFichero);
File fich = new File(pathFichero.toString());
fich.createNewFile();
fileOutputStream = new FileOutputStream(fich);
fileOutputStream.write(byteFichero);
System.out.println("Fichero almacenado ok");
} catch (Exception e) {
System.out.println("Excepcion alamacenando fichero "
+ e.getMessage() + " " + pathFichero);
return respuesta;
} finally {
try {
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException ex) {
Logger.getLogger(
GestionFicheroObjetoService.class.getName())
.log(Level.SEVERE, null, ex);
}
pathFichero.delete(0, pathFichero.length());
}
}
Unfortunately, I get an empty image(1 KB). This is because the file value is not correct, it contains:
{"name":"1385711756945.jpg",
"fullPath":"file:///storage/sdcard0/DCIM/Camera/1385711756945.jpg",
"type":"image/jpeg",
"lastModifiedDate":1385711757000,
"size":2785413,
"start":0,
"end":0}
and when I encode this, I get a little base64 code:
[B#877d81
In other examples, they always use input type file to get the file (http://thiscouldbebetter.wordpress.com/2013/07/03/converting-a-file-to-a-base64-dataurl-in-javascript/) but I have to get the file from Camera.
What is the problem? Some other solution?
Thank you very much.

i am also facing this issue. i got solution after long time search
camera success function:
function capturesuceess(mediafiles){
var uploadimageurl= mediafile
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, rfail);
window.resolveLocalFileSystemURI(uploadimageurl, onResolveSuccess, fail);
}
function onFileSystemSuccess(fileSystem) {
console.log(fileSystem.name);
}
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
};
function onResolveSuccess(fileEntry) {
filenameofajax=fileEntry.name;
var efail = function(evt) {
console.log("File entry error "+error.code);
};
var win=function(file) {
console.log(file);
alert(bytesToSize(file.size));
var reader = new FileReader();
reader.onloadend = function(evt) {
console.log("read success");
console.log(evt.target.result);
var basestr=evt.target.result;
basestr= basestr.substr(basestr.indexOf("base64,")+7,basestr.length);
console.log(basestr);// this is a base64 string
};
reader.readAsDataURL(file);
};
fileEntry.file(win, efail);
}
try this working fine. and also u write efail and fail function with empty enjoy with phonegap

The best way to do this is using navigation.camera:
https://gist.github.com/pamelafox/2173589

Related

Send image socket io and android

I am a beginner in socket.io. I have been used a library
https://www.npmjs.com/package/socket.io-stream
We were successfully uploaded images using the browser. But now, I want to upload images from android application. If anyone have android code please give me ..
https://github.com/socketio/socket.io-client-java/issues/29
I have been searching on google, but not found any proper solution.
var imageBuffer = customJs.decodeBase64Image(base64Data);
var imageTypeDetected = imageBuffer.type.match(/\/(.*?)$/);
var filename = 'profile-' + Date.now() + '.' + imageTypeDetected[1];
// config.uploadImage --- Folder path where you want to save.
var uploadedImagePath = config.uploadImage + filename;
try {
fs.writeFile(uploadedImagePath, imageBuffer.data, function () {
dbMongo.updateImage({email: decoded.email, user_id: decoded.userId, 'profile_picture': config.showImagePath + filename}, function (res) {
if (res.error) {
socket.emit('set_update_image', {'error': 1, 'message': 'Error!' + res.message, 'data': null, 'status': 400});
} else {
console.log(res);
socket.emit('set_update_image', res);
}
});
});
} catch (e) {
socket.emit('set_update_image', {'error': 1, 'message': 'Internal server error ' + e, 'data': null, 'status': 400});
}
From other file call a function
exports.decodeBase64Image = function decodeBase64Image(dataString) {
var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
var response = {};
if (matches.length !== 3)
{
return new Error('Invalid input string');
}
response.type = matches[1];
response.data = new Buffer(matches[2], 'base64');
return response;
}
For the upload image from android using socket you need to send image as base64 string,
Following is the example for convert Image into base64 then you send data same as another paramaters.
String base64Image = getBase64Data(dirPath + "/" + fileName);
public String getBase64Data(String filePath) {
try {
InputStream inputStream = new FileInputStream(filePath);//You can get an inputStream using any IO API
byte[] bytes;
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
}
bytes = output.toByteArray();
return "data:image/jpeg;base64," + Base64.encodeToString(bytes, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
In android, you need to encode the image by using Base64
public void sendImage(String path)
{
JSONObject sendData = new JSONObject();
try{
sendData.put("imageData", encodeImage(path));
socket.emit("image",sendData);
}catch(JSONException e){
}
}
private String encodeImage(String path)
{
File imagefile = new File(path);
FileInputStream fis = null;
try{
fis = new FileInputStream(imagefile);
}catch(FileNotFoundException e){
e.printStackTrace();
}
Bitmap bm = BitmapFactory.decodeStream(fis);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG,100,baos);
byte[] b = baos.toByteArray();
String encImage = Base64.encodeToString(b, Base64.DEFAULT);
//Base64.de
return encImage;
}
In server side, receive image and decode it
socket.on("image", function(info) {
var img = new Image();
img.src = 'data:image/jpeg;base64,' + info.imageData;
});

Length of uploaded couchDB attachment always 0 Bytes

So...I'm new to all this stuff and I'm developing an app for android with AngularJS and Ionic Framework and try to upload an audiofile I have recorded with the cordova capture Plugin like this:
// gets called from scope
$scope.captureAudio = function() {
var options = { limit: 1, duration: 10 };
$cordovaCapture.captureAudio(options).then(function(audioData) {
uploadFile(documentID, audioData);
}, function(err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (document, file) {
var baseUrl = 'urltomydatabase';
var name = encodeURIComponent'test.3gpp'),
type = file[0].type,
fileReader = new FileReader(),
putRequest = new XMLHttpRequest();
$http.get(baseUrl + encodeURIComponent(document))
.success(function (data) {
putRequest.open('PUT', baseUrl + encodeURIComponent(document) + '/' + name + '?rev=' + data._rev, true);
putRequest.setRequestHeader('Content-Type', type);
fileReader.readAsArrayBuffer(file[0]);
fileReader.onload = function (readerEvent) {
putRequest.send(readerEvent);
};
putRequest.onreadystatechange = function (response) {
if (putRequest.readyState == 4) {
//success - be happy
}
};
})
.error(function () {
// failure
});
};
How the file looks in the console.log:
Playing the recorded file on the device works nice.
But everytime I upload the recording and the upload has finished, the uploaded attachment inside the document has the length '0' in the couchDB.
How the created file looks in the database after the upload:
What am I doing wrong?
EDIT: I just found out, when I upload an image, passed from this function as blob, it works well:
function upload(imageURL) {
var image = new Image();
var onload = function () {
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
canvas.toBlob(function (blob) {
uploadFile(documentID, blob);
});
};
image.onload = onload;
image.src = imageURL;
}
So maybe the solution is creating a blob from the audiofile? But everytime I try it, my blob has the size of 0 bytes even before uploading it and I don't find somewhere a great explanation of how to convert a MediaFile object to blob...
It looks like your code does not send the content of your file as multipart attachment. To see what is really send to couchdb, capture the traffic with wireshark (https://www.wireshark.org/) or such.
This thread brought me to the solution, PouchDB purifies it. Now my upload function looks like this and can handle every file format
// e.g capture Audio
$scope.captureAudio = function () {
var options = {limit: 1, duration: 10};
$cordovaCapture.captureAudio(options).then(function (audioData) {
uploadFile(documentID, audioData, 'audio');
}, function (err) {
console.log('error code: ' + err);
});
};
var uploadFile = function (id, file, mediatype) {
var fileName = makeID();
if (mediatype == 'image') var name = encodeURIComponent(fileName + '.jpg');
if (mediatype == 'audio') var name = encodeURIComponent(fileName + '.3gpp');
if (mediatype == 'video') var name = encodeURIComponent(fileName + '.3gp');
db.get(id).then(function (doc) {
var path = file.fullPath;
window.resolveLocalFileSystemURL(path, function (fileEntry) {
return fileEntry.file(function (data) {
var reader = new FileReader();
reader.onloadend = function (e) {
var blob = b64toBlobAlt(e.target.result, file.type);
if (blob) {
db.putAttachment(id, name, doc._rev, blob, file.type).then(function () {
if (mediatype == 'video' || mediatype == 'image') getMedia();
if (mediatype == 'audio') $scope.audios.push(source);
});
}
};
return reader.readAsDataURL(data);
});
});
});
};
// creating the blob from the base64 string
function b64toBlobAlt(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
}

JSZip Memory Issue

I am experiencing high memory consumption on my Node.js app, when loading ~100MB zip files one after the other it is keeping them in memory as a "NodeBufferReader". The library I am using is called JSZip and is found here: https://stuk.github.io/jszip/
If I access the same zip file twice then it doesn't increase memory usage but for every 'extra' .zip file I access the memory increases by approx the size of the .zip file. The files I am accessing are all around 100MB or larger so as you can imagine this has the potential to get rather large, rather quickly.
The Node.js application is a websocket server that reads files from within .zip files and returns them back to the requestor as base64 data. The function in question is here:
function handleFileRequest(args, connection_id) {
var zipIndex = 0,
pathLen = 0,
zip_file = "",
zip_subdir = "";
try {
if (args.custom.file.indexOf(".zip") > -1) {
// We have a .zip directory!
zipIndex = args.custom.file.indexOf(".zip") + 4;
pathLen = args.custom.file.length;
zip_file = args.custom.file.substring(0, zipIndex);
zip_subdir = args.custom.file.substring(zipIndex + 1, pathLen);
fs.readFile(zip_file, function (err, data) {
if (!err) {
zipObj.load(data);
if (zipObj.file(zip_subdir)) {
var binary = zipObj.file(zip_subdir).asBinary();
var base64data = btoa(binary);
var extension = args.custom.file.split('.').pop();
var b64Header = "data:" + MIME[extension] + ";base64,";
var tag2 = args.custom.tag2 || "unset";
var tag3 = args.custom.tag3 || "unset";
var rargs = {
action: "getFile",
tag: args.tag,
dialogName: connections[connection_id].dialogName,
custom: {
file: b64Header + base64data,
tag2: tag2,
tag3: tag3
}
};
connections[connection_id].sendUTF(JSON.stringify(rargs));
rargs = null;
binary = null;
base64data = null;
} else {
serverLog(connection_id, "Requested file doesn't exist");
}
} else {
serverLog(connection_id, "There was an error retrieving the zip file data");
}
});
} else {
// File isn't a .zip
}
} catch (e) {
serverLog(connection_id, e);
}
}
Any help would be much appreciated in getting rid of this problem - Thanks!
Working Code Example
function handleFileRequest(args, connection_id) {
var zipIndex = 0,
pathLen = 0,
f = "",
d = "";
try {
if (args.custom.file.indexOf(".zip") > -1) {
// We have a .zip directory!
zipIndex = args.custom.file.indexOf(".zip") + 4;
pathLen = args.custom.file.length;
f = args.custom.file.substring(0, zipIndex);
d = args.custom.file.substring(zipIndex + 1, pathLen);
fs.readFile(f, function (err, data) {
var rargs = null,
binary = null,
base64data = null,
zipObj = null;
if (!err) {
zipObj = new JSZip();
zipObj.load(data);
if (zipObj.file(d)) {
binary = zipObj.file(d).asBinary();
base64data = btoa(binary);
var extension = args.custom.file.split('.').pop();
var b64Header = "data:" + MIME[extension] + ";base64,";
var tag2 = args.custom.tag2 || "unset";
var tag3 = args.custom.tag3 || "unset";
rargs = {
action: "getFile",
tag: args.tag,
dialogName: connections[connection_id].dialogName,
custom: {
file: b64Header + base64data,
tag2: tag2,
tag3: tag3
}
};
connections[connection_id].sendUTF(JSON.stringify(rargs));
} else {
serverLog(connection_id, "Requested file doesn't exist");
}
} else {
serverLog(connection_id, "There was an error retrieving the zip file data");
}
rargs = null;
binary = null;
base64data = null;
zipObj = null;
});
} else {
// Non-Zip file
}
} catch (e) {
serverLog(connection_id, e);
}
}
If you use the same JSZip instance to load each and every file, you will keep everything in memory : the load method doesn't replace the existing content.
Try using a new JSZip instance each time :
var zipObj = new JSZip();
zipObj.load(data);
// or var zipObj = new JSZip(data);

Cordova - Capture video and retrieve base64 data

I am using phonegap to record a video and I am wanting to save the base64 data-encoded string. So far I have tried this..
function captureSuccess(mediaFiles) {
var i, path, len;
path = mediaFiles[0];
win(path);
}
function win(file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
console.log("read success");
console.log(evt.target.result);
};
reader.readAsDataURL(file);
};
function captureError(error) {
navigator.notification.alert('Error code: ' + error.code, null, 'Capture Error');
}
function captureVideo() {
navigator.device.capture.captureVideo(captureSuccess, captureError, {limit: 1});
}
I have used readAsDataURL as specified in the documentation. The output of evt.target.result is "data:video/mp4;base64," but there isn't any encoded data after the filetype.
Is there anything else I need to add in order to get the full base64 data of the video?
I am really struggling to find anything that can help me. Any help would be greatly appreciated.
var b64toBlobAlt = function(dataURI, contentType) {
var ab, byteString, i, ia;
byteString = atob(dataURI.split(',')[1]);
ab = new ArrayBuffer(byteString.length);
ia = new Uint8Array(ab);
i = 0;
while (i < byteString.length) {
ia[i] = byteString.charCodeAt(i);
i++;
}
return new Blob([ab], {
type: contentType
});
};
var path = mediaFiles[0].fullPath;
window.resolveLocalFileSystemURL(path, function(fileEntry) {
return fileEntry.file(function(data) {
var reader = new FileReader();
reader.onloadend = function(e) {
var blob = b64toBlobAlt(e.target.result, 'video/mp4');
if (blob) {
// do whatever you want with blob
});
}
};
return reader.readAsDataURL(data);
});
});

How To Upload Multiple Files To Server Using Javascript

I am using PhoneGap, and uploading a file (using a HTTP POST) like this,
function uploadSingleFile()
{
var ft = new FileTransfer();
// set up parameters etc
ft.upload(imageName, "http://serviceaddress/UploadFile.ashx", win, fail, options);
}
function win(r)
{
// success callback
}
I am wanting to upload muliple files, so in the success callback I want to call the uploadSingleFile to move onto the next file.
How can I store which file I am up to? I am using the localStorage to store the file names. So I would want to do this,
upload file localStorage.file0
upload file localStorage.file1
upload file localStorage.file2
So all I would need to do would be to store the number on the end, 0, 1, etc of where we are up to. Do I need to use a global variable? Seems messy.
If only I could pass through to the success callback a number as a additional parameter?
Hmmm. Is the problem worth doubting? Just store an array of file names and use JSON.stringify / JSON.parse for conversion between array and string.
function uploadSingleFile(fileName) {
var ft = new FileTransfer();
ft.upload("fileUrl",
"server",
function (result , fileName) {
console.log(fileName + ' has been uploaded successfully to server');
},
function (error) {
console.log(error);
},
{fileName: fileName, fileKey: "file"});
}
function uploadFiles() {
var files = JSON.parse(localStorage.files);
for(var i=0; i < files.length; i++) {
uploadSingleFile(files[i]);
}
}
You can send the index of file as parameter to uploadSingleFile() then using it in console.log()
First add all your images to array :
var TemplstImg = [];
function UploadImages()
{
var lstImages = [localStorage.file0,localStorage.file1,localStorage.file2];
TemplstImg=lstImages ;
if (TemplstImg.length > 0) {
var img = TemplstImg.pop();
uploadPhoto(img);
}
}
function uploadPhoto(imageURI) {
imageURI = imageURI.ImageFile;
var options = new FileUploadOptions();
options.fileKey = "file";
options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
options.mimeType = "image/jpeg";
var params = {};
params.value1 = "test";
params.value2 = "param";
options.params = params;
var ft = new FileTransfer();
ft.upload(imageURI, yourServerPath, winImg, failImg,options);
}
function winImg(r) {
if (TemplstImg.length == 0) {
alert ('Done , all files was uploaded');
} else {
var img = TemplstImg.pop();
uploadPhoto(img);
}
}
function failImg(error) {
alert("failImg An error has occurred: Code = " + error.code);
console.log("upload error source " + error.source);
console.log("upload error target " + error.target);
}

Categories