diff --git a/README.md b/README.md
index f3d04d56e..73e3187cf 100644
--- a/README.md
+++ b/README.md
@@ -266,6 +266,10 @@ Optional parameters to customize the camera settings.
| saveToPhotoAlbum | Boolean
| | Save the image to the photo album on the device after capture. |
| popoverOptions | [CameraPopoverOptions](#module_CameraPopoverOptions)
| | iOS-only options that specify popover location in iPad. |
| cameraDirection | [Direction](#module_Camera.Direction)
| BACK
| Choose the camera to use (front- or back-facing). |
+| customCameraContainer | string
| | Browser-only option, specify the id of custom camera's container element. |
+| customCaptureButton | string
| | Browser-only option, specify the id of custom camera's capture button. |
+| customCancelButton | string
| | Browser-only option, specify the id of custom camera's cancel button. |
+| customSourceInput | string
| | Browser-only option, specify the id of custom source input element, when using diffrerent mode than the default `sourceType`. |
---
diff --git a/src/browser/CameraProxy.js b/src/browser/CameraProxy.js
index ff81257a6..03489b3d1 100644
--- a/src/browser/CameraProxy.js
+++ b/src/browser/CameraProxy.js
@@ -19,103 +19,187 @@
*
*/
-var HIGHEST_POSSIBLE_Z_INDEX = 2147483647;
+let localMediaStream;
-function takePicture (success, error, opts) {
+function takePicture (successCallback, errorCallback, opts) {
if (opts && opts[2] === 1) {
- capture(success, error, opts);
+ capture(successCallback, errorCallback, opts);
} else {
- var input = document.createElement('input');
- input.style.position = 'relative';
- input.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX;
- input.className = 'cordova-camera-select';
- input.type = 'file';
- input.name = 'files[]';
+ const customSourceInput = opts[15];
- input.onchange = function (inputEvent) {
- var reader = new FileReader(); /* eslint no-undef : 0 */
- reader.onload = function (readerEvent) {
- input.parentNode.removeChild(input);
+ let sourceInput = customSourceInput ? document.getElementById(customSourceInput) : createSourceInput();
- var imageData = readerEvent.target.result;
+ handleSourceInput(successCallback, sourceInput);
- return success(imageData.substr(imageData.indexOf(',') + 1));
- };
-
- reader.readAsDataURL(inputEvent.target.files[0]);
- };
+ if (!customSourceInput) {
+ document.body.appendChild(sourceInput);
+ }
+ }
+}
- document.body.appendChild(input);
+function capture (successCallback, errorCallback, opts) {
+ let targetWidth = opts[3];
+ let targetHeight = opts[4];
+ const customCameraContainer = opts[12];
+ const customCaptureButton = opts[13];
+ const customCancelButton = opts[14];
+
+ const customElements = {customCameraContainer, customCaptureButton, customCancelButton};
+
+ let parent = customCameraContainer ? document.getElementById(customCameraContainer) : createCameraContainer();
+ let video = createVideoStreamContainer(parent, targetWidth, targetHeight);
+ let captureButton = customCaptureButton ? document.getElementById(customCaptureButton) : createButton(parent, 'Capture');
+ let cancelButton = customCancelButton ? document.getElementById(customCancelButton) : createButton(parent, 'Cancel');
+ // start video stream
+ startLocalMediaStream(errorCallback, video);
+
+ // if custom camera container is not set by the user,
+ // append parent to the document.body
+ if (!customCameraContainer) {
+ document.body.appendChild(video.parentNode);
}
+
+ // handle button click events
+ handleCaptureButton(successCallback, errorCallback, captureButton, video, customElements);
+ handleCancelButton(cancelButton, video, customElements);
}
-function capture (success, errorCallback, opts) {
- var localMediaStream;
- var targetWidth = opts[3];
- var targetHeight = opts[4];
+function createCameraContainer () {
+ let parent = document.createElement('div');
+ parent.style.position = 'relative';
+ parent.style.zIndex = '2147483647'; // set highest possible z index
+ parent.className = 'cordova-camera-capture';
+
+ return parent;
+}
+function createVideoStreamContainer (parent, targetWidth, targetHeight) {
targetWidth = targetWidth === -1 ? 320 : targetWidth;
targetHeight = targetHeight === -1 ? 240 : targetHeight;
- var video = document.createElement('video');
- var button = document.createElement('button');
- var parent = document.createElement('div');
- parent.style.position = 'relative';
- parent.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX;
- parent.className = 'cordova-camera-capture';
+ let video = document.createElement('video');
+ video.width = targetWidth;
+ video.height = targetHeight;
+
parent.appendChild(video);
+
+ return video;
+}
+
+function createButton (parent, innerText) {
+ let button = document.createElement('button');
+ button.innerHTML = innerText;
+
parent.appendChild(button);
- video.width = targetWidth;
- video.height = targetHeight;
- button.innerHTML = 'Capture!';
+ return button;
+}
- button.onclick = function () {
+function handleCaptureButton (successCallback, errorCallback, captureButton, video, customElements) {
+ captureButton.onclick = function () {
// create a canvas and capture a frame from video stream
- var canvas = document.createElement('canvas');
- canvas.width = targetWidth;
- canvas.height = targetHeight;
- canvas.getContext('2d').drawImage(video, 0, 0, targetWidth, targetHeight);
+ let canvas = document.createElement('canvas');
+ canvas.width = video.width;
+ canvas.height = video.height;
+ canvas.getContext('2d').drawImage(video, 0, 0, video.width, video.height);
// convert image stored in canvas to base64 encoded image
- var imageData = canvas.toDataURL('image/png');
+ let imageData = canvas.toDataURL('image/png');
imageData = imageData.replace('data:image/png;base64,', '');
- // stop video stream, remove video and button.
- // Note that MediaStream.stop() is deprecated as of Chrome 47.
- if (localMediaStream.stop) {
- localMediaStream.stop();
- } else {
- localMediaStream.getTracks().forEach(function (track) {
- track.stop();
- });
- }
- parent.parentNode.removeChild(parent);
+ // stop video stream
+ stopLocalMediaStream(video, customElements);
- return success(imageData);
+ return successCallback(imageData);
};
+}
- navigator.getUserMedia = navigator.getUserMedia ||
- navigator.webkitGetUserMedia ||
- navigator.mozGetUserMedia ||
- navigator.msGetUserMedia;
+function handleCancelButton (cancelButton, video, customElements) {
+ cancelButton.onclick = function () {
+ // stop video stream
+ stopLocalMediaStream(video, customElements);
+ };
+}
+
+function startLocalMediaStream (errorCallback, video) {
- var successCallback = function (stream) {
+ const successCallback = function (stream) {
localMediaStream = stream;
- if ('srcObject' in video) {
- video.srcObject = localMediaStream;
- } else {
- video.src = window.URL.createObjectURL(localMediaStream);
- }
+ video.src = window.URL.createObjectURL(localMediaStream);
video.play();
- document.body.appendChild(parent);
};
+ navigator.getUserMedia = navigator.getUserMedia ||
+ navigator.webkitGetUserMedia ||
+ navigator.mozGetUserMedia ||
+ navigator.msGetUserMedia;
+
if (navigator.getUserMedia) {
- navigator.getUserMedia({video: true, audio: false}, successCallback, errorCallback);
+ navigator.getUserMedia({video: true, audio: true}, successCallback, errorCallback);
+ } else {
+ alert('Your browser does not support camera.');
+ }
+}
+
+function stopLocalMediaStream (video, customElements) {
+ // stop video stream, remove video and captureButton.
+ // note: MediaStream.stop() is deprecated as of Chrome 47.
+ if (localMediaStream.stop) {
+ localMediaStream.stop();
} else {
- alert('Browser does not support camera :(');
+ localMediaStream.getTracks().forEach(function (track) {
+ track.stop();
+ });
}
+
+ // remove newly created elements
+ removeAppendedCameraElements(video, customElements);
+}
+
+function removeAppendedCameraElements (video, customElements) {
+
+ const parent = video.parentNode;
+
+ if (!customElements.customCameraContainer) {
+ parent.parentNode.removeChild(parent);
+ } else if (!customElements.customCaptureButton && !customElements.customCancelButton) {
+ while (parent.hasChildNodes()) {
+ parent.removeChild(parent.lastChild);
+ }
+ } else if (parent.hasChildNodes() && !customElements.customCaptureButton) {
+ parent.removeChild(video);
+ parent.removeChild(parent.lastChild);
+ } else if (parent.hasChildNodes() && !customElements.customCancelButton) {
+ parent.removeChild(video);
+ parent.removeChild(parent.lastChild);
+ } else {
+ parent.removeChild(video);
+ }
+}
+
+function createSourceInput () {
+ let input = document.createElement('input');
+ input.style.position = 'relative';
+ input.style.zIndex = '2147483647'; // set highest possible z index
+ input.className = 'cordova-camera-select';
+ input.type = 'file';
+ input.name = 'files[]';
+
+ return input;
+}
+
+function handleSourceInput (successCallback, sourceInput) {
+ sourceInput.onchange = function (inputEvent) {
+ let reader = new FileReader(); /* eslint no-undef : 0 */
+ reader.onload = function (readerEvent) {
+ sourceInput.parentNode.removeChild(sourceInput);
+
+ const imageData = readerEvent.target.result;
+
+ return successCallback(imageData.substr(imageData.indexOf(',') + 1));
+ };
+ reader.readAsDataURL(inputEvent.target.files[0]);
+ };
}
module.exports = {
diff --git a/www/Camera.js b/www/Camera.js
index 0eade0fe3..93e9d1335 100644
--- a/www/Camera.js
+++ b/www/Camera.js
@@ -19,11 +19,9 @@
*
*/
-var argscheck = require('cordova/argscheck');
-var exec = require('cordova/exec');
-var Camera = require('./Camera');
-// XXX: commented out
-// CameraPopoverHandle = require('./CameraPopoverHandle');
+const argscheck = require('cordova/argscheck');
+const exec = require('cordova/exec');
+const Camera = require('./Camera');
/**
* @namespace navigator
@@ -32,10 +30,10 @@ var Camera = require('./Camera');
/**
* @exports camera
*/
-var cameraExport = {};
+const cameraExport = {};
// Tack on the Camera Constants to the base camera plugin.
-for (var key in Camera) {
+for (let key in Camera) {
cameraExport[key] = Camera[key];
}
@@ -134,27 +132,31 @@ for (var key in Camera) {
cameraExport.getPicture = function (successCallback, errorCallback, options) {
argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
options = options || {};
- var getValue = argscheck.getValue;
+ const getValue = argscheck.getValue;
- var quality = getValue(options.quality, 50);
- var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
- var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
- var targetWidth = getValue(options.targetWidth, -1);
- var targetHeight = getValue(options.targetHeight, -1);
- var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
- var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
- var allowEdit = !!options.allowEdit;
- var correctOrientation = !!options.correctOrientation;
- var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
- var popoverOptions = getValue(options.popoverOptions, null);
- var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+ const quality = getValue(options.quality, 50);
+ const destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ const sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ const targetWidth = getValue(options.targetWidth, -1);
+ const targetHeight = getValue(options.targetHeight, -1);
+ const encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ const mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ const allowEdit = !!options.allowEdit;
+ const correctOrientation = !!options.correctOrientation;
+ const saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ const popoverOptions = getValue(options.popoverOptions, null);
+ const cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
- var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
- mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+ const customCameraContainer = getValue(options.customCameraContainer, null);
+ const customCaptureButton = getValue(options.customCaptureButton, null);
+ const customCancelButton = getValue(options.customCancelButton, null);
+ const customSourceInput = getValue(options.customSourceInput, null);
+
+ const args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection,
+ customCameraContainer, customCaptureButton, customCancelButton, customSourceInput];
exec(successCallback, errorCallback, 'Camera', 'takePicture', args);
- // XXX: commented out
- // return new CameraPopoverHandle();
};
/**