This is a bare bones example of using Cordova or Phonegap to take a photo with your IPhone or IPad camera.
The project uses XCode 4.3.2 and was tested using iOS 5.1 on a IPhone 4. There are no frills. I did make the button large enough for IPhone human guideline standards. I also added a simple console area to display debugging messages from the Javascript.
I also stripped out most of the extra Cordova comments that were not relevant.
Each time you take a picture another file is added. This example does not provide a way to delete the files. If you remove the app from the phone, the images are deleted. You may need to study the Cordova File API for how to manage your app’s local storage.
Here are the screens for the app.
The left screen is the app before any photo has been taken. It shows the integrated debugging console with the logged message that the Cordova onDeviceReady() method was called.
The middle screen is the IPhone Camera app with a photo just taken.
The right screen shows the app with a photo taken. You also see in the integrated console messages logged from the Javascript. The second line is the method called by touching the “Take Picture” button. The final message is the callback method from the Cordova getPicture camera method for a successful photo take. In particular you can see the file path and name of the photo.
Step 1 – Install Cordova for XCode
Instructions for setting up your development environment are located at the PhoneGap site Getting Started with iOS.
Step 2 – Create New Cordova-based Application
Step 3 – Set XCode Project Options
Set the XCode project options as follows:
- Product name: Here I used CordovaCamera as the project name. You can use a name of your own choosing.
- Company identifier: Provide your own reverse domain.
- Use Automatic Reference Counting: Uncheck
Step 4 – Choose A File Location
Once you select a file location on your computer you will have a folder structure as follows:
And in XCode you will see a project window as follows:
You may notice the project has a warning. Ignore this for now.
Step 5 – Create and Add the www Folder and Files to the Project
These are the normal setup instructions for a Cordova alias PhoneGap XCode project. You can skip this step if you are used to creating Cordova XCode projects.
The process is creating a www folder by running the app once in the IPhone simulator and then add to the project explorer.
First run the app in the IPhone simulator.
The app runs but complains of the missing index.html file.
A www folder with this file and one other js file were created on your file system as this the app launched in the simulator. Here you see them and you need to drag the www folder into the Project Explorer. Do not drag to or copy to the XCode folders outside of XCode.
Fill out the “Choose options for adding these files” dialog as follows.
- Destination: Unchecked
- Folders: “Created folder references for added folders” selected.
- Add to targets: CordovaCamera checked.
And this is the final results you see in the Project Explorer window.
Run the app in the IPhone simulator one more time.
This time you will be greeted with an Alert dialog with the “Cordova is working” message.
[ad name=”Google Adsense”]
Step 7 – Code the index.html File
I removed code comments and commented code that is included in the index.html file.
Here is the full index.html file completed for your copy convenience.
<!DOCTYPE html> <html> <head> <title>Camera</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" /> <meta charset="utf-8"> <script type="text/javascript" charset="utf-8" src="cordova-1.5.0.js"></script> <script type="text/javascript"> // Debugging div on device var console_log; function onBodyLoad() { document.addEventListener("deviceready", onDeviceReady, false); } /* Cordova has been initialized and is ready to roll */ function onDeviceReady() { console_log = document.getElementById('console_div'); console_log.innerHTML += "onDeviceReady()<br/>"; } /* Open the device camera app */ function capturePhoto() { console_log.innerHTML += "capturePhoto()<br/>"; // navigator.camera.getPicture( cameraSuccess, cameraError, [ cameraOptions ] ); navigator.camera.getPicture(getPhoto, onFail, { quality: 50, destinationType: Camera.DestinationType.FILE_URI, // // Return image file URI sourceType:Camera.PictureSourceType.CAMERA, targetWidth:120, // Width in pixels to scale image. Aspect ratio is maintained. Required targetHeight. targetHeight:180 // Height in pixels to scale image. Aspect ratio is maintained. Required targetWidth. }); } /* navigator.camera.getPicture success function */ function getPhoto(imageData) { var cameraImage = document.getElementById('cameraImage'); cameraImage.src = imageData; console_log.innerHTML += "getPhoto() - cameraImage.src: " + cameraImage.src + "<br/>"; } /* navigator.camera.getPicture fail function */ function onFail(message) { alert('Failed because: ' + message); } </script> </head> <body onload="onBodyLoad()" style = "text-align:center;background-color:#ccc;padding:0px;"> <div> <h1 style = "margin-bottom:0px;">Cordova Camera</h1> <button style = "font-size:20px;width:200px;height:44px;;margin-bottom:5px;" onclick="capturePhoto();">Take Picture</button> <br> <img style="width:120px;height:180px;;background-color:#fff;" id="cameraImage" src="" /> <div id="console_div" style = "text-align:left;border:1px solid black;background-color:#fff;height:150px;overflow:auto;"></div> </div> </body> </html>
First look at the html starting on line 53. To simplify, the css is placed inline with tags versus the better approach of using an external css file.
<body onload="onBodyLoad()" style = "text-align:center;background-color:#ccc;padding:0px;"> <div> <h1 style = "margin-bottom:0px;">Cordova Camera</h1> <button style = "font-size:20px;width:200px;height:44px;;margin-bottom:5px;" onclick="capturePhoto();">Take Picture</button> <br> <img style="width:120px;height:180px;;background-color:#fff;" id="cameraImage" src="" /> <div id="console_div" style = "text-align:left;border:1px solid black;background-color:#fff;height:150px;overflow:auto;"></div> </div> </body>
Line 54 is the container div.
Line 55 provides a simple page heading.
Line 56 is the “Take Picture” button. It calls the capturePhoto() method when touched. Notice that you use the onClick handler, Cordova does the translation to touch up event for you.
Line 57 is the img tag for the photo once we take a picture.
Line 58 is a debugging div for output from your javascript. There are other debugging console solutions that may better serve your needs.
Back to the top of index.html, line 10 declares the console_log variable. It will globally reference the console_div div tag in the html. You can then see on lines 20 and 21 getting the reference from the DOM for console_div div tag.
<!DOCTYPE html> <html> <head> <title>Camera</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" /> <meta charset="utf-8"> <script type="text/javascript" charset="utf-8" src="cordova-1.5.0.js"></script> <script type="text/javascript"> // Debugging div on device var console_log; function onBodyLoad() { document.addEventListener("deviceready", onDeviceReady, false); } /* Cordova has been initialized and is ready to roll */ function onDeviceReady() { console_log = document.getElementById('console_div'); console_log.innerHTML += "onDeviceReady()<br/>"; }
The onBodyLoad function on line 12 is called from the DOM body tag onload event. It then provides a listener to the deviceready event from Cordova.
The deviceready event calls the onDeviceReady function to get the ball rolling.
This boot strapping is all standard for Cordova apps as it has since it was called PhoneGap.
Moving down to line 24 the capturePhoto function was added and is called by the “Take Picture” button in the html.
The function logs to our makeshift console on line 27.
The key item is the Cordova Camera API being used on line 29.
You see the Cordova API is attached to the DOM navigator object.
In this case we are using the camera.getPicture method.
The first argument is the function to call for a successful use of the device camera and the second is for failed usage of the device camera.
/* Open the device camera app */ function capturePhoto() { console_log.innerHTML += "capturePhoto()<br/>"; // navigator.camera.getPicture( cameraSuccess, cameraError, [ cameraOptions ] ); navigator.camera.getPicture(getPhoto, onFail, { quality: 50, destinationType: Camera.DestinationType.FILE_URI, // // Return image file URI sourceType:Camera.PictureSourceType.CAMERA, targetWidth:120, // Width in pixels to scale image. Aspect ratio is maintained. Required targetHeight. targetHeight:180 // Height in pixels to scale image. Aspect ratio is maintained. Required targetWidth. }); }
The details are in the third argument which is an array of properties called cameraOptions.
For the quality option on line 32 I choose the value of 50. This is a blatant copy from the documentation. But also I read that values over 50 may become a factor in memory issues. Something for you to research if you need a quality value over 50.
On line 33 the destinationType option takes values defined by Camera.DestinationType.
For the destinationType option I choose Camera.DestinationType.FILE_URI. The Camera.DestinationType.FILE_URI sends a file url of the picture taken to the success function. The only other choice for the destinationType property as of this writing is Camera.DestinationType.DATA_URL which returns an image as base64 encoded string to the success function.
Line 34 sets the sourceType option. It uses values from Camera.PictureSourceType. The official documentation leaves the sourceType option values up to your interpretation based on naming. The sourceType option I used is Camera.PictureSourceType.CAMERA since my plan is to use the device camera. The other two values are Camera.PictureSourceType.PHOTOLIBRARY and Camera.PictureSourceType.SAVEDPHOTOALBUM.
Finally on lines 35 and 36 I included the targetWidth and targetHeight options.
I found if you omit the targetWidth and targetHeight options you may have aspect ratio issues with displaying correct scaling. I discovered this when taking a picture using portrait and using landscape orientations in the camera app. The landscape orientation would have a distorted aspect ratio.
The html I set the img tag height and width to 120px and 180px respectively. As you see I used the same values for targetWidth and targetHeight respectively and that resolved my scaling issue. You see I copied the API documentation comments for these two options and added my own interpretation.
The last part of the javascript contains the navigator.camera.getPicture method success and fail functions named getPhoto and onFail respectively.
/* navigator.camera.getPicture success function */ function getPhoto(imageData) { var cameraImage = document.getElementById('cameraImage'); cameraImage.src = imageData; console_log.innerHTML += "getPhoto() - cameraImage.src: " + cameraImage.src + "<br/>"; } /* navigator.camera.getPicture fail function */ function onFail(message) { alert('Failed because: ' + message); }
For getPhoto the image url is passed in the imageData argument in line 40. All is needed is to assign the url to img tag src property. In the html the img tag has the id of cameraImage and on line 42 we get a reference from the DOM and on line 43 the url assignment to the img tag is complete.
Line 44 displays the url in our makeshift console window for observation.
The navigator.camera.getPicture fail callback is the onFail function on line 47. Line 49 displays feedback using the argument which has a message. I have not yet hit a problem and do not know how to simulate one.
Step 8 – Run the App
When you run the app, you need to use your IPhone or IPad. The camera cannot be simulated. Here is the first screen. At the beginning of the blog are all the screens for your reference.
Good luck!
[ad name=”Google Adsense”]