skip to Main Content

I’m using parse.com rest api https://www.parse.com/docs/rest#files I’m trying to upload a photo from a cordova app. I’m using the ngCordova projects wrapper of the file plugin and file transfer plugin.

When I upload a photo it’s being corrupted somehow. See http://files.parsetfss.com/73b88ac0-8858-4f64-92bf-de6aaf29f525/tfss-7b54f8e8-77fd-4e3d-bbbe-83bf67bb08d0-profile-image.jpeg

if I change the post requests Content-Type to application/json we see the folowing http://files.parsetfss.com/73b88ac0-8858-4f64-92bf-de6aaf29f525/tfss-219ecbb4-091f-45e6-9da1-35ad84022db6-profile-image.jpeg which is equivalent to this hex dump of the uploaded jpeg.

--+++++org.apache.cordova.formBoundary
Content-Disposition: form-data; name="file"; filename="no-filename"
Content-Type: image/jpeg
Content-Length: 35476

<binary>
--+++++org.apache.cordova.formBoundary--

Loading this image into preview brings up a warning that it’s corrupted. In photoshop it gets loaded properly, so the information is there, there’s just been some corruption.

I’m suspecting that the cordova file-transfer plugin is immature and by default adds unneeded parameters file and filename. And there’s no way to remove them. See https://github.com/apache/cordova-plugin-file-transfer/blob/master/doc/index.md#upload

How do I upload a jpeg binary to parse.com using the rest api and the file-transfer plugin?

profilesController.js

// uploads photo to rest api given local file_uri
$scope.addPhoto = function() {

  var options = {};
  options.mimeType = 'image/jpeg';
  options.headers = {
    'X-Parse-Application-Id': 'my-id',
    'X-Parse-REST-API-Key': 'my-key',
    'Content-Type': 'image/jpeg'
  };

  $cordovaFile.uploadFile('https://api.parse.com/1/files/profile-image.jpeg', $scope.imageSrc, options).then(function(result) {
    console.log('result:', result);
    $ionicLoading.hide();
  }, function(err) {
    // An error occured. Show a message to the user
  });
};

6

Answers


  1. Chosen as BEST ANSWER

    Answer is the plugin's api is not compatible with the format parse is expecting. I resorted to using the javascript sdk's file method https://www.parse.com/docs/js_guide#files-classes and the Camera plugin's DATA_URL method https://github.com/apache/cordova-plugin-camera/blob/master/doc/index.md#options


  2. can you dump the http headers from the cordova request? IMO its sending Content-type: mime/multipart and not what the Docs specify. In general if the plugin simply formats the headers mention in the REST api docs and if the files bytes are wrapped in Http.Entity in the body of the request , you will be fine.

    Its not a bad idea to invoke the curl samples yourself listing headers with “-v” switch then, test your app dumping the http headers ( and if necessary, the WIRE ) in order to verify your sending what the curl sends.

    curl -v -X POST  -H "X-Parse-Application-Id: AbR" -H "X-Parse-REST-API-Key: kuI9"  -H "Content-Type: image/*"  --data-binary '@test.png' https://api.parse.com/1/files/test.png
    
    Login or Signup to reply.
  3. You can use REST api to upload file from cordova app.

    In your controller :

    var cameraOptions = {
        destinationType: 0, // base64
        encodingType: 0 
    };
    
    $scope.takePicture = function() {
        cameraOptions.sourceType = 1;
        navigator.camera.getPicture(onSuccess, onFail, cameraOptions);
    }
    
    $scope.selectPicture = function() {
        cameraOptions.sourceType = 0;
        navigator.camera.getPicture(onSuccess, onFail, cameraOptions);
    }
    
    function onSuccess(picture) {
    
        File.upload(picture)
            .success(function(data) {
                // upload finish
            });
    
        $scope.$apply(function() {
            $scope.preview = 'data:image/jpeg;base64,' + picture;
        });
    }
    
    function onFail(resp) {
        alert('Error: ' + resp);
    }
    

    In File service :

    angular.factory('File', function ($http) {
        return {
            upload: function (photo) {
    
                var json = {
                    'base64': photo,
                    '_ContentType': 'image/jpeg'
                }
    
                var config = {
                    method: 'POST',
                    url: 'https://api.parse.com/1/files/pict.jpg',
                    data: json,
                    headers: {
                        'X-Parse-Application-Id': 'XXXXX',
                        'X-Parse-REST-API-Key': 'XXXXX'
                    }
                };
    
                return $http(config);
            }
        }
    });
    
    Login or Signup to reply.
  4. Currently, the file transfer plugin sends multiform part data which adds multi part headers to the payload. Perhaps, the server does not accept multipart headers. Try installing the file-tranfer version from master which states that:
    ‘if a header named Content-Type is present, multipart form data will NOT be used.’

    You can install the the file transfer plugin from master:
    cordova plugin add https://github.com/apache/cordova-plugin-file-transfer.git

    Login or Signup to reply.
  5. Took me awhile to figure this about this is the way I removed the Multi-part Header.

    Open:
    platformsandroidsrcorgapachecordovafiletransferFileTransfer.java

    Look for:

    sendStream.write(beforeDataBytes);
    totalBytes += beforeDataBytes.length;
    

    Comment away or delete these 2 lines. They are the code that adds the multi-part header.

    Login or Signup to reply.
  6. I have made 2 changes which worked for me.

    1.  <preference name="CameraUsesGeolocation" value="false" />
      2.  In camera options 
          saveToPhotoAlbum:true
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search