| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| var MediaFile = require('cordova-plugin-media-capture.MediaFile'); |
| var MediaFileData = require('cordova-plugin-media-capture.MediaFileData'); |
| var CaptureError = require('cordova-plugin-media-capture.CaptureError'); |
| |
| /** |
| * Helper function that converts data URI to Blob |
| * @param {String} dataURI Data URI to convert |
| * @return {Blob} Blob, covnerted from DataURI String |
| */ |
| function dataURItoBlob (dataURI) { |
| // convert base64 to raw binary data held in a string |
| // doesn't handle URLEncoded DataURIs |
| var byteString = atob(dataURI.split(',')[1]); // eslint-disable-line no-undef |
| |
| // separate out the mime component |
| var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; |
| |
| // write the bytes of the string to an ArrayBuffer |
| var ab = new ArrayBuffer(byteString.length); |
| var ia = new Uint8Array(ab); |
| for (var i = 0; i < byteString.length; i++) { |
| ia[i] = byteString.charCodeAt(i); |
| } |
| |
| // write the ArrayBuffer to a blob, and you're done |
| return new Blob([ab], { type: mimeString }); // eslint-disable-line no-undef |
| } |
| |
| /** |
| * Creates basic camera UI with preview 'video' element and 'Cancel' button |
| * Capture starts, when you clicking on preview. |
| */ |
| function CameraUI () { |
| // Root element for preview |
| var container = document.createElement('div'); |
| container.style.cssText = |
| 'left: 0px; top: 0px; width: 100%; height: 100%; position: fixed; z-index:9999;' + |
| 'padding: 40px; background-color: rgba(0,0,0,0.75);' + |
| 'text-align:center; visibility: hidden'; |
| |
| // Set up root element contetnts |
| container.innerHTML = |
| '<div id="captureHint" style="height:100%; position:relative; display:inline-flex; align-content:flex-start;">' + |
| '<h2 style="position: absolute; width: 100%; background-color: rgba(255,255,255,0.25); margin: 0">' + |
| 'Click on preview to capture image. Click outside of preview to cancel.</h1>' + |
| '<video id="capturePreview" style="height: 100%"></video>' + |
| '</div>'; |
| |
| // Add container element to DOM but do not display it since visibility == hidden |
| document.body.appendChild(container); |
| |
| // Create fullscreen preview |
| var preview = document.getElementById('capturePreview'); |
| preview.autoplay = true; |
| // We'll show preview only when video element content |
| // is fully loaded to avoid glitches |
| preview.onplay = function () { |
| container.style.visibility = 'visible'; |
| }; |
| |
| this.container = container; |
| this.preview = preview; |
| } |
| |
| /** |
| * Displays capture preview |
| * @param {Number} count Number of images to take |
| * @param {Function} successCB Success callback, that accepts data URL of captured image |
| * @param {Function} errorCB Error callback |
| */ |
| CameraUI.prototype.startPreview = function (count, successCB, errorCB) { |
| var that = this; |
| |
| this.preview.onclick = function (e) { |
| // proceed with capture here |
| // We don't need to propagate click event to parent elements. |
| // Otherwise click on vieo element will trigger click event handler |
| // for preview root element and cause preview cancellation |
| e.stopPropagation(); |
| // Create canvas element, put video frame on it |
| // and save its contant as Data URL |
| var canvas = document.createElement('canvas'); |
| canvas.width = this.videoWidth; |
| canvas.height = this.videoHeight; |
| canvas.getContext('2d').drawImage(that.preview, 0, 0); |
| successCB(canvas.toDataURL('image/jpeg')); |
| }; |
| |
| this.container.onclick = function () { |
| // Cancel capture here |
| errorCB(new CaptureError(CaptureError.CAPTURE_NO_MEDIA_FILES)); |
| }; |
| |
| navigator.getUserMedia( |
| { video: true }, |
| function (previewStream) { |
| // Save video stream to be able to stop it later |
| that._previewStream = previewStream; |
| that.preview.src = URL.createObjectURL(previewStream); // eslint-disable-line no-undef |
| // We don't need to set visibility = true for preview element |
| // since this will be done automatically in onplay event handler |
| }, |
| function (/* err */) { |
| errorCB(new CaptureError(CaptureError.CAPTURE_INTERNAL_ERR)); |
| } |
| ); |
| }; |
| |
| /** |
| * Destroys camera preview, removes all elements created |
| */ |
| CameraUI.prototype.destroyPreview = function () { |
| this.preview.pause(); |
| this.preview.src = null; |
| this._previewStream.stop(); |
| this._previewStream = null; |
| if (this.container) { |
| document.body.removeChild(this.container); |
| } |
| }; |
| |
| module.exports = { |
| captureAudio: function (successCallback, errorCallback) { |
| if (errorCallback) { |
| errorCallback(new CaptureError(CaptureError.CAPTURE_NOT_SUPPORTED)); |
| } |
| }, |
| |
| captureVideo: function (successCallback, errorCallback) { |
| if (errorCallback) { |
| errorCallback(new CaptureError(CaptureError.CAPTURE_NOT_SUPPORTED)); |
| } |
| }, |
| |
| captureImage: function (successCallback, errorCallback, args) { |
| var fail = function (code) { |
| if (errorCallback) { |
| errorCallback(new CaptureError(code || CaptureError.CAPTURE_INTERNAL_ERR)); |
| } |
| }; |
| |
| var options = args[0]; |
| |
| var limit = options.limit || 1; |
| if (typeof limit !== 'number' || limit < 1) { |
| fail(CaptureError.CAPTURE_INVALID_ARGUMENT); |
| return; |
| } |
| |
| // Counter for already taken images |
| var imagesTaken = 0; |
| |
| navigator.getUserMedia = |
| navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; |
| |
| if (!navigator.getUserMedia) { |
| fail(CaptureError.CAPTURE_NOT_SUPPORTED); |
| return; |
| } |
| |
| var ui = new CameraUI(); |
| ui.startPreview( |
| limit, |
| function (data) { |
| // Check if we're done with capture. If so, then destroy UI |
| if (++imagesTaken >= limit) { |
| ui.destroyPreview(); |
| } |
| |
| // Array of resultant MediaFiles |
| var mediaFiles = []; |
| |
| // save data to file here |
| window.requestFileSystem( |
| window.TEMPORARY, |
| data.length * limit, |
| function (fileSystem) { |
| // If we need to capture multiple files, then append counter to filename |
| var fileName = limit <= 1 ? 'image.jpg' : 'image' + imagesTaken + '.jpg'; |
| fileSystem.root.getFile( |
| fileName, |
| { create: true }, |
| function (file) { |
| file.createWriter(function (writer) { |
| writer.onwriteend = function () { |
| file.getMetadata(function (meta) { |
| mediaFiles.push( |
| new MediaFile(file.name, file.toURL(), 'image/jpeg', meta.modificationTime, meta.size) |
| ); |
| // Check if we're done with capture. If so, then call a successCallback |
| if (imagesTaken >= limit) { |
| successCallback(mediaFiles); |
| } |
| }, fail); |
| }; |
| writer.onerror = fail; |
| // Since success callback for start preview returns |
| // a base64 encoded string, we need to convert it to blob first |
| writer.write(dataURItoBlob(data)); |
| }); |
| }, |
| fail |
| ); |
| }, |
| fail |
| ); |
| }, |
| function (err) { |
| ui.destroyPreview(); |
| fail(err.code); |
| } |
| ); |
| }, |
| |
| getFormatData: function (successCallback, errorCallback, args) { |
| var img = document.createElement('img'); |
| img.src = args[0]; |
| img.onload = function () { |
| if (successCallback) { |
| successCallback(new MediaFileData(null, 0, img.height, img.width, 0)); |
| } |
| }; |
| } |
| }; |
| |
| require('cordova/exec/proxy').add('Capture', module.exports); |