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.

About these ads

About Gonzalo Ayuso

Web Architect specialized in Open Source technologies. PHP, Python, JQuery, Dojo, PostgreSQL, CouchDB and node.js but always learning.

Posted on October 28, 2013, in android, cordova, phonegap, Technology and tagged , , , , , . Bookmark the permalink. 29 Comments.

  1. Very nice. Could you do an article the other way around too? Download a picture from a URL, store it in localStorage or SD card and reference to it in the app.

  2. Can you tell how to show progress-bar while uploading multiple images to the server.

  3. 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?

    • 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

  4. Hey, i am unable to upload images with the above code.. it works fine till capturing the image. but its not sending to server

    • 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)

    • You should probably pay more attention to your code. We got it working.

  5. 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

  6. hey please respond ASAP thanks in advance

    • Gonzalo Ayuso

      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

  7. 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!!

  8. which method it uses to send the image among “POST”,”PUT” etc
    can we send it using “PUT” method…..

    • 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.

  9. 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?

    • use adb logcat (with android) to check what’s the error.

      • 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.

      • 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.

      • I have been using videojs with great results. Easy to implement: http://www.videojs.com/

      • Gonzalo Ayuso

        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)

      • 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.

  10. 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!

    • 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)

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

  11. 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

  1. Pingback: Tire fotos com um aplicativo phonegap/cordova e envie-as para o servidor | iMasters

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 992 other followers

%d bloggers like this: