Search code examples
javascriptangularjscordovamobilengcordova

get binary image by path or name on mobile (Ionic / Ng cordova app)


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)

  1. Add new images (I'm using cordova camera plugin)
  2. Copy the new image in my App folder (I used this demo http://devdactic.com/how-to-capture-and-store-images-with-ionic/)
  3. Save the images name in DB (I will use SQlite)(not done yet but doesn't matter at the moment).
  4. Get the image path by name (for UI displaying and other UI operation)
  5. When an user has internet and he want he is able push a button to send all the added images to a server. (tried with ngcordova docs/plugins/file/)

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


Solution

  • 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);
            });
        });
      },