5 lines
16 KiB
JavaScript
5 lines
16 KiB
JavaScript
// qr-scanner@1.4.2 downloaded from https://ga.jspm.io/npm:qr-scanner@1.4.2/qr-scanner.min.js
|
|
|
|
class e{constructor(t,i,a,s,n){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=t;this.$canvas=document.createElement("canvas");a&&"object"===typeof a?this._onDecode=i:(a||s||n?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=i);i="object"===typeof a?a:{};this._onDecodeError=i.onDecodeError||("function"===typeof a?a:this._onDecodeError);this._calculateScanRegion=i.calculateScanRegion||("function"===typeof s?s:this._calculateScanRegion);this._preferredCamera=i.preferredCamera||n||this._preferredCamera;this._legacyCanvasSize="number"===typeof a?a:"number"===typeof s?s:this._legacyCanvasSize;this._maxScansPerSecond=i.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);t.disablePictureInPicture=!0;t.playsInline=!0;t.muted=!0;let r=!1;t.hidden&&(t.hidden=!1,r=!0);document.body.contains(t)||(document.body.appendChild(t),r=!0);a=t.parentElement;if(i.highlightScanRegion||i.highlightCodeOutline){s=!!i.overlay;this.$overlay=i.overlay||document.createElement("div");n=this.$overlay.style;n.position="absolute";n.display="none";n.pointerEvents="none";this.$overlay.classList.add("scan-region-highlight");if(!s&&i.highlightScanRegion){this.$overlay.innerHTML='<svg class="scan-region-highlight-svg" viewBox="0 0 238 238" preserveAspectRatio="none" style="position:absolute;width:100%;height:100%;left:0;top:0;fill:none;stroke:#e9b213;stroke-width:4;stroke-linecap:round;stroke-linejoin:round"><path d="M31 2H10a8 8 0 0 0-8 8v21M207 2h21a8 8 0 0 1 8 8v21m0 176v21a8 8 0 0 1-8 8h-21m-176 0H10a8 8 0 0 1-8-8v-21"/></svg>';try{this.$overlay.firstElementChild.animate({transform:["scale(.98)","scale(1.01)"]},{duration:400,iterations:Infinity,direction:"alternate",easing:"ease-in-out"})}catch(t){}a.insertBefore(this.$overlay,this.$video.nextSibling)}i.highlightCodeOutline&&(this.$overlay.insertAdjacentHTML("beforeend",'<svg class="code-outline-highlight" preserveAspectRatio="none" style="display:none;width:100%;height:100%;fill:none;stroke:#e9b213;stroke-width:5;stroke-dasharray:25;stroke-linecap:round;stroke-linejoin:round"><polygon/></svg>'),this.$codeOutlineHighlight=this.$overlay.lastElementChild)}this._scanRegion=this._calculateScanRegion(t);requestAnimationFrame((()=>{let i=window.getComputedStyle(t);"none"===i.display&&(t.style.setProperty("display","block","important"),r=!0);"visible"!==i.visibility&&(t.style.setProperty("visibility","visible","important"),r=!0);r&&(console.warn("QrScanner has overwritten the video hiding style to avoid Safari stopping the playback."),t.style.opacity="0",t.style.width="0",t.style.height="0",this.$overlay&&this.$overlay.parentElement&&this.$overlay.parentElement.removeChild(this.$overlay),delete this.$overlay,delete this.$codeOutlineHighlight);this.$overlay&&this._updateOverlay()}));t.addEventListener("play",this._onPlay);t.addEventListener("loadedmetadata",this._onLoadedMetaData);document.addEventListener("visibilitychange",this._onVisibilityChange);window.addEventListener("resize",this._updateOverlay);this._qrEnginePromise=e.createQrEngine()}static set WORKER_PATH(t){console.warn("Setting QrScanner.WORKER_PATH is not required and not supported anymore. Have a look at the README for new setup instructions.")}static async hasCamera(){try{return!!(await e.listCameras(!1)).length}catch(t){return!1}}static async listCameras(t=!1){if(!navigator.mediaDevices)return[];let i,b=async()=>(await navigator.mediaDevices.enumerateDevices()).filter((t=>"videoinput"===t.kind));try{t&&(await b()).every((t=>!t.label))&&(i=await navigator.mediaDevices.getUserMedia({audio:!1,video:!0}))}catch(t){}try{return(await b()).map(((t,i)=>({id:t.deviceId,label:t.label||(0===i?"Default Camera":`Camera ${i+1}`)})))}finally{i&&(console.warn("Call listCameras after successfully starting a QR scanner to avoid creating a temporary video stream"),e._stopVideoStream(i))}}async hasFlash(){let t;try{if(this.$video.srcObject){if(!(this.$video.srcObject instanceof MediaStream))return!1;t=this.$video.srcObject}else t=(await this._getCameraStream()).stream;return"torch"in t.getVideoTracks()[0].getSettings()}catch(t){return!1}finally{t&&t!==this.$video.srcObject&&(console.warn("Call hasFlash after successfully starting the scanner to avoid creating a temporary video stream"),e._stopVideoStream(t))}}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(t){throw this._flashOn=!1,t}}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._destroyed)throw Error("The QR scanner can not be started as it had been destroyed.");if((!this._active||this._paused)&&("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:t,facingMode:i}=await this._getCameraStream();!this._active||this._paused?e._stopVideoStream(t):(this._setVideoMirror(i),this.$video.srcObject=t,await this.$video.play(),this._flashOn&&(this._flashOn=!1,this.turnFlashOn().catch((()=>{}))))}catch(t){if(!this._paused)throw this._active=!1,t}}stop(){this.pause();this._active=!1}async pause(t=!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(t)return b(),!0;await new Promise((t=>setTimeout(t,300)));if(!this._paused)return!1;b();return!0}async setCamera(t){t!==this._preferredCamera&&(this._preferredCamera=t,await this._restartVideoStream())}static async scanImage(t,i,a,s,n=!1,r=!1){let o,h=!1;i&&("scanRegion"in i||"qrEngine"in i||"canvas"in i||"disallowCanvasResizing"in i||"alsoTryWithoutScanRegion"in i||"returnDetailedScanResult"in i)?(o=i.scanRegion,a=i.qrEngine,s=i.canvas,n=i.disallowCanvasResizing||!1,r=i.alsoTryWithoutScanRegion||!1,h=!0):i||a||s||n||r?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.");i=!!a;try{let c,l;[a,c]=await Promise.all([a||e.createQrEngine(),e._loadImage(t)]);[s,l]=e._drawToCanvas(c,o,s,n);let g;if(a instanceof Worker){let t=a;i||e._postWorkerMessageSync(t,"inversionMode","both");g=await new Promise(((i,a)=>{let n,r,h,c=-1;r=s=>{s.data.id===c&&(t.removeEventListener("message",r),t.removeEventListener("error",h),clearTimeout(n),null!==s.data.data?i({data:s.data.data,cornerPoints:e._convertPoints(s.data.cornerPoints,o)}):a(e.NO_QR_CODE_FOUND))};h=i=>{t.removeEventListener("message",r);t.removeEventListener("error",h);clearTimeout(n);a("Scanner error: "+(i?i.message||i:"Unknown Error"))};t.addEventListener("message",r);t.addEventListener("error",h);n=setTimeout((()=>h("timeout")),1e4);let g=l.getImageData(0,0,s.width,s.height);c=e._postWorkerMessageSync(t,"decode",g,[g.data.buffer])}))}else g=await Promise.race([new Promise(((t,i)=>window.setTimeout((()=>i("Scanner error: timeout")),1e4))),(async()=>{try{var[i]=await a.detect(s);if(!i)throw e.NO_QR_CODE_FOUND;return{data:i.rawValue,cornerPoints:e._convertPoints(i.cornerPoints,o)}}catch(a){i=a.message||a;if(/not implemented|service unavailable/.test(i))return e._disableBarcodeDetector=!0,e.scanImage(t,{scanRegion:o,canvas:s,disallowCanvasResizing:n,alsoTryWithoutScanRegion:r});throw`Scanner error: ${i}`}})()]);return h?g:g.data}catch(i){if(!o||!r)throw i;let c=await e.scanImage(t,{qrEngine:a,canvas:s,disallowCanvasResizing:n});return h?c:c.data}finally{i||e._postWorkerMessage(a,"close")}}setGrayscaleWeights(t,i,a,s=!0){e._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:t,green:i,blue:a,useIntegerApproximation:s})}setInversionMode(t){e._postWorkerMessage(this._qrEnginePromise,"inversionMode",t)}static async createQrEngine(t){t&&console.warn("Specifying a worker path is not required and not supported anymore.");t=()=>import("./qr-scanner-worker.min.js").then((t=>t.createWorker()));if(!(!e._disableBarcodeDetector&&"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(await BarcodeDetector.getSupportedFormats()).includes("qr_code")))return t();let i=navigator.userAgentData;return i&&i.brands.some((({brand:t})=>/Chromium/i.test(t)))&&/mac ?OS/i.test(i.platform)&&await i.getHighEntropyValues(["architecture","platformVersion"]).then((({architecture:t,platformVersion:i})=>/arm/i.test(t||"arm")&&13<=parseInt(i||"13"))).catch((()=>!0))?t():new BarcodeDetector({formats:["qr_code"]})}_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(t){let i=Math.round(2/3*Math.min(t.videoWidth,t.videoHeight));return{x:Math.round((t.videoWidth-i)/2),y:Math.round((t.videoHeight-i)/2),width:i,height:i,downScaledWidth:this._legacyCanvasSize,downScaledHeight:this._legacyCanvasSize}}_updateOverlay(){requestAnimationFrame((()=>{if(this.$overlay){var t=this.$video,i=t.videoWidth,a=t.videoHeight,s=t.offsetWidth,n=t.offsetHeight,r=t.offsetLeft,o=t.offsetTop,h=window.getComputedStyle(t),c=h.objectFit,l=i/a,g=s/n;switch(c){case"none":var m=i;var v=a;break;case"fill":m=s;v=n;break;default:("cover"===c?l>g:l<g)?(v=n,m=v*l):(m=s,v=m/l),"scale-down"===c&&(m=Math.min(m,i),v=Math.min(v,a))}var[u,_]=h.objectPosition.split(" ").map(((t,i)=>{const a=parseFloat(t);return t.endsWith("%")?(i?n-v:s-m)*a/100:a}));h=this._scanRegion.width||i;g=this._scanRegion.height||a;c=this._scanRegion.x||0;var y=this._scanRegion.y||0;l=this.$overlay.style;l.width=h/i*m+"px";l.height=g/a*v+"px";l.top=`${o+_+y/a*v}px`;a=/scaleX\(-1\)/.test(t.style.transform);l.left=`${r+(a?s-u-m:u)+(a?i-c-h:c)/i*m}px`;l.transform=t.style.transform}}))}static _convertPoints(t,i){if(!i)return t;let a=i.x||0,s=i.y||0,n=i.width&&i.downScaledWidth?i.width/i.downScaledWidth:1;i=i.height&&i.downScaledHeight?i.height/i.downScaledHeight:1;for(let r of t)r.x=r.x*n+a,r.y=r.y*i+s;return t}_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 t=Date.now()-this._lastScanTimestamp,i=1e3/this._maxScansPerSecond;t<i&&await new Promise((a=>setTimeout(a,i-t)));this._lastScanTimestamp=Date.now();try{var a=await e.scanImage(this.$video,{scanRegion:this._scanRegion,qrEngine:this._qrEnginePromise,canvas:this.$canvas})}catch(t){if(!this._active)return;this._onDecodeError(t)}!e._disableBarcodeDetector||await this._qrEnginePromise instanceof Worker||(this._qrEnginePromise=e.createQrEngine());a?(this._onDecode?this._onDecode(a):this._legacyOnDecode&&this._legacyOnDecode(a.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",a.cornerPoints.map((({x:t,y:i})=>`${t},${i}`)).join(" ")),this.$codeOutlineHighlight.style.display="")):this.$codeOutlineHighlight&&!this._codeOutlineHighlightRemovalTimeout&&(this._codeOutlineHighlightRemovalTimeout=setTimeout((()=>this.$codeOutlineHighlight.style.display="none"),100))}this._scanFrame()}))}_onDecodeError(t){t!==e.NO_QR_CODE_FOUND&&console.log(t)}async _getCameraStream(){if(!navigator.mediaDevices)throw"Camera not found.";let t=/^(environment|user)$/.test(this._preferredCamera)?"facingMode":"deviceId",i=[{width:{min:1024}},{width:{min:768}},{}],a=i.map((i=>Object.assign({},i,{[t]:{exact:this._preferredCamera}})));for(let t of[...a,...i])try{let i=await navigator.mediaDevices.getUserMedia({video:t,audio:!1}),a=this._getFacingMode(i)||(t.facingMode?this._preferredCamera:"environment"===this._preferredCamera?"user":"environment");return{stream:i,facingMode:a}}catch(t){}throw"Camera not found."}async _restartVideoStream(){let t=this._paused;await this.pause(!0)&&!t&&this._active&&await this.start()}static _stopVideoStream(t){for(let i of t.getTracks())i.stop(),t.removeTrack(i)}_setVideoMirror(t){this.$video.style.transform="scaleX("+("user"===t?-1:1)+")"}_getFacingMode(t){return(t=t.getVideoTracks()[0])?/rear|back|environment/i.test(t.label)?"environment":/front|user|face/i.test(t.label)?"user":null:null}static _drawToCanvas(t,i,a,s=!1){a=a||document.createElement("canvas");let n=i&&i.x?i.x:0,r=i&&i.y?i.y:0,o=i&&i.width?i.width:t.videoWidth||t.width,h=i&&i.height?i.height:t.videoHeight||t.height;s||(s=i&&i.downScaledWidth?i.downScaledWidth:o,i=i&&i.downScaledHeight?i.downScaledHeight:h,a.width!==s&&(a.width=s),a.height!==i&&(a.height=i));i=a.getContext("2d",{alpha:!1});i.imageSmoothingEnabled=!1;i.drawImage(t,n,r,o,h,0,0,a.width,a.height);return[a,i]}static async _loadImage(t){if(t instanceof Image)return await e._awaitImageLoad(t),t;if(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement||t instanceof SVGImageElement||"OffscreenCanvas"in window&&t instanceof OffscreenCanvas||"ImageBitmap"in window&&t instanceof ImageBitmap)return t;if(!(t instanceof File||t instanceof Blob||t instanceof URL||"string"===typeof t))throw"Unsupported image type.";{let i=new Image;i.src=t instanceof File||t instanceof Blob?URL.createObjectURL(t):t.toString();try{return await e._awaitImageLoad(i),i}finally{(t instanceof File||t instanceof Blob)&&URL.revokeObjectURL(i.src)}}}static async _awaitImageLoad(t){t.complete&&0!==t.naturalWidth||await new Promise(((i,a)=>{let d=s=>{t.removeEventListener("load",d);t.removeEventListener("error",d);s instanceof ErrorEvent?a("Image load error"):i()};t.addEventListener("load",d);t.addEventListener("error",d)}))}static async _postWorkerMessage(t,i,a,s){return e._postWorkerMessageSync(await t,i,a,s)}static _postWorkerMessageSync(t,i,a,s){if(!(t instanceof Worker))return-1;let n=e._workerMessageId++;t.postMessage({id:n,type:i,data:a},s);return n}}e.DEFAULT_CANVAS_SIZE=400;e.NO_QR_CODE_FOUND="No QR code found";e._disableBarcodeDetector=!1;e._workerMessageId=0;export{e as default};
|
|
|