From fe31236d51442d210707a4fe5a35b203f7c9df38 Mon Sep 17 00:00:00 2001 From: Daniel Date: Mon, 16 Aug 2021 21:20:32 +0200 Subject: [PATCH] Fix turning flash off applyConstraints with torch: false does not work to turn the flashlight off, as a stream's torch stays continuously on, see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#torch. Therefore, we have to stop the stream to turn the flashlight off. --- qr-scanner.min.js | 38 +++++++++++----------- qr-scanner.min.js.map | 2 +- qr-scanner.umd.min.js | 35 ++++++++++---------- qr-scanner.umd.min.js.map | 2 +- src/qr-scanner.js | 68 +++++++++++++++++++++++---------------- 5 files changed, 80 insertions(+), 65 deletions(-) diff --git a/qr-scanner.min.js b/qr-scanner.min.js index 5280f3c..be07d95 100644 --- a/qr-scanner.min.js +++ b/qr-scanner.min.js @@ -1,20 +1,20 @@ -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);this._flashOn&&this.turnFlashOn().catch(()=>{})}).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){this._flashOn=a;return!a||this._active&&!this._paused? -this.hasFlash().then(b=>b?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:a}]}):Promise.reject("No flash available")).catch(b=>{this._flashOn=!a;throw b;}):Promise.resolve()}_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 +class f{static hasCamera(){return f.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,g="environment"){this.$video=a;this.$canvas=document.createElement("canvas");this._onDecode=b;this._legacyCanvasSize=f.DEFAULT_CANVAS_SIZE;this._preferredCamera=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 h=!1;a.hidden&&(a.hidden=!1,h=!0);document.body.contains(a)||(document.body.appendChild(a),h= +!0);requestAnimationFrame(()=>{let b=window.getComputedStyle(a);"none"===b.display&&(a.style.setProperty("display","block","important"),h=!0);"visible"!==b.visibility&&(a.style.setProperty("visibility","visible","important"),h=!0);h&&(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=f.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._flashOn?this.turnFlashOff():this.turnFlashOn()}turnFlashOn(){if(this._flashOn)return Promise.resolve(); +this._flashOn=!0;return!this._active||this._paused?Promise.resolve():this.hasFlash().then(a=>a?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:!0}]}):Promise.reject("No flash available")).catch(()=>{this._flashOn=!1;throw e;})}turnFlashOff(){if(this._flashOn)return this._flashOn=!1,this._restartVideoStream()}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange", +this._onVisibilityChange);this.stop();f._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);this._flashOn&&(this._flashOn=!1,this.turnFlashOn().catch(()=>{}))}).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;return this._restartVideoStream()}static scanImage(a,b=null,c=null,d=null,g=!1,h=!1){let k=c instanceof Worker,l=Promise.all([c|| +f.createQrEngine(),f._loadImage(a)]).then(([a,h])=>{c=a;let l;[d,l]=this._drawToCanvas(h,b,d,g);return c instanceof Worker?(k||c.postMessage({type:"inversionMode",data:"both"}),new Promise((a,b)=>{let g,h,k;h=d=>{"qrResult"===d.data.type&&(c.removeEventListener("message",h),c.removeEventListener("error",k),clearTimeout(g),null!==d.data.data?a(d.data.data):b(f.NO_QR_CODE_FOUND))};k=a=>{c.removeEventListener("message",h);c.removeEventListener("error",k);clearTimeout(g);b("Scanner error: "+(a?a.message|| +a:"Unknown Error"))};c.addEventListener("message",h);c.addEventListener("error",k);g=setTimeout(()=>k("timeout"),1E4);let m=l.getImageData(0,0,d.width,d.height);c.postMessage({type:"decode",data:m},[m.data.buffer])})):new Promise((a,b)=>{let g=setTimeout(()=>b("Scanner error: timeout"),1E4);c.detect(d).then(c=>{c.length?a(c[0].rawValue):b(f.NO_QR_CODE_FOUND)}).catch(a=>b("Scanner error: "+(a.message||a))).finally(()=>clearTimeout(g))})});b&&h&&(l=l.catch(()=>f.scanImage(a,null,c,d,g)));return l=l.finally(()=> +{k||f._postWorkerMessage(c,"close")})}setGrayscaleWeights(a,b,c,d=!0){f._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:c,useIntegerApproximation:d})}setInversionMode(a){f._postWorkerMessage(this._qrEnginePromise,"inversionMode",a)}static createQrEngine(a=f.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=>f.scanImage(this.$video,this._scanRegion,a,this.$canvas)).then(this._onDecode,a=>{this._active&&(-1!==(a.message||a).indexOf("service unavailable")&&(this._qrEnginePromise=f.createQrEngine()),this._onDecodeError(a))}).then(()=>this._scanFrame())})}_onDecodeError(a){a!==f.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.")}_restartVideoStream(){let a=this._paused;return this.pause(!0).then(b=>{if(b&&!a&&this._active)return this.start()})}_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,h=b&&b.y?b.y:0,k=b&&b.width?b.width:a.width||a.videoWidth,l=b&&b.height?b.height:a.height||a.videoHeight;d||(d=b&&b.downScaledWidth?b.downScaledWidth:k,b=b&&b.downScaledHeight?b.downScaledHeight:l,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,h,k,l,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 f._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 f._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})})}}f.DEFAULT_CANVAS_SIZE=400;f.NO_QR_CODE_FOUND="No QR code found";f.WORKER_PATH="qr-scanner-worker.min.js";export default f //# sourceMappingURL=qr-scanner.min.js.map diff --git a/qr-scanner.min.js.map b/qr-scanner.min.js.map index e751d65..d85d18f 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 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 // Restart the flash if it was previously on\n if (this._flashOn) {\n this.turnFlashOn().catch(() => {});\n }\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 this._flashOn = on;\n if (on && (!this._active || this._paused)) return Promise.resolve(); // will be started later on .start\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 }).catch((e) => {\n this._flashOn = !on;\n throw e;\n });\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","turnFlashOn","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 +{"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 if (this._flashOn) {\n return this.turnFlashOff();\n } else {\n return this.turnFlashOn();\n }\n }\n\n /* async */\n turnFlashOn() {\n if (this._flashOn) return Promise.resolve();\n this._flashOn = true;\n if (!this._active || this._paused) return Promise.resolve(); // flash will be turned on later on .start()\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: true }],\n });\n }).catch(() => {\n this._flashOn = false;\n throw e;\n });\n }\n\n /* async */\n turnFlashOff() {\n if (!this._flashOn) return;\n // applyConstraints with torch: false does not work to turn the flashlight off, as a stream's torch stays\n // continuously on, see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#torch. Therefore,\n // we have to stop the stream to turn the flashlight off.\n this._flashOn = false;\n return this._restartVideoStream();\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 // Restart the flash if it was previously on\n if (this._flashOn) {\n this._flashOn = false; // force turnFlashOn to restart the flash\n this.turnFlashOn().catch(() => {});\n }\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 /* async */\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.\n return this._restartVideoStream();\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 /* async */\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 /* async */\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 _restartVideoStream() {\n // Note that we always pause the stream and not only if !this._paused as even if this._paused === true, the\n // stream 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 _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","turnFlashOff","turnFlashOn","hasFlash","srcObject","getVideoTracks","applyConstraints","advanced","torch","e","_restartVideoStream","removeEventListener","_postWorkerMessage","location","protocol","play","facingModeGuess","_getCameraStream","_getFacingMode","_setVideoMirror","pause","stopStreamImmediately","tracks","getTracks","stopStream","setTimeout","facingModeOrDeviceId","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","start","videoHeight","x","Math","round","videoWidth","scanRegionSize","y","downScaledWidth","downScaledHeight","paused","ended","readyState","log","exact","min","constraintsToTry","forEach","constraint","preferenceType","_getMatchingCameraStream","shift","wasPaused","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 4aea0fd..b5456d0 100644 --- a/qr-scanner.umd.min.js +++ b/qr-scanner.umd.min.js @@ -1,20 +1,21 @@ '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= +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,f=this._calculateScanRegion,k="environment"){this.$video=a;this.$canvas=document.createElement("canvas");this._onDecode=b;this._legacyCanvasSize=d.DEFAULT_CANVAS_SIZE;this._preferredCamera=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 f?(this._legacyCanvasSize=f,console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future")):this._calculateScanRegion=f;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=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);this._flashOn&&this.turnFlashOn().catch(()=>{})}).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){this._flashOn=a;return!a||this._active&&!this._paused?this.hasFlash().then(b=>b?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:a}]}):Promise.reject("No flash available")).catch(b=>{this._flashOn=!a;throw b;}):Promise.resolve()}_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}) +return!1}):Promise.reject("Camera not started or not available")}isFlashOn(){return this._flashOn}toggleFlash(){return this._flashOn?this.turnFlashOff():this.turnFlashOn()}turnFlashOn(){if(this._flashOn)return Promise.resolve();this._flashOn=!0;return!this._active||this._paused?Promise.resolve():this.hasFlash().then(a=>a?this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:!0}]}):Promise.reject("No flash available")).catch(()=>{this._flashOn=!1;throw e;})}turnFlashOff(){if(this._flashOn)return this._flashOn= +!1,this._restartVideoStream()}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);this._flashOn&& +(this._flashOn=!1,this.turnFlashOn().catch(()=>{}))}).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;return this._restartVideoStream()}static scanImage(a,b=null,c=null,f=null,k=!1,g=!1){let h=c instanceof Worker,l=Promise.all([c||d.createQrEngine(),d._loadImage(a)]).then(([a,g])=>{c=a;let l;[f,l]=this._drawToCanvas(g,b,f,k);return c instanceof Worker?(h||c.postMessage({type:"inversionMode",data:"both"}),new Promise((a,b)=>{let k,g,h;g=f=>{"qrResult"===f.data.type&&(c.removeEventListener("message",g),c.removeEventListener("error", +h),clearTimeout(k),null!==f.data.data?a(f.data.data):b(d.NO_QR_CODE_FOUND))};h=a=>{c.removeEventListener("message",g);c.removeEventListener("error",h);clearTimeout(k);b("Scanner error: "+(a?a.message||a:"Unknown Error"))};c.addEventListener("message",g);c.addEventListener("error",h);k=setTimeout(()=>h("timeout"),1E4);let m=l.getImageData(0,0,f.width,f.height);c.postMessage({type:"decode",data:m},[m.data.buffer])})):new Promise((a,b)=>{let k=setTimeout(()=>b("Scanner error: timeout"),1E4);c.detect(f).then(c=> +{c.length?a(c[0].rawValue):b(d.NO_QR_CODE_FOUND)}).catch(a=>b("Scanner error: "+(a.message||a))).finally(()=>clearTimeout(k))})});b&&g&&(l=l.catch(()=>d.scanImage(a,null,c,f,k)));return l=l.finally(()=>{h||d._postWorkerMessage(c,"close")})}setGrayscaleWeights(a,b,c,f=!0){d._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:c,useIntegerApproximation:f})}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 f="environment"===a||"user"===a?"facingMode":"deviceId";b&&(a={exact:a});c.forEach(b=>b[f]=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.")}_restartVideoStream(){let a=this._paused;return this.pause(!0).then(b=>{if(b&&!a&&this._active)return this.start()})}_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,f=!1){c=c||document.createElement("canvas");let d=b&&b.x?b.x:0,g=b&&b.y?b.y:0,h= +b&&b.width?b.width:a.width||a.videoWidth,l=b&&b.height?b.height:a.height||a.videoHeight;f||(f=b&&b.downScaledWidth?b.downScaledWidth:h,b=b&&b.downScaledHeight?b.downScaledHeight:l,c.width!==f&&(c.width=f),c.height!==b&&(c.height=b));b=c.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,d,g,h,l,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 f,d;f=()=>{a.removeEventListener("load",f);a.removeEventListener("error",d);b()};d=()=>{a.removeEventListener("load",f);a.removeEventListener("error",d);c("Image load error")};a.addEventListener("load",f);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 f20184a..1ee0f0f 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 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 // Restart the flash if it was previously on\n if (this._flashOn) {\n this.turnFlashOn().catch(() => {});\n }\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 this._flashOn = on;\n if (on && (!this._active || this._paused)) return Promise.resolve(); // will be started later on .start\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 }).catch((e) => {\n this._flashOn = !on;\n throw e;\n });\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","turnFlashOn","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 +{"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 if (this._flashOn) {\n return this.turnFlashOff();\n } else {\n return this.turnFlashOn();\n }\n }\n\n /* async */\n turnFlashOn() {\n if (this._flashOn) return Promise.resolve();\n this._flashOn = true;\n if (!this._active || this._paused) return Promise.resolve(); // flash will be turned on later on .start()\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: true }],\n });\n }).catch(() => {\n this._flashOn = false;\n throw e;\n });\n }\n\n /* async */\n turnFlashOff() {\n if (!this._flashOn) return;\n // applyConstraints with torch: false does not work to turn the flashlight off, as a stream's torch stays\n // continuously on, see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#torch. Therefore,\n // we have to stop the stream to turn the flashlight off.\n this._flashOn = false;\n return this._restartVideoStream();\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 // Restart the flash if it was previously on\n if (this._flashOn) {\n this._flashOn = false; // force turnFlashOn to restart the flash\n this.turnFlashOn().catch(() => {});\n }\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 /* async */\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.\n return this._restartVideoStream();\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 /* async */\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 /* async */\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 _restartVideoStream() {\n // Note that we always pause the stream and not only if !this._paused as even if this._paused === true, the\n // stream 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 _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","turnFlashOff","turnFlashOn","hasFlash","srcObject","getVideoTracks","applyConstraints","advanced","torch","e","_restartVideoStream","removeEventListener","_postWorkerMessage","location","protocol","play","facingModeGuess","_getCameraStream","_getFacingMode","_setVideoMirror","pause","stopStreamImmediately","tracks","getTracks","stopStream","setTimeout","facingModeOrDeviceId","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","start","videoHeight","x","Math","round","videoWidth","scanRegionSize","y","downScaledWidth","downScaledHeight","paused","ended","readyState","log","exact","min","constraintsToTry","forEach","constraint","preferenceType","_getMatchingCameraStream","shift","wasPaused","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 f1b0783..6c7c0ed 100644 --- a/src/qr-scanner.js +++ b/src/qr-scanner.js @@ -152,17 +152,38 @@ export default class QrScanner { /* async */ toggleFlash() { - return this._setFlash(!this._flashOn); - } - - /* async */ - turnFlashOff() { - return this._setFlash(false); + if (this._flashOn) { + return this.turnFlashOff(); + } else { + return this.turnFlashOn(); + } } /* async */ turnFlashOn() { - return this._setFlash(true); + if (this._flashOn) return Promise.resolve(); + this._flashOn = true; + if (!this._active || this._paused) return Promise.resolve(); // flash will be turned on later on .start() + return this.hasFlash().then((hasFlash) => { + if (!hasFlash) return Promise.reject('No flash available'); + // Note that the video track is guaranteed to exist at this point + return this.$video.srcObject.getVideoTracks()[0].applyConstraints({ + advanced: [{ torch: true }], + }); + }).catch(() => { + this._flashOn = false; + throw e; + }); + } + + /* async */ + turnFlashOff() { + if (!this._flashOn) return; + // applyConstraints with torch: false does not work to turn the flashlight off, as a stream's torch stays + // continuously on, see https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#torch. Therefore, + // we have to stop the stream to turn the flashlight off. + this._flashOn = false; + return this._restartVideoStream(); } destroy() { @@ -219,6 +240,7 @@ export default class QrScanner { // Restart the flash if it was previously on if (this._flashOn) { + this._flashOn = false; // force turnFlashOn to restart the flash this.turnFlashOn().catch(() => {}); } }) @@ -233,6 +255,7 @@ export default class QrScanner { this._active = false; } + /* async */ pause(stopStreamImmediately = false) { this._paused = true; if (!this._active) { @@ -266,14 +289,8 @@ export default class QrScanner { 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(); - }); + // Restart the scanner with the new camera which will also update the video mirror and the scan region. + return this._restartVideoStream(); } /* async */ @@ -441,6 +458,7 @@ export default class QrScanner { console.log(error); } + /* async */ _getCameraStream(preferredCamera, exact = false) { const constraintsToTry = [{ width: { min: 1024 } @@ -461,6 +479,7 @@ export default class QrScanner { return this._getMatchingCameraStream(constraintsToTry); } + /* async */ _getMatchingCameraStream(constraintsToTry) { if (!navigator.mediaDevices || constraintsToTry.length === 0) { return Promise.reject('Camera not found.'); @@ -471,18 +490,13 @@ export default class QrScanner { } /* async */ - _setFlash(on) { - this._flashOn = on; - if (on && (!this._active || this._paused)) return Promise.resolve(); // will be started later on .start - return this.hasFlash().then((hasFlash) => { - if (!hasFlash) return Promise.reject('No flash available'); - // Note that the video track is guaranteed to exist at this point - return this.$video.srcObject.getVideoTracks()[0].applyConstraints({ - advanced: [{ torch: on }], - }); - }).catch((e) => { - this._flashOn = !on; - throw e; + _restartVideoStream() { + // 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(); }); }