Mobile Web

Task: Self Camera

This task, based on the SelfCamera sample delivered with the Tizen SDK, demonstrates how you can use the getUserMedia API to access and display the camera video stream, and capture a single photo. For more information on the sample functionality and creating the sample with the full source code, see the SelfCamera.

This task consists of the following parts:

This sample is a fully functional camera application for taking photos with the device front camera. The user can set the timer delay and access photos by clicking on the photo previews.

Defining the Application Layout

The SelfCamera sample application layout contains only 1 screen: the main screen that displays the camera view and application control elements (buttons).

The following figure shows the main screen of the application.

Figure: SelfCamera screen

SelfCamera screen

Defining the Main Screen

  1. index.html Source File

    The <div> elements are used to define the camera elements for the screen.

    <body>
       <div id="camera"></div>
    
       <div id="countdown"></div>
    
       <div class="timers">
          <div id="timer2"></div>
          <div id="timer5"></div>
          <div id="timer10"></div>
       </div>
    
       <div id="thumbnail">
          <div id="upImage"></div>
       </div>
    
       <div id="shutter-container">
          <div id="shutter"></div>
       </div>
    </body>
  2. css/style.css Source File

    The style.css file defines the positions and styles of the camera elements.

    #camera
    {
       width: 100%;
       height: 100%;
       overflow: hidden;
    }
    
    div#countdown
    {
       position: absolute;
       width: 100%;
       height: 100%;
       top: 20%;
       font-size: 200pt;
       text-align: center;
       vertical-align: middle;
       color: rgba(135, 226, 0, 0.8);
       margin: auto 0;
       z-index: 10;
    }
    
    .timers
    {
       position: absolute;
       width: 100%;
       background-color: rgba(10, 10, 10, 0.4);
       top: 0;
       left: 0;
    }
    
    div#thumbnail
    {
       position: absolute;
       width: 56px;
       height: 64px;
       left: 13px;
       bottom: 19px;
       background-size: 56px 64px;
       background-color: transparent;
       background-image: url('../images/none.png');
       background-repeat: no-repeat;
       z-index: 100;
    }
    
    div#shutter-container
    {
       width: 100%;
       height: 86px;
       position: absolute;
       bottom: 0;
       z-index: 11
    }
    

Initializing the Application

  1. config.xml Source File

    The required privileges are declared in the config.xml file.

    <!--Configuration file content-->
    <widget ...>
       <!--Other configuration details-->
       <tizen:privilege name="http://tizen.org/privilege/application.launch"/>
       <tizen:privilege name="http://tizen.org/privilege/filesystem.read"/>
       <tizen:privilege name="http://tizen.org/privilege/filesystem.write"/>
       <tizen:privilege name="http://tizen.org/privilege/content.read"/>
       <tizen:privilege name="http://tizen.org/privilege/content.write"/>
    </widget>

Accessing the Camera Stream

This section builds upon the elements described in Accessing a Video Stream.

Managing the Application Object

The application object functionality is implemented in the main.js file.

  1. Creating and Initializing the Application Object
    1. The SelfCamera object represents the entire application entity, and by using the prototype, the member methods are registered in the object.
      var selfCamera;
      function SelfCamera()
      {
         "use strict";
      }
      
      function()
      {
         "use strict";
         var DELAY_2_SECOND = 2, DELAY_5_SECOND = 5, DELAY_10_SECOND = 10;
         var previewLock = false;
      
         SelfCamera.prototype =
         {
            countdown: -1, /* Current value after clicking the camera button */
            countdownTimeoutID: -1,
            countSound: new Audio('sounds/sounds_count.wav'),
            img: document.createElement('canvas'),
            filename: '',
            loadDirectory: '',
            saveDirectory: 'images/',
            IMG_PREFIX: 'SelfCamera_',
            shutterSound: new Audio('sounds/sounds_Shutter_01.wav'),
            timer: null, /* Value set by the buttons */
            systemIO: null,
            video: null,
            src: null,
            isMediaWorking: false
            previewLock: false
         };
      }
    2. The SelfCamera object is created and initialized.
      selfCamera = new SelfCamera();
      $(document).ready(function()
      {
         "use strict";
         selfCamera.init();
      }); 
  2. Binding Events to the Application Object
    1. To bind video events to the application object, call the bindVideoEvents() method, which registers the event handlers to the corresponding events using the bind() method.

      SelfCamera.prototype.bindVideoEvents = function()
      {
         var self = this;
         $(this.video).on("stalled", function(e) {this.load();});
         $(this.video).on("playing", this.resizeVideo.bind(this));
         $(this.video).on('click', function() {this.play();});
      };
      
    2. To bind button and hardware key events to the application object, call the bindEvents() method, which register the event handlers to the corresponding events using the bind() method.

      SelfCamera.prototype.bindEvents = function bindEvents()
      {
         var self = this;
      
         document.addEventListener('webkitvisibilitychange', function(event)
         {
            self.clearCountdown();
            previewLock = false;
            if (document.webkitVisibilityState === 'visible')
            {
               if (self.video !== null)
               {
                  self.reloadSaveDirectory(function() {self.video.play();});
               }
               self.loadThumbnail(true, false);
            }
         });
      
         $('shutter').mousedown(function(ev) {$('shutter').addClass('active');})
                     .mouseup(function(ev) {$('shutter').removeClass('active');})
                     .on('touchstart', function(ev) {$('shutter').addClass('active');})
                     .on('touchend', function(ev) {$('shutter').removeClass('active');});
      
         $(window).on('tizenhwkey', function(e)
         {
            if (e.originalEvent.keyName === "back")
            {
               if (self.countdownTimeoutID !== -1)
               {
                  self.clearCountdown();
                  self.loadThumbnail(true, false);
               }
               else
               {
                  tizen.application.getCurrentApplication().exit();
               }
         });
      
         this.bindTimerClicks();
      
         $('#thumbnail').on('click', this.launchPreview.bind(this));
         $('#shutter').on('touchstart', this.shutterTouched.bind(this));
      };

Accessing the Camera Stream

  1. main.js Source File
    1. The startPreview() method requests the video stream using the getUserMedia() method of the navigator.
      navigator.getUserMedia(options, this.onCaptureVideoSuccess.bind(this),
                             this.onCaptureVideoError.bind(this));
      
    2. The onCaptureVideoSuccess() event handler obtains the stream URL and creates the video element with the createVideoElement() method.
      SelfCamera.prototype.onCaptureVideoSuccess = function onCaptureVideoSuccess(stream)
      {
         var urlStream;
         urlStream = window.webkitURL.createObjectURL(stream); /* Create stream */
         this.isMediaWorking = true;
         this.createVideoElement(urlStream); /* Create video element with stream handler */
         this.setTimer(DELAY_2_SECOND); /* Initialize timer button options */
      };
      
    3. The createVideoElement() method defines the video element, except for the src attribute, which is already defined by the onCaptureVideoSuccess() event handler.

      SelfCamera.prototype.createVideoElement = function(src)
      {
         this.video = $('<video/>',
         {
            autoplay: 'autoplay',
            id: 'video',
            style: 'height:' + $(window).height() + 'px',
            src: src
         }).appendTo("#camera").get(0);
      
         this.bindVideoEvents();
      };

Capturing Pictures from Video

  1. main.js Source File
    1. Capture a video frame with canvas.
      SelfCamera.prototype.captureImage = function captureImage(video)
      {
         var sourceWidth = window.innerWidth,
             sourceHeight = window.innerHeight,
             sourceX = (sourceWidth - $(video).width()) / 2,
             sourceY = (sourceHeight - $(video).height()) / 2;
      
         this.img.width = sourceWidth;
         this.img.height = sourceHeight;
      
         /* Crop image to viewport dimensions */
         this.img.getContext('2d').drawImage(video, sourceX, sourceY,
                                             $(video).width(), $(video).height());
      
         /* For the best available dimension, use the following: */
         /* this.img.width = video.videoWidth; */
         /* this.img.height = video.videoHeight; */
         /* this.img.getContext('2d').drawImage(video, 0, 0); */
      };
      
    2. Extract the image data from the canvas.
      SelfCamera.prototype.saveCanvas = function saveCanvas(canvas, fileName)
      {
         var data, self = this,
             onSuccess = function(fileHandle)
             {
                this.setLoadDirectory(this.getFileDirectoryURI(fileHandle));
                tizen.content.scanFile(fileName,
                                       function() {self.loadThumbnail(false, false);},
                                       function() {/* Error handling */});
             }.bind(this);
      
         data = canvas.toDataURL().replace('data:image/png;base64,', '').replace('data:,', '');
      
         this.systemIO.saveFileContent(fileName, data, onSuccess, 'base64');
      };
    3. Save the image.
      saveFileContent: function SystemIO_saveFileContent(filePath, fileContent,
                                                         onSaveSuccess, fileEncoding)
      {
         var pathData = this.getPathData(filePath),
             self = this,
             fileHandle;
      
         function onOpenDirSuccess(dir)
         {
            /* Create a new file */
            fileHandle = self.createFile(dir, pathData.fileName);
            if (fileHandle !== false)
            {
               /* Save data into the file */
               self.writeFile(fileHandle, fileContent, onSaveSuccess, false, fileEncoding);
            }
         }
      
         /* Open the directory */
         this.openDir(pathData.dirName, onOpenDirSuccess);
      };
Go to top