Harry Moreno
Harry Moreno

Reputation: 11673

courrupted jpeg when uploading to parse.com with cordova file transfer plugin

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

Upvotes: 3

Views: 1395

Answers (6)

Atul
Atul

Reputation: 31

I have made 2 changes which worked for me.

1.  <preference name="CameraUsesGeolocation" value="false" />
  2.  In camera options 
      saveToPhotoAlbum:true

Upvotes: 0

Gabriel Eng
Gabriel Eng

Reputation: 53

Took me awhile to figure this about this is the way I removed the Multi-part Header.

Open: \platforms\android\src\org\apache\cordova\filetransfer\FileTransfer.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.

Upvotes: 0

Shoebie
Shoebie

Reputation: 1263

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

Upvotes: 1

Bluety
Bluety

Reputation: 1909

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

Upvotes: 0

Harry Moreno
Harry Moreno

Reputation: 11673

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

Upvotes: 0

Robert Rowntree
Robert Rowntree

Reputation: 6289

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

Upvotes: 1

Related Questions