Cordova plugin camera a tutorial

 

To capture and select images or videos , using cordova , the plugin cordova-plugin-camera can be used .

$ cordova create demo-camera com.twiserandom.mobileapps.demo.camera "Demo Camera"
# Create an application , in a folder named
# demo-camera , with an id of 
# com.twiserandom.mobileapps.demo.camera 
# and a title of : Demo Camera

$ cd demo-camera

$ cordova platform add ios
# add the iOS platform 

$ cordova platform add android
# add the android platform 

$ cordova plugin add cordova-plugin-camera
# add the camera plugin . 

To get a picture or a video , the function :

navigator.camera.getPicture(cameraSuccessFct , cameraErrorFct , cameraOptions );

can be used .

The navigator.camera object is globally accessible , after the deviceready event has been fired .

The navigator.camera.getPicture function , takes as arguments two functions , one called on success , and the other one called on error . The last argument that it takes , is an object containing options for the media and the camera . This object has the following format .

/*Camera object properties .*/
{
  "mediaType": 
      Camera.MediaType.PICTURE
        /*Select a picture , default .*/
      Camera.MediaType.VIDEO
        /*Select a video , returns url only .*/
      Camera.MediaType.ALLMEDIA
       /*Select from all media .*/ ,
  "sourceType": 
      Camera.PictureSourceType.PHOTOLIBRARY 
        /*Source , device photo library .*/
      Camera.PictureSourceType.CAMERA
        /*Source camera , default .*/
      Camera.PictureSourceType.SAVEDPHOTOALBUM
        /*Source Roll album , iOS only .*/ ,
  "cameraDirection": 
      Camera.Direction.BACK
        /*Back Camera default .*/
      Camera.Direction.FRONT
        /*Front Camera .*/ ,
  "destinationType":
      Camera.DestinationType.DATA_URL
        /*Return a base 64 encoded stream .*/
      Camera.DestinationType.FILE_URI
        /*Return a file url , default , for example : 
             file:///var/mobile/Containers/Data/...../cdv_photo_001.jpg 
          In iOS , Pictures or videos are saved in the app , 
          temporary directory , which is emptied when the app
          exits .*/
        Camera.DestinationType.NATIVE_URI ,
       /* In iOS files are saved in the save Photo Album , when
          source type is camera , and editing is ignored when
          source type is PHOTOLIBRARY .*/
  "saveToPhotoAlbum": true
      /*True or false , save image to 
        photo album , default true .*/ ,
  "encodingType": 
      Camera.EncodingType.JPEG
        /*Returned image encoding type 
          JPEG , default .*/
      Camera.EncodingType. PNG
        /*Returned image encoding type
          PNG  .*/ ,
  "quality": 50
      /*Quality of the captured image , 
        between 0 and 100 , default is
        50 .*/ ,
  "allowEdit": false
      /*True or false .
        Allow image editing before
        selection , iOS only , default
        false .*/ ,
  "targetWidth": undefined
      /*Width in px to scale image , 
        must be used with targetHeight .
        Aspect ratio remains constant 
        , default undefined .*/ ,
  "targetHeight": undefined
      /*Height in px to scale image , 
        must be used with targetWidth .
        Aspect ratio remains constant ,
        default undefined .*/ ,
  "correctOrientation": undefined
      /*True or false .
        Correct rotation of device using capture
        by rotating the image ,
        default undefined .*/ ,
  "popoverOptions": undefined 
      /*default , undefined . 
        new CameraPopoverOptions(
           /*Where to anchor PopOver , iPad , iOS only .*/
            300, /*x coordinate px  , default 0 .*/
            300, /*y coordinate px , default 32 .*/
            100, /*width px element where anchor popover , default 320 .*/
            100, /*Height px element where anchor popover , default 480 .*/
            Camera.PopoverArrowDirection.ARROW_ANY, 
              /*Specify location arrow location on
                popover , iPad , iOS Only , default ARROW_ANY
                  Camera.PopoverArrowDirection.ARROW_UP
                  Camera.PopoverArrowDirection.ARROW_DOWN
                  Camera.PopoverArrowDirection.ARROW_LEFT
                  Camera.PopoverArrowDirection.ARROW_RIGHT
                  Camera.PopoverArrowDirection. ARROW_ANY */
            300, /*width pop over , default 0 , apple default */
            600  /*Height pop over , default 0 , apple default */ ) .*/
}

For iOS , for this plugin to work , it must be set what the application is doing . This can be done by editing the config.xml file , found in the root of your application , to look like this :

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.twiserandom.mobileapps.demo.camera" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>Demo Camera</name>
    <description>
        A sample Apache Cordova application that responds to the deviceready event.
    </description>
    <author email="dev@cordova.apache.org" href="http://cordova.io">
        Apache Cordova Team
    </author>
    <content src="index.html" />
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
    <platform name="android">
        <allow-intent href="market:*" />
    </platform>
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
    </platform>

<!-- IOS  camera access  , for cordova camera plugin -->
    <edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
        <string>need camera access to take pictures</string>
    </edit-config>

    <edit-config target="NSPhotoLibraryUsageDescription" file="*-Info.plist" mode="merge">
        <string>need photo library access to get pictures from there</string>
    </edit-config>

    <edit-config target="NSLocationWhenInUseUsageDescription" file="*-Info.plist" mode="merge">
        <string>need location access to find things nearby</string>
    </edit-config>

    <edit-config target="NSPhotoLibraryAddUsageDescription" file="*-Info.plist" mode="merge">
        <string>need photo library access to save pictures there</string>
    </edit-config>

    <preference name="CameraUsesGeolocation" value="false" />
    <!-- Enable Geolocation for iOS , set the value to
         true , it seems there is a problem , with geolocation
         enabled in this plugin . -->
<!-- IOS  camera access  , for cordova camera plugin -->
</widget>

Edit the www/index.html to be like this :

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-Security-Policy" >
    <meta name="format-detection" content="telephone=no">
    <meta name="msapplication-tap-highlight" content="no">
    <meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover">
    <meta name="color-scheme" content="light dark">
    <link rel="stylesheet" href="css/index.css">
    <title>Demo Cordova camera plugin</title>
</head>

<body>
    <div class="app">
        <h1>Demo Cordova camera plugin</h1>
        <div class="xmpl">
            <div  
                class="button" 
                ontouchstart="btnTouchStart(this )"
                ontouchend="btnTouchEnd(this )"
                onclick="exampleOneClicked(this.nextElementSibling )">
                    Camera Picture</div>
            <img 
            />
        </div>
    
        <div class="xmpl">
            <div  
                class="button" 
                ontouchstart="btnTouchStart(this )"
                ontouchend="btnTouchEnd(this )"
                onclick="exampleTwoClicked(this.nextElementSibling )">
                    Photo Library Picture</div>
            <img 
            />
        </div>

        <div class="xmpl">
            <div  
                class="button" 
                ontouchstart="btnTouchStart(this )"
                ontouchend="btnTouchEnd(this )"
                onclick="exampleThreeClicked(this.nextElementSibling )">
                    Ipad Photo Library Pop Over </div>
            <img 
            />
        </div>

        <div class="xmpl">
            <div  
                class="button" 
                ontouchstart="btnTouchStart(this )"
                ontouchend="btnTouchEnd(this )"
                onclick="exampleFourClicked(this.nextElementSibling )">
                    Photo Library Video</div>
            <video  
                controls 
                preload="metadata"
            />
        </div>

    </div>
    <script src="cordova.js"></script>
    <script src="js/index.js"></script>
</body>

</html>

Edit the www/css/index.css file to be like this :

*{
    border : 0px;
    margin : 0px;
    padding : 0px;
    border-radius: 0px; }

html{
   box-sizing: border-box; }

html * , html *::after , html *::before{
    box-sizing: inherit; }

body{
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
    -webkit-user-select: none; /* Safari */        
    -moz-user-select: none; /* Firefox */
    -ms-user-select: none; /* IE10+/Edge */
    user-select: none; /* Standard */ 
    background-color: cornsilk; }

h1{
    margin: 6px 0px;
    font-size : 28px;
    text-align: center; 
    color : firebrick; }

.xmpl {
    display: flex;
    flex-direction: column; }

.xmpl .button{
    text-align: center;
    margin: 0px 19px 6px;
    border : 1px solid salmon;
    border-radius: 18px 9px;
    color: rgb(172, 55, 123);
    padding : 4px 0px;
    font-family: monospace; 
    font-size : 22px;
    background-color: white; }


.xmpl .button.touchStart{
    background-color: transparent; }

.xmpl img , .xmpl video{
    object-fit: contain;
    width : 100%; 
    border : 6px solid ivory;
    background-image: url(data:image/png;base64,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);
    min-height: 128px;
    margin-bottom: 12px; }

Edit the www/js/index.js to look like this :

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

let isDeviceReady = false; 

function btnTouchStart(btn ){
    btn.classList.add("touchStart" ); }

function btnTouchEnd(btn ){
    btn.classList.remove("touchStart" ); }

function onDeviceReady( ) {
    isDeviceReady = true ; }


function exampleOneClicked(img ){   
    /* Front Camera , disable save to phone ,
        data url , quality 60 . */
    if(isDeviceReady ){
        let pictureOptions = {
            cameraDirection: Camera.Direction.FRONT,
            saveToPhotoAlbum: false,
            destinationType: Camera.DestinationType.DATA_URL,
            quality: 60 };

        function fctSuccess(image ){
            img.src = `data:image/jpeg;base64,${image }`; }

        function fctFailure(errorMsg ){
            console.log(errorMsg ); }

        navigator
            .camera
            .getPicture(fctSuccess , 
                        fctFailure , 
                        pictureOptions ); }}


function exampleTwoClicked(img ){
    /* Photo Library , allow Edit */
    if(isDeviceReady ){

        let pictureOptions = {
            sourceType: Camera.PictureSourceType.PHOTOLIBRARY ,
            allowEdit: true };

        function fctSuccess(image ){
            img.src = image; }

        function fctFailure(errorMsg ){
            console.log(errorMsg ); }

        navigator
            .camera
            .getPicture(fctSuccess , 
                        fctFailure , 
                        pictureOptions ); }}


function exampleThreeClicked(img ){
    /* Photo Library , popover  */
    if(isDeviceReady ){

        let pictureOptions = {
            sourceType: Camera.PictureSourceType.PHOTOLIBRARY ,
            popoverOptions: new CameraPopoverOptions(
                0 , 
                200 , 
                300, 
                400 , 
                Camera.PopoverArrowDirection.ARROW_UP , 
                0 , 
                0 ) };

        function fctSuccess(image ){
            img.src = image; }

        function fctFailure(errorMsg ){
            console.log(errorMsg ); }

        navigator
                .camera
                .getPicture(fctSuccess , 
                            fctFailure , 
                            pictureOptions ); 

        function updatePopOverLocation(){
            let cameraPopoverHandle = new CameraPopoverHandle();
            let cameraPopoverOptions = new CameraPopoverOptions(
                    100 , 
                    300 , 
                    300 , 
                    600 , 
                    Camera.PopoverArrowDirection.ARROW_DOWN , 
                    0 , 
                    0 );
            cameraPopoverHandle.setPosition(cameraPopoverOptions ); }

        window.setTimeout(updatePopOverLocation , 4000 ); }}                        

        
function exampleFourClicked(vdo ){
    /* video ,  Photo Library */
    if(isDeviceReady ){

        let pictureOptions = {
            mediaType: Camera.MediaType.VIDEO ,
            sourceType: Camera.PictureSourceType.PHOTOLIBRARY };

        function fctSuccess(video ){
            vdo.src = video; }

        function fctFailure(errorMsg ){
            console.log(errorMsg ); }

        navigator
            .camera
            .getPicture(fctSuccess , 
                        fctFailure , 
                        pictureOptions ); }}

Run the application :

$ cordova emulate ios 
# on iOS

$ cordova emulate android 
# on android

When setting the sourceType to Camera.PictureSourceType.CAMERA , and the destinationType to Camera.DestinationType.FILE_URI , temporary files on iOS can be cleaned by calling the method :

navigator.camera.cleanup(cleanupSuccessFct, cleanupFailFct );
/*Call the cleanup method , to clean
  temporary files on iOS .
  Pass an on success function and an 
  on failure function  .*/

function cleanupSuccessFct( ){
    console.log("Cleanup Success" ); }

function cleanupFailFct(errorMsg ){
    console.log(errorMsg ); }