diff --git a/README.md b/README.md
index 065fab8..3693f99 100644
--- a/README.md
+++ b/README.md
@@ -140,7 +140,7 @@ As an optional third parameter an error handler to be invoked on decoding errors
As an optional fourth parameter a method can be provided that determines a region to which scanning should be restricted as a performance improvement. This region can optionally also be scaled down before performing the scan as an additional performance improvement. The region is specified as `x`, `y`, `width` and `height`; the dimensions for the downscaled region as `downScaledWidth` and `downScaledHeight`. Note that the aspect ratio between `width` and `height` and `downScaledWidth` and `downScaledHeight` should remain the same. By default, the scan region is restricted to a centered square of two thirds of the video width or height, whichever is smaller, and scaled down to a 400x400 square.
-As an optional fifth parameter a preference for the camera to use can be specified. Allowed values are `'environment'` and `'user'`. The default is `'environment'`.
+As an optional fifth parameter a preference for the camera to use can be specified. The preference can be either a device id as returned by `listCameras` or a facing mode specified as `'environment'` or `'user'`. The default is `'environment'`. Note that there is no guarantee that the preference can actually be fulfilled.
To use the default value for an optional parameter, omit it or use `undefined`.
@@ -195,6 +195,24 @@ This library provides a utility method for checking whether the device has a cam
QrScanner.hasCamera(); // async
```
+### Getting the list of available Cameras
+
+This library provides a utility method for getting a list of the device's cameras, defined via their `id` and `label`. This can be useful for letting a user choose a specific camera to use.
+
+You can optionally request the camera's labels. Note that this however requires the user's permission to acess the cameras, which he will be asked for if not granted already. If not specifically requested, device labels are determined on a best effort basis, i.e. actual labels are returned if permissions were already granted and fallback labels otherwise.
+```js
+QrScanner.listCameras(); // async; without requesting camera labels
+QrScanner.listCameras(true); // async; requesting camera labels, potentially asking the user for permission
+```
+
+### Specifying which camera to use
+
+You can change the preferred camera to be used. The preference can be either a device id as returned by `listCameras` or a facing mode specified as `'environment'` or `'user'`. Note that there is no guarantee that the preference can actually be fulfilled.
+
+```js
+qrScanner.setCamera(facingModeOrDeviceId); // async
+```
+
### Color Inverted Mode
The scanner by default scans for dark QR codes on a bright background. You can change this behavior to scan for bright QR codes on dark background or for both at the same time:
```js
diff --git a/demo/index.html b/demo/index.html
index dcafe7c..3469e33 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -22,12 +22,6 @@
Scan from WebCam:
- Device has camera:
-
-
- Device has flash:
-
-
-
-
-
+Device has camera:
+
+
+
+ Preferred camera:
+
+
+Camera has flash:
+
+
+
+
+ Detected QR code: None
@@ -67,6 +74,7 @@
const video = document.getElementById('qr-video');
const camHasCamera = document.getElementById('cam-has-camera');
+ const camList = document.getElementById('cam-list');
const camHasFlash = document.getElementById('cam-has-flash');
const flashToggle = document.getElementById('flash-toggle');
const flashState = document.getElementById('flash-state');
@@ -85,24 +93,34 @@
// ####### Web Cam Scanning #######
- QrScanner.hasCamera().then(hasCamera => camHasCamera.textContent = hasCamera);
-
const scanner = new QrScanner(video, result => setResult(camQrResult, result), error => {
camQrResult.textContent = error;
camQrResult.style.color = 'inherit';
});
- scanner.start().then(() => {
+
+ const updateFlashAvailability = () => {
scanner.hasFlash().then(hasFlash => {
camHasFlash.textContent = hasFlash;
- if (hasFlash) {
- flashToggle.style.display = 'inline-block';
- flashToggle.addEventListener('click', () => {
- scanner.toggleFlash().then(() => flashState.textContent = scanner.isFlashOn() ? 'on' : 'off');
- });
- }
+ flashToggle.style.display = hasFlash ? 'inline-block' : 'none';
});
+ };
+
+ scanner.start().then(() => {
+ updateFlashAvailability();
+ // List cameras after the scanner started to avoid listCamera's stream and the scanner's stream being requested
+ // at the same time which can result in listCamera's unconstrained stream also being offered to the scanner.
+ // Note that we can also start the scanner after listCameras, we just have it this way around in the demo to
+ // start the scanner earlier.
+ QrScanner.listCameras(true).then(cameras => cameras.forEach(camera => {
+ const option = document.createElement('option');
+ option.value = camera.id;
+ option.text = camera.label;
+ camList.add(option);
+ }));
});
+ QrScanner.hasCamera().then(hasCamera => camHasCamera.textContent = hasCamera);
+
// for debugging
window.scanner = scanner;
@@ -117,6 +135,14 @@
scanner.setInversionMode(event.target.value);
});
+ camList.addEventListener('change', event => {
+ scanner.setCamera(event.target.value).then(updateFlashAvailability);
+ });
+
+ flashToggle.addEventListener('click', () => {
+ scanner.toggleFlash().then(() => flashState.textContent = scanner.isFlashOn() ? 'on' : 'off');
+ });
+
document.getElementById('start-button').addEventListener('click', () => {
scanner.start();
});
diff --git a/qr-scanner.min.js b/qr-scanner.min.js
index cbfc34c..c6bceb3 100644
--- a/qr-scanner.min.js
+++ b/qr-scanner.min.js
@@ -1,18 +1,19 @@
-class e{static hasCamera(){return navigator.mediaDevices?navigator.mediaDevices.enumerateDevices().then(a=>a.some(a=>"videoinput"===a.kind)).catch(()=>!1):Promise.resolve(!1)}constructor(a,b,c=this._onDecodeError,d=this._calculateScanRegion,g="environment"){this.$video=a;this.$canvas=document.createElement("canvas");this._onDecode=b;this._legacyCanvasSize=e.DEFAULT_CANVAS_SIZE;this._preferredFacingMode=g;this._flashOn=this._paused=this._active=!1;"number"===typeof c?(this._legacyCanvasSize=
-c,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._onDecodeError=c;"number"===typeof d?(this._legacyCanvasSize=d,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._calculateScanRegion=d;this._scanRegion=this._calculateScanRegion(a);this._onPlay=this._onPlay.bind(this);this._onLoadedMetaData=this._onLoadedMetaData.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);
-a.disablePictureInPicture=!0;a.playsInline=!0;a.muted=!0;let f=!1;a.hidden&&(a.hidden=!1,f=!0);document.body.contains(a)||(document.body.appendChild(a),f=!0);requestAnimationFrame(()=>{let b=window.getComputedStyle(a);"none"===b.display&&(a.style.setProperty("display","block","important"),f=!0);"visible"!==b.visibility&&(a.style.setProperty("visibility","visible","important"),f=!0);f&&(console.warn("QrScanner has overwritten the video hiding style to avoid Safari stopping the playback."),a.style.opacity=
-0,a.style.width=0,a.style.height=0)});a.addEventListener("play",this._onPlay);a.addEventListener("loadedmetadata",this._onLoadedMetaData);document.addEventListener("visibilitychange",this._onVisibilityChange);this._qrEnginePromise=e.createQrEngine()}hasFlash(){if(!("ImageCapture"in window))return Promise.resolve(!1);let a=this.$video.srcObject?this.$video.srcObject.getVideoTracks()[0]:null;return a?(new ImageCapture(a)).getPhotoCapabilities().then(a=>a.fillLightMode.includes("flash")).catch(a=>{console.warn(a);
-return!1}):Promise.reject("Camera not started or not available")}isFlashOn(){return this._flashOn}toggleFlash(){return this._setFlash(!this._flashOn)}turnFlashOff(){return this._setFlash(!1)}turnFlashOn(){return this._setFlash(!0)}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);this.stop();e._postWorkerMessage(this._qrEnginePromise,"close")}start(){if(this._active&&
-!this._paused)return Promise.resolve();"https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https.");this._active=!0;this._paused=!1;if(document.hidden)return Promise.resolve();clearTimeout(this._offTimeout);this._offTimeout=null;if(this.$video.srcObject)return this.$video.play(),Promise.resolve();let a=this._preferredFacingMode;return this._getCameraStream(a,!0).catch(()=>{a="environment"===a?"user":"environment";return this._getCameraStream()}).then(b=>
-{a=this._getFacingMode(b)||a;this.$video.srcObject=b;this.$video.play();this._setVideoMirror(a)}).catch(a=>{this._active=!1;throw a;})}stop(){this.pause();this._active=!1}pause(){this._paused=!0;this._active&&(this.$video.pause(),this._offTimeout||(this._offTimeout=setTimeout(()=>{let a=this.$video.srcObject?this.$video.srcObject.getTracks():[];for(let b of a)b.stop();this._offTimeout=this.$video.srcObject=null},300)))}static scanImage(a,b=null,c=null,d=null,g=!1,f=!1){let h=c instanceof Worker,k=
-Promise.all([c||e.createQrEngine(),e._loadImage(a)]).then(([a,f])=>{c=a;let k;[d,k]=this._drawToCanvas(f,b,d,g);return c instanceof Worker?(h||c.postMessage({type:"inversionMode",data:"both"}),new Promise((a,b)=>{let g,f,h;f=d=>{"qrResult"===d.data.type&&(c.removeEventListener("message",f),c.removeEventListener("error",h),clearTimeout(g),null!==d.data.data?a(d.data.data):b(e.NO_QR_CODE_FOUND))};h=a=>{c.removeEventListener("message",f);c.removeEventListener("error",h);clearTimeout(g);b("Scanner error: "+
-(a?a.message||a:"Unknown Error"))};c.addEventListener("message",f);c.addEventListener("error",h);g=setTimeout(()=>h("timeout"),1E4);let l=k.getImageData(0,0,d.width,d.height);c.postMessage({type:"decode",data:l},[l.data.buffer])})):new Promise((a,b)=>{let f=setTimeout(()=>b("Scanner error: timeout"),1E4);c.detect(d).then(c=>{c.length?a(c[0].rawValue):b(e.NO_QR_CODE_FOUND)}).catch(a=>b("Scanner error: "+(a.message||a))).finally(()=>clearTimeout(f))})});b&&f&&(k=k.catch(()=>e.scanImage(a,null,c,d,g)));
-return k=k.finally(()=>{h||e._postWorkerMessage(c,"close")})}setGrayscaleWeights(a,b,c,d=!0){e._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:c,useIntegerApproximation:d})}setInversionMode(a){e._postWorkerMessage(this._qrEnginePromise,"inversionMode",a)}static createQrEngine(a=e.WORKER_PATH){return("BarcodeDetector"in window?BarcodeDetector.getSupportedFormats():Promise.resolve([])).then(b=>-1!==b.indexOf("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a))}_onPlay(){this._scanRegion=
-this._calculateScanRegion(this.$video);this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video)}_onVisibilityChange(){document.hidden?this.pause():this._active&&this.start()}_calculateScanRegion(a){let b=Math.round(2/3*Math.min(a.videoWidth,a.videoHeight));return{x:Math.round((a.videoWidth-b)/2),y:Math.round((a.videoHeight-b)/2),width:b,height:b,downScaledWidth:this._legacyCanvasSize,downScaledHeight:this._legacyCanvasSize}}_scanFrame(){if(!this._active||this.$video.paused||
-this.$video.ended)return!1;requestAnimationFrame(()=>{1>=this.$video.readyState?this._scanFrame():this._qrEnginePromise.then(a=>e.scanImage(this.$video,this._scanRegion,a,this.$canvas)).then(this._onDecode,a=>{this._active&&(-1!==(a.message||a).indexOf("service unavailable")&&(this._qrEnginePromise=e.createQrEngine()),this._onDecodeError(a))}).then(()=>this._scanFrame())})}_onDecodeError(a){a!==e.NO_QR_CODE_FOUND&&console.log(a)}_getCameraStream(a,b=!1){let c=[{width:{min:1024}},{width:{min:768}},
-{}];a&&(b&&(a={exact:a}),c.forEach(b=>b.facingMode=a));return this._getMatchingCameraStream(c)}_getMatchingCameraStream(a){return navigator.mediaDevices&&0!==a.length?navigator.mediaDevices.getUserMedia({video:a.shift()}).catch(()=>this._getMatchingCameraStream(a)):Promise.reject("Camera not found.")}_setFlash(a){return this.hasFlash().then(b=>b?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:a}]}):Promise.reject("No flash available")).then(()=>this._flashOn=a)}_setVideoMirror(a){this.$video.style.transform=
-"scaleX("+("user"===a?-1:1)+")"}_getFacingMode(a){return(a=a.getVideoTracks()[0])?/rear|back|environment/i.test(a.label)?"environment":/front|user|face/i.test(a.label)?"user":null:null}static _drawToCanvas(a,b=null,c=null,d=!1){c=c||document.createElement("canvas");let g=b&&b.x?b.x:0,f=b&&b.y?b.y:0,h=b&&b.width?b.width:a.width||a.videoWidth,k=b&&b.height?b.height:a.height||a.videoHeight;d||(d=b&&b.downScaledWidth?b.downScaledWidth:h,b=b&&b.downScaledHeight?b.downScaledHeight:k,c.width!==d&&(c.width=
-d),c.height!==b&&(c.height=b));b=c.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,g,f,h,k,0,0,c.width,c.height);return[c,b]}static _loadImage(a){if(a instanceof HTMLCanvasElement||a instanceof HTMLVideoElement||window.ImageBitmap&&a instanceof window.ImageBitmap||window.OffscreenCanvas&&a instanceof window.OffscreenCanvas)return Promise.resolve(a);if(a instanceof Image)return e._awaitImageLoad(a).then(()=>a);if(a instanceof File||a instanceof Blob||a instanceof URL||"string"===
-typeof a){let b=new Image;b.src=a instanceof File||a instanceof Blob?URL.createObjectURL(a):a;return e._awaitImageLoad(b).then(()=>{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src);return b})}return Promise.reject("Unsupported image type.")}static _awaitImageLoad(a){return new Promise((b,c)=>{if(a.complete&&0!==a.naturalWidth)b();else{let d,g;d=()=>{a.removeEventListener("load",d);a.removeEventListener("error",g);b()};g=()=>{a.removeEventListener("load",d);a.removeEventListener("error",
-g);c("Image load error")};a.addEventListener("load",d);a.addEventListener("error",g)}})}static _postWorkerMessage(a,b,c){return Promise.resolve(a).then(a=>{a instanceof Worker&&a.postMessage({type:b,data:c})})}}e.DEFAULT_CANVAS_SIZE=400;e.NO_QR_CODE_FOUND="No QR code found";e.WORKER_PATH="qr-scanner-worker.min.js";export default e
+class e{static hasCamera(){return e.listCameras(!1).then(a=>!!a.length).catch(()=>!1)}static listCameras(a=!1){if(!navigator.mediaDevices)return Promise.resolve([]);let b=null;return(a?navigator.mediaDevices.getUserMedia({audio:!1,video:!0}).then(a=>b=a).catch(()=>{}):Promise.resolve()).then(()=>navigator.mediaDevices.enumerateDevices()).then(a=>a.filter(a=>"videoinput"===a.kind).map((a,b)=>({id:a.deviceId,label:a.label||(0===b?"Default Camera":`Camera ${b+1}`)}))).finally(()=>{if(b)for(let a of b.getTracks())a.stop(),
+b.removeTrack(a)})}constructor(a,b,c=this._onDecodeError,d=this._calculateScanRegion,f="environment"){this.$video=a;this.$canvas=document.createElement("canvas");this._onDecode=b;this._legacyCanvasSize=e.DEFAULT_CANVAS_SIZE;this._preferredCamera=f;this._flashOn=this._paused=this._active=!1;"number"===typeof c?(this._legacyCanvasSize=c,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._onDecodeError=c;"number"===typeof d?(this._legacyCanvasSize=
+d,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._calculateScanRegion=d;this._scanRegion=this._calculateScanRegion(a);this._onPlay=this._onPlay.bind(this);this._onLoadedMetaData=this._onLoadedMetaData.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);a.disablePictureInPicture=!0;a.playsInline=!0;a.muted=!0;let g=!1;a.hidden&&(a.hidden=!1,g=!0);document.body.contains(a)||(document.body.appendChild(a),g=
+!0);requestAnimationFrame(()=>{let b=window.getComputedStyle(a);"none"===b.display&&(a.style.setProperty("display","block","important"),g=!0);"visible"!==b.visibility&&(a.style.setProperty("visibility","visible","important"),g=!0);g&&(console.warn("QrScanner has overwritten the video hiding style to avoid Safari stopping the playback."),a.style.opacity=0,a.style.width=0,a.style.height=0)});a.addEventListener("play",this._onPlay);a.addEventListener("loadedmetadata",this._onLoadedMetaData);document.addEventListener("visibilitychange",
+this._onVisibilityChange);this._qrEnginePromise=e.createQrEngine()}hasFlash(){if(!("ImageCapture"in window))return Promise.resolve(!1);let a=this.$video.srcObject?this.$video.srcObject.getVideoTracks()[0]:null;return a?(new ImageCapture(a)).getPhotoCapabilities().then(a=>a.fillLightMode.includes("flash")).catch(a=>{console.warn(a);return!1}):Promise.reject("Camera not started or not available")}isFlashOn(){return this._flashOn}toggleFlash(){return this._setFlash(!this._flashOn)}turnFlashOff(){return this._setFlash(!1)}turnFlashOn(){return this._setFlash(!0)}destroy(){this.$video.removeEventListener("loadedmetadata",
+this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);this.stop();e._postWorkerMessage(this._qrEnginePromise,"close")}start(){if(this._active&&!this._paused)return Promise.resolve();"https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https.");this._active=!0;if(document.hidden)return Promise.resolve();this._paused=!1;if(this.$video.srcObject)return this.$video.play(),
+Promise.resolve();let a="environment"===this._preferredCamera||"user"===this._preferredCamera?this._preferredCamera:null;return this._getCameraStream(this._preferredCamera,!0).catch(()=>{a="environment"===a?"user":"environment";return this._getCameraStream()}).then(b=>{a=this._getFacingMode(b)||a||"environment";this.$video.srcObject=b;this.$video.play();this._setVideoMirror(a)}).catch(a=>{this._active=!1;throw a;})}stop(){this.pause();this._active=!1}pause(a=!1){this._paused=!0;if(!this._active)return Promise.resolve(!0);
+this.$video.pause();let b=()=>{const a=this.$video.srcObject?this.$video.srcObject.getTracks():[];for(const b of a)b.stop(),this.$video.srcObject.removeTrack(b);this.$video.srcObject=null};return a?(b(),Promise.resolve(!0)):(new Promise(a=>setTimeout(a,300))).then(()=>{if(!this._paused)return!1;b();return!0})}setCamera(a){if(a===this._preferredCamera)return Promise.resolve();this._preferredCamera=a;let b=this._paused;return this.pause(!0).then(a=>{if(a&&!b&&this._active)return this.start()})}static scanImage(a,
+b=null,c=null,d=null,f=!1,g=!1){let h=c instanceof Worker,k=Promise.all([c||e.createQrEngine(),e._loadImage(a)]).then(([a,g])=>{c=a;let k;[d,k]=this._drawToCanvas(g,b,d,f);return c instanceof Worker?(h||c.postMessage({type:"inversionMode",data:"both"}),new Promise((a,b)=>{let f,g,h;g=d=>{"qrResult"===d.data.type&&(c.removeEventListener("message",g),c.removeEventListener("error",h),clearTimeout(f),null!==d.data.data?a(d.data.data):b(e.NO_QR_CODE_FOUND))};h=a=>{c.removeEventListener("message",g);c.removeEventListener("error",
+h);clearTimeout(f);b("Scanner error: "+(a?a.message||a:"Unknown Error"))};c.addEventListener("message",g);c.addEventListener("error",h);f=setTimeout(()=>h("timeout"),1E4);let l=k.getImageData(0,0,d.width,d.height);c.postMessage({type:"decode",data:l},[l.data.buffer])})):new Promise((a,b)=>{let f=setTimeout(()=>b("Scanner error: timeout"),1E4);c.detect(d).then(c=>{c.length?a(c[0].rawValue):b(e.NO_QR_CODE_FOUND)}).catch(a=>b("Scanner error: "+(a.message||a))).finally(()=>clearTimeout(f))})});b&&g&&
+(k=k.catch(()=>e.scanImage(a,null,c,d,f)));return k=k.finally(()=>{h||e._postWorkerMessage(c,"close")})}setGrayscaleWeights(a,b,c,d=!0){e._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:c,useIntegerApproximation:d})}setInversionMode(a){e._postWorkerMessage(this._qrEnginePromise,"inversionMode",a)}static createQrEngine(a=e.WORKER_PATH){return("BarcodeDetector"in window?BarcodeDetector.getSupportedFormats():Promise.resolve([])).then(b=>-1!==b.indexOf("qr_code")?new BarcodeDetector({formats:["qr_code"]}):
+new Worker(a))}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video)}_onVisibilityChange(){document.hidden?this.pause():this._active&&this.start()}_calculateScanRegion(a){let b=Math.round(2/3*Math.min(a.videoWidth,a.videoHeight));return{x:Math.round((a.videoWidth-b)/2),y:Math.round((a.videoHeight-b)/2),width:b,height:b,downScaledWidth:this._legacyCanvasSize,downScaledHeight:this._legacyCanvasSize}}_scanFrame(){if(!this._active||
+this.$video.paused||this.$video.ended)return!1;requestAnimationFrame(()=>{1>=this.$video.readyState?this._scanFrame():this._qrEnginePromise.then(a=>e.scanImage(this.$video,this._scanRegion,a,this.$canvas)).then(this._onDecode,a=>{this._active&&(-1!==(a.message||a).indexOf("service unavailable")&&(this._qrEnginePromise=e.createQrEngine()),this._onDecodeError(a))}).then(()=>this._scanFrame())})}_onDecodeError(a){a!==e.NO_QR_CODE_FOUND&&console.log(a)}_getCameraStream(a,b=!1){let c=[{width:{min:1024}},
+{width:{min:768}},{}];if(a){let d="environment"===a||"user"===a?"facingMode":"deviceId";b&&(a={exact:a});c.forEach(b=>b[d]=a)}return this._getMatchingCameraStream(c)}_getMatchingCameraStream(a){return navigator.mediaDevices&&0!==a.length?navigator.mediaDevices.getUserMedia({video:a.shift()}).catch(()=>this._getMatchingCameraStream(a)):Promise.reject("Camera not found.")}_setFlash(a){return this.hasFlash().then(b=>b?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:a}]}):
+Promise.reject("No flash available")).then(()=>this._flashOn=a)}_setVideoMirror(a){this.$video.style.transform="scaleX("+("user"===a?-1:1)+")"}_getFacingMode(a){return(a=a.getVideoTracks()[0])?/rear|back|environment/i.test(a.label)?"environment":/front|user|face/i.test(a.label)?"user":null:null}static _drawToCanvas(a,b=null,c=null,d=!1){c=c||document.createElement("canvas");let f=b&&b.x?b.x:0,g=b&&b.y?b.y:0,h=b&&b.width?b.width:a.width||a.videoWidth,k=b&&b.height?b.height:a.height||a.videoHeight;
+d||(d=b&&b.downScaledWidth?b.downScaledWidth:h,b=b&&b.downScaledHeight?b.downScaledHeight:k,c.width!==d&&(c.width=d),c.height!==b&&(c.height=b));b=c.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,f,g,h,k,0,0,c.width,c.height);return[c,b]}static _loadImage(a){if(a instanceof HTMLCanvasElement||a instanceof HTMLVideoElement||window.ImageBitmap&&a instanceof window.ImageBitmap||window.OffscreenCanvas&&a instanceof window.OffscreenCanvas)return Promise.resolve(a);if(a instanceof
+Image)return e._awaitImageLoad(a).then(()=>a);if(a instanceof File||a instanceof Blob||a instanceof URL||"string"===typeof a){let b=new Image;b.src=a instanceof File||a instanceof Blob?URL.createObjectURL(a):a;return e._awaitImageLoad(b).then(()=>{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src);return b})}return Promise.reject("Unsupported image type.")}static _awaitImageLoad(a){return new Promise((b,c)=>{if(a.complete&&0!==a.naturalWidth)b();else{let d,f;d=()=>{a.removeEventListener("load",
+d);a.removeEventListener("error",f);b()};f=()=>{a.removeEventListener("load",d);a.removeEventListener("error",f);c("Image load error")};a.addEventListener("load",d);a.addEventListener("error",f)}})}static _postWorkerMessage(a,b,c){return Promise.resolve(a).then(a=>{a instanceof Worker&&a.postMessage({type:b,data:c})})}}e.DEFAULT_CANVAS_SIZE=400;e.NO_QR_CODE_FOUND="No QR code found";e.WORKER_PATH="qr-scanner-worker.min.js";export default e
//# sourceMappingURL=qr-scanner.min.js.map
diff --git a/qr-scanner.min.js.map b/qr-scanner.min.js.map
index f754485..a65acfa 100644
--- a/qr-scanner.min.js.map
+++ b/qr-scanner.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"qr-scanner.min.js","sources":["src/qr-scanner.js"],"sourcesContent":["export default class QrScanner {\n /* async */\n static hasCamera() {\n if (!navigator.mediaDevices) return Promise.resolve(false);\n // note that enumerateDevices can always be called and does not prompt the user for permission. However, device\n // labels are only readable if served via https and an active media stream exists or permanent permission is\n // given. That doesn't matter for us though as we don't require labels.\n return navigator.mediaDevices.enumerateDevices()\n .then(devices => devices.some(device => device.kind === 'videoinput'))\n .catch(() => false);\n }\n\n constructor(\n video,\n onDecode,\n canvasSizeOrOnDecodeError = this._onDecodeError,\n canvasSizeOrCalculateScanRegion = this._calculateScanRegion,\n preferredFacingMode = 'environment'\n ) {\n this.$video = video;\n this.$canvas = document.createElement('canvas');\n this._onDecode = onDecode;\n this._legacyCanvasSize = QrScanner.DEFAULT_CANVAS_SIZE;\n this._preferredFacingMode = preferredFacingMode;\n this._active = false;\n this._paused = false;\n this._flashOn = false;\n\n if (typeof canvasSizeOrOnDecodeError === 'number') {\n // legacy function signature where the third argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrOnDecodeError;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._onDecodeError = canvasSizeOrOnDecodeError;\n }\n\n if (typeof canvasSizeOrCalculateScanRegion === 'number') {\n // legacy function signature where the fourth argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrCalculateScanRegion;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._calculateScanRegion = canvasSizeOrCalculateScanRegion;\n }\n\n this._scanRegion = this._calculateScanRegion(video);\n\n this._onPlay = this._onPlay.bind(this);\n this._onLoadedMetaData = this._onLoadedMetaData.bind(this);\n this._onVisibilityChange = this._onVisibilityChange.bind(this);\n\n video.disablePictureInPicture = true;\n // Allow inline playback on iPhone instead of requiring full screen playback,\n // see https://webkit.org/blog/6784/new-video-policies-for-ios/\n video.playsInline = true;\n // Allow play() on iPhone without requiring a user gesture. Should not really be needed as camera stream\n // includes no audio, but just to be safe.\n video.muted = true;\n\n // Avoid Safari stopping the video stream on a hidden video.\n // See https://github.com/cozmo/jsQR/issues/185\n let shouldHideVideo = false;\n if (video.hidden) {\n video.hidden = false;\n shouldHideVideo = true;\n }\n if (!document.body.contains(video)) {\n document.body.appendChild(video);\n shouldHideVideo = true;\n }\n requestAnimationFrame(() => {\n // Checking in requestAnimationFrame which should avoid a potential additional re-flow for getComputedStyle.\n const computedStyle = window.getComputedStyle(video);\n if (computedStyle.display === 'none') {\n video.style.setProperty('display', 'block', 'important');\n shouldHideVideo = true;\n }\n if (computedStyle.visibility !== 'visible') {\n video.style.setProperty('visibility', 'visible', 'important');\n shouldHideVideo = true;\n }\n if (shouldHideVideo) {\n // Hide the video in a way that doesn't cause Safari to stop the playback.\n console.warn('QrScanner has overwritten the video hiding style to avoid Safari stopping the playback.');\n video.style.opacity = 0;\n video.style.width = 0;\n video.style.height = 0;\n }\n });\n\n video.addEventListener('play', this._onPlay);\n video.addEventListener('loadedmetadata', this._onLoadedMetaData);\n document.addEventListener('visibilitychange', this._onVisibilityChange);\n\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n\n /* async */\n hasFlash() {\n if (!('ImageCapture' in window)) {\n return Promise.resolve(false);\n }\n\n const track = this.$video.srcObject ? this.$video.srcObject.getVideoTracks()[0] : null;\n if (!track) {\n return Promise.reject('Camera not started or not available');\n }\n\n const imageCapture = new ImageCapture(track);\n return imageCapture.getPhotoCapabilities()\n .then((result) => {\n return result.fillLightMode.includes('flash');\n })\n .catch((error) => {\n console.warn(error);\n return false;\n });\n }\n\n isFlashOn() {\n return this._flashOn;\n }\n\n /* async */\n toggleFlash() {\n return this._setFlash(!this._flashOn);\n }\n\n /* async */\n turnFlashOff() {\n return this._setFlash(false);\n }\n\n /* async */\n turnFlashOn() {\n return this._setFlash(true);\n }\n\n destroy() {\n this.$video.removeEventListener('loadedmetadata', this._onLoadedMetaData);\n this.$video.removeEventListener('play', this._onPlay);\n document.removeEventListener('visibilitychange', this._onVisibilityChange);\n\n this.stop();\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'close');\n }\n\n /* async */\n start() {\n if (this._active && !this._paused) {\n return Promise.resolve();\n }\n if (window.location.protocol !== 'https:') {\n // warn but try starting the camera anyways\n console.warn('The camera stream is only accessible if the page is transferred via https.');\n }\n this._active = true;\n this._paused = false;\n if (document.hidden) {\n // camera will be started as soon as tab is in foreground\n return Promise.resolve();\n }\n clearTimeout(this._offTimeout);\n this._offTimeout = null;\n if (this.$video.srcObject) {\n // camera stream already/still set\n this.$video.play();\n return Promise.resolve();\n }\n\n let facingMode = this._preferredFacingMode;\n return this._getCameraStream(facingMode, true)\n .catch(() => {\n // We (probably) don't have a camera of the requested facing mode\n facingMode = facingMode === 'environment' ? 'user' : 'environment';\n return this._getCameraStream(); // throws if camera is not accessible (e.g. due to not https)\n })\n .then(stream => {\n // Try to determine the facing mode from the stream, otherwise use our guess. Note that the guess is not\n // always accurate as Safari returns cameras of different facing mode, even for exact constraints.\n facingMode = this._getFacingMode(stream) || facingMode;\n this.$video.srcObject = stream;\n this.$video.play();\n this._setVideoMirror(facingMode);\n })\n .catch(e => {\n this._active = false;\n throw e;\n });\n }\n\n stop() {\n this.pause();\n this._active = false;\n }\n\n pause() {\n this._paused = true;\n if (!this._active) {\n return;\n }\n this.$video.pause();\n if (this._offTimeout) {\n return;\n }\n this._offTimeout = setTimeout(() => {\n const tracks = this.$video.srcObject ? this.$video.srcObject.getTracks() : [];\n for (const track of tracks) {\n track.stop(); // note that this will also automatically turn the flashlight off\n }\n this.$video.srcObject = null;\n this._offTimeout = null;\n }, 300);\n }\n\n /* async */\n static scanImage(imageOrFileOrUrl, scanRegion=null, qrEngine=null, canvas=null, disallowCanvasResizing=false,\n alsoTryWithoutScanRegion=false) {\n const gotExternalWorker = qrEngine instanceof Worker;\n\n let promise = Promise.all([\n qrEngine || QrScanner.createQrEngine(),\n QrScanner._loadImage(imageOrFileOrUrl),\n ]).then(([engine, image]) => {\n qrEngine = engine;\n let canvasContext;\n [canvas, canvasContext] = this._drawToCanvas(image, scanRegion, canvas, disallowCanvasResizing);\n\n if (qrEngine instanceof Worker) {\n if (!gotExternalWorker) {\n // Enable scanning of inverted color qr codes. Not using _postWorkerMessage as it's async\n qrEngine.postMessage({ type: 'inversionMode', data: 'both' });\n }\n return new Promise((resolve, reject) => {\n let timeout, onMessage, onError;\n onMessage = event => {\n if (event.data.type !== 'qrResult') {\n return;\n }\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n if (event.data.data !== null) {\n resolve(event.data.data);\n } else {\n reject(QrScanner.NO_QR_CODE_FOUND);\n }\n };\n onError = (e) => {\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n const errorMessage = !e ? 'Unknown Error' : (e.message || e);\n reject('Scanner error: ' + errorMessage);\n };\n qrEngine.addEventListener('message', onMessage);\n qrEngine.addEventListener('error', onError);\n timeout = setTimeout(() => onError('timeout'), 10000);\n const imageData = canvasContext.getImageData(0, 0, canvas.width, canvas.height);\n qrEngine.postMessage({\n type: 'decode',\n data: imageData\n }, [imageData.data.buffer]);\n });\n } else {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => reject('Scanner error: timeout'), 10000);\n qrEngine.detect(canvas).then(scanResults => {\n if (!scanResults.length) {\n reject(QrScanner.NO_QR_CODE_FOUND);\n } else {\n resolve(scanResults[0].rawValue);\n }\n }).catch((e) => reject('Scanner error: ' + (e.message || e))).finally(() => clearTimeout(timeout));\n });\n }\n });\n\n if (scanRegion && alsoTryWithoutScanRegion) {\n promise = promise.catch(() =>\n QrScanner.scanImage(imageOrFileOrUrl, null, qrEngine, canvas, disallowCanvasResizing));\n }\n\n promise = promise.finally(() => {\n if (gotExternalWorker) return;\n QrScanner._postWorkerMessage(qrEngine, 'close');\n });\n\n return promise;\n }\n\n setGrayscaleWeights(red, green, blue, useIntegerApproximation = true) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations work also\n // well with colored qr codes.\n QrScanner._postWorkerMessage(\n this._qrEnginePromise,\n 'grayscaleWeights',\n { red, green, blue, useIntegerApproximation }\n );\n }\n\n setInversionMode(inversionMode) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations scan normal\n // and inverted qr codes by default\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'inversionMode', inversionMode);\n }\n\n /* async */\n static createQrEngine(workerPath = QrScanner.WORKER_PATH) {\n return ('BarcodeDetector' in window ? BarcodeDetector.getSupportedFormats() : Promise.resolve([]))\n .then((supportedFormats) => supportedFormats.indexOf('qr_code') !== -1\n ? new BarcodeDetector({ formats: ['qr_code'] })\n : new Worker(workerPath)\n );\n }\n\n _onPlay() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n this._scanFrame();\n }\n\n _onLoadedMetaData() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n }\n\n _onVisibilityChange() {\n if (document.hidden) {\n this.pause();\n } else if (this._active) {\n this.start();\n }\n }\n\n _calculateScanRegion(video) {\n // Default scan region calculation. Note that this can be overwritten in the constructor.\n const smallestDimension = Math.min(video.videoWidth, video.videoHeight);\n const scanRegionSize = Math.round(2 / 3 * smallestDimension);\n return {\n x: Math.round((video.videoWidth - scanRegionSize) / 2),\n y: Math.round((video.videoHeight - scanRegionSize) / 2),\n width: scanRegionSize,\n height: scanRegionSize,\n downScaledWidth: this._legacyCanvasSize,\n downScaledHeight: this._legacyCanvasSize,\n };\n }\n\n _scanFrame() {\n if (!this._active || this.$video.paused || this.$video.ended) return false;\n // using requestAnimationFrame to avoid scanning if tab is in background\n requestAnimationFrame(() => {\n if (this.$video.readyState <= 1) {\n // Skip scans until the video is ready as drawImage() only works correctly on a video with readyState\n // > 1, see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#Notes.\n // This also avoids false positives for videos paused after a successful scan which remains visible on\n // the canvas until the video is started again and ready.\n this._scanFrame();\n return;\n }\n this._qrEnginePromise\n .then((qrEngine) => QrScanner.scanImage(this.$video, this._scanRegion, qrEngine, this.$canvas))\n .then(this._onDecode, (error) => {\n if (!this._active) return;\n const errorMessage = error.message || error;\n if (errorMessage.indexOf('service unavailable') !== -1) {\n // When the native BarcodeDetector crashed, create a new one\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n this._onDecodeError(error);\n })\n .then(() => this._scanFrame());\n });\n }\n\n _onDecodeError(error) {\n // default error handler; can be overwritten in the constructor\n if (error === QrScanner.NO_QR_CODE_FOUND) return;\n console.log(error);\n }\n\n _getCameraStream(facingMode, exact = false) {\n const constraintsToTry = [{\n width: { min: 1024 }\n }, {\n width: { min: 768 }\n }, {}];\n\n if (facingMode) {\n if (exact) {\n facingMode = { exact: facingMode };\n }\n constraintsToTry.forEach(constraint => constraint.facingMode = facingMode);\n }\n return this._getMatchingCameraStream(constraintsToTry);\n }\n\n _getMatchingCameraStream(constraintsToTry) {\n if (!navigator.mediaDevices || constraintsToTry.length === 0) {\n return Promise.reject('Camera not found.');\n }\n return navigator.mediaDevices.getUserMedia({\n video: constraintsToTry.shift()\n }).catch(() => this._getMatchingCameraStream(constraintsToTry));\n }\n\n /* async */\n _setFlash(on) {\n return this.hasFlash().then((hasFlash) => {\n if (!hasFlash) return Promise.reject('No flash available');\n // Note that the video track is guaranteed to exist at this point\n return this.$video.srcObject.getVideoTracks()[0].applyConstraints({\n advanced: [{ torch: on }],\n });\n }).then(() => this._flashOn = on);\n }\n\n _setVideoMirror(facingMode) {\n // in user facing mode mirror the video to make it easier for the user to position the QR code\n const scaleFactor = facingMode==='user'? -1 : 1;\n this.$video.style.transform = 'scaleX(' + scaleFactor + ')';\n }\n\n _getFacingMode(videoStream) {\n const videoTrack = videoStream.getVideoTracks()[0];\n if (!videoTrack) return null; // unknown\n // inspired by https://github.com/JodusNodus/react-qr-reader/blob/master/src/getDeviceId.js#L13\n return /rear|back|environment/i.test(videoTrack.label)\n ? 'environment'\n : /front|user|face/i.test(videoTrack.label)\n ? 'user'\n : null; // unknown\n }\n\n static _drawToCanvas(image, scanRegion=null, canvas=null, disallowCanvasResizing=false) {\n canvas = canvas || document.createElement('canvas');\n const scanRegionX = scanRegion && scanRegion.x? scanRegion.x : 0;\n const scanRegionY = scanRegion && scanRegion.y? scanRegion.y : 0;\n const scanRegionWidth = scanRegion && scanRegion.width? scanRegion.width : image.width || image.videoWidth;\n const scanRegionHeight = scanRegion && scanRegion.height? scanRegion.height : image.height || image.videoHeight;\n\n if (!disallowCanvasResizing) {\n const canvasWidth = scanRegion && scanRegion.downScaledWidth\n ? scanRegion.downScaledWidth\n : scanRegionWidth;\n const canvasHeight = scanRegion && scanRegion.downScaledHeight\n ? scanRegion.downScaledHeight\n : scanRegionHeight;\n // Setting the canvas width or height clears the canvas, even if the values didn't change, therefore only\n // set them if they actually changed.\n if (canvas.width !== canvasWidth) {\n canvas.width = canvasWidth;\n }\n if (canvas.height !== canvasHeight) {\n canvas.height = canvasHeight;\n }\n }\n\n const context = canvas.getContext('2d', { alpha: false });\n context.imageSmoothingEnabled = false; // gives less blurry images\n context.drawImage(\n image,\n scanRegionX, scanRegionY, scanRegionWidth, scanRegionHeight,\n 0, 0, canvas.width, canvas.height\n );\n return [canvas, context];\n }\n\n /* async */\n static _loadImage(imageOrFileOrBlobOrUrl) {\n if (imageOrFileOrBlobOrUrl instanceof HTMLCanvasElement || imageOrFileOrBlobOrUrl instanceof HTMLVideoElement\n || window.ImageBitmap && imageOrFileOrBlobOrUrl instanceof window.ImageBitmap\n || window.OffscreenCanvas && imageOrFileOrBlobOrUrl instanceof window.OffscreenCanvas) {\n return Promise.resolve(imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof Image) {\n return QrScanner._awaitImageLoad(imageOrFileOrBlobOrUrl).then(() => imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob\n || imageOrFileOrBlobOrUrl instanceof URL || typeof(imageOrFileOrBlobOrUrl)==='string') {\n const image = new Image();\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n image.src = URL.createObjectURL(imageOrFileOrBlobOrUrl);\n } else {\n image.src = imageOrFileOrBlobOrUrl;\n }\n return QrScanner._awaitImageLoad(image).then(() => {\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n URL.revokeObjectURL(image.src);\n }\n return image;\n });\n } else {\n return Promise.reject('Unsupported image type.');\n }\n }\n\n /* async */\n static _awaitImageLoad(image) {\n return new Promise((resolve, reject) => {\n if (image.complete && image.naturalWidth!==0) {\n // already loaded\n resolve();\n } else {\n let onLoad, onError;\n onLoad = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n resolve();\n };\n onError = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n reject('Image load error');\n };\n image.addEventListener('load', onLoad);\n image.addEventListener('error', onError);\n }\n });\n }\n\n /* async */\n static _postWorkerMessage(qrEngineOrQrEnginePromise, type, data) {\n return Promise.resolve(qrEngineOrQrEnginePromise).then((qrEngine) => {\n if (!(qrEngine instanceof Worker)) return;\n qrEngine.postMessage({ type, data });\n });\n }\n}\nQrScanner.DEFAULT_CANVAS_SIZE = 400;\nQrScanner.NO_QR_CODE_FOUND = 'No QR code found';\nQrScanner.WORKER_PATH = 'qr-scanner-worker.min.js';\n"],"names":["QrScanner","navigator","mediaDevices","enumerateDevices","then","devices","some","device","kind","catch","Promise","resolve","video","onDecode","canvasSizeOrOnDecodeError","_onDecodeError","canvasSizeOrCalculateScanRegion","_calculateScanRegion","preferredFacingMode","$video","$canvas","document","createElement","_onDecode","_legacyCanvasSize","DEFAULT_CANVAS_SIZE","_preferredFacingMode","_flashOn","_paused","_active","console","warn","_scanRegion","_onPlay","bind","_onLoadedMetaData","_onVisibilityChange","disablePictureInPicture","playsInline","muted","shouldHideVideo","hidden","body","contains","appendChild","requestAnimationFrame","computedStyle","display","style","setProperty","visibility","opacity","width","height","addEventListener","_qrEnginePromise","createQrEngine","window","track","getPhotoCapabilities","result","fillLightMode","includes","error","reject","_setFlash","removeEventListener","stop","_postWorkerMessage","location","protocol","clearTimeout","_offTimeout","srcObject","play","facingMode","_getCameraStream","stream","_getFacingMode","_setVideoMirror","e","pause","setTimeout","imageOrFileOrUrl","scanRegion","qrEngine","canvas","disallowCanvasResizing","alsoTryWithoutScanRegion","promise","all","_loadImage","engine","image","canvasContext","_drawToCanvas","Worker","gotExternalWorker","postMessage","type","data","timeout","onMessage","onError","event","NO_QR_CODE_FOUND","imageData","buffer","detect","scanResults","length","rawValue","message","finally","scanImage","red","green","blue","useIntegerApproximation","inversionMode","workerPath","WORKER_PATH","BarcodeDetector","getSupportedFormats","supportedFormats","indexOf","formats","_scanFrame","start","videoHeight","x","Math","round","videoWidth","scanRegionSize","y","downScaledWidth","downScaledHeight","paused","ended","readyState","log","exact","min","constraintsToTry","forEach","constraint","_getMatchingCameraStream","getUserMedia","shift","on","hasFlash","getVideoTracks","applyConstraints","advanced","torch","transform","videoStream","test","videoTrack","label","scanRegionWidth","scanRegionHeight","canvasWidth","canvasHeight","alpha","context","imageSmoothingEnabled","drawImage","scanRegionX","scanRegionY","imageOrFileOrBlobOrUrl","HTMLCanvasElement","HTMLVideoElement","ImageBitmap","OffscreenCanvas","Image","_awaitImageLoad","File","Blob","URL","src","createObjectURL","revokeObjectURL","complete","naturalWidth","onLoad","qrEngineOrQrEnginePromise"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"qr-scanner.min.js","sources":["src/qr-scanner.js"],"sourcesContent":["export default class QrScanner {\n /* async */\n static hasCamera() {\n return QrScanner.listCameras(false)\n .then(cameras => !!cameras.length)\n .catch(() => false);\n }\n\n /* async */\n static listCameras(requestLabels = false) {\n if (!navigator.mediaDevices) return Promise.resolve([]);\n\n // Note that enumerateDevices can always be called and does not prompt the user for permission.\n // However, enumerateDevices only includes device labels if served via https and an active media stream exists\n // or permission to access the camera was given. Therefore, ask for camera permission by opening a stream, if\n // labels were requested.\n let openedStream = null;\n return (requestLabels\n ? navigator.mediaDevices.getUserMedia({ audio: false, video: true })\n .then(stream => openedStream = stream)\n // Fail gracefully, especially if the device has no camera or on mobile when the camera is already in\n // use and some browsers disallow a second stream.\n .catch(() => {})\n : Promise.resolve()\n )\n .then(() => navigator.mediaDevices.enumerateDevices())\n .then(devices => devices.filter(device => device.kind === 'videoinput').map((device, i) => ({\n id: device.deviceId,\n label: device.label || (i === 0 ? 'Default Camera' : `Camera ${i + 1}`),\n })))\n .finally(() => {\n // close the stream we just opened for getting camera access for listing the device labels\n if (!openedStream) return;\n for (const track of openedStream.getTracks()) {\n track.stop();\n openedStream.removeTrack(track);\n }\n });\n }\n\n constructor(\n video,\n onDecode,\n canvasSizeOrOnDecodeError = this._onDecodeError,\n canvasSizeOrCalculateScanRegion = this._calculateScanRegion,\n preferredCamera = 'environment'\n ) {\n this.$video = video;\n this.$canvas = document.createElement('canvas');\n this._onDecode = onDecode;\n this._legacyCanvasSize = QrScanner.DEFAULT_CANVAS_SIZE;\n this._preferredCamera = preferredCamera;\n this._active = false;\n this._paused = false;\n this._flashOn = false;\n\n if (typeof canvasSizeOrOnDecodeError === 'number') {\n // legacy function signature where the third argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrOnDecodeError;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._onDecodeError = canvasSizeOrOnDecodeError;\n }\n\n if (typeof canvasSizeOrCalculateScanRegion === 'number') {\n // legacy function signature where the fourth argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrCalculateScanRegion;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._calculateScanRegion = canvasSizeOrCalculateScanRegion;\n }\n\n this._scanRegion = this._calculateScanRegion(video);\n\n this._onPlay = this._onPlay.bind(this);\n this._onLoadedMetaData = this._onLoadedMetaData.bind(this);\n this._onVisibilityChange = this._onVisibilityChange.bind(this);\n\n video.disablePictureInPicture = true;\n // Allow inline playback on iPhone instead of requiring full screen playback,\n // see https://webkit.org/blog/6784/new-video-policies-for-ios/\n video.playsInline = true;\n // Allow play() on iPhone without requiring a user gesture. Should not really be needed as camera stream\n // includes no audio, but just to be safe.\n video.muted = true;\n\n // Avoid Safari stopping the video stream on a hidden video.\n // See https://github.com/cozmo/jsQR/issues/185\n let shouldHideVideo = false;\n if (video.hidden) {\n video.hidden = false;\n shouldHideVideo = true;\n }\n if (!document.body.contains(video)) {\n document.body.appendChild(video);\n shouldHideVideo = true;\n }\n requestAnimationFrame(() => {\n // Checking in requestAnimationFrame which should avoid a potential additional re-flow for getComputedStyle.\n const computedStyle = window.getComputedStyle(video);\n if (computedStyle.display === 'none') {\n video.style.setProperty('display', 'block', 'important');\n shouldHideVideo = true;\n }\n if (computedStyle.visibility !== 'visible') {\n video.style.setProperty('visibility', 'visible', 'important');\n shouldHideVideo = true;\n }\n if (shouldHideVideo) {\n // Hide the video in a way that doesn't cause Safari to stop the playback.\n console.warn('QrScanner has overwritten the video hiding style to avoid Safari stopping the playback.');\n video.style.opacity = 0;\n video.style.width = 0;\n video.style.height = 0;\n }\n });\n\n video.addEventListener('play', this._onPlay);\n video.addEventListener('loadedmetadata', this._onLoadedMetaData);\n document.addEventListener('visibilitychange', this._onVisibilityChange);\n\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n\n /* async */\n hasFlash() {\n if (!('ImageCapture' in window)) {\n return Promise.resolve(false);\n }\n\n const track = this.$video.srcObject ? this.$video.srcObject.getVideoTracks()[0] : null;\n if (!track) {\n return Promise.reject('Camera not started or not available');\n }\n\n const imageCapture = new ImageCapture(track);\n return imageCapture.getPhotoCapabilities()\n .then((result) => {\n return result.fillLightMode.includes('flash');\n })\n .catch((error) => {\n console.warn(error);\n return false;\n });\n }\n\n isFlashOn() {\n return this._flashOn;\n }\n\n /* async */\n toggleFlash() {\n return this._setFlash(!this._flashOn);\n }\n\n /* async */\n turnFlashOff() {\n return this._setFlash(false);\n }\n\n /* async */\n turnFlashOn() {\n return this._setFlash(true);\n }\n\n destroy() {\n this.$video.removeEventListener('loadedmetadata', this._onLoadedMetaData);\n this.$video.removeEventListener('play', this._onPlay);\n document.removeEventListener('visibilitychange', this._onVisibilityChange);\n\n this.stop();\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'close');\n }\n\n /* async */\n start() {\n if (this._active && !this._paused) {\n return Promise.resolve();\n }\n if (window.location.protocol !== 'https:') {\n // warn but try starting the camera anyways\n console.warn('The camera stream is only accessible if the page is transferred via https.');\n }\n this._active = true;\n if (document.hidden) {\n // camera will be started as soon as tab is in foreground\n return Promise.resolve();\n }\n this._paused = false;\n if (this.$video.srcObject) {\n // camera stream already/still set\n this.$video.play();\n return Promise.resolve();\n }\n\n let facingModeGuess = this._preferredCamera === 'environment' || this._preferredCamera === 'user'\n ? this._preferredCamera\n : null;\n return this._getCameraStream(this._preferredCamera, true)\n .catch(() => {\n // If _preferredCamera was a facing mode, we (probably) don't have a camera of the requested facing mode\n // and switch our facing mode guess.\n facingModeGuess = facingModeGuess === 'environment'\n ? 'user' // switch as the requested facing mode was not available\n : 'environment'; // switch, or also assume 'environment' as default if facingModeGuess was null\n // Retry unconstrained. Throws if camera is not accessible (e.g. due to not https)\n return this._getCameraStream();\n })\n .then(stream => {\n // Try to determine the facing mode from the stream, otherwise use our guess or 'environment' as\n // default. Note that the guess is not always accurate as Safari returns cameras of different facing\n // mode, even for exact facingMode constraints.\n facingModeGuess = this._getFacingMode(stream) || facingModeGuess || 'environment';\n this.$video.srcObject = stream;\n this.$video.play();\n this._setVideoMirror(facingModeGuess);\n })\n .catch(e => {\n this._active = false;\n throw e;\n });\n }\n\n stop() {\n this.pause();\n this._active = false;\n }\n\n pause(stopStreamImmediately = false) {\n this._paused = true;\n if (!this._active) {\n return Promise.resolve(true);\n }\n this.$video.pause();\n\n const stopStream = () => {\n const tracks = this.$video.srcObject ? this.$video.srcObject.getTracks() : [];\n for (const track of tracks) {\n track.stop(); // note that this will also automatically turn the flashlight off\n this.$video.srcObject.removeTrack(track);\n }\n this.$video.srcObject = null;\n };\n\n if (stopStreamImmediately) {\n stopStream();\n return Promise.resolve(true);\n }\n\n return new Promise((resolve) => setTimeout(resolve, 300))\n .then(() => {\n if (!this._paused) return false;\n stopStream();\n return true;\n });\n }\n\n /* async */\n setCamera(facingModeOrDeviceId) {\n if (facingModeOrDeviceId === this._preferredCamera) return Promise.resolve();\n this._preferredCamera = facingModeOrDeviceId;\n // Restart the scanner with the new camera which will also update the video mirror and the scan region. Note\n // that we always pause the stream and not only if !this._paused as even if this._paused === true, the stream\n // might still be running, as it's by default only stopped after a delay of 300ms.\n const wasPaused = this._paused;\n return this.pause(true).then((paused) => {\n if (!paused || wasPaused || !this._active) return;\n return this.start();\n });\n }\n\n /* async */\n static scanImage(imageOrFileOrUrl, scanRegion=null, qrEngine=null, canvas=null, disallowCanvasResizing=false,\n alsoTryWithoutScanRegion=false) {\n const gotExternalWorker = qrEngine instanceof Worker;\n\n let promise = Promise.all([\n qrEngine || QrScanner.createQrEngine(),\n QrScanner._loadImage(imageOrFileOrUrl),\n ]).then(([engine, image]) => {\n qrEngine = engine;\n let canvasContext;\n [canvas, canvasContext] = this._drawToCanvas(image, scanRegion, canvas, disallowCanvasResizing);\n\n if (qrEngine instanceof Worker) {\n if (!gotExternalWorker) {\n // Enable scanning of inverted color qr codes. Not using _postWorkerMessage as it's async\n qrEngine.postMessage({ type: 'inversionMode', data: 'both' });\n }\n return new Promise((resolve, reject) => {\n let timeout, onMessage, onError;\n onMessage = event => {\n if (event.data.type !== 'qrResult') {\n return;\n }\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n if (event.data.data !== null) {\n resolve(event.data.data);\n } else {\n reject(QrScanner.NO_QR_CODE_FOUND);\n }\n };\n onError = (e) => {\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n const errorMessage = !e ? 'Unknown Error' : (e.message || e);\n reject('Scanner error: ' + errorMessage);\n };\n qrEngine.addEventListener('message', onMessage);\n qrEngine.addEventListener('error', onError);\n timeout = setTimeout(() => onError('timeout'), 10000);\n const imageData = canvasContext.getImageData(0, 0, canvas.width, canvas.height);\n qrEngine.postMessage({\n type: 'decode',\n data: imageData\n }, [imageData.data.buffer]);\n });\n } else {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => reject('Scanner error: timeout'), 10000);\n qrEngine.detect(canvas).then(scanResults => {\n if (!scanResults.length) {\n reject(QrScanner.NO_QR_CODE_FOUND);\n } else {\n resolve(scanResults[0].rawValue);\n }\n }).catch((e) => reject('Scanner error: ' + (e.message || e))).finally(() => clearTimeout(timeout));\n });\n }\n });\n\n if (scanRegion && alsoTryWithoutScanRegion) {\n promise = promise.catch(() =>\n QrScanner.scanImage(imageOrFileOrUrl, null, qrEngine, canvas, disallowCanvasResizing));\n }\n\n promise = promise.finally(() => {\n if (gotExternalWorker) return;\n QrScanner._postWorkerMessage(qrEngine, 'close');\n });\n\n return promise;\n }\n\n setGrayscaleWeights(red, green, blue, useIntegerApproximation = true) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations work also\n // well with colored qr codes.\n QrScanner._postWorkerMessage(\n this._qrEnginePromise,\n 'grayscaleWeights',\n { red, green, blue, useIntegerApproximation }\n );\n }\n\n setInversionMode(inversionMode) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations scan normal\n // and inverted qr codes by default\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'inversionMode', inversionMode);\n }\n\n /* async */\n static createQrEngine(workerPath = QrScanner.WORKER_PATH) {\n return ('BarcodeDetector' in window ? BarcodeDetector.getSupportedFormats() : Promise.resolve([]))\n .then((supportedFormats) => supportedFormats.indexOf('qr_code') !== -1\n ? new BarcodeDetector({ formats: ['qr_code'] })\n : new Worker(workerPath)\n );\n }\n\n _onPlay() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n this._scanFrame();\n }\n\n _onLoadedMetaData() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n }\n\n _onVisibilityChange() {\n if (document.hidden) {\n this.pause();\n } else if (this._active) {\n this.start();\n }\n }\n\n _calculateScanRegion(video) {\n // Default scan region calculation. Note that this can be overwritten in the constructor.\n const smallestDimension = Math.min(video.videoWidth, video.videoHeight);\n const scanRegionSize = Math.round(2 / 3 * smallestDimension);\n return {\n x: Math.round((video.videoWidth - scanRegionSize) / 2),\n y: Math.round((video.videoHeight - scanRegionSize) / 2),\n width: scanRegionSize,\n height: scanRegionSize,\n downScaledWidth: this._legacyCanvasSize,\n downScaledHeight: this._legacyCanvasSize,\n };\n }\n\n _scanFrame() {\n if (!this._active || this.$video.paused || this.$video.ended) return false;\n // using requestAnimationFrame to avoid scanning if tab is in background\n requestAnimationFrame(() => {\n if (this.$video.readyState <= 1) {\n // Skip scans until the video is ready as drawImage() only works correctly on a video with readyState\n // > 1, see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#Notes.\n // This also avoids false positives for videos paused after a successful scan which remains visible on\n // the canvas until the video is started again and ready.\n this._scanFrame();\n return;\n }\n this._qrEnginePromise\n .then((qrEngine) => QrScanner.scanImage(this.$video, this._scanRegion, qrEngine, this.$canvas))\n .then(this._onDecode, (error) => {\n if (!this._active) return;\n const errorMessage = error.message || error;\n if (errorMessage.indexOf('service unavailable') !== -1) {\n // When the native BarcodeDetector crashed, create a new one\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n this._onDecodeError(error);\n })\n .then(() => this._scanFrame());\n });\n }\n\n _onDecodeError(error) {\n // default error handler; can be overwritten in the constructor\n if (error === QrScanner.NO_QR_CODE_FOUND) return;\n console.log(error);\n }\n\n _getCameraStream(preferredCamera, exact = false) {\n const constraintsToTry = [{\n width: { min: 1024 }\n }, {\n width: { min: 768 }\n }, {}];\n\n if (preferredCamera) {\n const preferenceType = preferredCamera === 'environment' || preferredCamera === 'user'\n ? 'facingMode'\n : 'deviceId';\n if (exact) {\n preferredCamera = { exact: preferredCamera };\n }\n constraintsToTry.forEach(constraint => constraint[preferenceType] = preferredCamera);\n }\n\n return this._getMatchingCameraStream(constraintsToTry);\n }\n\n _getMatchingCameraStream(constraintsToTry) {\n if (!navigator.mediaDevices || constraintsToTry.length === 0) {\n return Promise.reject('Camera not found.');\n }\n return navigator.mediaDevices.getUserMedia({\n video: constraintsToTry.shift()\n }).catch(() => this._getMatchingCameraStream(constraintsToTry));\n }\n\n /* async */\n _setFlash(on) {\n return this.hasFlash().then((hasFlash) => {\n if (!hasFlash) return Promise.reject('No flash available');\n // Note that the video track is guaranteed to exist at this point\n return this.$video.srcObject.getVideoTracks()[0].applyConstraints({\n advanced: [{ torch: on }],\n });\n }).then(() => this._flashOn = on);\n }\n\n _setVideoMirror(facingMode) {\n // in user facing mode mirror the video to make it easier for the user to position the QR code\n const scaleFactor = facingMode==='user'? -1 : 1;\n this.$video.style.transform = 'scaleX(' + scaleFactor + ')';\n }\n\n _getFacingMode(videoStream) {\n const videoTrack = videoStream.getVideoTracks()[0];\n if (!videoTrack) return null; // unknown\n // inspired by https://github.com/JodusNodus/react-qr-reader/blob/master/src/getDeviceId.js#L13\n return /rear|back|environment/i.test(videoTrack.label)\n ? 'environment'\n : /front|user|face/i.test(videoTrack.label)\n ? 'user'\n : null; // unknown\n }\n\n static _drawToCanvas(image, scanRegion=null, canvas=null, disallowCanvasResizing=false) {\n canvas = canvas || document.createElement('canvas');\n const scanRegionX = scanRegion && scanRegion.x? scanRegion.x : 0;\n const scanRegionY = scanRegion && scanRegion.y? scanRegion.y : 0;\n const scanRegionWidth = scanRegion && scanRegion.width? scanRegion.width : image.width || image.videoWidth;\n const scanRegionHeight = scanRegion && scanRegion.height? scanRegion.height : image.height || image.videoHeight;\n\n if (!disallowCanvasResizing) {\n const canvasWidth = scanRegion && scanRegion.downScaledWidth\n ? scanRegion.downScaledWidth\n : scanRegionWidth;\n const canvasHeight = scanRegion && scanRegion.downScaledHeight\n ? scanRegion.downScaledHeight\n : scanRegionHeight;\n // Setting the canvas width or height clears the canvas, even if the values didn't change, therefore only\n // set them if they actually changed.\n if (canvas.width !== canvasWidth) {\n canvas.width = canvasWidth;\n }\n if (canvas.height !== canvasHeight) {\n canvas.height = canvasHeight;\n }\n }\n\n const context = canvas.getContext('2d', { alpha: false });\n context.imageSmoothingEnabled = false; // gives less blurry images\n context.drawImage(\n image,\n scanRegionX, scanRegionY, scanRegionWidth, scanRegionHeight,\n 0, 0, canvas.width, canvas.height\n );\n return [canvas, context];\n }\n\n /* async */\n static _loadImage(imageOrFileOrBlobOrUrl) {\n if (imageOrFileOrBlobOrUrl instanceof HTMLCanvasElement || imageOrFileOrBlobOrUrl instanceof HTMLVideoElement\n || window.ImageBitmap && imageOrFileOrBlobOrUrl instanceof window.ImageBitmap\n || window.OffscreenCanvas && imageOrFileOrBlobOrUrl instanceof window.OffscreenCanvas) {\n return Promise.resolve(imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof Image) {\n return QrScanner._awaitImageLoad(imageOrFileOrBlobOrUrl).then(() => imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob\n || imageOrFileOrBlobOrUrl instanceof URL || typeof(imageOrFileOrBlobOrUrl)==='string') {\n const image = new Image();\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n image.src = URL.createObjectURL(imageOrFileOrBlobOrUrl);\n } else {\n image.src = imageOrFileOrBlobOrUrl;\n }\n return QrScanner._awaitImageLoad(image).then(() => {\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n URL.revokeObjectURL(image.src);\n }\n return image;\n });\n } else {\n return Promise.reject('Unsupported image type.');\n }\n }\n\n /* async */\n static _awaitImageLoad(image) {\n return new Promise((resolve, reject) => {\n if (image.complete && image.naturalWidth!==0) {\n // already loaded\n resolve();\n } else {\n let onLoad, onError;\n onLoad = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n resolve();\n };\n onError = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n reject('Image load error');\n };\n image.addEventListener('load', onLoad);\n image.addEventListener('error', onError);\n }\n });\n }\n\n /* async */\n static _postWorkerMessage(qrEngineOrQrEnginePromise, type, data) {\n return Promise.resolve(qrEngineOrQrEnginePromise).then((qrEngine) => {\n if (!(qrEngine instanceof Worker)) return;\n qrEngine.postMessage({ type, data });\n });\n }\n}\nQrScanner.DEFAULT_CANVAS_SIZE = 400;\nQrScanner.NO_QR_CODE_FOUND = 'No QR code found';\nQrScanner.WORKER_PATH = 'qr-scanner-worker.min.js';\n"],"names":["QrScanner","listCameras","then","cameras","length","catch","requestLabels","navigator","mediaDevices","Promise","resolve","openedStream","getUserMedia","audio","video","stream","enumerateDevices","devices","filter","device","kind","map","i","id","deviceId","label","finally","track","stop","removeTrack","onDecode","canvasSizeOrOnDecodeError","_onDecodeError","canvasSizeOrCalculateScanRegion","_calculateScanRegion","preferredCamera","$video","$canvas","document","createElement","_onDecode","_legacyCanvasSize","DEFAULT_CANVAS_SIZE","_preferredCamera","_flashOn","_paused","_active","console","warn","_scanRegion","_onPlay","bind","_onLoadedMetaData","_onVisibilityChange","disablePictureInPicture","playsInline","muted","shouldHideVideo","hidden","body","contains","appendChild","requestAnimationFrame","computedStyle","display","style","setProperty","visibility","opacity","width","height","addEventListener","_qrEnginePromise","createQrEngine","window","getPhotoCapabilities","result","fillLightMode","includes","error","reject","_setFlash","removeEventListener","_postWorkerMessage","location","protocol","srcObject","play","facingModeGuess","_getCameraStream","_getFacingMode","_setVideoMirror","e","pause","stopStreamImmediately","tracks","getTracks","stopStream","setTimeout","facingModeOrDeviceId","paused","wasPaused","start","imageOrFileOrUrl","scanRegion","qrEngine","canvas","disallowCanvasResizing","alsoTryWithoutScanRegion","promise","all","_loadImage","engine","image","canvasContext","_drawToCanvas","Worker","gotExternalWorker","postMessage","type","data","timeout","onMessage","onError","event","clearTimeout","NO_QR_CODE_FOUND","imageData","buffer","detect","scanResults","rawValue","message","scanImage","red","green","blue","useIntegerApproximation","inversionMode","workerPath","WORKER_PATH","BarcodeDetector","getSupportedFormats","supportedFormats","indexOf","formats","_scanFrame","videoHeight","x","Math","round","videoWidth","scanRegionSize","y","downScaledWidth","downScaledHeight","ended","readyState","log","exact","min","constraintsToTry","forEach","constraint","preferenceType","_getMatchingCameraStream","shift","on","hasFlash","getVideoTracks","applyConstraints","advanced","torch","facingMode","transform","videoStream","test","videoTrack","scanRegionWidth","scanRegionHeight","canvasWidth","canvasHeight","alpha","context","imageSmoothingEnabled","drawImage","scanRegionX","scanRegionY","imageOrFileOrBlobOrUrl","HTMLCanvasElement","HTMLVideoElement","ImageBitmap","OffscreenCanvas","Image","_awaitImageLoad","File","Blob","URL","src","createObjectURL","revokeObjectURL","complete","naturalWidth","onLoad","qrEngineOrQrEnginePromise"],"mappings":"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"}
\ No newline at end of file
diff --git a/qr-scanner.umd.min.js b/qr-scanner.umd.min.js
index 57c2f86..1c0cdd1 100644
--- a/qr-scanner.umd.min.js
+++ b/qr-scanner.umd.min.js
@@ -1,19 +1,20 @@
-'use strict';(function(d,a){"object"===typeof exports&&"undefined"!==typeof module?module.exports=a():"function"===typeof define&&define.amd?define(a):(d=d||self,d.QrScanner=a())})(this,function(){class d{static hasCamera(){return navigator.mediaDevices?navigator.mediaDevices.enumerateDevices().then(a=>a.some(a=>"videoinput"===a.kind)).catch(()=>!1):Promise.resolve(!1)}constructor(a,b,c=this._onDecodeError,e=this._calculateScanRegion,k="environment"){this.$video=a;this.$canvas=document.createElement("canvas");
-this._onDecode=b;this._legacyCanvasSize=d.DEFAULT_CANVAS_SIZE;this._preferredFacingMode=k;this._flashOn=this._paused=this._active=!1;"number"===typeof c?(this._legacyCanvasSize=c,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._onDecodeError=c;"number"===typeof e?(this._legacyCanvasSize=e,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._calculateScanRegion=
-e;this._scanRegion=this._calculateScanRegion(a);this._onPlay=this._onPlay.bind(this);this._onLoadedMetaData=this._onLoadedMetaData.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);a.disablePictureInPicture=!0;a.playsInline=!0;a.muted=!0;let f=!1;a.hidden&&(a.hidden=!1,f=!0);document.body.contains(a)||(document.body.appendChild(a),f=!0);requestAnimationFrame(()=>{let b=window.getComputedStyle(a);"none"===b.display&&(a.style.setProperty("display","block","important"),f=!0);"visible"!==
-b.visibility&&(a.style.setProperty("visibility","visible","important"),f=!0);f&&(console.warn("QrScanner has overwritten the video hiding style to avoid Safari stopping the playback."),a.style.opacity=0,a.style.width=0,a.style.height=0)});a.addEventListener("play",this._onPlay);a.addEventListener("loadedmetadata",this._onLoadedMetaData);document.addEventListener("visibilitychange",this._onVisibilityChange);this._qrEnginePromise=d.createQrEngine()}hasFlash(){if(!("ImageCapture"in window))return Promise.resolve(!1);
-let a=this.$video.srcObject?this.$video.srcObject.getVideoTracks()[0]:null;return a?(new ImageCapture(a)).getPhotoCapabilities().then(a=>a.fillLightMode.includes("flash")).catch(a=>{console.warn(a);return!1}):Promise.reject("Camera not started or not available")}isFlashOn(){return this._flashOn}toggleFlash(){return this._setFlash(!this._flashOn)}turnFlashOff(){return this._setFlash(!1)}turnFlashOn(){return this._setFlash(!0)}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData);
-this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);this.stop();d._postWorkerMessage(this._qrEnginePromise,"close")}start(){if(this._active&&!this._paused)return Promise.resolve();"https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https.");this._active=!0;this._paused=!1;if(document.hidden)return Promise.resolve();clearTimeout(this._offTimeout);this._offTimeout=
-null;if(this.$video.srcObject)return this.$video.play(),Promise.resolve();let a=this._preferredFacingMode;return this._getCameraStream(a,!0).catch(()=>{a="environment"===a?"user":"environment";return this._getCameraStream()}).then(b=>{a=this._getFacingMode(b)||a;this.$video.srcObject=b;this.$video.play();this._setVideoMirror(a)}).catch(a=>{this._active=!1;throw a;})}stop(){this.pause();this._active=!1}pause(){this._paused=!0;this._active&&(this.$video.pause(),this._offTimeout||(this._offTimeout=setTimeout(()=>
-{let a=this.$video.srcObject?this.$video.srcObject.getTracks():[];for(let b of a)b.stop();this._offTimeout=this.$video.srcObject=null},300)))}static scanImage(a,b=null,c=null,e=null,k=!1,f=!1){let g=c instanceof Worker,h=Promise.all([c||d.createQrEngine(),d._loadImage(a)]).then(([a,f])=>{c=a;let h;[e,h]=this._drawToCanvas(f,b,e,k);return c instanceof Worker?(g||c.postMessage({type:"inversionMode",data:"both"}),new Promise((a,b)=>{let k,f,g;f=e=>{"qrResult"===e.data.type&&(c.removeEventListener("message",
-f),c.removeEventListener("error",g),clearTimeout(k),null!==e.data.data?a(e.data.data):b(d.NO_QR_CODE_FOUND))};g=a=>{c.removeEventListener("message",f);c.removeEventListener("error",g);clearTimeout(k);b("Scanner error: "+(a?a.message||a:"Unknown Error"))};c.addEventListener("message",f);c.addEventListener("error",g);k=setTimeout(()=>g("timeout"),1E4);let l=h.getImageData(0,0,e.width,e.height);c.postMessage({type:"decode",data:l},[l.data.buffer])})):new Promise((a,b)=>{let f=setTimeout(()=>b("Scanner error: timeout"),
-1E4);c.detect(e).then(c=>{c.length?a(c[0].rawValue):b(d.NO_QR_CODE_FOUND)}).catch(a=>b("Scanner error: "+(a.message||a))).finally(()=>clearTimeout(f))})});b&&f&&(h=h.catch(()=>d.scanImage(a,null,c,e,k)));return h=h.finally(()=>{g||d._postWorkerMessage(c,"close")})}setGrayscaleWeights(a,b,c,e=!0){d._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:c,useIntegerApproximation:e})}setInversionMode(a){d._postWorkerMessage(this._qrEnginePromise,"inversionMode",a)}static createQrEngine(a=
-d.WORKER_PATH){return("BarcodeDetector"in window?BarcodeDetector.getSupportedFormats():Promise.resolve([])).then(b=>-1!==b.indexOf("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a))}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video)}_onVisibilityChange(){document.hidden?this.pause():this._active&&this.start()}_calculateScanRegion(a){let b=Math.round(2/3*Math.min(a.videoWidth,
-a.videoHeight));return{x:Math.round((a.videoWidth-b)/2),y:Math.round((a.videoHeight-b)/2),width:b,height:b,downScaledWidth:this._legacyCanvasSize,downScaledHeight:this._legacyCanvasSize}}_scanFrame(){if(!this._active||this.$video.paused||this.$video.ended)return!1;requestAnimationFrame(()=>{1>=this.$video.readyState?this._scanFrame():this._qrEnginePromise.then(a=>d.scanImage(this.$video,this._scanRegion,a,this.$canvas)).then(this._onDecode,a=>{this._active&&(-1!==(a.message||a).indexOf("service unavailable")&&
-(this._qrEnginePromise=d.createQrEngine()),this._onDecodeError(a))}).then(()=>this._scanFrame())})}_onDecodeError(a){a!==d.NO_QR_CODE_FOUND&&console.log(a)}_getCameraStream(a,b=!1){let c=[{width:{min:1024}},{width:{min:768}},{}];a&&(b&&(a={exact:a}),c.forEach(b=>b.facingMode=a));return this._getMatchingCameraStream(c)}_getMatchingCameraStream(a){return navigator.mediaDevices&&0!==a.length?navigator.mediaDevices.getUserMedia({video:a.shift()}).catch(()=>this._getMatchingCameraStream(a)):Promise.reject("Camera not found.")}_setFlash(a){return this.hasFlash().then(b=>
-b?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:a}]}):Promise.reject("No flash available")).then(()=>this._flashOn=a)}_setVideoMirror(a){this.$video.style.transform="scaleX("+("user"===a?-1:1)+")"}_getFacingMode(a){return(a=a.getVideoTracks()[0])?/rear|back|environment/i.test(a.label)?"environment":/front|user|face/i.test(a.label)?"user":null:null}static _drawToCanvas(a,b=null,c=null,e=!1){c=c||document.createElement("canvas");let d=b&&b.x?b.x:0,f=b&&b.y?b.y:0,g=b&&
-b.width?b.width:a.width||a.videoWidth,h=b&&b.height?b.height:a.height||a.videoHeight;e||(e=b&&b.downScaledWidth?b.downScaledWidth:g,b=b&&b.downScaledHeight?b.downScaledHeight:h,c.width!==e&&(c.width=e),c.height!==b&&(c.height=b));b=c.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,d,f,g,h,0,0,c.width,c.height);return[c,b]}static _loadImage(a){if(a instanceof HTMLCanvasElement||a instanceof HTMLVideoElement||window.ImageBitmap&&a instanceof window.ImageBitmap||window.OffscreenCanvas&&
-a instanceof window.OffscreenCanvas)return Promise.resolve(a);if(a instanceof Image)return d._awaitImageLoad(a).then(()=>a);if(a instanceof File||a instanceof Blob||a instanceof URL||"string"===typeof a){let b=new Image;b.src=a instanceof File||a instanceof Blob?URL.createObjectURL(a):a;return d._awaitImageLoad(b).then(()=>{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src);return b})}return Promise.reject("Unsupported image type.")}static _awaitImageLoad(a){return new Promise((b,
-c)=>{if(a.complete&&0!==a.naturalWidth)b();else{let e,d;e=()=>{a.removeEventListener("load",e);a.removeEventListener("error",d);b()};d=()=>{a.removeEventListener("load",e);a.removeEventListener("error",d);c("Image load error")};a.addEventListener("load",e);a.addEventListener("error",d)}})}static _postWorkerMessage(a,b,c){return Promise.resolve(a).then(a=>{a instanceof Worker&&a.postMessage({type:b,data:c})})}}d.DEFAULT_CANVAS_SIZE=400;d.NO_QR_CODE_FOUND="No QR code found";d.WORKER_PATH="qr-scanner-worker.min.js";
-return d})
+'use strict';(function(d,a){"object"===typeof exports&&"undefined"!==typeof module?module.exports=a():"function"===typeof define&&define.amd?define(a):(d=d||self,d.QrScanner=a())})(this,function(){class d{static hasCamera(){return d.listCameras(!1).then(a=>!!a.length).catch(()=>!1)}static listCameras(a=!1){if(!navigator.mediaDevices)return Promise.resolve([]);let b=null;return(a?navigator.mediaDevices.getUserMedia({audio:!1,video:!0}).then(a=>b=a).catch(()=>{}):Promise.resolve()).then(()=>navigator.mediaDevices.enumerateDevices()).then(a=>
+a.filter(a=>"videoinput"===a.kind).map((a,b)=>({id:a.deviceId,label:a.label||(0===b?"Default Camera":`Camera ${b+1}`)}))).finally(()=>{if(b)for(let a of b.getTracks())a.stop(),b.removeTrack(a)})}constructor(a,b,c=this._onDecodeError,e=this._calculateScanRegion,h="environment"){this.$video=a;this.$canvas=document.createElement("canvas");this._onDecode=b;this._legacyCanvasSize=d.DEFAULT_CANVAS_SIZE;this._preferredCamera=h;this._flashOn=this._paused=this._active=!1;"number"===typeof c?(this._legacyCanvasSize=
+c,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._onDecodeError=c;"number"===typeof e?(this._legacyCanvasSize=e,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._calculateScanRegion=e;this._scanRegion=this._calculateScanRegion(a);this._onPlay=this._onPlay.bind(this);this._onLoadedMetaData=this._onLoadedMetaData.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);
+a.disablePictureInPicture=!0;a.playsInline=!0;a.muted=!0;let f=!1;a.hidden&&(a.hidden=!1,f=!0);document.body.contains(a)||(document.body.appendChild(a),f=!0);requestAnimationFrame(()=>{let b=window.getComputedStyle(a);"none"===b.display&&(a.style.setProperty("display","block","important"),f=!0);"visible"!==b.visibility&&(a.style.setProperty("visibility","visible","important"),f=!0);f&&(console.warn("QrScanner has overwritten the video hiding style to avoid Safari stopping the playback."),a.style.opacity=
+0,a.style.width=0,a.style.height=0)});a.addEventListener("play",this._onPlay);a.addEventListener("loadedmetadata",this._onLoadedMetaData);document.addEventListener("visibilitychange",this._onVisibilityChange);this._qrEnginePromise=d.createQrEngine()}hasFlash(){if(!("ImageCapture"in window))return Promise.resolve(!1);let a=this.$video.srcObject?this.$video.srcObject.getVideoTracks()[0]:null;return a?(new ImageCapture(a)).getPhotoCapabilities().then(a=>a.fillLightMode.includes("flash")).catch(a=>{console.warn(a);
+return!1}):Promise.reject("Camera not started or not available")}isFlashOn(){return this._flashOn}toggleFlash(){return this._setFlash(!this._flashOn)}turnFlashOff(){return this._setFlash(!1)}turnFlashOn(){return this._setFlash(!0)}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);this.stop();d._postWorkerMessage(this._qrEnginePromise,"close")}start(){if(this._active&&
+!this._paused)return Promise.resolve();"https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https.");this._active=!0;if(document.hidden)return Promise.resolve();this._paused=!1;if(this.$video.srcObject)return this.$video.play(),Promise.resolve();let a="environment"===this._preferredCamera||"user"===this._preferredCamera?this._preferredCamera:null;return this._getCameraStream(this._preferredCamera,!0).catch(()=>{a="environment"===a?
+"user":"environment";return this._getCameraStream()}).then(b=>{a=this._getFacingMode(b)||a||"environment";this.$video.srcObject=b;this.$video.play();this._setVideoMirror(a)}).catch(a=>{this._active=!1;throw a;})}stop(){this.pause();this._active=!1}pause(a=!1){this._paused=!0;if(!this._active)return Promise.resolve(!0);this.$video.pause();let b=()=>{const a=this.$video.srcObject?this.$video.srcObject.getTracks():[];for(const b of a)b.stop(),this.$video.srcObject.removeTrack(b);this.$video.srcObject=
+null};return a?(b(),Promise.resolve(!0)):(new Promise(a=>setTimeout(a,300))).then(()=>{if(!this._paused)return!1;b();return!0})}setCamera(a){if(a===this._preferredCamera)return Promise.resolve();this._preferredCamera=a;let b=this._paused;return this.pause(!0).then(a=>{if(a&&!b&&this._active)return this.start()})}static scanImage(a,b=null,c=null,e=null,h=!1,f=!1){let g=c instanceof Worker,k=Promise.all([c||d.createQrEngine(),d._loadImage(a)]).then(([a,f])=>{c=a;let k;[e,k]=this._drawToCanvas(f,b,e,
+h);return c instanceof Worker?(g||c.postMessage({type:"inversionMode",data:"both"}),new Promise((a,b)=>{let h,f,g;f=e=>{"qrResult"===e.data.type&&(c.removeEventListener("message",f),c.removeEventListener("error",g),clearTimeout(h),null!==e.data.data?a(e.data.data):b(d.NO_QR_CODE_FOUND))};g=a=>{c.removeEventListener("message",f);c.removeEventListener("error",g);clearTimeout(h);b("Scanner error: "+(a?a.message||a:"Unknown Error"))};c.addEventListener("message",f);c.addEventListener("error",g);h=setTimeout(()=>
+g("timeout"),1E4);let l=k.getImageData(0,0,e.width,e.height);c.postMessage({type:"decode",data:l},[l.data.buffer])})):new Promise((a,b)=>{let h=setTimeout(()=>b("Scanner error: timeout"),1E4);c.detect(e).then(c=>{c.length?a(c[0].rawValue):b(d.NO_QR_CODE_FOUND)}).catch(a=>b("Scanner error: "+(a.message||a))).finally(()=>clearTimeout(h))})});b&&f&&(k=k.catch(()=>d.scanImage(a,null,c,e,h)));return k=k.finally(()=>{g||d._postWorkerMessage(c,"close")})}setGrayscaleWeights(a,b,c,e=!0){d._postWorkerMessage(this._qrEnginePromise,
+"grayscaleWeights",{red:a,green:b,blue:c,useIntegerApproximation:e})}setInversionMode(a){d._postWorkerMessage(this._qrEnginePromise,"inversionMode",a)}static createQrEngine(a=d.WORKER_PATH){return("BarcodeDetector"in window?BarcodeDetector.getSupportedFormats():Promise.resolve([])).then(b=>-1!==b.indexOf("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a))}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video)}_onVisibilityChange(){document.hidden?
+this.pause():this._active&&this.start()}_calculateScanRegion(a){let b=Math.round(2/3*Math.min(a.videoWidth,a.videoHeight));return{x:Math.round((a.videoWidth-b)/2),y:Math.round((a.videoHeight-b)/2),width:b,height:b,downScaledWidth:this._legacyCanvasSize,downScaledHeight:this._legacyCanvasSize}}_scanFrame(){if(!this._active||this.$video.paused||this.$video.ended)return!1;requestAnimationFrame(()=>{1>=this.$video.readyState?this._scanFrame():this._qrEnginePromise.then(a=>d.scanImage(this.$video,this._scanRegion,
+a,this.$canvas)).then(this._onDecode,a=>{this._active&&(-1!==(a.message||a).indexOf("service unavailable")&&(this._qrEnginePromise=d.createQrEngine()),this._onDecodeError(a))}).then(()=>this._scanFrame())})}_onDecodeError(a){a!==d.NO_QR_CODE_FOUND&&console.log(a)}_getCameraStream(a,b=!1){let c=[{width:{min:1024}},{width:{min:768}},{}];if(a){let e="environment"===a||"user"===a?"facingMode":"deviceId";b&&(a={exact:a});c.forEach(b=>b[e]=a)}return this._getMatchingCameraStream(c)}_getMatchingCameraStream(a){return navigator.mediaDevices&&
+0!==a.length?navigator.mediaDevices.getUserMedia({video:a.shift()}).catch(()=>this._getMatchingCameraStream(a)):Promise.reject("Camera not found.")}_setFlash(a){return this.hasFlash().then(b=>b?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:a}]}):Promise.reject("No flash available")).then(()=>this._flashOn=a)}_setVideoMirror(a){this.$video.style.transform="scaleX("+("user"===a?-1:1)+")"}_getFacingMode(a){return(a=a.getVideoTracks()[0])?/rear|back|environment/i.test(a.label)?
+"environment":/front|user|face/i.test(a.label)?"user":null:null}static _drawToCanvas(a,b=null,c=null,e=!1){c=c||document.createElement("canvas");let d=b&&b.x?b.x:0,f=b&&b.y?b.y:0,g=b&&b.width?b.width:a.width||a.videoWidth,k=b&&b.height?b.height:a.height||a.videoHeight;e||(e=b&&b.downScaledWidth?b.downScaledWidth:g,b=b&&b.downScaledHeight?b.downScaledHeight:k,c.width!==e&&(c.width=e),c.height!==b&&(c.height=b));b=c.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,d,f,g,k,0,0,c.width,
+c.height);return[c,b]}static _loadImage(a){if(a instanceof HTMLCanvasElement||a instanceof HTMLVideoElement||window.ImageBitmap&&a instanceof window.ImageBitmap||window.OffscreenCanvas&&a instanceof window.OffscreenCanvas)return Promise.resolve(a);if(a instanceof Image)return d._awaitImageLoad(a).then(()=>a);if(a instanceof File||a instanceof Blob||a instanceof URL||"string"===typeof a){let b=new Image;b.src=a instanceof File||a instanceof Blob?URL.createObjectURL(a):a;return d._awaitImageLoad(b).then(()=>
+{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src);return b})}return Promise.reject("Unsupported image type.")}static _awaitImageLoad(a){return new Promise((b,c)=>{if(a.complete&&0!==a.naturalWidth)b();else{let e,d;e=()=>{a.removeEventListener("load",e);a.removeEventListener("error",d);b()};d=()=>{a.removeEventListener("load",e);a.removeEventListener("error",d);c("Image load error")};a.addEventListener("load",e);a.addEventListener("error",d)}})}static _postWorkerMessage(a,b,c){return Promise.resolve(a).then(a=>
+{a instanceof Worker&&a.postMessage({type:b,data:c})})}}d.DEFAULT_CANVAS_SIZE=400;d.NO_QR_CODE_FOUND="No QR code found";d.WORKER_PATH="qr-scanner-worker.min.js";return d})
//# sourceMappingURL=qr-scanner.umd.min.js.map
diff --git a/qr-scanner.umd.min.js.map b/qr-scanner.umd.min.js.map
index 24675ac..b2d19b7 100644
--- a/qr-scanner.umd.min.js.map
+++ b/qr-scanner.umd.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"qr-scanner.umd.min.js","sources":["src/qr-scanner.js"],"sourcesContent":["export default class QrScanner {\n /* async */\n static hasCamera() {\n if (!navigator.mediaDevices) return Promise.resolve(false);\n // note that enumerateDevices can always be called and does not prompt the user for permission. However, device\n // labels are only readable if served via https and an active media stream exists or permanent permission is\n // given. That doesn't matter for us though as we don't require labels.\n return navigator.mediaDevices.enumerateDevices()\n .then(devices => devices.some(device => device.kind === 'videoinput'))\n .catch(() => false);\n }\n\n constructor(\n video,\n onDecode,\n canvasSizeOrOnDecodeError = this._onDecodeError,\n canvasSizeOrCalculateScanRegion = this._calculateScanRegion,\n preferredFacingMode = 'environment'\n ) {\n this.$video = video;\n this.$canvas = document.createElement('canvas');\n this._onDecode = onDecode;\n this._legacyCanvasSize = QrScanner.DEFAULT_CANVAS_SIZE;\n this._preferredFacingMode = preferredFacingMode;\n this._active = false;\n this._paused = false;\n this._flashOn = false;\n\n if (typeof canvasSizeOrOnDecodeError === 'number') {\n // legacy function signature where the third argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrOnDecodeError;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._onDecodeError = canvasSizeOrOnDecodeError;\n }\n\n if (typeof canvasSizeOrCalculateScanRegion === 'number') {\n // legacy function signature where the fourth argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrCalculateScanRegion;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._calculateScanRegion = canvasSizeOrCalculateScanRegion;\n }\n\n this._scanRegion = this._calculateScanRegion(video);\n\n this._onPlay = this._onPlay.bind(this);\n this._onLoadedMetaData = this._onLoadedMetaData.bind(this);\n this._onVisibilityChange = this._onVisibilityChange.bind(this);\n\n video.disablePictureInPicture = true;\n // Allow inline playback on iPhone instead of requiring full screen playback,\n // see https://webkit.org/blog/6784/new-video-policies-for-ios/\n video.playsInline = true;\n // Allow play() on iPhone without requiring a user gesture. Should not really be needed as camera stream\n // includes no audio, but just to be safe.\n video.muted = true;\n\n // Avoid Safari stopping the video stream on a hidden video.\n // See https://github.com/cozmo/jsQR/issues/185\n let shouldHideVideo = false;\n if (video.hidden) {\n video.hidden = false;\n shouldHideVideo = true;\n }\n if (!document.body.contains(video)) {\n document.body.appendChild(video);\n shouldHideVideo = true;\n }\n requestAnimationFrame(() => {\n // Checking in requestAnimationFrame which should avoid a potential additional re-flow for getComputedStyle.\n const computedStyle = window.getComputedStyle(video);\n if (computedStyle.display === 'none') {\n video.style.setProperty('display', 'block', 'important');\n shouldHideVideo = true;\n }\n if (computedStyle.visibility !== 'visible') {\n video.style.setProperty('visibility', 'visible', 'important');\n shouldHideVideo = true;\n }\n if (shouldHideVideo) {\n // Hide the video in a way that doesn't cause Safari to stop the playback.\n console.warn('QrScanner has overwritten the video hiding style to avoid Safari stopping the playback.');\n video.style.opacity = 0;\n video.style.width = 0;\n video.style.height = 0;\n }\n });\n\n video.addEventListener('play', this._onPlay);\n video.addEventListener('loadedmetadata', this._onLoadedMetaData);\n document.addEventListener('visibilitychange', this._onVisibilityChange);\n\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n\n /* async */\n hasFlash() {\n if (!('ImageCapture' in window)) {\n return Promise.resolve(false);\n }\n\n const track = this.$video.srcObject ? this.$video.srcObject.getVideoTracks()[0] : null;\n if (!track) {\n return Promise.reject('Camera not started or not available');\n }\n\n const imageCapture = new ImageCapture(track);\n return imageCapture.getPhotoCapabilities()\n .then((result) => {\n return result.fillLightMode.includes('flash');\n })\n .catch((error) => {\n console.warn(error);\n return false;\n });\n }\n\n isFlashOn() {\n return this._flashOn;\n }\n\n /* async */\n toggleFlash() {\n return this._setFlash(!this._flashOn);\n }\n\n /* async */\n turnFlashOff() {\n return this._setFlash(false);\n }\n\n /* async */\n turnFlashOn() {\n return this._setFlash(true);\n }\n\n destroy() {\n this.$video.removeEventListener('loadedmetadata', this._onLoadedMetaData);\n this.$video.removeEventListener('play', this._onPlay);\n document.removeEventListener('visibilitychange', this._onVisibilityChange);\n\n this.stop();\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'close');\n }\n\n /* async */\n start() {\n if (this._active && !this._paused) {\n return Promise.resolve();\n }\n if (window.location.protocol !== 'https:') {\n // warn but try starting the camera anyways\n console.warn('The camera stream is only accessible if the page is transferred via https.');\n }\n this._active = true;\n this._paused = false;\n if (document.hidden) {\n // camera will be started as soon as tab is in foreground\n return Promise.resolve();\n }\n clearTimeout(this._offTimeout);\n this._offTimeout = null;\n if (this.$video.srcObject) {\n // camera stream already/still set\n this.$video.play();\n return Promise.resolve();\n }\n\n let facingMode = this._preferredFacingMode;\n return this._getCameraStream(facingMode, true)\n .catch(() => {\n // We (probably) don't have a camera of the requested facing mode\n facingMode = facingMode === 'environment' ? 'user' : 'environment';\n return this._getCameraStream(); // throws if camera is not accessible (e.g. due to not https)\n })\n .then(stream => {\n // Try to determine the facing mode from the stream, otherwise use our guess. Note that the guess is not\n // always accurate as Safari returns cameras of different facing mode, even for exact constraints.\n facingMode = this._getFacingMode(stream) || facingMode;\n this.$video.srcObject = stream;\n this.$video.play();\n this._setVideoMirror(facingMode);\n })\n .catch(e => {\n this._active = false;\n throw e;\n });\n }\n\n stop() {\n this.pause();\n this._active = false;\n }\n\n pause() {\n this._paused = true;\n if (!this._active) {\n return;\n }\n this.$video.pause();\n if (this._offTimeout) {\n return;\n }\n this._offTimeout = setTimeout(() => {\n const tracks = this.$video.srcObject ? this.$video.srcObject.getTracks() : [];\n for (const track of tracks) {\n track.stop(); // note that this will also automatically turn the flashlight off\n }\n this.$video.srcObject = null;\n this._offTimeout = null;\n }, 300);\n }\n\n /* async */\n static scanImage(imageOrFileOrUrl, scanRegion=null, qrEngine=null, canvas=null, disallowCanvasResizing=false,\n alsoTryWithoutScanRegion=false) {\n const gotExternalWorker = qrEngine instanceof Worker;\n\n let promise = Promise.all([\n qrEngine || QrScanner.createQrEngine(),\n QrScanner._loadImage(imageOrFileOrUrl),\n ]).then(([engine, image]) => {\n qrEngine = engine;\n let canvasContext;\n [canvas, canvasContext] = this._drawToCanvas(image, scanRegion, canvas, disallowCanvasResizing);\n\n if (qrEngine instanceof Worker) {\n if (!gotExternalWorker) {\n // Enable scanning of inverted color qr codes. Not using _postWorkerMessage as it's async\n qrEngine.postMessage({ type: 'inversionMode', data: 'both' });\n }\n return new Promise((resolve, reject) => {\n let timeout, onMessage, onError;\n onMessage = event => {\n if (event.data.type !== 'qrResult') {\n return;\n }\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n if (event.data.data !== null) {\n resolve(event.data.data);\n } else {\n reject(QrScanner.NO_QR_CODE_FOUND);\n }\n };\n onError = (e) => {\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n const errorMessage = !e ? 'Unknown Error' : (e.message || e);\n reject('Scanner error: ' + errorMessage);\n };\n qrEngine.addEventListener('message', onMessage);\n qrEngine.addEventListener('error', onError);\n timeout = setTimeout(() => onError('timeout'), 10000);\n const imageData = canvasContext.getImageData(0, 0, canvas.width, canvas.height);\n qrEngine.postMessage({\n type: 'decode',\n data: imageData\n }, [imageData.data.buffer]);\n });\n } else {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => reject('Scanner error: timeout'), 10000);\n qrEngine.detect(canvas).then(scanResults => {\n if (!scanResults.length) {\n reject(QrScanner.NO_QR_CODE_FOUND);\n } else {\n resolve(scanResults[0].rawValue);\n }\n }).catch((e) => reject('Scanner error: ' + (e.message || e))).finally(() => clearTimeout(timeout));\n });\n }\n });\n\n if (scanRegion && alsoTryWithoutScanRegion) {\n promise = promise.catch(() =>\n QrScanner.scanImage(imageOrFileOrUrl, null, qrEngine, canvas, disallowCanvasResizing));\n }\n\n promise = promise.finally(() => {\n if (gotExternalWorker) return;\n QrScanner._postWorkerMessage(qrEngine, 'close');\n });\n\n return promise;\n }\n\n setGrayscaleWeights(red, green, blue, useIntegerApproximation = true) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations work also\n // well with colored qr codes.\n QrScanner._postWorkerMessage(\n this._qrEnginePromise,\n 'grayscaleWeights',\n { red, green, blue, useIntegerApproximation }\n );\n }\n\n setInversionMode(inversionMode) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations scan normal\n // and inverted qr codes by default\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'inversionMode', inversionMode);\n }\n\n /* async */\n static createQrEngine(workerPath = QrScanner.WORKER_PATH) {\n return ('BarcodeDetector' in window ? BarcodeDetector.getSupportedFormats() : Promise.resolve([]))\n .then((supportedFormats) => supportedFormats.indexOf('qr_code') !== -1\n ? new BarcodeDetector({ formats: ['qr_code'] })\n : new Worker(workerPath)\n );\n }\n\n _onPlay() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n this._scanFrame();\n }\n\n _onLoadedMetaData() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n }\n\n _onVisibilityChange() {\n if (document.hidden) {\n this.pause();\n } else if (this._active) {\n this.start();\n }\n }\n\n _calculateScanRegion(video) {\n // Default scan region calculation. Note that this can be overwritten in the constructor.\n const smallestDimension = Math.min(video.videoWidth, video.videoHeight);\n const scanRegionSize = Math.round(2 / 3 * smallestDimension);\n return {\n x: Math.round((video.videoWidth - scanRegionSize) / 2),\n y: Math.round((video.videoHeight - scanRegionSize) / 2),\n width: scanRegionSize,\n height: scanRegionSize,\n downScaledWidth: this._legacyCanvasSize,\n downScaledHeight: this._legacyCanvasSize,\n };\n }\n\n _scanFrame() {\n if (!this._active || this.$video.paused || this.$video.ended) return false;\n // using requestAnimationFrame to avoid scanning if tab is in background\n requestAnimationFrame(() => {\n if (this.$video.readyState <= 1) {\n // Skip scans until the video is ready as drawImage() only works correctly on a video with readyState\n // > 1, see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#Notes.\n // This also avoids false positives for videos paused after a successful scan which remains visible on\n // the canvas until the video is started again and ready.\n this._scanFrame();\n return;\n }\n this._qrEnginePromise\n .then((qrEngine) => QrScanner.scanImage(this.$video, this._scanRegion, qrEngine, this.$canvas))\n .then(this._onDecode, (error) => {\n if (!this._active) return;\n const errorMessage = error.message || error;\n if (errorMessage.indexOf('service unavailable') !== -1) {\n // When the native BarcodeDetector crashed, create a new one\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n this._onDecodeError(error);\n })\n .then(() => this._scanFrame());\n });\n }\n\n _onDecodeError(error) {\n // default error handler; can be overwritten in the constructor\n if (error === QrScanner.NO_QR_CODE_FOUND) return;\n console.log(error);\n }\n\n _getCameraStream(facingMode, exact = false) {\n const constraintsToTry = [{\n width: { min: 1024 }\n }, {\n width: { min: 768 }\n }, {}];\n\n if (facingMode) {\n if (exact) {\n facingMode = { exact: facingMode };\n }\n constraintsToTry.forEach(constraint => constraint.facingMode = facingMode);\n }\n return this._getMatchingCameraStream(constraintsToTry);\n }\n\n _getMatchingCameraStream(constraintsToTry) {\n if (!navigator.mediaDevices || constraintsToTry.length === 0) {\n return Promise.reject('Camera not found.');\n }\n return navigator.mediaDevices.getUserMedia({\n video: constraintsToTry.shift()\n }).catch(() => this._getMatchingCameraStream(constraintsToTry));\n }\n\n /* async */\n _setFlash(on) {\n return this.hasFlash().then((hasFlash) => {\n if (!hasFlash) return Promise.reject('No flash available');\n // Note that the video track is guaranteed to exist at this point\n return this.$video.srcObject.getVideoTracks()[0].applyConstraints({\n advanced: [{ torch: on }],\n });\n }).then(() => this._flashOn = on);\n }\n\n _setVideoMirror(facingMode) {\n // in user facing mode mirror the video to make it easier for the user to position the QR code\n const scaleFactor = facingMode==='user'? -1 : 1;\n this.$video.style.transform = 'scaleX(' + scaleFactor + ')';\n }\n\n _getFacingMode(videoStream) {\n const videoTrack = videoStream.getVideoTracks()[0];\n if (!videoTrack) return null; // unknown\n // inspired by https://github.com/JodusNodus/react-qr-reader/blob/master/src/getDeviceId.js#L13\n return /rear|back|environment/i.test(videoTrack.label)\n ? 'environment'\n : /front|user|face/i.test(videoTrack.label)\n ? 'user'\n : null; // unknown\n }\n\n static _drawToCanvas(image, scanRegion=null, canvas=null, disallowCanvasResizing=false) {\n canvas = canvas || document.createElement('canvas');\n const scanRegionX = scanRegion && scanRegion.x? scanRegion.x : 0;\n const scanRegionY = scanRegion && scanRegion.y? scanRegion.y : 0;\n const scanRegionWidth = scanRegion && scanRegion.width? scanRegion.width : image.width || image.videoWidth;\n const scanRegionHeight = scanRegion && scanRegion.height? scanRegion.height : image.height || image.videoHeight;\n\n if (!disallowCanvasResizing) {\n const canvasWidth = scanRegion && scanRegion.downScaledWidth\n ? scanRegion.downScaledWidth\n : scanRegionWidth;\n const canvasHeight = scanRegion && scanRegion.downScaledHeight\n ? scanRegion.downScaledHeight\n : scanRegionHeight;\n // Setting the canvas width or height clears the canvas, even if the values didn't change, therefore only\n // set them if they actually changed.\n if (canvas.width !== canvasWidth) {\n canvas.width = canvasWidth;\n }\n if (canvas.height !== canvasHeight) {\n canvas.height = canvasHeight;\n }\n }\n\n const context = canvas.getContext('2d', { alpha: false });\n context.imageSmoothingEnabled = false; // gives less blurry images\n context.drawImage(\n image,\n scanRegionX, scanRegionY, scanRegionWidth, scanRegionHeight,\n 0, 0, canvas.width, canvas.height\n );\n return [canvas, context];\n }\n\n /* async */\n static _loadImage(imageOrFileOrBlobOrUrl) {\n if (imageOrFileOrBlobOrUrl instanceof HTMLCanvasElement || imageOrFileOrBlobOrUrl instanceof HTMLVideoElement\n || window.ImageBitmap && imageOrFileOrBlobOrUrl instanceof window.ImageBitmap\n || window.OffscreenCanvas && imageOrFileOrBlobOrUrl instanceof window.OffscreenCanvas) {\n return Promise.resolve(imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof Image) {\n return QrScanner._awaitImageLoad(imageOrFileOrBlobOrUrl).then(() => imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob\n || imageOrFileOrBlobOrUrl instanceof URL || typeof(imageOrFileOrBlobOrUrl)==='string') {\n const image = new Image();\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n image.src = URL.createObjectURL(imageOrFileOrBlobOrUrl);\n } else {\n image.src = imageOrFileOrBlobOrUrl;\n }\n return QrScanner._awaitImageLoad(image).then(() => {\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n URL.revokeObjectURL(image.src);\n }\n return image;\n });\n } else {\n return Promise.reject('Unsupported image type.');\n }\n }\n\n /* async */\n static _awaitImageLoad(image) {\n return new Promise((resolve, reject) => {\n if (image.complete && image.naturalWidth!==0) {\n // already loaded\n resolve();\n } else {\n let onLoad, onError;\n onLoad = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n resolve();\n };\n onError = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n reject('Image load error');\n };\n image.addEventListener('load', onLoad);\n image.addEventListener('error', onError);\n }\n });\n }\n\n /* async */\n static _postWorkerMessage(qrEngineOrQrEnginePromise, type, data) {\n return Promise.resolve(qrEngineOrQrEnginePromise).then((qrEngine) => {\n if (!(qrEngine instanceof Worker)) return;\n qrEngine.postMessage({ type, data });\n });\n }\n}\nQrScanner.DEFAULT_CANVAS_SIZE = 400;\nQrScanner.NO_QR_CODE_FOUND = 'No QR code found';\nQrScanner.WORKER_PATH = 'qr-scanner-worker.min.js';\n"],"names":["QrScanner","navigator","mediaDevices","enumerateDevices","then","devices","some","device","kind","catch","Promise","resolve","video","onDecode","canvasSizeOrOnDecodeError","_onDecodeError","canvasSizeOrCalculateScanRegion","_calculateScanRegion","preferredFacingMode","$video","$canvas","document","createElement","_onDecode","_legacyCanvasSize","DEFAULT_CANVAS_SIZE","_preferredFacingMode","_flashOn","_paused","_active","console","warn","_scanRegion","_onPlay","bind","_onLoadedMetaData","_onVisibilityChange","disablePictureInPicture","playsInline","muted","shouldHideVideo","hidden","body","contains","appendChild","requestAnimationFrame","computedStyle","display","style","setProperty","visibility","opacity","width","height","addEventListener","_qrEnginePromise","createQrEngine","window","track","getPhotoCapabilities","result","fillLightMode","includes","error","reject","_setFlash","removeEventListener","stop","_postWorkerMessage","location","protocol","clearTimeout","_offTimeout","srcObject","play","facingMode","_getCameraStream","stream","_getFacingMode","_setVideoMirror","e","pause","setTimeout","imageOrFileOrUrl","scanRegion","qrEngine","canvas","disallowCanvasResizing","alsoTryWithoutScanRegion","promise","all","_loadImage","engine","image","canvasContext","_drawToCanvas","Worker","gotExternalWorker","postMessage","type","data","timeout","onMessage","onError","event","NO_QR_CODE_FOUND","imageData","buffer","detect","scanResults","length","rawValue","message","finally","scanImage","red","green","blue","useIntegerApproximation","inversionMode","workerPath","WORKER_PATH","BarcodeDetector","getSupportedFormats","supportedFormats","indexOf","formats","_scanFrame","start","videoHeight","x","Math","round","videoWidth","scanRegionSize","y","downScaledWidth","downScaledHeight","paused","ended","readyState","log","exact","min","constraintsToTry","forEach","constraint","_getMatchingCameraStream","getUserMedia","shift","on","hasFlash","getVideoTracks","applyConstraints","advanced","torch","transform","videoStream","test","videoTrack","label","scanRegionWidth","scanRegionHeight","canvasWidth","canvasHeight","alpha","context","imageSmoothingEnabled","drawImage","scanRegionX","scanRegionY","imageOrFileOrBlobOrUrl","HTMLCanvasElement","HTMLVideoElement","ImageBitmap","OffscreenCanvas","Image","_awaitImageLoad","File","Blob","URL","src","createObjectURL","revokeObjectURL","complete","naturalWidth","onLoad","qrEngineOrQrEnginePromise"],"mappings":"qMAAe,KAAMA,EAAN,CAEJ,gBAAS,EAAG,CACf,MAAKC,UAAAC,aAAL,CAIOD,SAAAC,aAAAC,iBAAA,EAAAC,KAAA,CACGC,CAAA,EAAWA,CAAAC,KAAA,CAAaC,CAAA,EAA0B,YAA1B,GAAUA,CAAAC,KAAvB,CADd,CAAAC,MAAA,CAEI,EAAA,EAAM,CAAA,CAFV,CAJP,CAAoCC,OAAAC,QAAA,CAAgB,CAAA,CAAhB,CADrB,CAUnB,WAAW,CACPC,CADO,CAEPC,CAFO,CAGPC,CAAA,CAA4B,IAAAC,eAHrB,CAIPC,CAAA,CAAkC,IAAAC,qBAJ3B,CAKPC,CAAA,CAAsB,aALf,CAMT,CACE,IAAAC,OAAA,CAAcP,CACd,KAAAQ,QAAA,CAAeC,QAAAC,cAAA,CAAuB,QAAvB,CACf;IAAAC,UAAA,CAAiBV,CACjB,KAAAW,kBAAA,CAAyBxB,CAAAyB,oBACzB,KAAAC,qBAAA,CAA4BR,CAG5B,KAAAS,SAAA,CADA,IAAAC,QACA,CAFA,IAAAC,QAEA,CAFe,CAAA,CAI0B,SAAzC,GAAI,MAAOf,EAAX,EAEI,IAAAU,kBACA,CADyBV,CACzB,CAAAgB,OAAAC,KAAA,CAAa,oGAAb,CAHJ,EAMI,IAAAhB,eANJ,CAM0BD,CAGqB,SAA/C,GAAI,MAAOE,EAAX,EAEI,IAAAQ,kBACA,CADyBR,CACzB,CAAAc,OAAAC,KAAA,CAAa,oGAAb,CAHJ,EAMI,IAAAd,qBANJ;AAMgCD,CAGhC,KAAAgB,YAAA,CAAmB,IAAAf,qBAAA,CAA0BL,CAA1B,CAEnB,KAAAqB,QAAA,CAAe,IAAAA,QAAAC,KAAA,CAAkB,IAAlB,CACf,KAAAC,kBAAA,CAAyB,IAAAA,kBAAAD,KAAA,CAA4B,IAA5B,CACzB,KAAAE,oBAAA,CAA2B,IAAAA,oBAAAF,KAAA,CAA8B,IAA9B,CAE3BtB,EAAAyB,wBAAA,CAAgC,CAAA,CAGhCzB,EAAA0B,YAAA,CAAoB,CAAA,CAGpB1B,EAAA2B,MAAA,CAAc,CAAA,CAId,KAAIC,EAAkB,CAAA,CAClB5B,EAAA6B,OAAJ,GACI7B,CAAA6B,OACA,CADe,CAAA,CACf,CAAAD,CAAA,CAAkB,CAAA,CAFtB,CAIKnB,SAAAqB,KAAAC,SAAA,CAAuB/B,CAAvB,CAAL,GACIS,QAAAqB,KAAAE,YAAA,CAA0BhC,CAA1B,CACA,CAAA4B,CAAA,CAAkB,CAAA,CAFtB,CAIAK,sBAAA,CAAsB,EAAA,EAAM,CAExB,gCAC8B,OAA9B,GAAIC,CAAAC,QAAJ,GACInC,CAAAoC,MAAAC,YAAA,CAAwB,SAAxB,CAAmC,OAAnC,CAA4C,WAA5C,CACA,CAAAT,CAAA,CAAkB,CAAA,CAFtB,CAIiC,UAAjC;AAAIM,CAAAI,WAAJ,GACItC,CAAAoC,MAAAC,YAAA,CAAwB,YAAxB,CAAsC,SAAtC,CAAiD,WAAjD,CACA,CAAAT,CAAA,CAAkB,CAAA,CAFtB,CAIIA,EAAJ,GAEIV,OAAAC,KAAA,CAAa,yFAAb,CAGA,CAFAnB,CAAAoC,MAAAG,QAEA,CAFsB,CAEtB,CADAvC,CAAAoC,MAAAI,MACA,CADoB,CACpB,CAAAxC,CAAAoC,MAAAK,OAAA,CAAqB,CALzB,CAXwB,CAA5B,CAoBAzC,EAAA0C,iBAAA,CAAuB,MAAvB,CAA+B,IAAArB,QAA/B,CACArB,EAAA0C,iBAAA,CAAuB,gBAAvB,CAAyC,IAAAnB,kBAAzC,CACAd,SAAAiC,iBAAA,CAA0B,kBAA1B,CAA8C,IAAAlB,oBAA9C,CAEA,KAAAmB,iBAAA,CAAwBvD,CAAAwD,eAAA,EA7E1B,CAiFF,QAAQ,EAAG,CACP,GAAI,EAAE,cAAF,EAAoBC,OAApB,CAAJ,CACI,MAAO/C,QAAAC,QAAA,CAAgB,CAAA,CAAhB,CAGX;0EACA,OAAK+C,EAAL,CAKOC,oBAAAA,sBAAA,EAAAvD,KAAA,CACIwD,CAAD,EACKA,CAAAC,cAAAC,SAAA,CAA8B,OAA9B,CAFR,CAAArD,MAAA,CAIKsD,CAAD,EAAW,CACdjC,OAAAC,KAAA,CAAagC,CAAb,CACA,OAAO,CAAA,CAFO,CAJf,CALP,CACWrD,OAAAsD,OAAA,CAAe,qCAAf,CAPJ,CAqBX,SAAS,EAAG,CACV,MAAO,KAAArC,SADG,CAKZ,WAAW,EAAG,CACZ,MAAO,KAAAsC,UAAA,CAAe,CAAC,IAAAtC,SAAhB,CADK,CAKd,YAAY,EAAG,CACb,MAAO,KAAAsC,UAAA,CAAe,CAAA,CAAf,CADM,CAKf,WAAW,EAAG,CACZ,MAAO,KAAAA,UAAA,CAAe,CAAA,CAAf,CADK,CAId,OAAO,EAAG,CACN,IAAA9C,OAAA+C,oBAAA,CAAgC,gBAAhC,CAAkD,IAAA/B,kBAAlD,CACA;IAAAhB,OAAA+C,oBAAA,CAAgC,MAAhC,CAAwC,IAAAjC,QAAxC,CACAZ,SAAA6C,oBAAA,CAA6B,kBAA7B,CAAiD,IAAA9B,oBAAjD,CAEA,KAAA+B,KAAA,EACAnE,EAAAoE,mBAAA,CAA6B,IAAAb,iBAA7B,CAAoD,OAApD,CANM,CAUV,KAAK,EAAG,CACJ,GAAI,IAAA1B,QAAJ,EAAoB,CAAC,IAAAD,QAArB,CACI,MAAOlB,QAAAC,QAAA,EAEsB,SAAjC,GAAI8C,MAAAY,SAAAC,SAAJ,EAEIxC,OAAAC,KAAA,CAAa,4EAAb,CAEJ,KAAAF,QAAA,CAAe,CAAA,CACf,KAAAD,QAAA,CAAe,CAAA,CACf,IAAIP,QAAAoB,OAAJ,CAEI,MAAO/B,QAAAC,QAAA,EAEX4D,aAAA,CAAa,IAAAC,YAAb,CACA,KAAAA,YAAA;AAAmB,IACnB,IAAI,IAAArD,OAAAsD,UAAJ,CAGI,MADA,KAAAtD,OAAAuD,KAAA,EACO,CAAAhE,OAAAC,QAAA,EAGX,KAAIgE,EAAa,IAAAjD,qBACjB,OAAO,KAAAkD,iBAAA,CAAsBD,CAAtB,CAAkC,CAAA,CAAlC,CAAAlE,MAAA,CACI,EAAA,EAAM,CAETkE,CAAA,CAA4B,aAAf,GAAAA,CAAA,CAA+B,MAA/B,CAAwC,aACrD,OAAO,KAAAC,iBAAA,EAHE,CADV,CAAAxE,KAAA,CAMGyE,CAAA,EAAU,CAGZF,CAAA,CAAa,IAAAG,eAAA,CAAoBD,CAApB,CAAb,EAA4CF,CAC5C,KAAAxD,OAAAsD,UAAA,CAAwBI,CACxB,KAAA1D,OAAAuD,KAAA,EACA,KAAAK,gBAAA,CAAqBJ,CAArB,CANY,CANb,CAAAlE,MAAA,CAcIuE,CAAA,EAAK,CACR,IAAAnD,QAAA,CAAe,CAAA,CACf,MAAMmD,EAAN,CAFQ,CAdT,CAvBH,CA2CR,IAAI,EAAG,CACH,IAAAC,MAAA,EACA,KAAApD,QAAA,CAAe,CAAA,CAFZ,CAKP,KAAK,EAAG,CACJ,IAAAD,QAAA,CAAe,CAAA,CACV,KAAAC,QAAL,GAGA,IAAAV,OAAA8D,MAAA,EACA,CAAI,IAAAT,YAAJ,GAGA,IAAAA,YAHA,CAGmBU,UAAA,CAAW,EAAA;AAAM,CAChC,gEACA,KAAK,KAAL,KAAA,CACIxB,CAAAS,KAAA,EAGJ,KAAAK,YAAA,CADA,IAAArD,OAAAsD,UACA,CADwB,IALQ,CAAjB,CAOhB,GAPgB,CAHnB,CAJA,CAFI,CAoBD,gBAAS,CAACU,CAAD,CAAmBC,CAAA,CAAW,IAA9B,CAAoCC,CAAA,CAAS,IAA7C,CAAmDC,CAAA,CAAO,IAA1D,CAAgEC,CAAA,CAAuB,CAAA,CAAvF,CACCC,CAAA,CAAyB,CAAA,CAD1B,CACiC,CAC7C,yBAAA,CAEIC,EAAU/E,OAAAgF,IAAA,CAAY,CACtBL,CADsB,EACVrF,CAAAwD,eAAA,EADU,CAEtBxD,CAAA2F,WAAA,CAAqBR,CAArB,CAFsB,CAAZ,CAAA/E,KAAA,CAGN,CAAC,CAACwF,CAAD,CAASC,CAAT,CAAD,CAAA,EAAqB,CACzBR,CAAA,CAAWO,CACX,KAAIE,CACJ,EAACR,CAAD,CAASQ,CAAT,CAAA,CAA0B,IAAAC,cAAA,CAAmBF,CAAnB,CAA0BT,CAA1B,CAAsCE,CAAtC,CAA8CC,CAA9C,CAE1B,OAAIF,EAAJ,WAAwBW,OAAxB,EACSC,CAIE,EAFHZ,CAAAa,YAAA,CAAqB,CAAEC,KAAM,eAAR,CAAyBC,KAAM,MAA/B,CAArB,CAEG,CAAA,IAAI1F,OAAJ,CAAY,CAACC,CAAD,CAAUqD,CAAV,CAAA,EAAqB,CAAA,IAChCqC,CADgC,CACvBC,CADuB,CACZC,CACxBD,EAAA,CAAYE,CAAAF,EAAS,CACO,UAAxB,GAAIE,CAAAJ,KAAAD,KAAJ,GAGAd,CAAAnB,oBAAA,CAA6B,SAA7B;AAAwCoC,CAAxC,CAGA,CAFAjB,CAAAnB,oBAAA,CAA6B,OAA7B,CAAsCqC,CAAtC,CAEA,CADAhC,YAAA,CAAa8B,CAAb,CACA,CAAwB,IAAxB,GAAIG,CAAAJ,KAAAA,KAAJ,CACIzF,CAAA,CAAQ6F,CAAAJ,KAAAA,KAAR,CADJ,CAGIpC,CAAA,CAAOhE,CAAAyG,iBAAP,CATJ,CADiB,CAarBF,EAAA,CAAWvB,CAADuB,EAAO,CACblB,CAAAnB,oBAAA,CAA6B,SAA7B,CAAwCoC,CAAxC,CACAjB,EAAAnB,oBAAA,CAA6B,OAA7B,CAAsCqC,CAAtC,CACAhC,aAAA,CAAa8B,CAAb,CAEArC,EAAA,CAAO,iBAAP,gCAAA,EALa,CAOjBqB,EAAA/B,iBAAA,CAA0B,SAA1B,CAAqCgD,CAArC,CACAjB,EAAA/B,iBAAA,CAA0B,OAA1B,CAAmCiD,CAAnC,CACAF,EAAA,CAAUnB,UAAA,CAAW,EAAA,EAAMqB,CAAA,CAAQ,SAAR,CAAjB,CAAqC,GAArC,CACV,wBAA8C,EAAGjB,CAAAlC,OAAckC,CAAAjC,QAC/DgC,EAAAa,YAAA,CAAqB,CACjBC,KAAM,QADW,CAEjBC,KAAMM,CAFW,CAArB,CAGG,CAACA,CAAAN,KAAAO,OAAD,CAHH,CA1BoC,CAAjC,CALX,EAqCW,IAAIjG,OAAJ,CAAY,CAACC,CAAD,CAAUqD,CAAV,CAAA,EAAqB,CACpC;AAAiE,IACjEqB,EAAAuB,OAAA,CAAgBtB,CAAhB,CAAAlF,KAAA,CAA6ByG,CAAA,EAAe,CACnCA,CAAAC,OAAL,CAGInG,CAAA,CAAQkG,CAAA,CAAY,CAAZ,CAAAE,SAAR,CAHJ,CACI/C,CAAA,CAAOhE,CAAAyG,iBAAP,CAFoC,CAA5C,CAAAhG,MAAA,CAMUuE,CAAD,EAAOhB,CAAA,CAAO,iBAAP,EAA4BgB,CAAAgC,QAA5B,EAAyChC,CAAzC,EANhB,CAAAiC,QAAA,CAMsE,EAAA,EAAM1C,YAAA,CAAa8B,CAAb,CAN5E,CAFoC,CAAjC,CA1Cc,CAHf,CA0DVjB,EAAJ,EAAkBI,CAAlB,GACIC,CADJ,CACcA,CAAAhF,MAAA,CAAc,EAAA,EACpBT,CAAAkH,UAAA,CAAoB/B,CAApB,CAAsC,IAAtC,CAA4CE,CAA5C,CAAsDC,CAAtD,CAA8DC,CAA9D,CADM,CADd,CAUA,OALAE,EAKA,CALUA,CAAAwB,QAAA,CAAgB,EAAA,EAAM,CACxBhB,CAAJ,EACAjG,CAAAoE,mBAAA,CAA6BiB,CAA7B,CAAuC,OAAvC,CAF4B,CAAtB,CAlEmC,CA0EjD,mBAAmB,CAAC8B,CAAD,CAAMC,CAAN,CAAaC,CAAb,CAAmBC,CAAA,CAA0B,CAAA,CAA7C,CAAmD,CAGlEtH,CAAAoE,mBAAA,CACI,IAAAb,iBADJ,CAEI,kBAFJ,CAGI,CAAE4D,IAAAA,CAAF,CAAOC,MAAAA,CAAP,CAAcC,KAAAA,CAAd,CAAoBC,wBAAAA,CAApB,CAHJ,CAHkE,CAUtE,gBAAgB,CAACC,CAAD,CAAgB,CAG5BvH,CAAAoE,mBAAA,CAA6B,IAAAb,iBAA7B,CAAoD,eAApD,CAAqEgE,CAArE,CAH4B,CAOzB,qBAAc,CAACC,CAAA;AAAaxH,CAAAyH,YAAd,CAAqC,CACtD,MAAOrH,CAAC,iBAAA,EAAqBqD,OAArB,CAA8BiE,eAAAC,oBAAA,EAA9B,CAAsEjH,OAAAC,QAAA,CAAgB,EAAhB,CAAvEP,MAAA,CACIwH,CAAD,EAA8D,EAAxC,GAAAA,CAAAC,QAAA,CAAyB,SAAzB,CAAA,CACtB,IAAIH,eAAJ,CAAoB,CAAEI,QAAS,CAAC,SAAD,CAAX,CAApB,CADsB,CAEtB,IAAI9B,MAAJ,CAAWwB,CAAX,CAHH,CAD+C,CAQ1D,OAAO,EAAG,CACN,IAAAxF,YAAA,CAAmB,IAAAf,qBAAA,CAA0B,IAAAE,OAA1B,CACnB,KAAA4G,WAAA,EAFM,CAKV,iBAAiB,EAAG,CAChB,IAAA/F,YAAA,CAAmB,IAAAf,qBAAA,CAA0B,IAAAE,OAA1B,CADH,CAIpB,mBAAmB,EAAG,CACdE,QAAAoB,OAAJ,CACI,IAAAwC,MAAA,EADJ,CAEW,IAAApD,QAFX,EAGI,IAAAmG,MAAA,EAJc,CAQtB,oBAAoB,CAACpH,CAAD,CAAQ,CAGxB;AADmDA,CAAAqH,cAEnD,OAAO,CACHC,EAAGC,IAAAC,MAAA,EAAYxH,CAAAyH,WAAZ,CAA+BC,CAA/B,EAAiD,CAAjD,CADA,CAEHC,EAAGJ,IAAAC,MAAA,EAAYxH,CAAAqH,YAAZ,CAAgCK,CAAhC,EAAkD,CAAlD,CAFA,CAGHlF,MAAOkF,CAHJ,CAIHjF,OAAQiF,CAJL,CAKHE,gBAAiB,IAAAhH,kBALd,CAMHiH,iBAAkB,IAAAjH,kBANf,CAJiB,CAc5B,UAAU,EAAG,CACT,GAAI,CAAC,IAAAK,QAAL,EAAqB,IAAAV,OAAAuH,OAArB,EAA2C,IAAAvH,OAAAwH,MAA3C,CAA8D,MAAO,CAAA,CAErE9F,sBAAA,CAAsB,EAAA,EAAM,CACM,CAA9B,EAAI,IAAA1B,OAAAyH,WAAJ,CAKI,IAAAb,WAAA,EALJ,CAQA,IAAAxE,iBAAAnD,KAAA,CACWiF,CAAD,EAAcrF,CAAAkH,UAAA,CAAoB,IAAA/F,OAApB,CAAiC,IAAAa,YAAjC,CAAmDqD,CAAnD,CAA6D,IAAAjE,QAA7D,CADxB,CAAAhB,KAAA,CAEU,IAAAmB,UAFV,CAE2BwC,CAAD,EAAW,CACxB,IAAAlC,QAAL,GAEoD,EAIpD,GAJIgG,UAAAA,GAAAA,SAAA,CAAqB,qBAArB,CAIJ;CAFI,IAAAtE,iBAEJ,CAF4BvD,CAAAwD,eAAA,EAE5B,EAAA,IAAAzC,eAAA,CAAoBgD,CAApB,CANA,CAD6B,CAFrC,CAAA3D,KAAA,CAWU,EAAA,EAAM,IAAA2H,WAAA,EAXhB,CATwB,CAA5B,CAHS,CA2Bb,cAAc,CAAChE,CAAD,CAAQ,CAEdA,CAAJ,GAAc/D,CAAAyG,iBAAd,EACA3E,OAAA+G,IAAA,CAAY9E,CAAZ,CAHkB,CAMtB,gBAAgB,CAACY,CAAD,CAAamE,CAAA,CAAQ,CAAA,CAArB,CAA4B,CACxC,QACI1F,MAAO,CAAE2F,IAAK,IAAP,GACR,CACC3F,MAAO,CAAE2F,IAAK,GAAP,CADR,EAEA,GAECpE,EAAJ,GACQmE,CAGJ,GAFInE,CAEJ,CAFiB,CAAEmE,MAAOnE,CAAT,CAEjB,EAAAqE,CAAAC,QAAA,CAAyBC,CAAA,EAAcA,CAAAvE,WAAd,CAAsCA,CAA/D,CAJJ,CAMA,OAAO,KAAAwE,yBAAA,CAA8BH,CAA9B,CAbiC,CAgB5C,wBAAwB,CAACA,CAAD,CAAmB,CACvC,MAAK/I,UAAAC,aAAL,EAA2D,CAA3D,GAA+B8I,CAAAlC,OAA/B,CAGO7G,SAAAC,aAAAkJ,aAAA,CAAoC,CACvCxI,MAAOoI,CAAAK,MAAA,EADgC,CAApC,CAAA5I,MAAA,CAEE,EAAA,EAAM,IAAA0I,yBAAA,CAA8BH,CAA9B,CAFR,CAHP,CACWtI,OAAAsD,OAAA,CAAe,mBAAf,CAF4B,CAU3C,SAAS,CAACsF,CAAD,CAAK,CACV,MAAO,KAAAC,SAAA,EAAAnJ,KAAA,CAAsBmJ,CAAD;AACnBA,CAAL,CAEO,IAAApI,OAAAsD,UAAA+E,eAAA,EAAA,CAAuC,CAAvC,CAAAC,iBAAA,CAA2D,CAC9DC,SAAU,CAAC,CAAEC,MAAOL,CAAT,CAAD,CADoD,CAA3D,CAFP,CAAsB5I,OAAAsD,OAAA,CAAe,oBAAf,CADnB,CAAA5D,KAAA,CAMC,EAAA,EAAM,IAAAuB,SAAN,CAAsB2H,CANvB,CADG,CAUd,eAAe,CAAC3E,CAAD,CAAa,CAGxB,IAAAxD,OAAA6B,MAAA4G,UAAA,CAA8B,SAA9B,aADuC,IACvC,EAAwD,GAHhC,CAM5B,cAAc,CAACC,CAAD,CAAc,CAExB,MAAA,EAAA,sBAAA,EAEO,wBAAAC,KAAA,CAA8BC,CAAAC,MAA9B,CAAA,CACD,aADC,CAED,kBAAAF,KAAA,CAAwBC,CAAAC,MAAxB,CAAA,CACI,MADJ,CAEI,IANV,CAAwB,IAFA,CAWrB,oBAAa,CAACnE,CAAD,CAAQT,CAAA,CAAW,IAAnB,CAAyBE,CAAA,CAAO,IAAhC,CAAsCC,CAAA,CAAuB,CAAA,CAA7D,CAAoE,CACpFD,CAAA,CAASA,CAAT,EAAmBjE,QAAAC,cAAA,CAAuB,QAAvB,CACnB,cAA8C8D,CAAA8C,IAA9C,UAC8C9C,CAAAmD,IAD9C;QAEsDnD,CAAAhC,4BAFtD,eAGwDgC,CAAA/B,+BAEnDkC,EAAL,IAYI,sBAVMH,CAAAoD,iBACAyB,CASN,EAAA,uBAPM7E,CAAAqD,kBACAyB,CAMN,CAHI5E,CAAAlC,MAGJ,GAHqB+G,CAGrB,GAFI7E,CAAAlC,MAEJ,CAFmB+G,CAEnB,EAAI7E,CAAAjC,OAAJ,GAAsB+G,CAAtB,GACI9E,CAAAjC,OADJ,CACoB+G,CADpB,CAZJ,sBAiBsC,CAAEC,MAAO,CAAA,CAAT,EACtCC,EAAAC,sBAAA,CAAgC,CAAA,CAChCD,EAAAE,UAAA,CACI3E,CADJ,CAEI4E,CAFJ,CAEiBC,CAFjB,CAE8BT,CAF9B,CAE+CC,CAF/C,CAGI,CAHJ,CAGO,CAHP,CAGU5E,CAAAlC,MAHV,CAGwBkC,CAAAjC,OAHxB,CAKA,OAAO,CAACiC,CAAD,CAASgF,CAAT,CA/B6E,CAmCjF,iBAAU,CAACK,CAAD,CAAyB,CACtC,GAAIA,CAAJ,WAAsCC,kBAAtC,EAA2DD,CAA3D,WAA6FE,iBAA7F,EACOpH,MAAAqH,YADP,EAC6BH,CAD7B,WAC+DlH,OAAAqH,YAD/D,EAEOrH,MAAAsH,gBAFP;AAEiCJ,CAFjC,WAEmElH,OAAAsH,gBAFnE,CAGI,MAAOrK,QAAAC,QAAA,CAAgBgK,CAAhB,CACJ,IAAIA,CAAJ,WAAsCK,MAAtC,CACH,MAAOhL,EAAAiL,gBAAA,CAA0BN,CAA1B,CAAAvK,KAAA,CAAuD,EAAA,EAAMuK,CAA7D,CACJ,IAAIA,CAAJ,WAAsCO,KAAtC,EAA8CP,CAA9C,WAAgFQ,KAAhF,EACAR,CADA,WACkCS,IADlC,EAC0E,QAD1E,GACyC,MAAOT,EADhD,CACoF,CACvF,eAEI9E,EAAAwF,IAAA,CADAV,CAAJ,WAAsCO,KAAtC,EAA8CP,CAA9C,WAAgFQ,KAAhF,CACgBC,GAAAE,gBAAA,CAAoBX,CAApB,CADhB,CAGgBA,CAEhB,OAAO3K,EAAAiL,gBAAA,CAA0BpF,CAA1B,CAAAzF,KAAA,CAAsC,EAAA,EAAM,CAC/C,CAAIuK,CAAJ,WAAsCO,KAAtC,EAA8CP,CAA9C,WAAgFQ,KAAhF,GACIC,GAAAG,gBAAA,CAAoB1F,CAAAwF,IAApB,CAEJ,OAAOxF,EAJwC,CAA5C,CAPgF,CAcvF,MAAOnF,QAAAsD,OAAA,CAAe,yBAAf,CAtB2B,CA2BnC,sBAAe,CAAC6B,CAAD,CAAQ,CAC1B,MAAO,KAAInF,OAAJ,CAAY,CAACC,CAAD;AAAUqD,CAAV,CAAA,EAAqB,CACpC,GAAI6B,CAAA2F,SAAJ,EAA2C,CAA3C,GAAsB3F,CAAA4F,aAAtB,CAEI9K,CAAA,EAFJ,KAGO,CAAA,IACC+K,CADD,CACSnF,CACZmF,EAAA,CAAS,EAAAA,EAAM,CACX7F,CAAA3B,oBAAA,CAA0B,MAA1B,CAAkCwH,CAAlC,CACA7F,EAAA3B,oBAAA,CAA0B,OAA1B,CAAmCqC,CAAnC,CACA5F,EAAA,EAHW,CAKf4F,EAAA,CAAU,EAAAA,EAAM,CACZV,CAAA3B,oBAAA,CAA0B,MAA1B,CAAkCwH,CAAlC,CACA7F,EAAA3B,oBAAA,CAA0B,OAA1B,CAAmCqC,CAAnC,CACAvC,EAAA,CAAO,kBAAP,CAHY,CAKhB6B,EAAAvC,iBAAA,CAAuB,MAAvB,CAA+BoI,CAA/B,CACA7F,EAAAvC,iBAAA,CAAuB,OAAvB,CAAgCiD,CAAhC,CAbG,CAJ6B,CAAjC,CADmB,CAwBvB,yBAAkB,CAACoF,CAAD,CAA4BxF,CAA5B,CAAkCC,CAAlC,CAAwC,CAC7D,MAAO1F,QAAAC,QAAA,CAAgBgL,CAAhB,CAAAvL,KAAA,CAAiDiF,CAAD,EAAc,CAC3DA,CAAN,WAA0BW,OAA1B,EACAX,CAAAa,YAAA,CAAqB,CAAEC,KAAAA,CAAF,CAAQC,KAAAA,CAAR,CAArB,CAFiE,CAA9D,CADsD,CAxgBtD,CA+gBfpG,CAAAyB,oBAAA,CAAgC,GAChCzB,EAAAyG,iBAAA,CAA6B,kBAC7BzG,EAAAyH,YAAA,CAAwB;;"}
\ No newline at end of file
+{"version":3,"file":"qr-scanner.umd.min.js","sources":["src/qr-scanner.js"],"sourcesContent":["export default class QrScanner {\n /* async */\n static hasCamera() {\n return QrScanner.listCameras(false)\n .then(cameras => !!cameras.length)\n .catch(() => false);\n }\n\n /* async */\n static listCameras(requestLabels = false) {\n if (!navigator.mediaDevices) return Promise.resolve([]);\n\n // Note that enumerateDevices can always be called and does not prompt the user for permission.\n // However, enumerateDevices only includes device labels if served via https and an active media stream exists\n // or permission to access the camera was given. Therefore, ask for camera permission by opening a stream, if\n // labels were requested.\n let openedStream = null;\n return (requestLabels\n ? navigator.mediaDevices.getUserMedia({ audio: false, video: true })\n .then(stream => openedStream = stream)\n // Fail gracefully, especially if the device has no camera or on mobile when the camera is already in\n // use and some browsers disallow a second stream.\n .catch(() => {})\n : Promise.resolve()\n )\n .then(() => navigator.mediaDevices.enumerateDevices())\n .then(devices => devices.filter(device => device.kind === 'videoinput').map((device, i) => ({\n id: device.deviceId,\n label: device.label || (i === 0 ? 'Default Camera' : `Camera ${i + 1}`),\n })))\n .finally(() => {\n // close the stream we just opened for getting camera access for listing the device labels\n if (!openedStream) return;\n for (const track of openedStream.getTracks()) {\n track.stop();\n openedStream.removeTrack(track);\n }\n });\n }\n\n constructor(\n video,\n onDecode,\n canvasSizeOrOnDecodeError = this._onDecodeError,\n canvasSizeOrCalculateScanRegion = this._calculateScanRegion,\n preferredCamera = 'environment'\n ) {\n this.$video = video;\n this.$canvas = document.createElement('canvas');\n this._onDecode = onDecode;\n this._legacyCanvasSize = QrScanner.DEFAULT_CANVAS_SIZE;\n this._preferredCamera = preferredCamera;\n this._active = false;\n this._paused = false;\n this._flashOn = false;\n\n if (typeof canvasSizeOrOnDecodeError === 'number') {\n // legacy function signature where the third argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrOnDecodeError;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._onDecodeError = canvasSizeOrOnDecodeError;\n }\n\n if (typeof canvasSizeOrCalculateScanRegion === 'number') {\n // legacy function signature where the fourth argument is the canvas size\n this._legacyCanvasSize = canvasSizeOrCalculateScanRegion;\n console.warn('You\\'re using a deprecated version of the QrScanner constructor which will be removed in '\n + 'the future');\n } else {\n this._calculateScanRegion = canvasSizeOrCalculateScanRegion;\n }\n\n this._scanRegion = this._calculateScanRegion(video);\n\n this._onPlay = this._onPlay.bind(this);\n this._onLoadedMetaData = this._onLoadedMetaData.bind(this);\n this._onVisibilityChange = this._onVisibilityChange.bind(this);\n\n video.disablePictureInPicture = true;\n // Allow inline playback on iPhone instead of requiring full screen playback,\n // see https://webkit.org/blog/6784/new-video-policies-for-ios/\n video.playsInline = true;\n // Allow play() on iPhone without requiring a user gesture. Should not really be needed as camera stream\n // includes no audio, but just to be safe.\n video.muted = true;\n\n // Avoid Safari stopping the video stream on a hidden video.\n // See https://github.com/cozmo/jsQR/issues/185\n let shouldHideVideo = false;\n if (video.hidden) {\n video.hidden = false;\n shouldHideVideo = true;\n }\n if (!document.body.contains(video)) {\n document.body.appendChild(video);\n shouldHideVideo = true;\n }\n requestAnimationFrame(() => {\n // Checking in requestAnimationFrame which should avoid a potential additional re-flow for getComputedStyle.\n const computedStyle = window.getComputedStyle(video);\n if (computedStyle.display === 'none') {\n video.style.setProperty('display', 'block', 'important');\n shouldHideVideo = true;\n }\n if (computedStyle.visibility !== 'visible') {\n video.style.setProperty('visibility', 'visible', 'important');\n shouldHideVideo = true;\n }\n if (shouldHideVideo) {\n // Hide the video in a way that doesn't cause Safari to stop the playback.\n console.warn('QrScanner has overwritten the video hiding style to avoid Safari stopping the playback.');\n video.style.opacity = 0;\n video.style.width = 0;\n video.style.height = 0;\n }\n });\n\n video.addEventListener('play', this._onPlay);\n video.addEventListener('loadedmetadata', this._onLoadedMetaData);\n document.addEventListener('visibilitychange', this._onVisibilityChange);\n\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n\n /* async */\n hasFlash() {\n if (!('ImageCapture' in window)) {\n return Promise.resolve(false);\n }\n\n const track = this.$video.srcObject ? this.$video.srcObject.getVideoTracks()[0] : null;\n if (!track) {\n return Promise.reject('Camera not started or not available');\n }\n\n const imageCapture = new ImageCapture(track);\n return imageCapture.getPhotoCapabilities()\n .then((result) => {\n return result.fillLightMode.includes('flash');\n })\n .catch((error) => {\n console.warn(error);\n return false;\n });\n }\n\n isFlashOn() {\n return this._flashOn;\n }\n\n /* async */\n toggleFlash() {\n return this._setFlash(!this._flashOn);\n }\n\n /* async */\n turnFlashOff() {\n return this._setFlash(false);\n }\n\n /* async */\n turnFlashOn() {\n return this._setFlash(true);\n }\n\n destroy() {\n this.$video.removeEventListener('loadedmetadata', this._onLoadedMetaData);\n this.$video.removeEventListener('play', this._onPlay);\n document.removeEventListener('visibilitychange', this._onVisibilityChange);\n\n this.stop();\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'close');\n }\n\n /* async */\n start() {\n if (this._active && !this._paused) {\n return Promise.resolve();\n }\n if (window.location.protocol !== 'https:') {\n // warn but try starting the camera anyways\n console.warn('The camera stream is only accessible if the page is transferred via https.');\n }\n this._active = true;\n if (document.hidden) {\n // camera will be started as soon as tab is in foreground\n return Promise.resolve();\n }\n this._paused = false;\n if (this.$video.srcObject) {\n // camera stream already/still set\n this.$video.play();\n return Promise.resolve();\n }\n\n let facingModeGuess = this._preferredCamera === 'environment' || this._preferredCamera === 'user'\n ? this._preferredCamera\n : null;\n return this._getCameraStream(this._preferredCamera, true)\n .catch(() => {\n // If _preferredCamera was a facing mode, we (probably) don't have a camera of the requested facing mode\n // and switch our facing mode guess.\n facingModeGuess = facingModeGuess === 'environment'\n ? 'user' // switch as the requested facing mode was not available\n : 'environment'; // switch, or also assume 'environment' as default if facingModeGuess was null\n // Retry unconstrained. Throws if camera is not accessible (e.g. due to not https)\n return this._getCameraStream();\n })\n .then(stream => {\n // Try to determine the facing mode from the stream, otherwise use our guess or 'environment' as\n // default. Note that the guess is not always accurate as Safari returns cameras of different facing\n // mode, even for exact facingMode constraints.\n facingModeGuess = this._getFacingMode(stream) || facingModeGuess || 'environment';\n this.$video.srcObject = stream;\n this.$video.play();\n this._setVideoMirror(facingModeGuess);\n })\n .catch(e => {\n this._active = false;\n throw e;\n });\n }\n\n stop() {\n this.pause();\n this._active = false;\n }\n\n pause(stopStreamImmediately = false) {\n this._paused = true;\n if (!this._active) {\n return Promise.resolve(true);\n }\n this.$video.pause();\n\n const stopStream = () => {\n const tracks = this.$video.srcObject ? this.$video.srcObject.getTracks() : [];\n for (const track of tracks) {\n track.stop(); // note that this will also automatically turn the flashlight off\n this.$video.srcObject.removeTrack(track);\n }\n this.$video.srcObject = null;\n };\n\n if (stopStreamImmediately) {\n stopStream();\n return Promise.resolve(true);\n }\n\n return new Promise((resolve) => setTimeout(resolve, 300))\n .then(() => {\n if (!this._paused) return false;\n stopStream();\n return true;\n });\n }\n\n /* async */\n setCamera(facingModeOrDeviceId) {\n if (facingModeOrDeviceId === this._preferredCamera) return Promise.resolve();\n this._preferredCamera = facingModeOrDeviceId;\n // Restart the scanner with the new camera which will also update the video mirror and the scan region. Note\n // that we always pause the stream and not only if !this._paused as even if this._paused === true, the stream\n // might still be running, as it's by default only stopped after a delay of 300ms.\n const wasPaused = this._paused;\n return this.pause(true).then((paused) => {\n if (!paused || wasPaused || !this._active) return;\n return this.start();\n });\n }\n\n /* async */\n static scanImage(imageOrFileOrUrl, scanRegion=null, qrEngine=null, canvas=null, disallowCanvasResizing=false,\n alsoTryWithoutScanRegion=false) {\n const gotExternalWorker = qrEngine instanceof Worker;\n\n let promise = Promise.all([\n qrEngine || QrScanner.createQrEngine(),\n QrScanner._loadImage(imageOrFileOrUrl),\n ]).then(([engine, image]) => {\n qrEngine = engine;\n let canvasContext;\n [canvas, canvasContext] = this._drawToCanvas(image, scanRegion, canvas, disallowCanvasResizing);\n\n if (qrEngine instanceof Worker) {\n if (!gotExternalWorker) {\n // Enable scanning of inverted color qr codes. Not using _postWorkerMessage as it's async\n qrEngine.postMessage({ type: 'inversionMode', data: 'both' });\n }\n return new Promise((resolve, reject) => {\n let timeout, onMessage, onError;\n onMessage = event => {\n if (event.data.type !== 'qrResult') {\n return;\n }\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n if (event.data.data !== null) {\n resolve(event.data.data);\n } else {\n reject(QrScanner.NO_QR_CODE_FOUND);\n }\n };\n onError = (e) => {\n qrEngine.removeEventListener('message', onMessage);\n qrEngine.removeEventListener('error', onError);\n clearTimeout(timeout);\n const errorMessage = !e ? 'Unknown Error' : (e.message || e);\n reject('Scanner error: ' + errorMessage);\n };\n qrEngine.addEventListener('message', onMessage);\n qrEngine.addEventListener('error', onError);\n timeout = setTimeout(() => onError('timeout'), 10000);\n const imageData = canvasContext.getImageData(0, 0, canvas.width, canvas.height);\n qrEngine.postMessage({\n type: 'decode',\n data: imageData\n }, [imageData.data.buffer]);\n });\n } else {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => reject('Scanner error: timeout'), 10000);\n qrEngine.detect(canvas).then(scanResults => {\n if (!scanResults.length) {\n reject(QrScanner.NO_QR_CODE_FOUND);\n } else {\n resolve(scanResults[0].rawValue);\n }\n }).catch((e) => reject('Scanner error: ' + (e.message || e))).finally(() => clearTimeout(timeout));\n });\n }\n });\n\n if (scanRegion && alsoTryWithoutScanRegion) {\n promise = promise.catch(() =>\n QrScanner.scanImage(imageOrFileOrUrl, null, qrEngine, canvas, disallowCanvasResizing));\n }\n\n promise = promise.finally(() => {\n if (gotExternalWorker) return;\n QrScanner._postWorkerMessage(qrEngine, 'close');\n });\n\n return promise;\n }\n\n setGrayscaleWeights(red, green, blue, useIntegerApproximation = true) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations work also\n // well with colored qr codes.\n QrScanner._postWorkerMessage(\n this._qrEnginePromise,\n 'grayscaleWeights',\n { red, green, blue, useIntegerApproximation }\n );\n }\n\n setInversionMode(inversionMode) {\n // Note that for the native BarcodeDecoder, this is a no-op. However, the native implementations scan normal\n // and inverted qr codes by default\n QrScanner._postWorkerMessage(this._qrEnginePromise, 'inversionMode', inversionMode);\n }\n\n /* async */\n static createQrEngine(workerPath = QrScanner.WORKER_PATH) {\n return ('BarcodeDetector' in window ? BarcodeDetector.getSupportedFormats() : Promise.resolve([]))\n .then((supportedFormats) => supportedFormats.indexOf('qr_code') !== -1\n ? new BarcodeDetector({ formats: ['qr_code'] })\n : new Worker(workerPath)\n );\n }\n\n _onPlay() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n this._scanFrame();\n }\n\n _onLoadedMetaData() {\n this._scanRegion = this._calculateScanRegion(this.$video);\n }\n\n _onVisibilityChange() {\n if (document.hidden) {\n this.pause();\n } else if (this._active) {\n this.start();\n }\n }\n\n _calculateScanRegion(video) {\n // Default scan region calculation. Note that this can be overwritten in the constructor.\n const smallestDimension = Math.min(video.videoWidth, video.videoHeight);\n const scanRegionSize = Math.round(2 / 3 * smallestDimension);\n return {\n x: Math.round((video.videoWidth - scanRegionSize) / 2),\n y: Math.round((video.videoHeight - scanRegionSize) / 2),\n width: scanRegionSize,\n height: scanRegionSize,\n downScaledWidth: this._legacyCanvasSize,\n downScaledHeight: this._legacyCanvasSize,\n };\n }\n\n _scanFrame() {\n if (!this._active || this.$video.paused || this.$video.ended) return false;\n // using requestAnimationFrame to avoid scanning if tab is in background\n requestAnimationFrame(() => {\n if (this.$video.readyState <= 1) {\n // Skip scans until the video is ready as drawImage() only works correctly on a video with readyState\n // > 1, see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage#Notes.\n // This also avoids false positives for videos paused after a successful scan which remains visible on\n // the canvas until the video is started again and ready.\n this._scanFrame();\n return;\n }\n this._qrEnginePromise\n .then((qrEngine) => QrScanner.scanImage(this.$video, this._scanRegion, qrEngine, this.$canvas))\n .then(this._onDecode, (error) => {\n if (!this._active) return;\n const errorMessage = error.message || error;\n if (errorMessage.indexOf('service unavailable') !== -1) {\n // When the native BarcodeDetector crashed, create a new one\n this._qrEnginePromise = QrScanner.createQrEngine();\n }\n this._onDecodeError(error);\n })\n .then(() => this._scanFrame());\n });\n }\n\n _onDecodeError(error) {\n // default error handler; can be overwritten in the constructor\n if (error === QrScanner.NO_QR_CODE_FOUND) return;\n console.log(error);\n }\n\n _getCameraStream(preferredCamera, exact = false) {\n const constraintsToTry = [{\n width: { min: 1024 }\n }, {\n width: { min: 768 }\n }, {}];\n\n if (preferredCamera) {\n const preferenceType = preferredCamera === 'environment' || preferredCamera === 'user'\n ? 'facingMode'\n : 'deviceId';\n if (exact) {\n preferredCamera = { exact: preferredCamera };\n }\n constraintsToTry.forEach(constraint => constraint[preferenceType] = preferredCamera);\n }\n\n return this._getMatchingCameraStream(constraintsToTry);\n }\n\n _getMatchingCameraStream(constraintsToTry) {\n if (!navigator.mediaDevices || constraintsToTry.length === 0) {\n return Promise.reject('Camera not found.');\n }\n return navigator.mediaDevices.getUserMedia({\n video: constraintsToTry.shift()\n }).catch(() => this._getMatchingCameraStream(constraintsToTry));\n }\n\n /* async */\n _setFlash(on) {\n return this.hasFlash().then((hasFlash) => {\n if (!hasFlash) return Promise.reject('No flash available');\n // Note that the video track is guaranteed to exist at this point\n return this.$video.srcObject.getVideoTracks()[0].applyConstraints({\n advanced: [{ torch: on }],\n });\n }).then(() => this._flashOn = on);\n }\n\n _setVideoMirror(facingMode) {\n // in user facing mode mirror the video to make it easier for the user to position the QR code\n const scaleFactor = facingMode==='user'? -1 : 1;\n this.$video.style.transform = 'scaleX(' + scaleFactor + ')';\n }\n\n _getFacingMode(videoStream) {\n const videoTrack = videoStream.getVideoTracks()[0];\n if (!videoTrack) return null; // unknown\n // inspired by https://github.com/JodusNodus/react-qr-reader/blob/master/src/getDeviceId.js#L13\n return /rear|back|environment/i.test(videoTrack.label)\n ? 'environment'\n : /front|user|face/i.test(videoTrack.label)\n ? 'user'\n : null; // unknown\n }\n\n static _drawToCanvas(image, scanRegion=null, canvas=null, disallowCanvasResizing=false) {\n canvas = canvas || document.createElement('canvas');\n const scanRegionX = scanRegion && scanRegion.x? scanRegion.x : 0;\n const scanRegionY = scanRegion && scanRegion.y? scanRegion.y : 0;\n const scanRegionWidth = scanRegion && scanRegion.width? scanRegion.width : image.width || image.videoWidth;\n const scanRegionHeight = scanRegion && scanRegion.height? scanRegion.height : image.height || image.videoHeight;\n\n if (!disallowCanvasResizing) {\n const canvasWidth = scanRegion && scanRegion.downScaledWidth\n ? scanRegion.downScaledWidth\n : scanRegionWidth;\n const canvasHeight = scanRegion && scanRegion.downScaledHeight\n ? scanRegion.downScaledHeight\n : scanRegionHeight;\n // Setting the canvas width or height clears the canvas, even if the values didn't change, therefore only\n // set them if they actually changed.\n if (canvas.width !== canvasWidth) {\n canvas.width = canvasWidth;\n }\n if (canvas.height !== canvasHeight) {\n canvas.height = canvasHeight;\n }\n }\n\n const context = canvas.getContext('2d', { alpha: false });\n context.imageSmoothingEnabled = false; // gives less blurry images\n context.drawImage(\n image,\n scanRegionX, scanRegionY, scanRegionWidth, scanRegionHeight,\n 0, 0, canvas.width, canvas.height\n );\n return [canvas, context];\n }\n\n /* async */\n static _loadImage(imageOrFileOrBlobOrUrl) {\n if (imageOrFileOrBlobOrUrl instanceof HTMLCanvasElement || imageOrFileOrBlobOrUrl instanceof HTMLVideoElement\n || window.ImageBitmap && imageOrFileOrBlobOrUrl instanceof window.ImageBitmap\n || window.OffscreenCanvas && imageOrFileOrBlobOrUrl instanceof window.OffscreenCanvas) {\n return Promise.resolve(imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof Image) {\n return QrScanner._awaitImageLoad(imageOrFileOrBlobOrUrl).then(() => imageOrFileOrBlobOrUrl);\n } else if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob\n || imageOrFileOrBlobOrUrl instanceof URL || typeof(imageOrFileOrBlobOrUrl)==='string') {\n const image = new Image();\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n image.src = URL.createObjectURL(imageOrFileOrBlobOrUrl);\n } else {\n image.src = imageOrFileOrBlobOrUrl;\n }\n return QrScanner._awaitImageLoad(image).then(() => {\n if (imageOrFileOrBlobOrUrl instanceof File || imageOrFileOrBlobOrUrl instanceof Blob) {\n URL.revokeObjectURL(image.src);\n }\n return image;\n });\n } else {\n return Promise.reject('Unsupported image type.');\n }\n }\n\n /* async */\n static _awaitImageLoad(image) {\n return new Promise((resolve, reject) => {\n if (image.complete && image.naturalWidth!==0) {\n // already loaded\n resolve();\n } else {\n let onLoad, onError;\n onLoad = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n resolve();\n };\n onError = () => {\n image.removeEventListener('load', onLoad);\n image.removeEventListener('error', onError);\n reject('Image load error');\n };\n image.addEventListener('load', onLoad);\n image.addEventListener('error', onError);\n }\n });\n }\n\n /* async */\n static _postWorkerMessage(qrEngineOrQrEnginePromise, type, data) {\n return Promise.resolve(qrEngineOrQrEnginePromise).then((qrEngine) => {\n if (!(qrEngine instanceof Worker)) return;\n qrEngine.postMessage({ type, data });\n });\n }\n}\nQrScanner.DEFAULT_CANVAS_SIZE = 400;\nQrScanner.NO_QR_CODE_FOUND = 'No QR code found';\nQrScanner.WORKER_PATH = 'qr-scanner-worker.min.js';\n"],"names":["QrScanner","listCameras","then","cameras","length","catch","requestLabels","navigator","mediaDevices","Promise","resolve","openedStream","getUserMedia","audio","video","stream","enumerateDevices","devices","filter","device","kind","map","i","id","deviceId","label","finally","track","stop","removeTrack","onDecode","canvasSizeOrOnDecodeError","_onDecodeError","canvasSizeOrCalculateScanRegion","_calculateScanRegion","preferredCamera","$video","$canvas","document","createElement","_onDecode","_legacyCanvasSize","DEFAULT_CANVAS_SIZE","_preferredCamera","_flashOn","_paused","_active","console","warn","_scanRegion","_onPlay","bind","_onLoadedMetaData","_onVisibilityChange","disablePictureInPicture","playsInline","muted","shouldHideVideo","hidden","body","contains","appendChild","requestAnimationFrame","computedStyle","display","style","setProperty","visibility","opacity","width","height","addEventListener","_qrEnginePromise","createQrEngine","window","getPhotoCapabilities","result","fillLightMode","includes","error","reject","_setFlash","removeEventListener","_postWorkerMessage","location","protocol","srcObject","play","facingModeGuess","_getCameraStream","_getFacingMode","_setVideoMirror","e","pause","stopStreamImmediately","tracks","getTracks","stopStream","setTimeout","facingModeOrDeviceId","paused","wasPaused","start","imageOrFileOrUrl","scanRegion","qrEngine","canvas","disallowCanvasResizing","alsoTryWithoutScanRegion","promise","all","_loadImage","engine","image","canvasContext","_drawToCanvas","Worker","gotExternalWorker","postMessage","type","data","timeout","onMessage","onError","event","clearTimeout","NO_QR_CODE_FOUND","imageData","buffer","detect","scanResults","rawValue","message","scanImage","red","green","blue","useIntegerApproximation","inversionMode","workerPath","WORKER_PATH","BarcodeDetector","getSupportedFormats","supportedFormats","indexOf","formats","_scanFrame","videoHeight","x","Math","round","videoWidth","scanRegionSize","y","downScaledWidth","downScaledHeight","ended","readyState","log","exact","min","constraintsToTry","forEach","constraint","preferenceType","_getMatchingCameraStream","shift","on","hasFlash","getVideoTracks","applyConstraints","advanced","torch","facingMode","transform","videoStream","test","videoTrack","scanRegionWidth","scanRegionHeight","canvasWidth","canvasHeight","alpha","context","imageSmoothingEnabled","drawImage","scanRegionX","scanRegionY","imageOrFileOrBlobOrUrl","HTMLCanvasElement","HTMLVideoElement","ImageBitmap","OffscreenCanvas","Image","_awaitImageLoad","File","Blob","URL","src","createObjectURL","revokeObjectURL","complete","naturalWidth","onLoad","qrEngineOrQrEnginePromise"],"mappings":"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"}
\ No newline at end of file
diff --git a/src/qr-scanner.js b/src/qr-scanner.js
index dfc2374..96324a9 100644
--- a/src/qr-scanner.js
+++ b/src/qr-scanner.js
@@ -1,27 +1,55 @@
export default class QrScanner {
/* async */
static hasCamera() {
- if (!navigator.mediaDevices) return Promise.resolve(false);
- // note that enumerateDevices can always be called and does not prompt the user for permission. However, device
- // labels are only readable if served via https and an active media stream exists or permanent permission is
- // given. That doesn't matter for us though as we don't require labels.
- return navigator.mediaDevices.enumerateDevices()
- .then(devices => devices.some(device => device.kind === 'videoinput'))
+ return QrScanner.listCameras(false)
+ .then(cameras => !!cameras.length)
.catch(() => false);
}
+ /* async */
+ static listCameras(requestLabels = false) {
+ if (!navigator.mediaDevices) return Promise.resolve([]);
+
+ // Note that enumerateDevices can always be called and does not prompt the user for permission.
+ // However, enumerateDevices only includes device labels if served via https and an active media stream exists
+ // or permission to access the camera was given. Therefore, ask for camera permission by opening a stream, if
+ // labels were requested.
+ let openedStream = null;
+ return (requestLabels
+ ? navigator.mediaDevices.getUserMedia({ audio: false, video: true })
+ .then(stream => openedStream = stream)
+ // Fail gracefully, especially if the device has no camera or on mobile when the camera is already in
+ // use and some browsers disallow a second stream.
+ .catch(() => {})
+ : Promise.resolve()
+ )
+ .then(() => navigator.mediaDevices.enumerateDevices())
+ .then(devices => devices.filter(device => device.kind === 'videoinput').map((device, i) => ({
+ id: device.deviceId,
+ label: device.label || (i === 0 ? 'Default Camera' : `Camera ${i + 1}`),
+ })))
+ .finally(() => {
+ // close the stream we just opened for getting camera access for listing the device labels
+ if (!openedStream) return;
+ for (const track of openedStream.getTracks()) {
+ track.stop();
+ openedStream.removeTrack(track);
+ }
+ });
+ }
+
constructor(
video,
onDecode,
canvasSizeOrOnDecodeError = this._onDecodeError,
canvasSizeOrCalculateScanRegion = this._calculateScanRegion,
- preferredFacingMode = 'environment'
+ preferredCamera = 'environment'
) {
this.$video = video;
this.$canvas = document.createElement('canvas');
this._onDecode = onDecode;
this._legacyCanvasSize = QrScanner.DEFAULT_CANVAS_SIZE;
- this._preferredFacingMode = preferredFacingMode;
+ this._preferredCamera = preferredCamera;
this._active = false;
this._paused = false;
this._flashOn = false;
@@ -156,33 +184,38 @@ export default class QrScanner {
console.warn('The camera stream is only accessible if the page is transferred via https.');
}
this._active = true;
- this._paused = false;
if (document.hidden) {
// camera will be started as soon as tab is in foreground
return Promise.resolve();
}
- clearTimeout(this._offTimeout);
- this._offTimeout = null;
+ this._paused = false;
if (this.$video.srcObject) {
// camera stream already/still set
this.$video.play();
return Promise.resolve();
}
- let facingMode = this._preferredFacingMode;
- return this._getCameraStream(facingMode, true)
+ let facingModeGuess = this._preferredCamera === 'environment' || this._preferredCamera === 'user'
+ ? this._preferredCamera
+ : null;
+ return this._getCameraStream(this._preferredCamera, true)
.catch(() => {
- // We (probably) don't have a camera of the requested facing mode
- facingMode = facingMode === 'environment' ? 'user' : 'environment';
- return this._getCameraStream(); // throws if camera is not accessible (e.g. due to not https)
+ // If _preferredCamera was a facing mode, we (probably) don't have a camera of the requested facing mode
+ // and switch our facing mode guess.
+ facingModeGuess = facingModeGuess === 'environment'
+ ? 'user' // switch as the requested facing mode was not available
+ : 'environment'; // switch, or also assume 'environment' as default if facingModeGuess was null
+ // Retry unconstrained. Throws if camera is not accessible (e.g. due to not https)
+ return this._getCameraStream();
})
.then(stream => {
- // Try to determine the facing mode from the stream, otherwise use our guess. Note that the guess is not
- // always accurate as Safari returns cameras of different facing mode, even for exact constraints.
- facingMode = this._getFacingMode(stream) || facingMode;
+ // Try to determine the facing mode from the stream, otherwise use our guess or 'environment' as
+ // default. Note that the guess is not always accurate as Safari returns cameras of different facing
+ // mode, even for exact facingMode constraints.
+ facingModeGuess = this._getFacingMode(stream) || facingModeGuess || 'environment';
this.$video.srcObject = stream;
this.$video.play();
- this._setVideoMirror(facingMode);
+ this._setVideoMirror(facingModeGuess);
})
.catch(e => {
this._active = false;
@@ -195,23 +228,47 @@ export default class QrScanner {
this._active = false;
}
- pause() {
+ pause(stopStreamImmediately = false) {
this._paused = true;
if (!this._active) {
- return;
+ return Promise.resolve(true);
}
this.$video.pause();
- if (this._offTimeout) {
- return;
- }
- this._offTimeout = setTimeout(() => {
+
+ const stopStream = () => {
const tracks = this.$video.srcObject ? this.$video.srcObject.getTracks() : [];
for (const track of tracks) {
track.stop(); // note that this will also automatically turn the flashlight off
+ this.$video.srcObject.removeTrack(track);
}
this.$video.srcObject = null;
- this._offTimeout = null;
- }, 300);
+ };
+
+ if (stopStreamImmediately) {
+ stopStream();
+ return Promise.resolve(true);
+ }
+
+ return new Promise((resolve) => setTimeout(resolve, 300))
+ .then(() => {
+ if (!this._paused) return false;
+ stopStream();
+ return true;
+ });
+ }
+
+ /* async */
+ setCamera(facingModeOrDeviceId) {
+ if (facingModeOrDeviceId === this._preferredCamera) return Promise.resolve();
+ this._preferredCamera = facingModeOrDeviceId;
+ // Restart the scanner with the new camera which will also update the video mirror and the scan region. Note
+ // that we always pause the stream and not only if !this._paused as even if this._paused === true, the stream
+ // might still be running, as it's by default only stopped after a delay of 300ms.
+ const wasPaused = this._paused;
+ return this.pause(true).then((paused) => {
+ if (!paused || wasPaused || !this._active) return;
+ return this.start();
+ });
}
/* async */
@@ -379,19 +436,23 @@ export default class QrScanner {
console.log(error);
}
- _getCameraStream(facingMode, exact = false) {
+ _getCameraStream(preferredCamera, exact = false) {
const constraintsToTry = [{
width: { min: 1024 }
}, {
width: { min: 768 }
}, {}];
- if (facingMode) {
+ if (preferredCamera) {
+ const preferenceType = preferredCamera === 'environment' || preferredCamera === 'user'
+ ? 'facingMode'
+ : 'deviceId';
if (exact) {
- facingMode = { exact: facingMode };
+ preferredCamera = { exact: preferredCamera };
}
- constraintsToTry.forEach(constraint => constraint.facingMode = facingMode);
+ constraintsToTry.forEach(constraint => constraint[preferenceType] = preferredCamera);
}
+
return this._getMatchingCameraStream(constraintsToTry);
}
diff --git a/types/qr-scanner.d.ts b/types/qr-scanner.d.ts
index 54d2cd2..8a5bb0a 100644
--- a/types/qr-scanner.d.ts
+++ b/types/qr-scanner.d.ts
@@ -9,12 +9,14 @@ declare class QrScanner {
static hasCamera(): Promise;
+ static listCameras(requestLabels: boolean): Promise>;
+
constructor(
video: HTMLVideoElement,
onDecode: (result: string) => void,
onDecodeError?: (error: string) => void,
calculateScanRegion?: (video: HTMLVideoElement) => QrScanner.ScanRegion,
- preferredFacingMode?: 'environment' | 'user',
+ preferredCamera?: 'environment' | 'user' | QrScanner.DeviceId,
);
/** @deprecated */
constructor(
@@ -22,7 +24,7 @@ declare class QrScanner {
onDecode: (result: string) => void,
onDecodeError?: (error: string) => void,
canvasSize?: number,
- preferredFacingMode?: 'environment' | 'user',
+ preferredCamera?: 'environment' | 'user' | QrScanner.DeviceId,
);
/** @deprecated */
constructor(video: HTMLVideoElement, onDecode: (result: string) => void, canvasSize?: number);
@@ -35,7 +37,8 @@ declare class QrScanner {
destroy(): void;
start(): Promise;
stop(): void;
- pause(): void;
+ pause(stopStreamImmediately?: boolean): Promise;
+ setCamera(facingModeOrDeviceId: 'environment' | 'user' | QrScanner.DeviceId): Promise;
setGrayscaleWeights(red: number, green: number, blue: number, useIntegerApproximation?: boolean): void;
setInversionMode(inversionMode: QrScanner.InversionMode): void;
static scanImage(
@@ -67,6 +70,13 @@ declare namespace QrScanner {
downScaledHeight?: number;
}
+ export type DeviceId = string;
+
+ export interface Camera {
+ id: DeviceId;
+ label: string;
+ }
+
export type InversionMode = 'original' | 'invert' | 'both';
}