Created
February 11, 2015 10:38
-
-
Save DeadlySystem/304d3da710a70ac0545c to your computer and use it in GitHub Desktop.
This is code that provides an interface to let you select the camera to be used with jsqrcode ( https://github.com/LazarSoft/jsqrcode ). To make it work, you will have to include said library and have elements with the IDs in the loadCommonHTMLElements method on your page. You may want to provide appropriate styling as well. This source code is …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
define(["require", "exports"], function (require, exports) { | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Browser compatibility definitions | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Private state | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
var qrcodescanner = null; | |
var cameralist = null; | |
var camerafeed = null; | |
var camerastream = null; | |
var canvas = null; | |
var drawingcontext = null; | |
var readtimeout = null; | |
var scanfrequency = 333; //In milliseconds | |
var nocameras = false; | |
var ready = false; | |
var closed = true; | |
var successcallback = defaultSuccess; | |
var failurecallback = defaultFailure; | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Exports | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
function load() { | |
if (ready) { | |
//Don't initialize twice | |
return; | |
} | |
loadCommonHTMLElements(); | |
installEventListeners(); | |
//Find all cameras and add them to the dropdown | |
MediaStreamTrack.getSources(function (sources) { | |
//Find video sources | |
var videosources = sources.filter(function (source) { | |
return source.kind === "video"; | |
}); | |
//Check if there are any video sources | |
if (videosources.length === 0) { | |
//If there are no video sources at all, the scanner will not work. | |
nocameras = true; | |
return; | |
} | |
//Add all video sources to the dropdown for camera selection | |
var unlabelledcameraindex = 1; | |
videosources.forEach(function (videosource) { | |
var option = document.createElement("option"); | |
option.value = videosource.id; //TODO: Apparently Chrome-specific; W3C specifies sourceId. | |
//Establish the label for the current video source | |
var cameralabel = videosource.label; | |
if (cameralabel === "") { | |
cameralabel = "Camera " + unlabelledcameraindex; | |
++unlabelledcameraindex; | |
} | |
if (videosource.facing) { | |
//The facing-property is Chrome-specific | |
cameralabel += " - " + videosource.facing; | |
if (videosource.facing === "environment") { | |
//Pre-select the video source facing the environment | |
option.selected = true; | |
} | |
} | |
option.text = cameralabel; | |
//Add the video source to the dropdown | |
cameralist.appendChild(option); | |
}); | |
//Signal that the QR code scanner is now ready | |
ready = true; | |
}); | |
} | |
exports.load = load; | |
function scan(onsuccess, onfailure) { | |
if (nocameras) { | |
//If there are no cameras, the scanner cannot operate - fail right away | |
failure("This device does not seem to have any cameras."); | |
return; | |
} | |
if (!ready) { | |
//If the scanner is not ready yet, try again later | |
window.setTimeout(scan, 200); | |
return; | |
} | |
//Default values for parameters | |
if (onsuccess === undefined || typeof onsuccess !== "function") { | |
onsuccess = defaultSuccess; | |
} | |
if (onfailure === undefined || typeof onfailure !== "function") { | |
onfailure = defaultFailure; | |
} | |
//Set up callbacks | |
successcallback = onsuccess; | |
failurecallback = onfailure; | |
//Set state to opened | |
closed = false; | |
//Clear the canvas (avoids re-scanning the previous QR code) | |
drawingcontext.clearRect(0, 0, canvas.width, canvas.height); | |
//Request camera access | |
requestCameraAccess(cameralist.value); | |
//Show the scanner | |
qrcodescanner.style.display = "block"; | |
} | |
exports.scan = scan; | |
function close() { | |
closed = true; | |
window.clearTimeout(readtimeout); | |
if (camerastream !== null) { | |
camerastream.stop(); | |
} | |
qrcodescanner.style.display = "none"; | |
} | |
exports.close = close; | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Private helper methods | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
function loadCommonHTMLElements() { | |
/* The types are as follows: | |
qrcodescanner = <HTMLDivElement> document.getElementById("QRCodeScannerOverlay"); | |
cameralist = <HTMLSelectElement> document.getElementById("cameraselection"); | |
camerafeed = <HTMLVideoElement> document.getElementById("camerafeed"); | |
canvas = <HTMLCanvasElement> document.getElementById("qr-canvas"); | |
*/ | |
qrcodescanner = document.getElementById("QRCodeScannerOverlay"); | |
cameralist = document.getElementById("cameraselection"); | |
camerafeed = document.getElementById("camerafeed"); | |
canvas = document.getElementById("qr-canvas"); | |
//Not really an HTML element, but anyway | |
drawingcontext = canvas.getContext("2d"); | |
} | |
function installEventListeners() { | |
//Add handler for camera selection | |
cameralist.addEventListener("change", function () { | |
requestCameraAccess(cameralist.value); | |
}); | |
//Set up callback for QR code decoding success | |
qrcode.callback = success; | |
} | |
function requestCameraAccess(sourceId) { | |
if (camerastream !== null) { | |
//The following is required to enable switching between cameras, as there cannot be multiple concurrent streams | |
camerastream.stop(); | |
} | |
//Request access to the specified camera | |
navigator.getUserMedia({ | |
"video": { | |
"optional": [ | |
{ "sourceId": sourceId } | |
] | |
}, | |
"audio": false | |
}, function (stream) { | |
camerastream = stream; | |
camerafeed.src = URL.createObjectURL(stream); | |
tryQRCodeReading(); | |
}, function (error) { | |
window["e"] = error; | |
failure("Could not access the camera (" + error.name + "). " + error.message); | |
}); | |
} | |
function tryQRCodeReading() { | |
try { | |
drawingcontext.drawImage(camerafeed, 0, 0); | |
try { | |
qrcode.decode(); | |
} | |
catch (e) { | |
//Happens all the time if QR code scanning did not succeed | |
//console.log("QR code decoding status: " + e); | |
if (!closed) { | |
readtimeout = window.setTimeout(tryQRCodeReading, scanfrequency); | |
} | |
} | |
} | |
catch (e) { | |
failure(e); | |
} | |
} | |
function success(data) { | |
navigator.vibrate([500]); | |
close(); | |
successcallback(data); | |
} | |
function failure(errormessage) { | |
close(); | |
failurecallback(errormessage); | |
} | |
function defaultSuccess(data) { | |
alert(data); | |
} | |
function defaultFailure(errormessage) { | |
alert("Error: " + errormessage); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey;
Do you have a working example of this code that works with https://github.com/LazarSoft/jsqrcode?
I currently use this code that works fine:
if(n.webkitGetUserMedia)
{
webkit=true;
n.webkitGetUserMedia({video: true, audio: false}, success, error);
}
I thought I change it to this below but it doesn't work! Any ideas?
if(n.webkitGetUserMedia)
{
webkit=true;
n.webkitGetUserMedia({video: {facingMode: "environment"},audio: false}, success, error);
}
Awesome in advance