diff --git a/example/css/fonts.css b/example/css/fonts.css index 9ee67c4..aa5a413 100644 --- a/example/css/fonts.css +++ b/example/css/fonts.css @@ -1 +1 @@ -@import url("http://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600"); +@import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600"); diff --git a/example/css/styles.css b/example/css/styles.css index a39a361..8b5e047 100644 --- a/example/css/styles.css +++ b/example/css/styles.css @@ -15,7 +15,7 @@ /* Main Secondary color (2) */ /* Generated by Paletton.com ├é┬® 2002-2014 */ /* http://paletton.com */ -@import url("http://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600"); +@import url("https://fonts.googleapis.com/css?family=Ubuntu:400,700|Cabin+Condensed:400,600"); /* line 1, ../sass/_viewport.scss */ #interactive.viewport { width: 640px; diff --git a/example/live_w_locator.html b/example/live_w_locator.html index a8a3787..9fb8337 100644 --- a/example/live_w_locator.html +++ b/example/live_w_locator.html @@ -81,6 +81,11 @@ +
@@ -91,7 +96,7 @@ diff --git a/example/live_w_locator.js b/example/live_w_locator.js index 327a0d8..412a14e 100644 --- a/example/live_w_locator.js +++ b/example/live_w_locator.js @@ -10,14 +10,14 @@ $(function() { } }); var App = { - init : function() { + init: function() { var self = this; Quagga.init(this.state, function(err) { if (err) { return self.handleError(err); } - Quagga.registerResultCollector(resultCollector); + //Quagga.registerResultCollector(resultCollector); App.attachListeners(); Quagga.start(); }); @@ -25,9 +25,31 @@ $(function() { handleError: function(err) { console.log(err); }, + initCameraSelection: function(){ + var streamLabel = Quagga.CameraAccess.getActiveStreamLabel(); + + return Quagga.CameraAccess.enumerateVideoDevices() + .then(function(devices) { + function pruneText(text) { + return text.length > 30 ? text.substr(0, 30) : text; + } + var $deviceSelection = document.getElementById("deviceSelection"); + while ($deviceSelection.firstChild) { + $deviceSelection.removeChild($deviceSelection.firstChild); + } + devices.forEach(function(device) { + var $option = document.createElement("option"); + $option.value = device.deviceId || device.id; + $option.appendChild(document.createTextNode(pruneText(device.label || device.deviceId || device.id))); + $option.selected = streamLabel === device.label; + $deviceSelection.appendChild($option); + }); + }); + }, attachListeners: function() { var self = this; + self.initCameraSelection(); $(".controls").on("click", "button.stop", function(e) { e.preventDefault(); Quagga.stop(); @@ -64,7 +86,11 @@ $(function() { return parts.reduce(function(o, key, i) { if (setter && (i + 1) === depth) { - o[key] = val; + if (typeof o[key] === "object" && typeof val === "object") { + Object.assign(o[key], val); + } else { + o[key] = val; + } } return key in o ? o[key] : {}; }, obj); @@ -95,10 +121,15 @@ $(function() { inputMapper: { inputStream: { constraints: function(value){ - var values = value.split('x'); + if (/^(\d+)x(\d+)$/.test(value)) { + var values = value.split('x'); + return { + width: {min: parseInt(values[0])}, + height: {min: parseInt(values[1])} + }; + } return { - width: {min: parseInt(values[0])}, - height: {min: parseInt(values[1])} + deviceId: value }; } }, diff --git a/karma-integration.conf.js b/karma-integration.conf.js index b10e9f4..60a983d 100644 --- a/karma-integration.conf.js +++ b/karma-integration.conf.js @@ -37,7 +37,6 @@ module.exports = function(config) { plugins: [ 'karma-chrome-launcher', 'karma-mocha', - 'karma-requirejs', 'karma-chai', 'karma-sinon', 'karma-sinon-chai', diff --git a/karma.conf.js b/karma.conf.js index 8c570ed..ce177aa 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -23,7 +23,7 @@ module.exports = function(config) { }, { test: /\.js$/, include: path.resolve('src'), - loader: 'babel-istanbul' + loader: 'babel-istanbul-loader' }] }, resolve: { diff --git a/package.json b/package.json index e858e20..222ead1 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "babel-cli": "^6.5.1", "babel-core": "^6.21.0", "babel-eslint": "^7.1.1", + "babel-istanbul": "^0.8.0", "babel-istanbul-loader": "^0.1.0", "babel-loader": "^6.2.10", "babel-plugin-add-module-exports": "^0.2.1", @@ -41,23 +42,23 @@ "grunt": "^0.4.5", "grunt-cli": "^0.1.13", "grunt-contrib-nodeunit": "^0.4.1", - "grunt-karma": "^0.12.1", + "grunt-karma": "^2.0.0", "isparta-loader": "^2.0.0", - "karma": "^0.13.9", + "karma": "^1.3.0", "karma-chai": "0.1.0", - "karma-chrome-launcher": "^0.2.0", - "karma-coverage": "^0.5.2", + "karma-chrome-launcher": "^2.0.0", + "karma-coverage": "^1.1.1", "karma-firefox-launcher": "^0.1.7", "karma-mocha": "~0.2.0", "karma-phantomjs-launcher": "^0.2.1", "karma-sinon": "^1.0.4", "karma-sinon-chai": "^1.1.0", "karma-source-map-support": "^1.1.0", - "karma-webpack": "^1.7.0", + "karma-webpack": "^1.8.1", "lolex": "^1.4.0", "mocha": "^2.3.2", "phantomjs": "^1.9.18", - "sinon": "^1.16.1", + "sinon": "^1.17.7", "sinon-chai": "^2.8.0", "webpack": "^2.2.0-rc.3", "webpack-sources": "^0.1.3" diff --git a/server.pem b/server.pem new file mode 100644 index 0000000..04fd185 --- /dev/null +++ b/server.pem @@ -0,0 +1,33 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQC9ORap3LvRegtrhRc8dLdH9Bp2QokcKEsWbtvyhtjisRRm2slK +A6Q11McB/YTb7oImFfNaCX+7vdM1oVXVLJ0ekQaNljXG5Dy7DXEcT1V6gpN4xmZJ +8f/KZ45VBINN0Ha74L7nS4kgImh5yvNolNr4IdlSjGf09kciFy8S3kPlGQIDAQAB +AoGAYDlaxBCC1liY3Bl3IoA7//QrTL4zGUWIQaUoZmGag1UHifJycBf/9nv4o5N3 +b5wPRSzebofsE93JPTmI+3nPf62k5rS2xOo8swwOZc+f5/v0EnUNixD7P0jBiLVR +B8kbMvNdNn33HuynW1/MSBFE0cfeDH2i8SVl+Z+fHYIUW10CQQD0yWB8xeM8AxYB +/ZZWClem6gf1lQAYLzid3x51pkLqRFpX+rG251cSBUouE+kVO14j2xrBqCyyOwNu +17eazy3DAkEAxeQdWP9b11ihKOf/kjXiczltLnBsotn6K9EEAe0QuH/6iXLm86mL +ZiQe+TrY1GWbK3ns0sfXgNJ2aeaRkeZn8wJAWF5WedTKisCmckOEwTzslbJI+0w2 +A4UQkFWa3mgOIhpY7wfunhP35+aG+AlyDJspChKwHxdCQ3lwbNRtUPLYFwJBAK8G +9QIbUbLlPB1/HOfH6xM4rp3NZ/idzQxmISJG+GwHHaPmUekfgyEDP7X2W4N4nsbU +XyeLA8t32q4N9aDS5gsCQDHqhsXqnY6e4IEZrvf90l2V1PpnTKfEl/F5wye3g69G +JN57scVUBHP/KKoyfge0fytWiQN/56KvWH+G5+N/JyA= +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIIC2zCCAkSgAwIBAgIJALUDN95Or7XlMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV +BAYTAkFUMQ8wDQYDVQQIEwZTdHlyaWExDTALBgNVBAcTBEdyYXoxETAPBgNVBAoT +CFF1YWdnYUpTMREwDwYDVQQDEwhxdWFnZ2FqczAeFw0xNzAxMDgxNjI5MjhaFw0x +ODAxMDgxNjI5MjhaMFMxCzAJBgNVBAYTAkFUMQ8wDQYDVQQIEwZTdHlyaWExDTAL +BgNVBAcTBEdyYXoxETAPBgNVBAoTCFF1YWdnYUpTMREwDwYDVQQDEwhxdWFnZ2Fq +czCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvTkWqdy70XoLa4UXPHS3R/Qa +dkKJHChLFm7b8obY4rEUZtrJSgOkNdTHAf2E2+6CJhXzWgl/u73TNaFV1SydHpEG +jZY1xuQ8uw1xHE9VeoKTeMZmSfH/ymeOVQSDTdB2u+C+50uJICJoecrzaJTa+CHZ +Uoxn9PZHIhcvEt5D5RkCAwEAAaOBtjCBszAdBgNVHQ4EFgQUYm5+uJVOOGiYa+Vx +2o++VHyWkwIwgYMGA1UdIwR8MHqAFGJufriVTjhomGvlcdqPvlR8lpMCoVekVTBT +MQswCQYDVQQGEwJBVDEPMA0GA1UECBMGU3R5cmlhMQ0wCwYDVQQHEwRHcmF6MREw +DwYDVQQKEwhRdWFnZ2FKUzERMA8GA1UEAxMIcXVhZ2dhanOCCQC1AzfeTq+15TAM +BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBACyzC/CKL1mgTuNgFDuUf6u+ +YMnqlc9wcnEaFuvXnkSh6fT+qMZm188C/tlZwcWTrGmoCM0K6mX1TpHOjm8vbeXZ +diezAVGIVN3VoHqm6yJldI2rgFI9r5BfwAWYC8XNjqnT3U6cm4k8iC7jmLC+dT9r +Ysx2ucAF6lNHayekRmNq +-----END CERTIFICATE----- diff --git a/simple-https-server.py b/simple-https-server.py new file mode 100644 index 0000000..6281cb5 --- /dev/null +++ b/simple-https-server.py @@ -0,0 +1,30 @@ +# taken from http://www.piware.de/2011/01/creating-an-https-server-in-python/ +# generate server.xml with the following command: +# openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes +# run as follows: +# python simple-https-server.py +# then in your browser, visit: +# https://localhost:4443 + +import BaseHTTPServer, SimpleHTTPServer +import ssl +import sys, getopt + +host = 'localhost' +port = 4443 +try: + opts, args = getopt.getopt(sys.argv[1:],"",["host=", "port="]) +except getopt.GetoptError: + print 'simple-https-server.py --host --port ' + sys.exit(2) +for opt, arg in opts: + if opt in ("--host"): + host = arg + elif opt in ("--port"): + port = int(arg) +print 'host is ', host +print 'port is ', port + +httpd = BaseHTTPServer.HTTPServer((host, port), SimpleHTTPServer.SimpleHTTPRequestHandler) +httpd.socket = ssl.wrap_socket (httpd.socket, certfile='./server.pem', server_side=True) +httpd.serve_forever() diff --git a/src/common/typedefs.js b/src/common/typedefs.js index 4d138b1..13d291b 100644 --- a/src/common/typedefs.js +++ b/src/common/typedefs.js @@ -24,3 +24,28 @@ Math.imul = Math.imul || function(a, b) { // the final |0 converts the unsigned value into a signed value return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) | 0); }; + +if (typeof Object.assign !== 'function') { + Object.assign = function(target) { // .length of function is 2 + 'use strict'; + if (target === null) { // TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource !== null) { // Skip over if undefined or null + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + }; +} diff --git a/src/input/camera_access.js b/src/input/camera_access.js index b11bb6b..e871dda 100644 --- a/src/input/camera_access.js +++ b/src/input/camera_access.js @@ -109,6 +109,11 @@ export function pickConstraints(videoConstraints) { return Promise.resolve(normalizedConstraints); } +function enumerateVideoDevices() { + return enumerateDevices() + .then(devices => devices.filter(device => device.kind === 'videoinput')); +} + export default { request: function(video, videoConstraints) { return pickConstraints(videoConstraints) @@ -120,5 +125,14 @@ export default { tracks[0].stop(); } streamRef = null; + }, + enumerateVideoDevices, + getActiveStreamLabel: function() { + if (streamRef) { + const tracks = streamRef.getVideoTracks(); + if (tracks && tracks.length) { + return tracks[0].label; + } + } } }; diff --git a/src/quagga.js b/src/quagga.js index 2bfa64d..3af98fa 100644 --- a/src/quagga.js +++ b/src/quagga.js @@ -539,5 +539,6 @@ export default { }, ImageWrapper: ImageWrapper, ImageDebug: ImageDebug, - ResultCollector: ResultCollector + ResultCollector: ResultCollector, + CameraAccess: CameraAccess, };