mirror of
https://github.com/nimiq/qr-scanner.git
synced 2026-07-27 19:56:28 +00:00
Vendored
+17
-17
@@ -30,21 +30,21 @@ this;return c.asyncExecutePromiseGeneratorFunction(function*(){if(!a._flashOn&&!
|
||||
this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);window.removeEventListener("resize",this._updateOverlay);this._destroyed=!0;this._flashOn=!1;this.stop();h._postWorkerMessage(this._qrEnginePromise,"close")}start(){const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){if(!(a._active&&!a._paused||a._destroyed||("https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https."),
|
||||
a._active=!0,document.hidden)))if(a._paused=!1,a.$video.srcObject)yield a.$video.play();else try{let {stream:b,facingMode:d}=yield a._getCameraStream();!a._active||a._paused?h._stopVideoStream(b):(a._setVideoMirror(d),a.$video.srcObject=b,yield a.$video.play(),a._flashOn&&(a._flashOn=!1,a.turnFlashOn().catch(()=>{})))}catch(b){if(!a._paused)throw a._active=!1,b;}})}stop(){this.pause();this._active=!1}pause(a=!1){const b=this;return c.asyncExecutePromiseGeneratorFunction(function*(){b._paused=!0;if(!b._active)return!0;
|
||||
b.$video.pause();b.$overlay&&(b.$overlay.style.display="none");let d=()=>{b.$video.srcObject instanceof MediaStream&&(h._stopVideoStream(b.$video.srcObject),b.$video.srcObject=null)};if(a)return d(),!0;yield new Promise(e=>setTimeout(e,300));if(!b._paused)return!1;d();return!0})}setCamera(a){const b=this;return c.asyncExecutePromiseGeneratorFunction(function*(){a!==b._preferredCamera&&(b._preferredCamera=a,yield b._restartVideoStream())})}static scanImage(a,b,d,e,f=!1,g=!1){return c.asyncExecutePromiseGeneratorFunction(function*(){let l,
|
||||
n=!1;b&&("scanRegion"in b||"qrEngine"in b||"canvas"in b||"disallowCanvasResizing"in b||"alsoTryWithoutScanRegion"in b||"returnDetailedScanResult"in b)?(l=b.scanRegion,d=b.qrEngine,e=b.canvas,f=b.disallowCanvasResizing||!1,g=b.alsoTryWithoutScanRegion||!1,n=!0):b||d||e||f||g?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true.");
|
||||
let t=!!d;try{let m,r;[d,m]=yield Promise.all([d||h.createQrEngine(),h._loadImage(a)]);[e,r]=h._drawToCanvas(m,l,e,f);if(d instanceof Worker){let k=d;t||k.postMessage({type:"inversionMode",data:"both"});return yield new Promise((p,w)=>{let x,v,u;v=q=>{"qrResult"===q.data.type&&(k.removeEventListener("message",v),k.removeEventListener("error",u),clearTimeout(x),null!==q.data.data?p(n?{data:q.data.data,cornerPoints:h._convertPoints(q.data.cornerPoints,l)}:q.data.data):w(h.NO_QR_CODE_FOUND))};u=q=>{k.removeEventListener("message",
|
||||
v);k.removeEventListener("error",u);clearTimeout(x);w("Scanner error: "+(q?q.message||q:"Unknown Error"))};k.addEventListener("message",v);k.addEventListener("error",u);x=setTimeout(()=>u("timeout"),1E4);let y=r.getImageData(0,0,e.width,e.height);k.postMessage({type:"decode",data:y},[y.data.buffer])})}return yield Promise.race([new Promise((k,p)=>window.setTimeout(()=>p("Scanner error: timeout"),1E4)),(()=>c.asyncExecutePromiseGeneratorFunction(function*(){try{let [k]=yield d.detect(e);if(!k)throw h.NO_QR_CODE_FOUND;
|
||||
return n?{data:k.rawValue,cornerPoints:h._convertPoints(k.cornerPoints,l)}:k.rawValue}catch(k){throw`Scanner error: ${k.message||k}`;}}))()])}catch(m){if(!l||!g)throw m;let r=yield h.scanImage(a,{qrEngine:d,canvas:e,disallowCanvasResizing:f});return n?r:r.data}finally{t||h._postWorkerMessage(d,"close")}})}setGrayscaleWeights(a,b,d,e=!0){h._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:d,useIntegerApproximation:e})}setInversionMode(a){h._postWorkerMessage(this._qrEnginePromise,
|
||||
"inversionMode",a)}static createQrEngine(a=h.WORKER_PATH){return c.asyncExecutePromiseGeneratorFunction(function*(){return"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(yield BarcodeDetector.getSupportedFormats()).includes("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a)})}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay();this.$overlay&&(this.$overlay.style.display="");this._scanFrame()}_onLoadedMetaData(){this._scanRegion=
|
||||
this._calculateScanRegion(this.$video);this._updateOverlay()}_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}}_updateOverlay(){requestAnimationFrame(()=>{if(this.$overlay){var a=this.$video,b=a.videoWidth,d=a.videoHeight,
|
||||
e=a.offsetWidth,f=a.offsetHeight,g=a.offsetLeft,l=a.offsetTop,n=window.getComputedStyle(a),t=n.objectFit,m=b/d,r=e/f;switch(t){case "none":var k=b;var p=d;break;case "fill":k=e;p=f;break;default:("cover"===t?m>r:m<r)?(p=f,k=p*m):(k=e,p=k/m),"scale-down"===t&&(k=Math.min(k,b),p=Math.min(p,d))}var [w,x]=n.objectPosition.split(" ").map((u,y)=>{const q=parseFloat(u);return u.endsWith("%")?(y?f-p:e-k)*q/100:q});n=this._scanRegion.width||b;r=this._scanRegion.height||d;t=this._scanRegion.x||0;var v=this._scanRegion.y||
|
||||
0;m=this.$overlay.style;m.width=`${n/b*k}px`;m.height=`${r/d*p}px`;m.top=`${l+x+v/d*p}px`;d=/scaleX\(-1\)/.test(a.style.transform);m.left=`${g+(d?e-w-k:w)+(d?b-t-n:t)/b*k}px`;m.transform=a.style.transform}})}static _convertPoints(a,b){if(!b)return a;let d=b.x||0,e=b.y||0,f=b.width&&b.downScaledWidth?b.width/b.downScaledWidth:1;b=b.height&&b.downScaledHeight?b.height/b.downScaledHeight:1;for(let g of a)g.x=g.x*f+d,g.y=g.y*b+e;return a}_scanFrame(){!this._active||this.$video.paused||this.$video.ended||
|
||||
("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):requestAnimationFrame)(()=>{const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){if(!(1>=a.$video.readyState)){var b=Date.now()-a._lastScanTimestamp,d=1E3/a._maxScansPerSecond;b<d&&(yield new Promise(f=>setTimeout(f,d-b)));a._lastScanTimestamp=Date.now();try{var e=yield h.scanImage(a.$video,{scanRegion:a._scanRegion,qrEngine:a._qrEnginePromise,canvas:a.$canvas})}catch(f){if(!a._active)return;
|
||||
(f.message||f).includes("service unavailable")&&(a._qrEnginePromise=h.createQrEngine());a._onDecodeError(f)}e?(a._onDecode?a._onDecode(e):a._legacyOnDecode&&a._legacyOnDecode(e.data),a.$codeOutlineHighlight&&(clearTimeout(a._codeOutlineHighlightRemovalTimeout),a._codeOutlineHighlightRemovalTimeout=void 0,a.$codeOutlineHighlight.setAttribute("viewBox",`${a._scanRegion.x||0} `+`${a._scanRegion.y||0} `+`${a._scanRegion.width||a.$video.videoWidth} `+`${a._scanRegion.height||a.$video.videoHeight}`),a.$codeOutlineHighlight.firstElementChild.setAttribute("points",
|
||||
e.cornerPoints.map(({x:f,y:g})=>`${f},${g}`).join(" ")),a.$codeOutlineHighlight.style.display="")):a.$codeOutlineHighlight&&!a._codeOutlineHighlightRemovalTimeout&&(a._codeOutlineHighlightRemovalTimeout=setTimeout(()=>a.$codeOutlineHighlight.style.display="none",100))}a._scanFrame()})})}_onDecodeError(a){a!==h.NO_QR_CODE_FOUND&&console.log(a)}_getCameraStream(){const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){if(!navigator.mediaDevices)throw"Camera not found.";let b=/^(environment|user)$/.test(a._preferredCamera)?
|
||||
"facingMode":"deviceId",d=[{width:{min:1024}},{width:{min:768}},{}],e=d.map(f=>Object.assign({},f,{[b]:{exact:a._preferredCamera}}));for(let f of[...e,...d])try{let g=yield navigator.mediaDevices.getUserMedia({video:f,audio:!1}),l=a._getFacingMode(g)||(f.facingMode?a._preferredCamera:"environment"===a._preferredCamera?"user":"environment");return{stream:g,facingMode:l}}catch(g){}throw"Camera not found.";})}_restartVideoStream(){const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){let b=
|
||||
a._paused;(yield a.pause(!0))&&!b&&a._active&&(yield a.start())})}static _stopVideoStream(a){for(let b of a.getTracks())b.stop(),a.removeTrack(b)}_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,d,e=!1){d=d||document.createElement("canvas");let f=b&&b.x?b.x:0,g=b&&b.y?b.y:0,l=b&&b.width?b.width:
|
||||
a.videoWidth||a.width,n=b&&b.height?b.height:a.videoHeight||a.height;e||(e=b&&b.downScaledWidth?b.downScaledWidth:l,b=b&&b.downScaledHeight?b.downScaledHeight:n,d.width!==e&&(d.width=e),d.height!==b&&(d.height=b));b=d.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,f,g,l,n,0,0,d.width,d.height);return[d,b]}static _loadImage(a){return c.asyncExecutePromiseGeneratorFunction(function*(){if(a instanceof Image)return yield h._awaitImageLoad(a),a;if(a instanceof HTMLVideoElement||a instanceof
|
||||
HTMLCanvasElement||a instanceof SVGImageElement||"OffscreenCanvas"in window&&a instanceof OffscreenCanvas||"ImageBitmap"in window&&a instanceof ImageBitmap)return 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.toString();try{return yield h._awaitImageLoad(b),b}finally{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src)}}else throw"Unsupported image type.";})}static _awaitImageLoad(a){return c.asyncExecutePromiseGeneratorFunction(function*(){a.complete&&
|
||||
0!==a.naturalWidth||(yield new Promise((b,d)=>{let e=f=>{a.removeEventListener("load",e);a.removeEventListener("error",e);f instanceof ErrorEvent?d("Image load error"):b()};a.addEventListener("load",e);a.addEventListener("error",e)}))})}static _postWorkerMessage(a,b,d){return c.asyncExecutePromiseGeneratorFunction(function*(){let e=yield a;e instanceof Worker&&e.postMessage({type:b,data:d})})}}h.DEFAULT_CANVAS_SIZE=400;h.NO_QR_CODE_FOUND="No QR code found";h.WORKER_PATH="qr-scanner-worker.min.js";
|
||||
export default h
|
||||
p=!1;b&&("scanRegion"in b||"qrEngine"in b||"canvas"in b||"disallowCanvasResizing"in b||"alsoTryWithoutScanRegion"in b||"returnDetailedScanResult"in b)?(l=b.scanRegion,d=b.qrEngine,e=b.canvas,f=b.disallowCanvasResizing||!1,g=b.alsoTryWithoutScanRegion||!1,p=!0):b||d||e||f||g?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true.");
|
||||
let r=!!d;try{let m,q;[d,m]=yield Promise.all([d||h.createQrEngine(),h._loadImage(a)]);[e,q]=h._drawToCanvas(m,l,e,f);let n;if(d instanceof Worker){let k=d;r||k.postMessage({type:"inversionMode",data:"both"});n=yield new Promise((t,z)=>{let x,v,w;v=u=>{"qrResult"===u.data.type&&(k.removeEventListener("message",v),k.removeEventListener("error",w),clearTimeout(x),null!==u.data.data?t({data:u.data.data,cornerPoints:h._convertPoints(u.data.cornerPoints,l)}):z(h.NO_QR_CODE_FOUND))};w=u=>{k.removeEventListener("message",
|
||||
v);k.removeEventListener("error",w);clearTimeout(x);z("Scanner error: "+(u?u.message||u:"Unknown Error"))};k.addEventListener("message",v);k.addEventListener("error",w);x=setTimeout(()=>w("timeout"),1E4);let y=q.getImageData(0,0,e.width,e.height);k.postMessage({type:"decode",data:y},[y.data.buffer])})}else n=yield Promise.race([new Promise((k,t)=>window.setTimeout(()=>t("Scanner error: timeout"),1E4)),(()=>c.asyncExecutePromiseGeneratorFunction(function*(){try{var [k]=yield d.detect(e);if(!k)throw h.NO_QR_CODE_FOUND;
|
||||
return{data:k.rawValue,cornerPoints:h._convertPoints(k.cornerPoints,l)}}catch(t){k=t.message||t;if(/not implemented|service unavailable/.test(k))return h._disableBarcodeDetector=!0,h.scanImage(a,{scanRegion:l,canvas:e,disallowCanvasResizing:f,alsoTryWithoutScanRegion:g});throw`Scanner error: ${k}`;}}))()]);return p?n:n.data}catch(m){if(!l||!g)throw m;let q=yield h.scanImage(a,{qrEngine:d,canvas:e,disallowCanvasResizing:f});return p?q:q.data}finally{r||h._postWorkerMessage(d,"close")}})}setGrayscaleWeights(a,
|
||||
b,d,e=!0){h._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:a,green:b,blue:d,useIntegerApproximation:e})}setInversionMode(a){h._postWorkerMessage(this._qrEnginePromise,"inversionMode",a)}static createQrEngine(a=h.WORKER_PATH){return c.asyncExecutePromiseGeneratorFunction(function*(){return!h._disableBarcodeDetector&&"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(yield BarcodeDetector.getSupportedFormats()).includes("qr_code")?new BarcodeDetector({formats:["qr_code"]}):
|
||||
new Worker(a)})}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay();this.$overlay&&(this.$overlay.style.display="");this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay()}_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}}_updateOverlay(){requestAnimationFrame(()=>{if(this.$overlay){var a=this.$video,b=a.videoWidth,d=a.videoHeight,e=a.offsetWidth,f=a.offsetHeight,g=a.offsetLeft,l=a.offsetTop,p=window.getComputedStyle(a),r=p.objectFit,m=b/d,q=e/f;switch(r){case "none":var n=b;var k=d;break;case "fill":n=e;k=f;break;default:("cover"===r?m>q:m<q)?(k=f,n=k*m):(n=e,k=n/m),"scale-down"===r&&(n=Math.min(n,b),k=Math.min(k,d))}var [t,
|
||||
z]=p.objectPosition.split(" ").map((v,w)=>{const y=parseFloat(v);return v.endsWith("%")?(w?f-k:e-n)*y/100:y});p=this._scanRegion.width||b;q=this._scanRegion.height||d;r=this._scanRegion.x||0;var x=this._scanRegion.y||0;m=this.$overlay.style;m.width=`${p/b*n}px`;m.height=`${q/d*k}px`;m.top=`${l+z+x/d*k}px`;d=/scaleX\(-1\)/.test(a.style.transform);m.left=`${g+(d?e-t-n:t)+(d?b-r-p:r)/b*n}px`;m.transform=a.style.transform}})}static _convertPoints(a,b){if(!b)return a;let d=b.x||0,e=b.y||0,f=b.width&&b.downScaledWidth?
|
||||
b.width/b.downScaledWidth:1;b=b.height&&b.downScaledHeight?b.height/b.downScaledHeight:1;for(let g of a)g.x=g.x*f+d,g.y=g.y*b+e;return a}_scanFrame(){!this._active||this.$video.paused||this.$video.ended||("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):requestAnimationFrame)(()=>{const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){if(!(1>=a.$video.readyState)){var b=Date.now()-a._lastScanTimestamp,d=1E3/a._maxScansPerSecond;b<d&&
|
||||
(yield new Promise(f=>setTimeout(f,d-b)));a._lastScanTimestamp=Date.now();try{var e=yield h.scanImage(a.$video,{scanRegion:a._scanRegion,qrEngine:a._qrEnginePromise,canvas:a.$canvas})}catch(f){if(!a._active)return;a._onDecodeError(f)}!h._disableBarcodeDetector||(yield a._qrEnginePromise)instanceof Worker||(a._qrEnginePromise=h.createQrEngine());e?(a._onDecode?a._onDecode(e):a._legacyOnDecode&&a._legacyOnDecode(e.data),a.$codeOutlineHighlight&&(clearTimeout(a._codeOutlineHighlightRemovalTimeout),a._codeOutlineHighlightRemovalTimeout=
|
||||
void 0,a.$codeOutlineHighlight.setAttribute("viewBox",`${a._scanRegion.x||0} `+`${a._scanRegion.y||0} `+`${a._scanRegion.width||a.$video.videoWidth} `+`${a._scanRegion.height||a.$video.videoHeight}`),a.$codeOutlineHighlight.firstElementChild.setAttribute("points",e.cornerPoints.map(({x:f,y:g})=>`${f},${g}`).join(" ")),a.$codeOutlineHighlight.style.display="")):a.$codeOutlineHighlight&&!a._codeOutlineHighlightRemovalTimeout&&(a._codeOutlineHighlightRemovalTimeout=setTimeout(()=>a.$codeOutlineHighlight.style.display=
|
||||
"none",100))}a._scanFrame()})})}_onDecodeError(a){a!==h.NO_QR_CODE_FOUND&&console.log(a)}_getCameraStream(){const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){if(!navigator.mediaDevices)throw"Camera not found.";let b=/^(environment|user)$/.test(a._preferredCamera)?"facingMode":"deviceId",d=[{width:{min:1024}},{width:{min:768}},{}],e=d.map(f=>Object.assign({},f,{[b]:{exact:a._preferredCamera}}));for(let f of[...e,...d])try{let g=yield navigator.mediaDevices.getUserMedia({video:f,
|
||||
audio:!1}),l=a._getFacingMode(g)||(f.facingMode?a._preferredCamera:"environment"===a._preferredCamera?"user":"environment");return{stream:g,facingMode:l}}catch(g){}throw"Camera not found.";})}_restartVideoStream(){const a=this;return c.asyncExecutePromiseGeneratorFunction(function*(){let b=a._paused;(yield a.pause(!0))&&!b&&a._active&&(yield a.start())})}static _stopVideoStream(a){for(let b of a.getTracks())b.stop(),a.removeTrack(b)}_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,d,e=!1){d=d||document.createElement("canvas");let f=b&&b.x?b.x:0,g=b&&b.y?b.y:0,l=b&&b.width?b.width:a.videoWidth||a.width,p=b&&b.height?b.height:a.videoHeight||a.height;e||(e=b&&b.downScaledWidth?b.downScaledWidth:l,b=b&&b.downScaledHeight?b.downScaledHeight:p,d.width!==e&&(d.width=e),d.height!==b&&(d.height=
|
||||
b));b=d.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,f,g,l,p,0,0,d.width,d.height);return[d,b]}static _loadImage(a){return c.asyncExecutePromiseGeneratorFunction(function*(){if(a instanceof Image)return yield h._awaitImageLoad(a),a;if(a instanceof HTMLVideoElement||a instanceof HTMLCanvasElement||a instanceof SVGImageElement||"OffscreenCanvas"in window&&a instanceof OffscreenCanvas||"ImageBitmap"in window&&a instanceof ImageBitmap)return 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.toString();try{return yield h._awaitImageLoad(b),b}finally{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src)}}else throw"Unsupported image type.";})}static _awaitImageLoad(a){return c.asyncExecutePromiseGeneratorFunction(function*(){a.complete&&0!==a.naturalWidth||(yield new Promise((b,d)=>{let e=f=>{a.removeEventListener("load",e);a.removeEventListener("error",
|
||||
e);f instanceof ErrorEvent?d("Image load error"):b()};a.addEventListener("load",e);a.addEventListener("error",e)}))})}static _postWorkerMessage(a,b,d){return c.asyncExecutePromiseGeneratorFunction(function*(){let e=yield a;e instanceof Worker&&e.postMessage({type:b,data:d})})}}h.DEFAULT_CANVAS_SIZE=400;h.NO_QR_CODE_FOUND="No QR code found";h.WORKER_PATH="qr-scanner-worker.min.js";h._disableBarcodeDetector=!1;export default h
|
||||
//# sourceMappingURL=qr-scanner.legacy.min.js.map
|
||||
|
||||
Vendored
+26
-26
@@ -1,29 +1,29 @@
|
||||
class f{constructor(a,b,c,d,e){this._legacyCanvasSize=f.DEFAULT_CANVAS_SIZE;this._preferredCamera="environment";this._maxScansPerSecond=25;this._lastScanTimestamp=-1;this._destroyed=this._flashOn=this._paused=this._active=!1;this.$video=a;this.$canvas=document.createElement("canvas");c&&"object"===typeof c?this._onDecode=b:(c||d||e?console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future"):console.warn("Note that the type of the scan result passed to onDecode will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true."),
|
||||
this._legacyOnDecode=b);b="object"===typeof c?c:{};this._onDecodeError=b.onDecodeError||("function"===typeof c?c:this._onDecodeError);this._calculateScanRegion=b.calculateScanRegion||("function"===typeof d?d:this._calculateScanRegion);this._preferredCamera=b.preferredCamera||e||this._preferredCamera;this._legacyCanvasSize="number"===typeof c?c:"number"===typeof d?d:this._legacyCanvasSize;this._maxScansPerSecond=b.maxScansPerSecond||this._maxScansPerSecond;this._onPlay=this._onPlay.bind(this);this._onLoadedMetaData=
|
||||
this._onLoadedMetaData.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);this._updateOverlay=this._updateOverlay.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);c=a.parentElement;if(b.highlightScanRegion||b.highlightCodeOutline)d=!!b.overlay,this.$overlay=b.overlay||document.createElement("div"),e=this.$overlay.style,e.position="absolute",e.display="none",
|
||||
e.pointerEvents="none",this.$overlay.classList.add("scan-region-highlight"),!d&&b.highlightScanRegion&&(e.outline="#e9b213 solid 5px",c.insertBefore(this.$overlay,this.$video.nextSibling)),b.highlightCodeOutline&&(this.$codeOutlineHighlight=document.createElementNS("http://www.w3.org/2000/svg","svg"),b=document.createElementNS("http://www.w3.org/2000/svg","polygon"),this.$codeOutlineHighlight.appendChild(b),this.$overlay.appendChild(this.$codeOutlineHighlight),b=this.$codeOutlineHighlight.style,b.width=
|
||||
class e{constructor(a,b,c,d,f){this._legacyCanvasSize=e.DEFAULT_CANVAS_SIZE;this._preferredCamera="environment";this._maxScansPerSecond=25;this._lastScanTimestamp=-1;this._destroyed=this._flashOn=this._paused=this._active=!1;this.$video=a;this.$canvas=document.createElement("canvas");c&&"object"===typeof c?this._onDecode=b:(c||d||f?console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future"):console.warn("Note that the type of the scan result passed to onDecode will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true."),
|
||||
this._legacyOnDecode=b);b="object"===typeof c?c:{};this._onDecodeError=b.onDecodeError||("function"===typeof c?c:this._onDecodeError);this._calculateScanRegion=b.calculateScanRegion||("function"===typeof d?d:this._calculateScanRegion);this._preferredCamera=b.preferredCamera||f||this._preferredCamera;this._legacyCanvasSize="number"===typeof c?c:"number"===typeof d?d:this._legacyCanvasSize;this._maxScansPerSecond=b.maxScansPerSecond||this._maxScansPerSecond;this._onPlay=this._onPlay.bind(this);this._onLoadedMetaData=
|
||||
this._onLoadedMetaData.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);this._updateOverlay=this._updateOverlay.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);c=a.parentElement;if(b.highlightScanRegion||b.highlightCodeOutline)d=!!b.overlay,this.$overlay=b.overlay||document.createElement("div"),f=this.$overlay.style,f.position="absolute",f.display="none",
|
||||
f.pointerEvents="none",this.$overlay.classList.add("scan-region-highlight"),!d&&b.highlightScanRegion&&(f.outline="#e9b213 solid 5px",c.insertBefore(this.$overlay,this.$video.nextSibling)),b.highlightCodeOutline&&(this.$codeOutlineHighlight=document.createElementNS("http://www.w3.org/2000/svg","svg"),b=document.createElementNS("http://www.w3.org/2000/svg","polygon"),this.$codeOutlineHighlight.appendChild(b),this.$overlay.appendChild(this.$codeOutlineHighlight),b=this.$codeOutlineHighlight.style,b.width=
|
||||
"100%",b.height="100%",this.$codeOutlineHighlight.setAttribute("preserveAspectRatio","none"),b.display="none",this.$codeOutlineHighlight.classList.add("code-outline-highlight"),b.fill="none",b.stroke="#e9b213",b.strokeWidth="4");this._scanRegion=this._calculateScanRegion(a);requestAnimationFrame(()=>{let m=window.getComputedStyle(a);"none"===m.display&&(a.style.setProperty("display","block","important"),h=!0);"visible"!==m.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",this.$overlay&&this.$overlay.parentElement&&this.$overlay.parentElement.removeChild(this.$overlay),delete this.$overlay,delete this.$codeOutlineHighlight);this.$overlay&&this._updateOverlay()});a.addEventListener("play",this._onPlay);a.addEventListener("loadedmetadata",this._onLoadedMetaData);document.addEventListener("visibilitychange",
|
||||
this._onVisibilityChange);window.addEventListener("resize",this._updateOverlay);this._qrEnginePromise=f.createQrEngine()}static async hasCamera(){try{return!!(await f.listCameras(!1)).length}catch(a){return!1}}static async listCameras(a=!1){if(!navigator.mediaDevices)return[];let b=async()=>(await navigator.mediaDevices.enumerateDevices()).filter(d=>"videoinput"===d.kind),c;try{a&&(await b()).every(d=>!d.label)&&(c=await navigator.mediaDevices.getUserMedia({audio:!1,video:!0}))}catch(d){}try{return(await b()).map((d,
|
||||
e)=>({id:d.deviceId,label:d.label||(0===e?"Default Camera":`Camera ${e+1}`)}))}finally{c&&(console.warn("Call listCameras after successfully starting a QR scanner to avoid creating a temporary video stream"),f._stopVideoStream(c))}}async hasFlash(){let a;try{if(this.$video.srcObject){if(!(this.$video.srcObject instanceof MediaStream))return!1;a=this.$video.srcObject}else a=(await this._getCameraStream()).stream;return"torch"in a.getVideoTracks()[0].getSettings()}catch(b){return!1}finally{a&&a!==this.$video.srcObject&&
|
||||
(console.warn("Call hasFlash after successfully starting the scanner to avoid creating a temporary video stream"),f._stopVideoStream(a))}}isFlashOn(){return this._flashOn}async toggleFlash(){this._flashOn?await this.turnFlashOff():await this.turnFlashOn()}async turnFlashOn(){if(!this._flashOn&&!this._destroyed&&(this._flashOn=!0,this._active&&!this._paused))try{if(!await this.hasFlash())throw"No flash available";await this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:!0}]})}catch(a){throw this._flashOn=
|
||||
!1,a;}}async turnFlashOff(){this._flashOn&&(this._flashOn=!1,await this._restartVideoStream())}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);window.removeEventListener("resize",this._updateOverlay);this._destroyed=!0;this._flashOn=!1;this.stop();f._postWorkerMessage(this._qrEnginePromise,"close")}async start(){if(!(this._active&&!this._paused||
|
||||
this._destroyed||("https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https."),this._active=!0,document.hidden)))if(this._paused=!1,this.$video.srcObject)await this.$video.play();else try{let {stream:a,facingMode:b}=await this._getCameraStream();!this._active||this._paused?f._stopVideoStream(a):(this._setVideoMirror(b),this.$video.srcObject=a,await this.$video.play(),this._flashOn&&(this._flashOn=!1,this.turnFlashOn().catch(()=>{})))}catch(a){if(!this._paused)throw this._active=
|
||||
!1,a;}}stop(){this.pause();this._active=!1}async pause(a=!1){this._paused=!0;if(!this._active)return!0;this.$video.pause();this.$overlay&&(this.$overlay.style.display="none");let b=()=>{this.$video.srcObject instanceof MediaStream&&(f._stopVideoStream(this.$video.srcObject),this.$video.srcObject=null)};if(a)return b(),!0;await new Promise(c=>setTimeout(c,300));if(!this._paused)return!1;b();return!0}async setCamera(a){a!==this._preferredCamera&&(this._preferredCamera=a,await this._restartVideoStream())}static async scanImage(a,
|
||||
b,c,d,e=!1,h=!1){let m,n=!1;b&&("scanRegion"in b||"qrEngine"in b||"canvas"in b||"disallowCanvasResizing"in b||"alsoTryWithoutScanRegion"in b||"returnDetailedScanResult"in b)?(m=b.scanRegion,c=b.qrEngine,d=b.canvas,e=b.disallowCanvasResizing||!1,h=b.alsoTryWithoutScanRegion||!1,n=!0):b||c||d||e||h?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true.");
|
||||
b=!!c;try{let q,k;[c,q]=await Promise.all([c||f.createQrEngine(),f._loadImage(a)]);[d,k]=f._drawToCanvas(q,m,d,e);if(c instanceof Worker){let g=c;b||g.postMessage({type:"inversionMode",data:"both"});return await new Promise((l,p)=>{let u,v,t;v=r=>{"qrResult"===r.data.type&&(g.removeEventListener("message",v),g.removeEventListener("error",t),clearTimeout(u),null!==r.data.data?l(n?{data:r.data.data,cornerPoints:f._convertPoints(r.data.cornerPoints,m)}:r.data.data):p(f.NO_QR_CODE_FOUND))};t=r=>{g.removeEventListener("message",
|
||||
v);g.removeEventListener("error",t);clearTimeout(u);p("Scanner error: "+(r?r.message||r:"Unknown Error"))};g.addEventListener("message",v);g.addEventListener("error",t);u=setTimeout(()=>t("timeout"),1E4);let w=k.getImageData(0,0,d.width,d.height);g.postMessage({type:"decode",data:w},[w.data.buffer])})}return await Promise.race([new Promise((g,l)=>window.setTimeout(()=>l("Scanner error: timeout"),1E4)),(async()=>{try{let [g]=await c.detect(d);if(!g)throw f.NO_QR_CODE_FOUND;return n?{data:g.rawValue,
|
||||
cornerPoints:f._convertPoints(g.cornerPoints,m)}:g.rawValue}catch(g){throw`Scanner error: ${g.message||g}`;}})()])}catch(q){if(!m||!h)throw q;let k=await f.scanImage(a,{qrEngine:c,canvas:d,disallowCanvasResizing:e});return n?k:k.data}finally{b||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 async createQrEngine(a=f.WORKER_PATH){return"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(await BarcodeDetector.getSupportedFormats()).includes("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a)}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay();this.$overlay&&(this.$overlay.style.display="");this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay()}_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}}_updateOverlay(){requestAnimationFrame(()=>{if(this.$overlay){var a=this.$video,b=a.videoWidth,c=a.videoHeight,d=a.offsetWidth,e=a.offsetHeight,h=a.offsetLeft,m=a.offsetTop,n=window.getComputedStyle(a),q=n.objectFit,
|
||||
k=b/c,g=d/e;switch(q){case "none":var l=b;var p=c;break;case "fill":l=d;p=e;break;default:("cover"===q?k>g:k<g)?(p=e,l=p*k):(l=d,p=l/k),"scale-down"===q&&(l=Math.min(l,b),p=Math.min(p,c))}var [u,v]=n.objectPosition.split(" ").map((w,r)=>{const x=parseFloat(w);return w.endsWith("%")?(r?e-p:d-l)*x/100:x});n=this._scanRegion.width||b;g=this._scanRegion.height||c;q=this._scanRegion.x||0;var t=this._scanRegion.y||0;k=this.$overlay.style;k.width=`${n/b*l}px`;k.height=`${g/c*p}px`;k.top=`${m+v+t/c*p}px`;
|
||||
c=/scaleX\(-1\)/.test(a.style.transform);k.left=`${h+(c?d-u-l:u)+(c?b-q-n:q)/b*l}px`;k.transform=a.style.transform}})}static _convertPoints(a,b){if(!b)return a;let c=b.x||0,d=b.y||0,e=b.width&&b.downScaledWidth?b.width/b.downScaledWidth:1;b=b.height&&b.downScaledHeight?b.height/b.downScaledHeight:1;for(let h of a)h.x=h.x*e+c,h.y=h.y*b+d;return a}_scanFrame(){!this._active||this.$video.paused||this.$video.ended||("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):
|
||||
requestAnimationFrame)(async()=>{if(!(1>=this.$video.readyState)){var a=Date.now()-this._lastScanTimestamp,b=1E3/this._maxScansPerSecond;a<b&&await new Promise(d=>setTimeout(d,b-a));this._lastScanTimestamp=Date.now();try{var c=await f.scanImage(this.$video,{scanRegion:this._scanRegion,qrEngine:this._qrEnginePromise,canvas:this.$canvas})}catch(d){if(!this._active)return;(d.message||d).includes("service unavailable")&&(this._qrEnginePromise=f.createQrEngine());this._onDecodeError(d)}c?(this._onDecode?
|
||||
this._onDecode(c):this._legacyOnDecode&&this._legacyOnDecode(c.data),this.$codeOutlineHighlight&&(clearTimeout(this._codeOutlineHighlightRemovalTimeout),this._codeOutlineHighlightRemovalTimeout=void 0,this.$codeOutlineHighlight.setAttribute("viewBox",`${this._scanRegion.x||0} `+`${this._scanRegion.y||0} `+`${this._scanRegion.width||this.$video.videoWidth} `+`${this._scanRegion.height||this.$video.videoHeight}`),this.$codeOutlineHighlight.firstElementChild.setAttribute("points",c.cornerPoints.map(({x:d,
|
||||
y:e})=>`${d},${e}`).join(" ")),this.$codeOutlineHighlight.style.display="")):this.$codeOutlineHighlight&&!this._codeOutlineHighlightRemovalTimeout&&(this._codeOutlineHighlightRemovalTimeout=setTimeout(()=>this.$codeOutlineHighlight.style.display="none",100))}this._scanFrame()})}_onDecodeError(a){a!==f.NO_QR_CODE_FOUND&&console.log(a)}async _getCameraStream(){if(!navigator.mediaDevices)throw"Camera not found.";let a=/^(environment|user)$/.test(this._preferredCamera)?"facingMode":"deviceId",b=[{width:{min:1024}},
|
||||
{width:{min:768}},{}],c=b.map(d=>Object.assign({},d,{[a]:{exact:this._preferredCamera}}));for(let d of[...c,...b])try{let e=await navigator.mediaDevices.getUserMedia({video:d,audio:!1}),h=this._getFacingMode(e)||(d.facingMode?this._preferredCamera:"environment"===this._preferredCamera?"user":"environment");return{stream:e,facingMode:h}}catch(e){}throw"Camera not found.";}async _restartVideoStream(){let a=this._paused;await this.pause(!0)&&!a&&this._active&&await this.start()}static _stopVideoStream(a){for(let b of a.getTracks())b.stop(),
|
||||
a.removeTrack(b)}_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,c,d=!1){c=c||document.createElement("canvas");let e=b&&b.x?b.x:0,h=b&&b.y?b.y:0,m=b&&b.width?b.width:a.videoWidth||a.width,n=b&&b.height?b.height:a.videoHeight||a.height;d||(d=b&&b.downScaledWidth?b.downScaledWidth:m,b=b&&b.downScaledHeight?
|
||||
b.downScaledHeight:n,c.width!==d&&(c.width=d),c.height!==b&&(c.height=b));b=c.getContext("2d",{alpha:!1});b.imageSmoothingEnabled=!1;b.drawImage(a,e,h,m,n,0,0,c.width,c.height);return[c,b]}static async _loadImage(a){if(a instanceof Image)return await f._awaitImageLoad(a),a;if(a instanceof HTMLVideoElement||a instanceof HTMLCanvasElement||a instanceof SVGImageElement||"OffscreenCanvas"in window&&a instanceof OffscreenCanvas||"ImageBitmap"in window&&a instanceof ImageBitmap)return 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.toString();try{return await f._awaitImageLoad(b),b}finally{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src)}}else throw"Unsupported image type.";}static async _awaitImageLoad(a){a.complete&&0!==a.naturalWidth||await new Promise((b,c)=>{let d=e=>{a.removeEventListener("load",d);a.removeEventListener("error",d);e instanceof ErrorEvent?
|
||||
c("Image load error"):b()};a.addEventListener("load",d);a.addEventListener("error",d)})}static async _postWorkerMessage(a,b,c){a=await 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
|
||||
this._onVisibilityChange);window.addEventListener("resize",this._updateOverlay);this._qrEnginePromise=e.createQrEngine()}static async hasCamera(){try{return!!(await e.listCameras(!1)).length}catch(a){return!1}}static async listCameras(a=!1){if(!navigator.mediaDevices)return[];let b=async()=>(await navigator.mediaDevices.enumerateDevices()).filter(d=>"videoinput"===d.kind),c;try{a&&(await b()).every(d=>!d.label)&&(c=await navigator.mediaDevices.getUserMedia({audio:!1,video:!0}))}catch(d){}try{return(await b()).map((d,
|
||||
f)=>({id:d.deviceId,label:d.label||(0===f?"Default Camera":`Camera ${f+1}`)}))}finally{c&&(console.warn("Call listCameras after successfully starting a QR scanner to avoid creating a temporary video stream"),e._stopVideoStream(c))}}async hasFlash(){let a;try{if(this.$video.srcObject){if(!(this.$video.srcObject instanceof MediaStream))return!1;a=this.$video.srcObject}else a=(await this._getCameraStream()).stream;return"torch"in a.getVideoTracks()[0].getSettings()}catch(b){return!1}finally{a&&a!==this.$video.srcObject&&
|
||||
(console.warn("Call hasFlash after successfully starting the scanner to avoid creating a temporary video stream"),e._stopVideoStream(a))}}isFlashOn(){return this._flashOn}async toggleFlash(){this._flashOn?await this.turnFlashOff():await this.turnFlashOn()}async turnFlashOn(){if(!this._flashOn&&!this._destroyed&&(this._flashOn=!0,this._active&&!this._paused))try{if(!await this.hasFlash())throw"No flash available";await this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:!0}]})}catch(a){throw this._flashOn=
|
||||
!1,a;}}async turnFlashOff(){this._flashOn&&(this._flashOn=!1,await this._restartVideoStream())}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);window.removeEventListener("resize",this._updateOverlay);this._destroyed=!0;this._flashOn=!1;this.stop();e._postWorkerMessage(this._qrEnginePromise,"close")}async start(){if(!(this._active&&!this._paused||
|
||||
this._destroyed||("https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https."),this._active=!0,document.hidden)))if(this._paused=!1,this.$video.srcObject)await this.$video.play();else try{let {stream:a,facingMode:b}=await this._getCameraStream();!this._active||this._paused?e._stopVideoStream(a):(this._setVideoMirror(b),this.$video.srcObject=a,await this.$video.play(),this._flashOn&&(this._flashOn=!1,this.turnFlashOn().catch(()=>{})))}catch(a){if(!this._paused)throw this._active=
|
||||
!1,a;}}stop(){this.pause();this._active=!1}async pause(a=!1){this._paused=!0;if(!this._active)return!0;this.$video.pause();this.$overlay&&(this.$overlay.style.display="none");let b=()=>{this.$video.srcObject instanceof MediaStream&&(e._stopVideoStream(this.$video.srcObject),this.$video.srcObject=null)};if(a)return b(),!0;await new Promise(c=>setTimeout(c,300));if(!this._paused)return!1;b();return!0}async setCamera(a){a!==this._preferredCamera&&(this._preferredCamera=a,await this._restartVideoStream())}static async scanImage(a,
|
||||
b,c,d,f=!1,h=!1){let m,n=!1;b&&("scanRegion"in b||"qrEngine"in b||"canvas"in b||"disallowCanvasResizing"in b||"alsoTryWithoutScanRegion"in b||"returnDetailedScanResult"in b)?(m=b.scanRegion,c=b.qrEngine,d=b.canvas,f=b.disallowCanvasResizing||!1,h=b.alsoTryWithoutScanRegion||!1,n=!0):b||c||d||f||h?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true.");
|
||||
b=!!c;try{let p,k;[c,p]=await Promise.all([c||e.createQrEngine(),e._loadImage(a)]);[d,k]=e._drawToCanvas(p,m,d,f);let r;if(c instanceof Worker){let g=c;b||g.postMessage({type:"inversionMode",data:"both"});r=await new Promise((l,v)=>{let w,u,t;u=q=>{"qrResult"===q.data.type&&(g.removeEventListener("message",u),g.removeEventListener("error",t),clearTimeout(w),null!==q.data.data?l({data:q.data.data,cornerPoints:e._convertPoints(q.data.cornerPoints,m)}):v(e.NO_QR_CODE_FOUND))};t=q=>{g.removeEventListener("message",
|
||||
u);g.removeEventListener("error",t);clearTimeout(w);v("Scanner error: "+(q?q.message||q:"Unknown Error"))};g.addEventListener("message",u);g.addEventListener("error",t);w=setTimeout(()=>t("timeout"),1E4);let x=k.getImageData(0,0,d.width,d.height);g.postMessage({type:"decode",data:x},[x.data.buffer])})}else r=await Promise.race([new Promise((g,l)=>window.setTimeout(()=>l("Scanner error: timeout"),1E4)),(async()=>{try{var [g]=await c.detect(d);if(!g)throw e.NO_QR_CODE_FOUND;return{data:g.rawValue,cornerPoints:e._convertPoints(g.cornerPoints,
|
||||
m)}}catch(l){g=l.message||l;if(/not implemented|service unavailable/.test(g))return e._disableBarcodeDetector=!0,e.scanImage(a,{scanRegion:m,canvas:d,disallowCanvasResizing:f,alsoTryWithoutScanRegion:h});throw`Scanner error: ${g}`;}})()]);return n?r:r.data}catch(p){if(!m||!h)throw p;let k=await e.scanImage(a,{qrEngine:c,canvas:d,disallowCanvasResizing:f});return n?k:k.data}finally{b||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 async createQrEngine(a=e.WORKER_PATH){return!e._disableBarcodeDetector&&"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(await BarcodeDetector.getSupportedFormats()).includes("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a)}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay();this.$overlay&&
|
||||
(this.$overlay.style.display="");this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay()}_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}}_updateOverlay(){requestAnimationFrame(()=>
|
||||
{if(this.$overlay){var a=this.$video,b=a.videoWidth,c=a.videoHeight,d=a.offsetWidth,f=a.offsetHeight,h=a.offsetLeft,m=a.offsetTop,n=window.getComputedStyle(a),p=n.objectFit,k=b/c,r=d/f;switch(p){case "none":var g=b;var l=c;break;case "fill":g=d;l=f;break;default:("cover"===p?k>r:k<r)?(l=f,g=l*k):(g=d,l=g/k),"scale-down"===p&&(g=Math.min(g,b),l=Math.min(l,c))}var [v,w]=n.objectPosition.split(" ").map((t,x)=>{const q=parseFloat(t);return t.endsWith("%")?(x?f-l:d-g)*q/100:q});n=this._scanRegion.width||
|
||||
b;r=this._scanRegion.height||c;p=this._scanRegion.x||0;var u=this._scanRegion.y||0;k=this.$overlay.style;k.width=`${n/b*g}px`;k.height=`${r/c*l}px`;k.top=`${m+w+u/c*l}px`;c=/scaleX\(-1\)/.test(a.style.transform);k.left=`${h+(c?d-v-g:v)+(c?b-p-n:p)/b*g}px`;k.transform=a.style.transform}})}static _convertPoints(a,b){if(!b)return a;let c=b.x||0,d=b.y||0,f=b.width&&b.downScaledWidth?b.width/b.downScaledWidth:1;b=b.height&&b.downScaledHeight?b.height/b.downScaledHeight:1;for(let h of a)h.x=h.x*f+c,h.y=
|
||||
h.y*b+d;return a}_scanFrame(){!this._active||this.$video.paused||this.$video.ended||("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):requestAnimationFrame)(async()=>{if(!(1>=this.$video.readyState)){var a=Date.now()-this._lastScanTimestamp,b=1E3/this._maxScansPerSecond;a<b&&await new Promise(d=>setTimeout(d,b-a));this._lastScanTimestamp=Date.now();try{var c=await e.scanImage(this.$video,{scanRegion:this._scanRegion,qrEngine:this._qrEnginePromise,canvas:this.$canvas})}catch(d){if(!this._active)return;
|
||||
this._onDecodeError(d)}!e._disableBarcodeDetector||await this._qrEnginePromise instanceof Worker||(this._qrEnginePromise=e.createQrEngine());c?(this._onDecode?this._onDecode(c):this._legacyOnDecode&&this._legacyOnDecode(c.data),this.$codeOutlineHighlight&&(clearTimeout(this._codeOutlineHighlightRemovalTimeout),this._codeOutlineHighlightRemovalTimeout=void 0,this.$codeOutlineHighlight.setAttribute("viewBox",`${this._scanRegion.x||0} `+`${this._scanRegion.y||0} `+`${this._scanRegion.width||this.$video.videoWidth} `+
|
||||
`${this._scanRegion.height||this.$video.videoHeight}`),this.$codeOutlineHighlight.firstElementChild.setAttribute("points",c.cornerPoints.map(({x:d,y:f})=>`${d},${f}`).join(" ")),this.$codeOutlineHighlight.style.display="")):this.$codeOutlineHighlight&&!this._codeOutlineHighlightRemovalTimeout&&(this._codeOutlineHighlightRemovalTimeout=setTimeout(()=>this.$codeOutlineHighlight.style.display="none",100))}this._scanFrame()})}_onDecodeError(a){a!==e.NO_QR_CODE_FOUND&&console.log(a)}async _getCameraStream(){if(!navigator.mediaDevices)throw"Camera not found.";
|
||||
let a=/^(environment|user)$/.test(this._preferredCamera)?"facingMode":"deviceId",b=[{width:{min:1024}},{width:{min:768}},{}],c=b.map(d=>Object.assign({},d,{[a]:{exact:this._preferredCamera}}));for(let d of[...c,...b])try{let f=await navigator.mediaDevices.getUserMedia({video:d,audio:!1}),h=this._getFacingMode(f)||(d.facingMode?this._preferredCamera:"environment"===this._preferredCamera?"user":"environment");return{stream:f,facingMode:h}}catch(f){}throw"Camera not found.";}async _restartVideoStream(){let a=
|
||||
this._paused;await this.pause(!0)&&!a&&this._active&&await this.start()}static _stopVideoStream(a){for(let b of a.getTracks())b.stop(),a.removeTrack(b)}_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,c,d=!1){c=c||document.createElement("canvas");let f=b&&b.x?b.x:0,h=b&&b.y?b.y:0,m=b&&b.width?
|
||||
b.width:a.videoWidth||a.width,n=b&&b.height?b.height:a.videoHeight||a.height;d||(d=b&&b.downScaledWidth?b.downScaledWidth:m,b=b&&b.downScaledHeight?b.downScaledHeight:n,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,h,m,n,0,0,c.width,c.height);return[c,b]}static async _loadImage(a){if(a instanceof Image)return await e._awaitImageLoad(a),a;if(a instanceof HTMLVideoElement||a instanceof HTMLCanvasElement||a instanceof SVGImageElement||
|
||||
"OffscreenCanvas"in window&&a instanceof OffscreenCanvas||"ImageBitmap"in window&&a instanceof ImageBitmap)return 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.toString();try{return await e._awaitImageLoad(b),b}finally{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src)}}else throw"Unsupported image type.";}static async _awaitImageLoad(a){a.complete&&0!==a.naturalWidth||
|
||||
await new Promise((b,c)=>{let d=f=>{a.removeEventListener("load",d);a.removeEventListener("error",d);f instanceof ErrorEvent?c("Image load error"):b()};a.addEventListener("load",d);a.addEventListener("error",d)})}static async _postWorkerMessage(a,b,c){a=await 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";e._disableBarcodeDetector=!1;export default e
|
||||
//# sourceMappingURL=qr-scanner.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+16
-16
@@ -11,20 +11,20 @@ try{if(this.$video.srcObject){if(!(this.$video.srcObject instanceof MediaStream)
|
||||
this._onVisibilityChange);window.removeEventListener("resize",this._updateOverlay);this._destroyed=!0;this._flashOn=!1;this.stop();e._postWorkerMessage(this._qrEnginePromise,"close")}async start(){if(!(this._active&&!this._paused||this._destroyed||("https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https."),this._active=!0,document.hidden)))if(this._paused=!1,this.$video.srcObject)await this.$video.play();else try{let {stream:a,facingMode:b}=
|
||||
await this._getCameraStream();!this._active||this._paused?e._stopVideoStream(a):(this._setVideoMirror(b),this.$video.srcObject=a,await this.$video.play(),this._flashOn&&(this._flashOn=!1,this.turnFlashOn().catch(()=>{})))}catch(a){if(!this._paused)throw this._active=!1,a;}}stop(){this.pause();this._active=!1}async pause(a=!1){this._paused=!0;if(!this._active)return!0;this.$video.pause();this.$overlay&&(this.$overlay.style.display="none");let b=()=>{this.$video.srcObject instanceof MediaStream&&(e._stopVideoStream(this.$video.srcObject),
|
||||
this.$video.srcObject=null)};if(a)return b(),!0;await new Promise(c=>setTimeout(c,300));if(!this._paused)return!1;b();return!0}async setCamera(a){a!==this._preferredCamera&&(this._preferredCamera=a,await this._restartVideoStream())}static async scanImage(a,b,c,d,f=!1,h=!1){let m,n=!1;b&&("scanRegion"in b||"qrEngine"in b||"canvas"in b||"disallowCanvasResizing"in b||"alsoTryWithoutScanRegion"in b||"returnDetailedScanResult"in b)?(m=b.scanRegion,c=b.qrEngine,d=b.canvas,f=b.disallowCanvasResizing||!1,
|
||||
h=b.alsoTryWithoutScanRegion||!1,n=!0):b||c||d||f||h?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true.");b=!!c;try{let q,k;[c,q]=await Promise.all([c||e.createQrEngine(),e._loadImage(a)]);[d,k]=e._drawToCanvas(q,m,d,f);if(c instanceof Worker){let g=c;b||g.postMessage({type:"inversionMode",
|
||||
data:"both"});return await new Promise((l,p)=>{let u,v,t;v=r=>{"qrResult"===r.data.type&&(g.removeEventListener("message",v),g.removeEventListener("error",t),clearTimeout(u),null!==r.data.data?l(n?{data:r.data.data,cornerPoints:e._convertPoints(r.data.cornerPoints,m)}:r.data.data):p(e.NO_QR_CODE_FOUND))};t=r=>{g.removeEventListener("message",v);g.removeEventListener("error",t);clearTimeout(u);p("Scanner error: "+(r?r.message||r:"Unknown Error"))};g.addEventListener("message",v);g.addEventListener("error",
|
||||
t);u=setTimeout(()=>t("timeout"),1E4);let w=k.getImageData(0,0,d.width,d.height);g.postMessage({type:"decode",data:w},[w.data.buffer])})}return await Promise.race([new Promise((g,l)=>window.setTimeout(()=>l("Scanner error: timeout"),1E4)),(async()=>{try{let [g]=await c.detect(d);if(!g)throw e.NO_QR_CODE_FOUND;return n?{data:g.rawValue,cornerPoints:e._convertPoints(g.cornerPoints,m)}:g.rawValue}catch(g){throw`Scanner error: ${g.message||g}`;}})()])}catch(q){if(!m||!h)throw q;let k=await e.scanImage(a,
|
||||
{qrEngine:c,canvas:d,disallowCanvasResizing:f});return n?k:k.data}finally{b||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 async createQrEngine(a=e.WORKER_PATH){return"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(await BarcodeDetector.getSupportedFormats()).includes("qr_code")?
|
||||
new BarcodeDetector({formats:["qr_code"]}):new Worker(a)}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay();this.$overlay&&(this.$overlay.style.display="");this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay()}_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}}_updateOverlay(){requestAnimationFrame(()=>{if(this.$overlay){var a=this.$video,b=a.videoWidth,c=a.videoHeight,d=a.offsetWidth,f=a.offsetHeight,h=a.offsetLeft,m=a.offsetTop,n=window.getComputedStyle(a),q=n.objectFit,k=b/c,g=d/f;switch(q){case "none":var l=b;var p=c;break;case "fill":l=d;p=f;break;default:("cover"===q?k>g:k<g)?(p=f,l=p*k):(l=d,p=l/k),"scale-down"===
|
||||
q&&(l=Math.min(l,b),p=Math.min(p,c))}var [u,v]=n.objectPosition.split(" ").map((w,r)=>{const x=parseFloat(w);return w.endsWith("%")?(r?f-p:d-l)*x/100:x});n=this._scanRegion.width||b;g=this._scanRegion.height||c;q=this._scanRegion.x||0;var t=this._scanRegion.y||0;k=this.$overlay.style;k.width=`${n/b*l}px`;k.height=`${g/c*p}px`;k.top=`${m+v+t/c*p}px`;c=/scaleX\(-1\)/.test(a.style.transform);k.left=`${h+(c?d-u-l:u)+(c?b-q-n:q)/b*l}px`;k.transform=a.style.transform}})}static _convertPoints(a,b){if(!b)return a;
|
||||
let c=b.x||0,d=b.y||0,f=b.width&&b.downScaledWidth?b.width/b.downScaledWidth:1;b=b.height&&b.downScaledHeight?b.height/b.downScaledHeight:1;for(let h of a)h.x=h.x*f+c,h.y=h.y*b+d;return a}_scanFrame(){!this._active||this.$video.paused||this.$video.ended||("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):requestAnimationFrame)(async()=>{if(!(1>=this.$video.readyState)){var a=Date.now()-this._lastScanTimestamp,b=1E3/this._maxScansPerSecond;a<b&&await new Promise(d=>
|
||||
setTimeout(d,b-a));this._lastScanTimestamp=Date.now();try{var c=await e.scanImage(this.$video,{scanRegion:this._scanRegion,qrEngine:this._qrEnginePromise,canvas:this.$canvas})}catch(d){if(!this._active)return;(d.message||d).includes("service unavailable")&&(this._qrEnginePromise=e.createQrEngine());this._onDecodeError(d)}c?(this._onDecode?this._onDecode(c):this._legacyOnDecode&&this._legacyOnDecode(c.data),this.$codeOutlineHighlight&&(clearTimeout(this._codeOutlineHighlightRemovalTimeout),this._codeOutlineHighlightRemovalTimeout=
|
||||
void 0,this.$codeOutlineHighlight.setAttribute("viewBox",`${this._scanRegion.x||0} `+`${this._scanRegion.y||0} `+`${this._scanRegion.width||this.$video.videoWidth} `+`${this._scanRegion.height||this.$video.videoHeight}`),this.$codeOutlineHighlight.firstElementChild.setAttribute("points",c.cornerPoints.map(({x:d,y:f})=>`${d},${f}`).join(" ")),this.$codeOutlineHighlight.style.display="")):this.$codeOutlineHighlight&&!this._codeOutlineHighlightRemovalTimeout&&(this._codeOutlineHighlightRemovalTimeout=
|
||||
setTimeout(()=>this.$codeOutlineHighlight.style.display="none",100))}this._scanFrame()})}_onDecodeError(a){a!==e.NO_QR_CODE_FOUND&&console.log(a)}async _getCameraStream(){if(!navigator.mediaDevices)throw"Camera not found.";let a=/^(environment|user)$/.test(this._preferredCamera)?"facingMode":"deviceId",b=[{width:{min:1024}},{width:{min:768}},{}],c=b.map(d=>Object.assign({},d,{[a]:{exact:this._preferredCamera}}));for(let d of[...c,...b])try{let f=await navigator.mediaDevices.getUserMedia({video:d,
|
||||
audio:!1}),h=this._getFacingMode(f)||(d.facingMode?this._preferredCamera:"environment"===this._preferredCamera?"user":"environment");return{stream:f,facingMode:h}}catch(f){}throw"Camera not found.";}async _restartVideoStream(){let a=this._paused;await this.pause(!0)&&!a&&this._active&&await this.start()}static _stopVideoStream(a){for(let b of a.getTracks())b.stop(),a.removeTrack(b)}_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,c,d=!1){c=c||document.createElement("canvas");let f=b&&b.x?b.x:0,h=b&&b.y?b.y:0,m=b&&b.width?b.width:a.videoWidth||a.width,n=b&&b.height?b.height:a.videoHeight||a.height;d||(d=b&&b.downScaledWidth?b.downScaledWidth:m,b=b&&b.downScaledHeight?b.downScaledHeight:n,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,h,m,n,0,0,c.width,c.height);return[c,b]}static async _loadImage(a){if(a instanceof Image)return await e._awaitImageLoad(a),a;if(a instanceof HTMLVideoElement||a instanceof HTMLCanvasElement||a instanceof SVGImageElement||"OffscreenCanvas"in window&&a instanceof OffscreenCanvas||"ImageBitmap"in window&&a instanceof ImageBitmap)return 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.toString();try{return await e._awaitImageLoad(b),b}finally{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src)}}else throw"Unsupported image type.";}static async _awaitImageLoad(a){a.complete&&0!==a.naturalWidth||await new Promise((b,c)=>{let d=f=>{a.removeEventListener("load",d);a.removeEventListener("error",d);f instanceof ErrorEvent?c("Image load error"):b()};a.addEventListener("load",d);a.addEventListener("error",d)})}static async _postWorkerMessage(a,b,c){a=await 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";return e})
|
||||
h=b.alsoTryWithoutScanRegion||!1,n=!0):b||c||d||f||h?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true.");b=!!c;try{let p,k;[c,p]=await Promise.all([c||e.createQrEngine(),e._loadImage(a)]);[d,k]=e._drawToCanvas(p,m,d,f);let r;if(c instanceof Worker){let g=c;b||g.postMessage({type:"inversionMode",
|
||||
data:"both"});r=await new Promise((l,v)=>{let w,u,t;u=q=>{"qrResult"===q.data.type&&(g.removeEventListener("message",u),g.removeEventListener("error",t),clearTimeout(w),null!==q.data.data?l({data:q.data.data,cornerPoints:e._convertPoints(q.data.cornerPoints,m)}):v(e.NO_QR_CODE_FOUND))};t=q=>{g.removeEventListener("message",u);g.removeEventListener("error",t);clearTimeout(w);v("Scanner error: "+(q?q.message||q:"Unknown Error"))};g.addEventListener("message",u);g.addEventListener("error",t);w=setTimeout(()=>
|
||||
t("timeout"),1E4);let x=k.getImageData(0,0,d.width,d.height);g.postMessage({type:"decode",data:x},[x.data.buffer])})}else r=await Promise.race([new Promise((g,l)=>window.setTimeout(()=>l("Scanner error: timeout"),1E4)),(async()=>{try{var [g]=await c.detect(d);if(!g)throw e.NO_QR_CODE_FOUND;return{data:g.rawValue,cornerPoints:e._convertPoints(g.cornerPoints,m)}}catch(l){g=l.message||l;if(/not implemented|service unavailable/.test(g))return e._disableBarcodeDetector=!0,e.scanImage(a,{scanRegion:m,canvas:d,
|
||||
disallowCanvasResizing:f,alsoTryWithoutScanRegion:h});throw`Scanner error: ${g}`;}})()]);return n?r:r.data}catch(p){if(!m||!h)throw p;let k=await e.scanImage(a,{qrEngine:c,canvas:d,disallowCanvasResizing:f});return n?k:k.data}finally{b||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 async createQrEngine(a=
|
||||
e.WORKER_PATH){return!e._disableBarcodeDetector&&"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(await BarcodeDetector.getSupportedFormats()).includes("qr_code")?new BarcodeDetector({formats:["qr_code"]}):new Worker(a)}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay();this.$overlay&&(this.$overlay.style.display="");this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video);this._updateOverlay()}_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}}_updateOverlay(){requestAnimationFrame(()=>{if(this.$overlay){var a=this.$video,b=a.videoWidth,c=a.videoHeight,d=a.offsetWidth,f=a.offsetHeight,h=a.offsetLeft,m=a.offsetTop,n=window.getComputedStyle(a),p=n.objectFit,
|
||||
k=b/c,r=d/f;switch(p){case "none":var g=b;var l=c;break;case "fill":g=d;l=f;break;default:("cover"===p?k>r:k<r)?(l=f,g=l*k):(g=d,l=g/k),"scale-down"===p&&(g=Math.min(g,b),l=Math.min(l,c))}var [v,w]=n.objectPosition.split(" ").map((t,x)=>{const q=parseFloat(t);return t.endsWith("%")?(x?f-l:d-g)*q/100:q});n=this._scanRegion.width||b;r=this._scanRegion.height||c;p=this._scanRegion.x||0;var u=this._scanRegion.y||0;k=this.$overlay.style;k.width=`${n/b*g}px`;k.height=`${r/c*l}px`;k.top=`${m+w+u/c*l}px`;
|
||||
c=/scaleX\(-1\)/.test(a.style.transform);k.left=`${h+(c?d-v-g:v)+(c?b-p-n:p)/b*g}px`;k.transform=a.style.transform}})}static _convertPoints(a,b){if(!b)return a;let c=b.x||0,d=b.y||0,f=b.width&&b.downScaledWidth?b.width/b.downScaledWidth:1;b=b.height&&b.downScaledHeight?b.height/b.downScaledHeight:1;for(let h of a)h.x=h.x*f+c,h.y=h.y*b+d;return a}_scanFrame(){!this._active||this.$video.paused||this.$video.ended||("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):
|
||||
requestAnimationFrame)(async()=>{if(!(1>=this.$video.readyState)){var a=Date.now()-this._lastScanTimestamp,b=1E3/this._maxScansPerSecond;a<b&&await new Promise(d=>setTimeout(d,b-a));this._lastScanTimestamp=Date.now();try{var c=await e.scanImage(this.$video,{scanRegion:this._scanRegion,qrEngine:this._qrEnginePromise,canvas:this.$canvas})}catch(d){if(!this._active)return;this._onDecodeError(d)}!e._disableBarcodeDetector||await this._qrEnginePromise instanceof Worker||(this._qrEnginePromise=e.createQrEngine());
|
||||
c?(this._onDecode?this._onDecode(c):this._legacyOnDecode&&this._legacyOnDecode(c.data),this.$codeOutlineHighlight&&(clearTimeout(this._codeOutlineHighlightRemovalTimeout),this._codeOutlineHighlightRemovalTimeout=void 0,this.$codeOutlineHighlight.setAttribute("viewBox",`${this._scanRegion.x||0} `+`${this._scanRegion.y||0} `+`${this._scanRegion.width||this.$video.videoWidth} `+`${this._scanRegion.height||this.$video.videoHeight}`),this.$codeOutlineHighlight.firstElementChild.setAttribute("points",c.cornerPoints.map(({x:d,
|
||||
y:f})=>`${d},${f}`).join(" ")),this.$codeOutlineHighlight.style.display="")):this.$codeOutlineHighlight&&!this._codeOutlineHighlightRemovalTimeout&&(this._codeOutlineHighlightRemovalTimeout=setTimeout(()=>this.$codeOutlineHighlight.style.display="none",100))}this._scanFrame()})}_onDecodeError(a){a!==e.NO_QR_CODE_FOUND&&console.log(a)}async _getCameraStream(){if(!navigator.mediaDevices)throw"Camera not found.";let a=/^(environment|user)$/.test(this._preferredCamera)?"facingMode":"deviceId",b=[{width:{min:1024}},
|
||||
{width:{min:768}},{}],c=b.map(d=>Object.assign({},d,{[a]:{exact:this._preferredCamera}}));for(let d of[...c,...b])try{let f=await navigator.mediaDevices.getUserMedia({video:d,audio:!1}),h=this._getFacingMode(f)||(d.facingMode?this._preferredCamera:"environment"===this._preferredCamera?"user":"environment");return{stream:f,facingMode:h}}catch(f){}throw"Camera not found.";}async _restartVideoStream(){let a=this._paused;await this.pause(!0)&&!a&&this._active&&await this.start()}static _stopVideoStream(a){for(let b of a.getTracks())b.stop(),
|
||||
a.removeTrack(b)}_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,c,d=!1){c=c||document.createElement("canvas");let f=b&&b.x?b.x:0,h=b&&b.y?b.y:0,m=b&&b.width?b.width:a.videoWidth||a.width,n=b&&b.height?b.height:a.videoHeight||a.height;d||(d=b&&b.downScaledWidth?b.downScaledWidth:m,b=b&&b.downScaledHeight?
|
||||
b.downScaledHeight:n,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,h,m,n,0,0,c.width,c.height);return[c,b]}static async _loadImage(a){if(a instanceof Image)return await e._awaitImageLoad(a),a;if(a instanceof HTMLVideoElement||a instanceof HTMLCanvasElement||a instanceof SVGImageElement||"OffscreenCanvas"in window&&a instanceof OffscreenCanvas||"ImageBitmap"in window&&a instanceof ImageBitmap)return 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.toString();try{return await e._awaitImageLoad(b),b}finally{(a instanceof File||a instanceof Blob)&&URL.revokeObjectURL(b.src)}}else throw"Unsupported image type.";}static async _awaitImageLoad(a){a.complete&&0!==a.naturalWidth||await new Promise((b,c)=>{let d=f=>{a.removeEventListener("load",d);a.removeEventListener("error",d);f instanceof ErrorEvent?
|
||||
c("Image load error"):b()};a.addEventListener("load",d);a.addEventListener("error",d)})}static async _postWorkerMessage(a,b,c){a=await 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";e._disableBarcodeDetector=!1;return e})
|
||||
//# sourceMappingURL=qr-scanner.umd.min.js.map
|
||||
|
||||
File diff suppressed because one or more lines are too long
+41
-18
@@ -2,6 +2,7 @@ export default class QrScanner {
|
||||
static readonly DEFAULT_CANVAS_SIZE = 400;
|
||||
static readonly NO_QR_CODE_FOUND = 'No QR code found';
|
||||
static WORKER_PATH = 'qr-scanner-worker.min.js';
|
||||
private static _disableBarcodeDetector = false;
|
||||
|
||||
static async hasCamera(): Promise<boolean> {
|
||||
try {
|
||||
@@ -485,6 +486,7 @@ export default class QrScanner {
|
||||
QrScanner._loadImage(imageOrFileOrBlobOrUrl),
|
||||
]);
|
||||
[canvas, canvasContext] = QrScanner._drawToCanvas(image, scanRegion, canvas, disallowCanvasResizing);
|
||||
let detailedScanResult: QrScanner.ScanResult;
|
||||
|
||||
if (qrEngine instanceof Worker) {
|
||||
const qrEngineWorker = qrEngine; // for ts to know that it's still a worker later in the event listeners
|
||||
@@ -492,7 +494,7 @@ export default class QrScanner {
|
||||
// Enable scanning of inverted color qr codes. Not using _postWorkerMessage as it's async
|
||||
qrEngineWorker.postMessage({ type: 'inversionMode', data: 'both' });
|
||||
}
|
||||
return await new Promise((resolve, reject) => {
|
||||
detailedScanResult = await new Promise((resolve, reject) => {
|
||||
let timeout: number;
|
||||
let onMessage: (event: MessageEvent) => void;
|
||||
let onError: (error: ErrorEvent | string) => void;
|
||||
@@ -504,10 +506,10 @@ export default class QrScanner {
|
||||
qrEngineWorker.removeEventListener('error', onError);
|
||||
clearTimeout(timeout);
|
||||
if (event.data.data !== null) {
|
||||
resolve(returnDetailedScanResult ? {
|
||||
resolve({
|
||||
data: event.data.data,
|
||||
cornerPoints: QrScanner._convertPoints(event.data.cornerPoints, scanRegion),
|
||||
} : event.data.data);
|
||||
});
|
||||
} else {
|
||||
reject(QrScanner.NO_QR_CODE_FOUND);
|
||||
}
|
||||
@@ -529,25 +531,45 @@ export default class QrScanner {
|
||||
}, [imageData.data.buffer]);
|
||||
});
|
||||
} else {
|
||||
return await Promise.race([
|
||||
new Promise<QrScanner.ScanResult | string>((resolve, reject) => window.setTimeout(
|
||||
detailedScanResult = await Promise.race([
|
||||
new Promise<QrScanner.ScanResult>((resolve, reject) => window.setTimeout(
|
||||
() => reject('Scanner error: timeout'),
|
||||
10000,
|
||||
)),
|
||||
(async (): Promise<QrScanner.ScanResult | string> => {
|
||||
(async (): Promise<QrScanner.ScanResult> => {
|
||||
try {
|
||||
const [scanResult] = await qrEngine.detect(canvas!);
|
||||
if (!scanResult) throw QrScanner.NO_QR_CODE_FOUND;
|
||||
return returnDetailedScanResult ? {
|
||||
return {
|
||||
data: scanResult.rawValue,
|
||||
cornerPoints: QrScanner._convertPoints(scanResult.cornerPoints, scanRegion),
|
||||
} : scanResult.rawValue;
|
||||
};
|
||||
} catch (e) {
|
||||
throw `Scanner error: ${(e as Error).message || e}`;
|
||||
const errorMessage = (e as Error).message || e as string;
|
||||
if (/not implemented|service unavailable/.test(errorMessage)) {
|
||||
// Not implemented can apparently for some reason happen even though getSupportedFormats
|
||||
// in createQrScanner reported that it's supported, see issue #98.
|
||||
// Service unavailable can happen after some time when the BarcodeDetector crashed and
|
||||
// can theoretically be recovered from by creating a new BarcodeDetector. However, in
|
||||
// newer browsers this issue does not seem to be present anymore and therefore we do not
|
||||
// apply this optimization anymore but just set _disableBarcodeDetector in both cases.
|
||||
// Also note that if we got an external qrEngine that crashed, we should possibly notify
|
||||
// the caller about it, but we also don't do this here, as it's such an unlikely case.
|
||||
QrScanner._disableBarcodeDetector = true;
|
||||
// retry without passing the broken BarcodeScanner instance
|
||||
return QrScanner.scanImage(imageOrFileOrBlobOrUrl, {
|
||||
scanRegion,
|
||||
canvas,
|
||||
disallowCanvasResizing,
|
||||
alsoTryWithoutScanRegion,
|
||||
});
|
||||
}
|
||||
throw `Scanner error: ${errorMessage}`;
|
||||
}
|
||||
})(),
|
||||
]);
|
||||
}
|
||||
return returnDetailedScanResult ? detailedScanResult : detailedScanResult.data;
|
||||
} catch (e) {
|
||||
if (!scanRegion || !alsoTryWithoutScanRegion) throw e;
|
||||
const detailedScanResult = await QrScanner.scanImage(
|
||||
@@ -579,10 +601,11 @@ export default class QrScanner {
|
||||
}
|
||||
|
||||
static async createQrEngine(workerPath: string = QrScanner.WORKER_PATH): Promise<Worker | BarcodeDetector> {
|
||||
const hasNativeBarcodeDetector = 'BarcodeDetector' in window && BarcodeDetector.getSupportedFormats
|
||||
? (await BarcodeDetector.getSupportedFormats()).includes('qr_code')
|
||||
: false;
|
||||
return hasNativeBarcodeDetector ? new BarcodeDetector({ formats: ['qr_code'] }) : new Worker(workerPath);
|
||||
const useNativeBarcodeDetector = !QrScanner._disableBarcodeDetector
|
||||
&& ('BarcodeDetector' in window && BarcodeDetector.getSupportedFormats
|
||||
? (await BarcodeDetector.getSupportedFormats()).includes('qr_code')
|
||||
: false);
|
||||
return useNativeBarcodeDetector ? new BarcodeDetector({ formats: ['qr_code'] }) : new Worker(workerPath);
|
||||
}
|
||||
|
||||
private _onPlay(): void {
|
||||
@@ -756,14 +779,14 @@ export default class QrScanner {
|
||||
});
|
||||
} catch (error) {
|
||||
if (!this._active) return;
|
||||
const errorMessage = (error as Error).message || error as string;
|
||||
if (errorMessage.includes('service unavailable')) {
|
||||
// When the native BarcodeDetector crashed, create a new one
|
||||
this._qrEnginePromise = QrScanner.createQrEngine();
|
||||
}
|
||||
this._onDecodeError(error as Error | string);
|
||||
}
|
||||
|
||||
if (QrScanner._disableBarcodeDetector && !(await this._qrEnginePromise instanceof Worker)) {
|
||||
// replace the disabled BarcodeDetector
|
||||
this._qrEnginePromise = QrScanner.createQrEngine();
|
||||
}
|
||||
|
||||
if (result) {
|
||||
if (this._onDecode) {
|
||||
this._onDecode(result);
|
||||
|
||||
Vendored
+1
@@ -3,6 +3,7 @@ export default class QrScanner {
|
||||
static readonly DEFAULT_CANVAS_SIZE = 400;
|
||||
static readonly NO_QR_CODE_FOUND = "No QR code found";
|
||||
static WORKER_PATH: string;
|
||||
private static _disableBarcodeDetector;
|
||||
static hasCamera(): Promise<boolean>;
|
||||
static listCameras(requestLabels?: boolean): Promise<Array<QrScanner.Camera>>;
|
||||
readonly $video: HTMLVideoElement;
|
||||
|
||||
Reference in New Issue
Block a user