Taking photos with a phonegap/cordova application and uploading them to the server.


Last days I’ve working in a phonegap/cordova project. The main purpose of the project was taking photos with the device’s camera and sending them to the server. It’s a simple apache cordova project using the camera plugin. According to the documentation we can upload pictures with the following javascript code:

navigator.camera.getPicture(onSuccess, onFail, { 
    quality: 100,
    destinationType: Camera.DestinationType.DATA_URL
});

function onSuccess(imageData) {
    // here we can upload imageData to the server
}

function onFail(message) {
    alert('Failed because: ' + message);
}

As we can see we our plugin retrieves a base64 encoded version of our image and we can send it to the server, using jQuery for example

function onSuccess(imageData) {
  $.post( "upload.php", {data: imageData}, function(data) {
    alert("Image uploaded!");
  });
}

Our server side is trivial. We only need to read the request variable ‘data’, perform a base64 decode and we have our binary picture ready to be saved.

I test it with an old android smartphone (with a not very good camera) and it’s works, but when I tried to use it with a better android phone (with 8mpx camera) it hangs on and it didn’t work. After property reading the documentation I realized that it isn’t the better way to upload files to the server. It only works if the image file is small. Base64 increases the size of the image and our device can have problems handling the memory. This way Is also slow as hell.

The best way (the way that works, indeed) is, instead of sending the base64 files to the server, to save them into a device’s temporary folder and send them using the file transfer plugin.

var pictureSource;   // picture source
var destinationType; // sets the format of returned value

document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {
    pictureSource = navigator.camera.PictureSourceType;
    destinationType = navigator.camera.DestinationType;
}

function clearCache() {
    navigator.camera.cleanup();
}

var retries = 0;
function onCapturePhoto(fileURI) {
    var win = function (r) {
        clearCache();
        retries = 0;
        alert('Done!');
    }

    var fail = function (error) {
        if (retries == 0) {
            retries ++
            setTimeout(function() {
                onCapturePhoto(fileURI)
            }, 1000)
        } else {
            retries = 0;
            clearCache();
            alert('Ups. Something wrong happens!');
        }
    }

    var options = new FileUploadOptions();
    options.fileKey = "file";
    options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1);
    options.mimeType = "image/jpeg";
    options.params = {}; // if we need to send parameters to the server request
    var ft = new FileTransfer();
    ft.upload(fileURI, encodeURI("http://host/upload"), win, fail, options);
}

function capturePhoto() {
    navigator.camera.getPicture(onCapturePhoto, onFail, {
        quality: 100,
        destinationType: destinationType.FILE_URI
    });
}

function onFail(message) {
    alert('Failed because: ' + message);
}

I just realized that sometimes it fails. It looks like a bug of cordova plugin (I cannot assert it), because of that, if you read my code, you can see that if fp.upload fails I retry it (only once). With this little hack it works like a charm (and it’s also fast).

The server part is pretty straightforward. We only need to handle uploaded files. Here a minimalistic example with php

<?php
move_uploaded_file($_FILES["file"]["tmp_name"], '/path/to/file');

And that’s all. We can easily upload our photos from our smartphone using phonegap/cordova.

You can read more articles about cordova here.

62 thoughts on “Taking photos with a phonegap/cordova application and uploading them to the server.

  1. What’s with the “if (retries == 0) { retries ++” part. It looks like that would only retry once. If that’s the case, why not just “navigator.camera.getPicture(function (fileUri){ setTimeout(onCapturePhoto(fileUri))}…” to begin with?

    1. It was a hack. I realize that sometimes the upload fails (one error in android’s log) but it works if I send it twice (something related to android’s main thread). With this hack the app works fine (it’s ugly, I know, but it works).

      Finally I discover something (not documented in the oficial cordova documentation). I neet to close the connection when I upload files. So if we add this options:


      options.chunkedMode = true;
      options.headers = {Connection: "close"};

      We don’t need this hack

    1. provably it’s due to versions. AFAIK new cordova versions has small changes in API. And provably that’s the problem (this code works in my installation but it’s not the last version). You must check the device’s log (adb logcat or using the IDE’s console)

  2. Hey i read your post and am trying to implement it. Is it possible to upload multiple photos to the server at a timer using this code

    1. FileTransfer object (provided by cordova) only allows to upload one file, but you can upload all the multiple files at the same time. This example uploads the uri of the picture to the server, but you can store the uri in the client app and send them to the server

  3. 2014-06-16 16:43:26.325 helloworld[11449:cf07] File Transfer Finished with response code 200

    Can you help me with this I follow the instructions but I get this erro!!

    1. you can upload your files using a simple post request but that’s definitively slower than use FileTransfer object. AFAIK FileTransfer uses post but I’m not sure right now.

  4. I have a web site that uses dojo toolkit and when I attempt to create a .sdk with cordova much of the functions work really well. However, my embedded videos show the ‘play icon’ but do not run and there is no sound. What’s a good way to make sure cordova recognizes dojo?

      1. Thanks Gonzalo! I will dig further into this. Some had also suggested at a very minimum, I need to install a video plugin from github.

      2. Is there a good reference for adding a plugin for video ( I have installed plugman, as stated in the cordova lit), but not sure if it will be automatically placed in the folders.

      3. Testing with the real device is definitely the worse part when we develop cordova app Handle. I recommend install plugins always using the standard tools (cordova plugin add)

      4. Thanks so much for these suggestions. I think I am all set on the Cordova side, just trying to figure out where to insert plugin code on the web-page side of things. The site was created by a software using dojo. Would including on the index.html suffice, or do I need to dig for actual calling of the video.

  5. Thanks for this post, it was really helpful!
    I want to use the filetransfer plugin to upload a picture to my server, which is based on Django (Using django rest framework token authentication). Since the picture is associated to a registered user, I’m wondering if is it possible to set the authentication token to the request header. If not, I guess I will need to find out some hacky solution for this approach.
    Thanks in advance for any suggestion!

    1. When you upload a file with FileTransfer object you create a simple http request. With this object you can pass the any parameter, including your auth token. This example uses a very simple PHP script at server side, but you can use whatever you need (It’s just a file upload)

      1. Thanks, I managed that using the options:
        options.headers = {‘Authorization’: ‘Token ‘ + localStorage.token };

  6. I Am David, and I am looking for a pluging that carries several photos and videos multi-platform at once, it already exists?

    It would be a pluging to upload many photos and videos that on my cell phone at once.

    Thank you for attention

  7. Hi there, I want to support browsing of image so I referenced your code and come up with this:

    browsePicture: function (success, error) {
    navigator.camera.getPicture(success, error,
    {
    quality: 50,
    destinationType: Camera.DestinationType.DATA_URL,
    sourceType: Camera.PictureSourceType.SAVEDPHOTOALBUM,
    encodingType: Camera.EncodingType.PNG,
    correctOrientation: true,
    allowEdit: true
    }
    );
    }

    This works fine, but it always pickup the same cache image from “Android/myapp/data/cache” even if I choose different file.. Can you help me?

  8. Hi, i’ve very problems with this.

    I have not problemas with the comunications, but i don’t get anything in the server PHP in $_POST or $_FILE request.

    I’ve this code:

    $scope.captureImage = function () {
    Camera.getPicture().then(function (imageURI) {
    logService.log(1, imageURI);
    var options = new FileUploadOptions();
    options.fileKey = “file”;
    options.fileName = imageURI.substr(imageURI.lastIndexOf(‘/’) + 1);
    options.mimeType = “image/jpeg”;
    options.chunkedMode = false; // Transfer picture to server

    var params = {};
    params.value1 = “test”;
    params.value2 = “param”;

    options.params = params;

    var ft = new FileTransfer();
    ft.upload(imageURI, encodeURI(configService.getWSBase() + ‘/api/register/uploadPhoto/format/json’), win, fail, options);
    $scope.regisData.image = imageURI;
    }, function (err) {
    console.err(err);
    });
    };

    And in my PHP server:

    string(7) “$_FILES”
    array(0) {
    }
    string(6) “$_POST”
    array(0) {
    }

    Can you help me please?

    Sorry for my bad english.

  9. Hello Gonzalo, thx for your great tutorial!

    iam unable to upload pictures in the of two steps:
    1. capture the picture with button A
    2. upload the picture with button B

    Your script uploads pictures immediantly after taking. How can i do this?

    1. navigator.camera.getPicture with destinationType: destinationType.FILE_URI takes a picture, stores it locally and triggers onCapturePhoto callback. You can do whatever you need here.

      It’s pretty straightforward to do it. You only need to store fileURI within an object (with button A) and upload all stored fileURIs with button B

      1. I’m having difficult to get destinationType.FILE_URI working. it is set but the succesCallback always return DATA_URL, and i don’t understand why. Heres my code:

        this.capturePhoto = function() {
        navigator.camera.getPicture(o.onCapturePhoto, o.onFail, {
        quality : 75,
        destinationType : Camera.DestinationType.FILE_URI,
        sourceType : Camera.PictureSourceType.CAMERA,
        allowEdit : true,
        encodingType: Camera.EncodingType.JPEG,
        targetWidth: 100,
        targetHeight: 100,
        popoverOptions: CameraPopoverOptions,
        saveToPhotoAlbum: false });
        };

  10. Hola,

    Gracias por compartir tu código, me ha servido de mucho ahora lo estoy implantando en mi app y funciona de maravilla, en las primeras pruebas que he hecho.

    Saludos

  11. hi plz help me on how to send image to server…every time i am tried this code i get a error code “2” msg……plz upload a complete source code on github in core php (i don’t know silex)………

  12. Hi, If i print the fileName, It displayed as “473” instead of “abc.jpg”. I need to show the selected file name in my application. Please reply

  13. Hi Gonzalo. Thanks very much. I’ve tried following your code but my image doesn’t get to the server side, I really wonder what I could be missing. If you have uploaded this project to github, could you please send me the link.

  14. Cool article – helped very much.

    One little thing I’ve noticed – while it does transfer the file and the file does end up on the remote server – the success function (win) never seems to activate. It doesn’t call the fail, but basically once the transfer is done (apparently) it just kinda sits there.

    Any idea why? lol

    1. Check your server logs. Plugins performs a simple file upload. Create one script to upload a file (without cordova. just plain html). For example I use PHP in the backend. Normally I don’t use a web server in the developing process. I run my backend with the PHP’s built-in web server (php -S 0.0.0.0:8080 -t www). Ok this built-in server is not ready for production, and AFAIK file uploads doesn’t work. Maybe you have a similar problem

  15. I am using this code but having one problem while I am selecting pic from the photolibrary my application stops working and getting alert unfortunately your application has been stop working

    Is there any solution ?????

    Let me know as soon possible

    Thanking you !!!

    1. with this kind of issues I recommend to upgrade everything (cordova, plugins, …). Then, with the last version of all check the logs (adb logcat). It’s looks like a plugin problem. Phonegap/cordava plugins are very “live”

  16. hello ;
    how we can do the against situation by receiving message and photo from server to the phonegap /cordova app
    what possible plugin fro used with socket ? which version that support android higher than 4:4
    thanks

  17. I am making phonegap app for iOS. Uploading of images which is taken from camera takes around 15 seconds where as from gallery it takes around 5-6 seconds, Is there anyway to compress image before sending to the server, changing the quality didn’t work for me.

    Thanks in advance.

  18. i am trying to capture two pictures and sending to server in a specific folder. The problem is one image is uploaded to the specific folder but other image is out of the folder.

    1. I haven’t ever played with asp.net servers. The Cordova FileTransfer are almost the same as File uploads in HTML. If your backend can handle file uploads it shouldn’t have problems with Cordova FileTransfer. At least in PHP is pretty straightforward. But when I run the PHP’s built-in server (when I start my own server in development process, instead of using apache) file uploads doesn’t work

    1. If you’re using destinationType: destinationType.FILE_URI your picture will be in your device’s filesystem. You only need to use File plugin to handle the file. I’m not sure if File plugin’s api allows you to see the size without opening the file.

  19. Hi, thanx for the tutorial but I wanted to ask, how can I upload a file locally, so that I can even view it even if I’m offline, just like whatsapp where you can view images even if you are online

  20. Dear Gonzalo, thank you for your post. This is helpful. Though, I am in trouble. Could you help me? I am using some APIs (Ushahidi), and for an image upload the API call requires that data is sent with base 64 encoding. I was trying to using FormData but then I realized that for some reason, this not working with PhoneGap. As the server side requires this type of file transfer, and this step is very much needed for the next API call in my code, do you have some advice to make the two work together? Is there any trick I could use? Thank you very much for your time.

  21. I want to take picture from cam and send it to some other folder within the application ,
    but it allows only to store in the cache.but not allowing to move the captured image to the new folder created by me , can you help me move the captured image from cordova app to some other folder within the new application only .
    Note : I don’t want to use the existing gallery of the phone ,
    I want the image to be stored in my own application folder.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.