This is what I tried to do with my mobile app (built with Ionic, Angular, Cordova/Ngcordova) : * all the testing I'have done was on a real device (Samsung with Android 4.4.2)
Everythings is working except the point 5. I cannot get the image binary to be able to send it to the server. I saw some others demo but everyone is using DATA_URL (instead FILE_URI - destinationType : Camera.DestinationType.FILE_URI,) to get the image in base64 and in the next step send it to the server.
I want to save all images; get them (from app folder)and send them when user want.
Is there any way to do this ? Is it posible in cordova ?
My code are below:
CONTROLLER:
'use strict';
angular.module('MyDemoApp.controllers')
.controller('SignupCtrl', function ($scope, $http,$cordovaFile, ImageService) {
$scope.user = {};
$scope.imgPath = '';
$scope.imgName = '';
$scope.addNewImage = function (method){
ImageService.addImage(method).then(function(data){
$scope.user.image = data.src;
$scope.imgPath = data.imgObj;
$scope.imgName = data.name;
window.alert(JSON.stringify(data));
/* RESULTS : {"name":"aaaaaxxxxxxxxx.jpg",
"src":"file:///data/data/com.example.DemoApp/files/aaaaaxxxxxxxxx.jpg",
"imgObj":"file:///storage/emulated/0/Android/data/com.example.DemoApp/cache/xxxxxxxxx.jpg"
}
xxxxxxxxx.jpg - the original name of photo
aaaaaxxxxxxxxx.jpg - new generated name in service
*/
},function(err){
window.alert('Add image error: ' + JSON.stringify(err));
});
}
$scope.signUp = function () {
// V1
// This method is used to return a File object that represents the current state of the file represented by the FileEntry object. The parameters consist of two callback functions:
// successCallback- This is a callback that is called with a File object.
// errorCallback- This is a callback that is called if an error occurs when creating the File object (in other words, the underlying file no longer exists).
function success(file) {
window.alert("File type: " + file.type); // RESULT: image/jpeg
window.alert("File size: " + file.size); // RESULT: 1191228
window.alert(JSON.stringify(file));
/* RESULTS : {"name":"aaaaaxxxxxxxxx.jpg",
"localURL":"cdvfile://localhost/files/aaaaaxxxxxxxxx.jpg",
"type":"image/jpeg"
"lastModified":"some value "
"lastModifiedDate":"some value "
"size":"1191228",
"start":"0"
"end":"1191228"
}
*/
}
function fail(error) { window.alert("Unable to retrieve file properties: " + error.code);}
// obtain properties of a file
entry.file(success, fail);
// $cordovaFile.readAsDataURL($scope.user.image, $scope.imgName)
// $cordovaFile.readAsBinaryString($scope.user.image, $scope.imgName)
$cordovaFile.readAsBinaryString(cordova.file.dataDirectory,$scope.imgName)
.then(function (success) {
window.alert(JSON.stringify(success))
//NEVER GET HERE
// success
}, function (error) {
// error
window.alert(JSON.stringify(error))
// ALL THE TIME I GET ERROR CODE 5 OR 1000 OR 1
});
}
});
MY SERVICE:
'use strict';
angular.module('MyDemoApp.services')
.service('ImageService', function($q, $cordovaCamera, $cordovaFile, $localStorage) {
// 1
this.addImage = function (method){
var deferred = $q.defer();
var promise = deferred.promise;
var imageDetails ={'name':'', 'src':'', 'imgObj':''};
// 2
// Set the "options array" [who is passed to the cordovaCamera] by method [take | choose]
// Docs : http://plugins.cordova.io/#/package/org.apache.cordova.camera
var options ={};
if (method==='take'){
options = {
destinationType : Camera.DestinationType.FILE_URI,
sourceType : Camera.PictureSourceType.CAMERA,
allowEdit : false,
encodingType: Camera.EncodingType.JPEG,
popoverOptions: CameraPopoverOptions,
};
} else if (method==='choose'){
options = {
destinationType : Camera.DestinationType.FILE_URI,
sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
allowEdit : false,
encodingType: Camera.EncodingType.JPEG,
popoverOptions: CameraPopoverOptions,
};
}
// 3
// Call the ngCodrova module cordovaCamera we injected to our service.
$cordovaCamera.getPicture(options).then(function(imageData) {
// 4
// When the image capture returns data, we pass the information to our success function,
// which will call some other functions to copy the original image to our app folder.
// window.alert(JSON.stringify(imageData));
onImageSuccess(imageData);
function onImageSuccess(fileURI) {
createFileEntry(fileURI);
}
function createFileEntry(fileURI) {
imageDetails.imgObj=fileURI;
window.resolveLocalFileSystemURL(fileURI, copyFile, fail);
}
// 5
// This function copies the original file to our app directory.
// We have to deal with duplicate images, we give a new name to the file consisting of a random string and the original name of the image.
function copyFile(fileEntry) {
//var name = fileEntry.fullPath.substr(fileEntry.fullPath.lastIndexOf('/') + 1);
var name = fileEntry.nativeURL.substr(fileEntry.nativeURL.lastIndexOf('/') + 1);
var newName = makeid() + name;
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function(fileSystem2) {
fileEntry.copyTo(
fileSystem2,
newName,
onCopySuccess,
fail
);
},
fail);
}
// 6
// If the copy task finishes successful, we push the image url to our scope array of images.
// Make sure to use the apply() function to update the scope and view!
function onCopySuccess(entry) {
// entry = { 'isFile':'', 'isDirectory':'', 'Name':'', 'fullPath':'', 'fileSystem':'', 'NativeUrl':''}
imageDetails.name=entry.name;
imageDetails.src=entry.nativeURL;
deferred.resolve(imageDetails)
}
function fail(error) { deferred.reject(error);}
function makeid() {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i=0; i < 5; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
}, function(err) {
deferred.reject(err);
});
return deferred.promise
}; // end addImage();
this.urlForImage = function (imageName){
// "urlForImage" function receive a param "imageName" and return the URL of image
var trueOrigin='';
var name = imageName.substr(imageName.lastIndexOf('/') + 1);
trueOrigin = cordova.file.dataDirectory + name;
return trueOrigin;
}; // end urlForImage()
this.getImageObjByPath = function (imagePath){
// Here I want to do something that return the image binary
return imageObject;
};
});
I really appreciate any help
Thanks
Hi The issue is that the camera plugin stores the image inside the cache folder and you are trying to access to the image using cordova.file.dataDirectory, that's why cordova can't find the image.
Try to read from cache or after using the Camera plugin to take the image, please copy the image to the cordova.file.dataDirectory, and then work from there. Do in it this way your image will be private and you are going to be able to manage the image with cordova.file.dataDirectory.
Hope it helps. Let me show you what I did:
saveToFile: function(imageUrl) {
return $q(function(resolve, reject) {
function makeid() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i=0; i < 5; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
var name = imageUrl.substr(imageUrl.lastIndexOf('/') + 1);
var namePath = imageUrl.substr(0, imageUrl.lastIndexOf('/') + 1);
var newName = makeid() + name;
$cordovaFile.copyFile(namePath, name, cordova.file.dataDirectory, newName)
.then(function(info){
resolve(newName);
}, function(e){
reject(e);
});
});
},