diff --git a/README.md b/README.md index d3fe011..f501659 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,6 @@ IScan.config({ // 自动选择可用扫码方式:桥接 -> 微信 -> Web 摄像头 -> 图片识别 IScan.startScan(); -// 仅打开 Web 视频扫码 -IScan.scanVideo(); - // 仅选择图片识别 IScan.scanImage(); @@ -126,6 +123,11 @@ interface ScanConfigOptions { | `webScanImageFallbackOnVideoError` | 摄像头不可用或打开失败时,是否自动弹出拍照/选图(适用于部分安卓内置浏览器) | `true` | | `webScanVideoAccessTimeout` | 打开摄像头超时(毫秒),超时后走图片回退 | `10000` | | `webScanVideoReadyTimeout` | 摄像头已开但无画面超时(毫秒),超时后走图片回退 | `8000` | +| `webScanCameraPermissionDialogEnabled` | `startScan` 走 Web 摄像头前是否先展示权限说明弹窗 | `true` | +| `webScanCameraPermissionTitle` | 权限说明弹窗标题 | `需要使用摄像头` | +| `webScanCameraPermissionMessage` | 权限说明弹窗正文 | 见类型定义默认值 | +| `webScanCameraPermissionConfirmText` | 确认按钮文案 | `继续` | +| `webScanCameraPermissionCancelText` | 取消按钮文案 | `取消` | | `scanBeepAudio` | 扫码成功提示音地址(任意模式匹配成功时播放) | 内置提示音 | | `scanBeepEnabled` | 扫码成功是否播放提示音 | `true` | | `initWechatJssdk` | 微信 JSSDK 初始化配置,仅微信环境生效 | 无 | @@ -292,14 +294,6 @@ console.log(IScan.getStatus()); IScan.startScan(); ``` -### `scanVideo(): void` - -直接开启 Web 摄像头扫码。扫码结果通过 `onScanListener` 回调。 - -```js -IScan.scanVideo(); -``` - ### `scanImage(): void` 直接选择图片进行识别。识别结果通过 `onScanListener` 回调。 diff --git a/demo.html b/demo.html index 963c142..b35df38 100644 --- a/demo.html +++ b/demo.html @@ -207,7 +207,6 @@

点击开始后,会按桥接、微信、Web 摄像头、图片识别的顺序选择可用扫码方式。

-
@@ -247,7 +246,6 @@ IScan.startScan(); IScan.scanImage(); -IScan.scanVideo(); IScan.stopScan(); @@ -349,10 +347,6 @@ IScan.stopScan(); IScan.scanImage(); } - function scanVideo() { - IScan.scanVideo(); - } - ready(); diff --git a/dist/index.d.ts b/dist/index.d.ts index 560ca55..a5b6f3e 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -45,6 +45,58 @@ interface ScanConfigOptions { * 2. 结束扫码的方法名称为:stopScan */ bridgeName?: string, + /** + * 桥接扫码超时(毫秒),超时后回退 Web/图片识别,默认 5000 + */ + bridgeScanTimeout?: number, + /** + * 是否允许 H5 摄像头扫码:true 强制开启(仍需有媒体 API),false 强制关闭 + */ + webScanCameraEnabled?: boolean, + /** + * @deprecated 请用 webScanCameraEnabled;保留兼容 + */ + webScanCameraInWechat?: boolean, + /** + * @deprecated 摄像头权限已后置到 startScan,请用 webScanVideoAccessTimeout + */ + webScanCameraProbeTimeout?: number, + /** + * startScan 走 Web 摄像头前是否展示权限说明弹窗,默认 true + */ + webScanCameraPermissionDialogEnabled?: boolean, + /** + * 摄像头权限说明弹窗标题 + */ + webScanCameraPermissionTitle?: string, + /** + * 摄像头权限说明弹窗正文 + */ + webScanCameraPermissionMessage?: string, + /** + * 摄像头权限说明弹窗确认按钮文案 + */ + webScanCameraPermissionConfirmText?: string, + /** + * 摄像头权限说明弹窗取消按钮文案 + */ + webScanCameraPermissionCancelText?: string, + /** + * 选图后延迟读取 file 对象(毫秒),微信/安卓 WebView 默认 100 + */ + webScanFileReadDelay?: number, + /** + * 强制使用 WASM ponyfill 识别(微信/部分 WebView 建议开启,默认微信内自动开启) + */ + webScanPreferPonyfill?: boolean, + /** + * WASM 文件完整 URL;未配置时相对 SDK 脚本地址解析 lib/reader.wasm + */ + webScanWasmUrl?: string, + /** + * WASM 基准路径(SDK 脚本 URL 或目录);用于 async/defer 加载时修正 reader.wasm 路径 + */ + webScanWasmBaseUrl?: string, /** * webScan是否启用,默认启用 */ @@ -101,6 +153,41 @@ interface ScanConfigOptions { * 摄像头已打开但长时间无画面时触发图片回退(毫秒),默认 8000 */ webScanVideoReadyTimeout?: number, + /** + * 图片/回退识别时 detect 超时(毫秒),默认 15000 + */ + webScanDetectTimeout?: number, + /** + * 图片识别是否优先使用 ZXing ponyfill(原生 detect 在部分 WebView 可能卡住),默认 true + */ + webScanImagePreferPonyfill?: boolean, + /** + * 移动端图片回退是否使用 capture 拍照(false 为相册选图,兼容性更好),默认 false + */ + webScanImagePreferCapture?: boolean, + /** + * 图片识别是否优先 canvas 解码(安卓 WebView 建议开启),默认在安卓/微信内自动开启 + */ + webScanImageDetectPreferCanvas?: boolean, + /** + * ZXing WASM 加载超时(毫秒),默认 20000 + */ + webScanPrepareTimeout?: number, + /** + * 选图等待超时(毫秒),默认 120000 + */ + webScanChooseImageTimeout?: number, + /** + * 选图方式:button=显示「选择图片」按钮(安卓/微信默认,需用户点击);auto=自动弹出系统选图 + */ + webScanImagePickerMode?: 'auto' | 'button', + webScanImagePickerTitle?: string, + webScanImagePickerButtonText?: string, + webScanImagePickerCancelText?: string, + /** + * 单次扫码会话超时(毫秒),超时后状态恢复 ready,默认 90000 + */ + scanSessionTimeout?: number, /** * 扫码成功提示音地址,默认使用内置提示音;任意识别模式匹配成功时播放 */ @@ -161,6 +248,16 @@ interface ScanResult { key: string } +/** + * 扫码错误 + */ +interface ScanErrorInfo { + error: string, + key: string, + source?: string, + cancel?: number +} + /** * 监听key */ @@ -197,6 +294,22 @@ type ScanStatus = "scanning" | "ready"; */ type ScanResultCallback = (result: ScanResult) => any; +/** + * 监听扫码错误回调 + */ +type ScanErrorCallback = (error: ScanErrorInfo) => any; + +/** + * 扫码错误监听信息 + */ +interface ScanErrorListenerInfo { + key?: string; + match?: string; + level?: number; + listener: ScanErrorCallback; + cancel: () => void; +} + /** * 监听状态回调 */ @@ -227,6 +340,19 @@ interface IScan { * @param callback 监听回调,或监听key */ offScanListener(callback: ScanResultCallback | string): void; + /** + * 添加监听扫码错误(如图片识别失败) + * @param callback 错误回调 + * @param key 监听 key + * @param match 可选正则,匹配 error 文本后回调 + * @param level 优先级 + */ + onScanErrorListener(callback: ScanErrorCallback, key: string, match?: string, level?: number): ScanErrorListenerInfo; + /** + * 取消监听扫码错误 + * @param callback 监听回调,或监听 key + */ + offScanErrorListener(callback: ScanErrorCallback | string): void; /** * 获取扫码状态 * @returns ScanStatus @@ -240,14 +366,12 @@ interface IScan { * 开启扫码 */ startScan(): void; - /** - * 开启视频扫码 - */ - scanVideo(): void; /** * 选择图片进行识别 */ scanImage(): void; + /** 由业务/原生传入已选图片 File 识别(WebView input.files 异常时使用) */ + scanImageFromFile(file: File | Blob): void; /** * 清除全部监听 */ diff --git a/dist/index.html b/dist/index.html index de3ad3f..8bcb152 100644 --- a/dist/index.html +++ b/dist/index.html @@ -161,7 +161,7 @@ section { margin-bottom: 16px; - }

IScan 通用扫码SDK

统一接入桥接扫码、微信小程序、微信 JSSDK 扫码、Web 摄像头扫码、图片识别和扫码枪输入。

功能说明

  • 支持桥接扫码、微信 JSSDK 扫码、Web 摄像头扫码、图片识别和扫码枪输入。
  • 浏览器环境使用WASM库识别二维码和条形码。
  • 扫码结果由监听规则统一回调,支持正则匹配和优先级排序。

当前状态

SDK 状态:loading

运行环境:

操作

点击开始后,会按桥接、微信、Web 摄像头、图片识别的顺序选择可用扫码方式。

扫码结果

错误信息

错误信息可能来源于扫码结果、扫码过程、扫码初始化等。

接入方式

IScan.config({
+    }

IScan 通用扫码SDK

统一接入桥接扫码、微信小程序、微信 JSSDK 扫码、Web 摄像头扫码、图片识别和扫码枪输入。

功能说明

  • 支持桥接扫码、微信 JSSDK 扫码、Web 摄像头扫码、图片识别和扫码枪输入。
  • 浏览器环境使用WASM库识别二维码和条形码。
  • 扫码结果由监听规则统一回调,支持正则匹配和优先级排序。

当前状态

SDK 状态:loading

运行环境:

操作

点击开始后,会按桥接、微信、Web 摄像头、图片识别的顺序选择可用扫码方式。

扫码结果

错误信息

错误信息可能来源于扫码结果、扫码过程、扫码初始化等。

接入方式

IScan.config({
   webScanEnabled: true,
   webScanCanvasEnabled: true,
   webScanCloseButtonStyle: "background: rgba(27, 99, 244, 0.88);",
@@ -182,7 +182,6 @@
 
 IScan.startScan();
 IScan.scanImage();
-IScan.scanVideo();
 IScan.stopScan();
\ No newline at end of file diff --git a/dist/index.js b/dist/index.js index 4441ebc..368fbe6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=11)}([function(e,t,r){"use strict";t.__esModule=!0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};t.getVersion=function(){return o},t.getConfig=function(e){if(Object.prototype.hasOwnProperty.call(a,e))return a[e];if(Object.prototype.hasOwnProperty.call(i,e))return i[e];return},t.setConfig=function(e){e&&"object"==(void 0===e?"undefined":n(e))&&Object.assign(a,e)};var o="0.0.1.0525.2044",i={embedProxyMode:"auto"},a={}},function(e,t,r){"use strict";t.__esModule=!0,t.createUUID=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(e){var t=16*Math.random()|0;return("x"==e?t:3&t|8).toString(16)}))}},function(e,t,r){"use strict";t.__esModule=!0;var n={};n="undefined"!=typeof GameGlobal?Object.assign({},GameGlobal):"undefined"==typeof window?{setTimeout:function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}((function(){return setTimeout.apply(void 0,arguments)})),setInterval:function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}((function(){return setInterval.apply(void 0,arguments)})),clearTimeout:function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}((function(){return clearTimeout.apply(void 0,arguments)})),clearInterval:function(e){function t(){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}((function(){return clearInterval.apply(void 0,arguments)}))}:window,t.default=n},function(e,t,r){"use strict";t.__esModule=!0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};t.toAny=function(e,t){if(null==e)return t;var r=function(e){if("string"!=typeof e)return void 0===e?"undefined":n(e);try{var t=JSON.parse(e);return void 0===t?"undefined":n(t)}catch(t){var r=parseFloat(e);return isNaN(r)||""+r!==e?"string":"number"}}(e);null!=t&&(r=void 0===t?"undefined":n(t));switch(r){case"number":return function(e){try{return JSON.parse(e)}catch(t){return parseFloat(e)}}(e);case"boolean":return function(e){return!!e&&"false"!=e&&"0"!=e}(e);case"object":return function(e,t){if("object"===(void 0===e?"undefined":n(e)))return e;try{return JSON.parse(e)}catch(e){}return t}(e,t);case"string":return function(e,t){try{var r=void 0===e?"undefined":n(e);if("string"===r)return e;if("boolean"===r)return e?"true":"false";if("number"===r)return""+e;if("object"===r)return JSON.stringify(e)}catch(e){}return t}(e,t)}return t}},function(e,t,r){"use strict";t.__esModule=!0,t.printError=function(e){for(var t,r=arguments.length,n=Array(r>1?r-1:0),o=1;o1?r-1:0),o=1;o1?r-1:0),o=1;o0?(0,a.startScanner)((function(e){I(e=g(e))})):(0,a.stopScanner)()}function w(e,t){var r=null;return t&&"string"==typeof t&&(r=new RegExp(t)),!r||r.test(e)}function b(e){e=g(e),(0,A.forwardEmbedScanResultIfNeeded)(e);for(var t=!1,r=0;r1)for(var r=1;r=0&&r.splice(n,1)}},t.bridgeSync=d,t.bridgeAsync=function(e,t,r){return new Promise((function(n,o){if(f()){var a=!1,u=null;r>0&&(u=setTimeout((function(){a=!0,u=null,o("bridgeAsync timeout")}),r));var s=(0,i.createUUID)()+"_"+Date.now();A=s,(l=function(e,t){a||(u&&clearTimeout(u),0==e?n(t):o(t))})&&"function"==typeof l&&(c[A]=l),d(e,Object.assign({request_id:s},t))}else o("Can't bridgeAsync, because not in runtime");var A,l})).then((function(r){var n=[e];return t&&(n.push("params:"),n.push(t)),r&&(n.push("resp:"),n.push(r)),o.printDebug.apply(void 0,["bridge resp >>>"].concat(n)),r})).catch((function(r){throw t?(0,o.printWarn)("bridge err >>>",e,"params:",t,r):(0,o.printWarn)("bridge err >>>",e,r),r}))};var n=r(3),o=r(4),i=r(1),a=r(0),u={},c={};function s(){return"undefined"==typeof window?null:window}function A(){return(0,a.getConfig)("bridgeName")?(0,a.getConfig)("bridgeName"):"__bridge_client__"}function l(){var e=s();if(e){var t=A()+"_handle_callback";e[t]||(e[t]=function(e){var t=(0,n.toAny)(e,{}),r=t.method,o=t.payload,i=t.code,a=t.request_id,s=(0,n.toAny)(o,{});a?c[a]&&c[a](i,s):u[r]&&u[r].forEach((function(e){e&&e(s)}))})}}function f(){var e=s();return!!e&&!!e[A()]&&!1!==(0,a.getConfig)("bridgeEnabled")}function d(e,t){l();var r=(0,n.toAny)(function(e){var t=e.split("."),r=s();if(r){for(;t.length>1;)r=r[t.shift()];if(r&&1==t.length&&r.hasOwnProperty(t[0])){for(var n,o=arguments.length,i=Array(o>1?o-1:0),a=1;a>>"].concat(i)),r}},function(e,t,r){"use strict";t.__esModule=!0,t.playScanBeep=function(){if(!P())return;var e=k();if(!e)return;try{e.muted=!1,e.volume=1,e.currentTime=0;var t=e.play();t&&t.catch&&t.catch((function(e){e&&"NotAllowedError"===e.name&&(v=!1)}))}catch(e){}},t.unlockScanBeep=D,t.isSupportWebScan=function(){return"undefined"!=typeof navigator&&navigator.mediaDevices&&navigator.mediaDevices.getUserMedia&&!!x()&&!1!==(0,a.getConfig)("webScanEnabled")},t.isSupportImageScan=B,t.isWebScanImageFallbackEnabled=U,t.stopScanForWeb=function(){return Promise.resolve().then((function(){C()}))},t.startScanForImage=function(){return F().then((function(e){return e?M((0,a.getConfig)("webScanType")).then((function(t){return j(t,e)})):null})).then((function(e){return e&&e.rawValue?{result:e.rawValue}:{success:!1,error:"未识别到二维码或条形码"}}))},t.startScanForWeb=function(e){var t=null,r={imageFallbackStarted:!1};return new Promise((function(n,o){try{C(),s.uuid=(0,i.createUUID)(),s.finish=!1,t=s.uuid;var u,c=(0,a.getConfig)("webScanCanvasStyle"),A=(0,a.getConfig)("webScanCanvasClass"),f=b("video","__webscan_video__","display: none",!1),d=!1!==(0,a.getConfig)("webScanCanvasEnabled"),p=!c&&!A?function(){if("undefined"==typeof window)return{width:300,height:300};if(I()){var e=Math.min(window.innerWidth||300,window.innerHeight||300);return{width:Math.max(1,Math.round(e)),height:Math.max(1,Math.round(e))}}return{width:300,height:300}}():{width:300,height:300},h=p.width,m=p.height,v=c||(A?"":"position: fixed; width: "+p.width+"px; height: "+p.height+"px; top: 0; left: 0; z-index: 9999;"),g=b("canvas","__webscan_canvas__",v+" display: none;",!0);g.style.display,g.style.cssText=v,g.className=A||"",u=g.style.display;var y=R(g,h,m);g.style.display="none";var w=null,E=null;d&&((w=b("button","__webscan_close_button__","display: none;",!0)).type="button",w.className=(0,a.getConfig)("webScanCloseButtonClass")||"",w.innerHTML='',w.setAttribute("aria-label","close"),w.onclick=function(e){e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation(),s.uuid===t&&(s.uuid=null)},w.uuid=s.uuid,B()&&((E=b("button","__webscan_pick_image_button__","display: none;",!0)).type="button",E.className=(0,a.getConfig)("webScanPickImageButtonClass")||"",E.innerHTML='',E.setAttribute("aria-label","pick image"),E.uuid=s.uuid));var x=g.getContext("2d");f.width=300,f.height=300,f.uuid=s.uuid,g.uuid=s.uuid,M((0,a.getConfig)("webScanType")).then((function(e){return(t={video:{facingMode:"environment"}},n=(0,a.getConfig)("webScanVideoAccessTimeout"),r="number"==typeof n&&n>0?n:1e4,new Promise((function(e,n){var o=!1,i=setTimeout((function(){o||(o=!0,n(new Error("getUserMedia timeout")))}),r);navigator.mediaDevices.getUserMedia(t).then((function(t){o?S(t):(o=!0,clearTimeout(i),e(t))})).catch((function(e){o||(o=!0,clearTimeout(i),n(e))}))}))).then((function(t){return{detector:e,stream:t}}));var t,r,n})).then((function(i){var c=i.detector,A=i.stream;if(s.uuid!==t)return S(A),void o({cancel:1});s.stream=A,s.videoEl=f;var p=function(e){var t=(0,a.getConfig)("webScanVideoMirror");if("boolean"==typeof t)return t;try{var r=e&&e.getVideoTracks&&e.getVideoTracks()[0],n=r&&r.getSettings&&r.getSettings();if(n&&"environment"===n.facingMode)return!1;if(n&&"user"===n.facingMode)return!0}catch(e){}return!I()}(A),v=!0===(0,a.getConfig)("webScanVideoMirrorVertical");f.srcObject=A,f.setAttribute("playsinline",!0),g.style.display="none";var b,C=!1,T=!1,M=!1,P=null,O=function(){P&&(clearTimeout(P),P=null)};O(),P=setTimeout((function(){s.uuid!==t||M||s.finish||f.readyState>=f.HAVE_ENOUGH_DATA||(M=!0,k(),V(e,n,o,r))}),"number"==typeof(b=(0,a.getConfig)("webScanVideoReadyTimeout"))&&b>0?b:8e3);var k=function(){if(!M){M=!0,O(),S(A),s.uuid!==t&&s.stream!==A||(s.stream=null,s.videoEl=null);try{f.pause&&f.pause(),f.srcObject=null}catch(e){}w&&(w.style.display="none"),E&&(E.style.display="none")}},B=f.play&&f.play();B&&B.catch&&B.catch((function(){s.uuid!==t||M||s.finish||(k(),V(e,n,o,r))})),E&&(E.onclick=function(r){r.preventDefault&&r.preventDefault(),r.stopPropagation&&r.stopPropagation(),s.uuid!==t||M||(D(),F().then((function(r){r&&s.uuid===t&&!M&&j(c,r).then((function(r){r&&r.rawValue&&s.uuid===t&&!M&&e&&e(r.rawValue)&&(s.uuid=null,s.finish=!0,k(),n({result:r.rawValue}))})).catch((function(){}))})))});var U=function r(){try{if(f.readyState===f.HAVE_ENOUGH_DATA&&!C){O(),g.width=y.width,g.height=y.height;var i=(A=f.videoWidth,b=f.videoHeight,S=g.width,I=g.height,{scale:M=Math.max(S/A,I/b),width:P=A*M,height:D=b*M,x:(S-P)/2,y:(I-D)/2});x.setTransform(p?-1:1,0,0,v?-1:1,p?g.width:0,v?g.height:0),x.drawImage(f,i.x,i.y,i.width,i.height),x.setTransform(1,0,0,1,0,0),d&&!T&&(T=!0,g.style.display=u||"",y=R(g,h,m),function(e,t){if(!e)return;var r=(0,a.getConfig)("webScanCloseButtonStyle")||"";e.style.cssText=l()+function(e){var t=e.getBoundingClientRect(),r=Math.max(0,Math.round(t.top+8)),n=Math.max(0,Math.round(t.right-48));return"position: fixed; top: "+r+"px; left: "+n+"px;"}(t)+r}(w,g),w&&(w.style.display="flex"),E&&(!function(e,t){if(!e)return;var r=(0,a.getConfig)("webScanPickImageButtonStyle")||"";e.style.cssText=l()+function(e){var t=e.getBoundingClientRect(),r=Math.max(0,Math.round(t.top+8+40+10)),n=Math.max(0,Math.round(t.right-48));return"position: fixed; top: "+r+"px; left: "+n+"px;"}(t)+r}(E,g),E.style.display="flex")),C=!0,c.detect(f).then((function(r){var o=r&&r[0];if(o&&o.rawValue&&s.uuid==t){if(!e||!e(o.rawValue))return;!function(e,t,r,n,o,i,a){var u=n.cornerPoints;if(u&&u.length){for(var c=0;ce[5]),r.filter(e=>"*"===e[1]).map(e=>e[0]),r.filter(e=>"*"!==e[1]).map(e=>e[0]),r.filter(e=>" "===e[2]).map(e=>e[0]),r.filter(e=>"l"===e[3][0]).map(e=>e[0]),r.filter(e=>"m"===e[3][0]).map(e=>e[0]),r.filter(e=>"r"===e[3][1]).map(e=>e[0]),r.filter(e=>"w"===e[3][2]||0!==e[4]).map(e=>e[0]),r.filter(e=>"G"===e[3][3]).map(e=>e[0]),r.filter(e=>"R"===e[3][4]).map(e=>e[0]),r.filter(e=>"I"===e[3][4]).map(e=>e[0]);var a=["LocalAverage","GlobalHistogram","FixedThreshold","BoolCast"];function u(e){return a.indexOf(e)}var c="Unknown.ASCII.ISO8859_1.ISO8859_2.ISO8859_3.ISO8859_4.ISO8859_5.ISO8859_6.ISO8859_7.ISO8859_8.ISO8859_9.ISO8859_10.ISO8859_11.ISO8859_13.ISO8859_14.ISO8859_15.ISO8859_16.Cp437.Cp1250.Cp1251.Cp1252.Cp1256.Shift_JIS.Big5.GB2312.GB18030.EUC_JP.EUC_KR.UTF16BE.UTF8.UTF16LE.UTF32BE.UTF32LE.BINARY".split(".");function s(e){return"UnicodeBig"===e?c.indexOf("UTF16BE"):c.indexOf(e)}var A=["Text","Binary","Mixed","GS1","ISO15434","UnknownECI"];function l(e){return A[e]}var f=["Ignore","Read","Require"];function d(e){return f.indexOf(e)}var p=["Plain","ECI","HRI","Escaped","Hex","HexECI"];function h(e){return p.indexOf(e)}var m={formats:[],tryHarder:!0,tryRotate:!0,tryInvert:!0,tryDownscale:!0,tryDenoise:!1,binarizer:"LocalAverage",isPure:!1,downscaleFactor:3,downscaleThreshold:500,minLineCount:2,maxNumberOfSymbols:255,validateOptionalChecksum:!1,returnErrors:!1,eanAddOnSymbol:"Ignore",textMode:"HRI",characterSet:"Unknown",tryCode39ExtendedMode:!0};function v(e){var t;return{...e,formats:i(e.formats),binarizer:u(e.binarizer),eanAddOnSymbol:d(e.eanAddOnSymbol),textMode:h(e.textMode),characterSet:s(e.characterSet),tryCode39ExtendedMode:null==(t=e.tryCode39ExtendedMode)||t}}function g(e){return{...e,format:e.format,symbology:e.symbology,contentType:l(e.contentType)}}var y={locateFile:(e,t)=>{let r=e.match(/_(.+?)\.wasm$/);return r?`https://fastly.jsdelivr.net/npm/zxing-wasm@3.0.2/dist/${r[1]}/${e}`:t+e}},w=new WeakMap;function b(e,t){return Object.is(e,t)||Object.keys(e).length===Object.keys(t).length&&Object.keys(e).every(r=>Object.hasOwn(t,r)&&e[r]===t[r])}function S(e,{overrides:t,equalityFn:r=b,fireImmediately:n=!1}={}){var o,i;let a,[u,c]=null==(o=w.get(e))?[y]:o,s=null==t?u:t;if(n){if(c&&(a=r(u,s)))return c;let t=e({...s});return w.set(e,[s,t]),t}(null==(i=a)?r(u,s):i)||w.set(e,[s])}async function C(e,t,r=m){let n,o,i={...m,...r},a=await S(e,{fireImmediately:!0});if("width"in t&&"height"in t&&"data"in t){let{data:e,width:r,height:u}=t,c=function(e){let t=e.byteLength>>2,r=new Uint8Array(t);for(let n=0;n>10}return r}(e),s=c.byteLength;if(o=a._malloc(s),!o)throw Error(`Failed to allocate ${s} bytes in WASM memory`);try{a.HEAPU8.set(c,o),n=a.readBarcodesFromPixmap(o,r,u,v(i))}finally{a._free(o)}}else{let e,r;if("buffer"in t)[e,r]=[t.byteLength,t];else if("byteLength"in t)[e,r]=[t.byteLength,new Uint8Array(t)];else{if(!("size"in t))throw TypeError("Invalid input type");[e,r]=[t.size,new Uint8Array(await t.arrayBuffer())]}if(o=a._malloc(e),!o)throw Error(`Failed to allocate ${e} bytes in WASM memory`);try{a.HEAPU8.set(r,o),n=a.readBarcodesFromImage(o,e,v(i))}finally{a._free(o)}}let u=[];for(let e=0;e{var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)}),u=async e=>{var t=await fetch(e,{credentials:"same-origin"});if(t.ok)return t.arrayBuffer();throw Error(t.status+" : "+t.url)}}var l,f,d,p,h=console.log.bind(console),m=console.error.bind(console),v=!1,g=!1;function y(){var e=Pt.buffer;I=new Int8Array(e),E=new Int16Array(e),n.HEAPU8=P=new Uint8Array(e),M=new Uint16Array(e),_=new Int32Array(e),R=new Uint32Array(e),x=new Float32Array(e),T=new Float64Array(e)}function w(e){var t,r;null==(t=n.onAbort)||t.call(n,e),m(e="Aborted("+e+")"),v=!0,e+=". Build with -sASSERTIONS for more info.";var o=new WebAssembly.RuntimeError(e);throw null==(r=d)||r(o),o}function b(){return function(e){return n.locateFile?n.locateFile(e,A):A+e}("zxing_reader.wasm")}async function S(e){if(!l)try{var t=await u(e);return new Uint8Array(t)}catch{}return function(e){if(e==p&&l)return new Uint8Array(l);if(c)return c(e);throw"both async and sync fetching of the wasm failed"}(e)}async function C(e,t,r){if(!e&&WebAssembly.instantiateStreaming)try{var n=fetch(t,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(n,r)}catch(e){m("wasm streaming compile failed: "+e),m("falling back to ArrayBuffer instantiation")}return async function(e,t){try{var r=await S(e);return await WebAssembly.instantiate(r,t)}catch(e){m("failed to asynchronously prepare wasm: "+e),w(e)}}(t,r)}var E,_,I,x,T,M,R,P,O=e=>{for(;e.length>0;)e.shift()(n)},k=[],D=e=>k.push(e),B=[],U=e=>B.push(e),V=e=>Et(e),F=()=>_t(),j=[],Q=0,W=0;class ${constructor(e){this.excPtr=e,this.ptr=e-24}set_type(e){R[this.ptr+4>>2]=e}get_type(){return R[this.ptr+4>>2]}set_destructor(e){R[this.ptr+8>>2]=e}get_destructor(){return R[this.ptr+8>>2]}set_caught(e){e=e?1:0,I[this.ptr+12]=e}get_caught(){return 0!=I[this.ptr+12]}set_rethrown(e){e=e?1:0,I[this.ptr+13]=e}get_rethrown(){return 0!=I[this.ptr+13]}init(e,t){this.set_adjusted_ptr(0),this.set_type(e),this.set_destructor(t)}set_adjusted_ptr(e){R[this.ptr+16>>2]=e}get_adjusted_ptr(){return R[this.ptr+16>>2]}}var q=e=>Ct(e),L=e=>{var t=W;if(!t)return q(0),0;var r=new $(t);r.set_adjusted_ptr(t);var n=r.get_type();if(!n)return q(0),t;for(var o of e){if(0===o||o===n)break;var i=r.ptr+16;if(Tt(o,n,i))return q(o),t}return q(n),t},G={},N=e=>{for(;e.length;){var t=e.pop();e.pop()(t)}};function H(e){return this.fromWireType(R[e>>2])}var K={},J={},Z={},z=class extends Error{constructor(e){super(e),this.name="InternalError"}},Y=e=>{throw new z(e)},X=(e,t,r)=>{function n(t){var n=r(t);n.length!==e.length&&Y("Mismatched type converter count");for(var o=0;oZ[e]=t);var o=Array(t.length),i=[],a=0;{let e=t;for(let t=0;t{o[t]=J[r],++a===i.length&&n(o)}))}}0===i.length&&n(o)},ee=e=>{for(var t="";;){var r=P[e++];if(!r)return t;t+=String.fromCharCode(r)}},te=class extends Error{constructor(e){super(e),this.name="BindingError"}},re=e=>{throw new te(e)};function ne(e,t){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};var n=t.name;if(e||re(`type "${n}" must have a positive integer typeid pointer`),J.hasOwnProperty(e)){if(r.ignoreDuplicateRegistrations)return;re(`Cannot register type '${n}' twice`)}if(J[e]=t,delete Z[e],K.hasOwnProperty(e)){var o=K[e];delete K[e],o.forEach(e=>e())}}function oe(e,t){return ne(e,t,arguments.length>2&&void 0!==arguments[2]?arguments[2]:{})}var ie=e=>({count:e.count,deleteScheduled:e.deleteScheduled,preservePointerOnDelete:e.preservePointerOnDelete,ptr:e.ptr,ptrType:e.ptrType,smartPtr:e.smartPtr,smartPtrType:e.smartPtrType}),ae=e=>{re(function(e){return e.$$.ptrType.registeredClass.name}(e)+" instance already deleted")},ue=!1,ce=e=>{},se=e=>{--e.count.value,0===e.count.value&&(e=>{e.smartPtr?e.smartPtrType.rawDestructor(e.smartPtr):e.ptrType.registeredClass.rawDestructor(e.ptr)})(e)},Ae=e=>globalThis.FinalizationRegistry?(ue=new FinalizationRegistry(e=>{se(e.$$)}),ce=e=>ue.unregister(e),(Ae=e=>{var t=e.$$;if(t.smartPtr){var r={$$:t};ue.register(e,r,e)}return e})(e)):(Ae=e=>e,e),le=[];function fe(){}var de=(e,t)=>Object.defineProperty(t,"name",{value:e}),pe={},he=(e,t,r)=>{if(void 0===e[t].overloadTable){var n=e[t];e[t]=function(){var n=[...arguments];return e[t].overloadTable.hasOwnProperty(n.length)||re(`Function '${r}' called with an invalid number of arguments (${n.length}) - expects one of (${e[t].overloadTable})!`),e[t].overloadTable[n.length].apply(this,n)},e[t].overloadTable=[],e[t].overloadTable[n.argCount]=n}},me=(e,t,r)=>{n.hasOwnProperty(e)?((void 0===r||void 0!==n[e].overloadTable&&void 0!==n[e].overloadTable[r])&&re(`Cannot register public name '${e}' twice`),he(n,e,e),n[e].overloadTable.hasOwnProperty(r)&&re(`Cannot register multiple overloads of a function with the same number of arguments (${r})!`),n[e].overloadTable[r]=t):(n[e]=t,n[e].argCount=r)};function ve(e,t,r,n,o,i,a,u){this.name=e,this.constructor=t,this.instancePrototype=r,this.rawDestructor=n,this.baseClass=o,this.getActualType=i,this.upcast=a,this.downcast=u,this.pureVirtualFunctions=[]}var ge=(e,t,r)=>{for(;t!==r;)t.upcast||re(`Expected null or instance of ${r.name}, got an instance of ${t.name}`),e=t.upcast(e),t=t.baseClass;return e},ye=e=>{if(null===e)return"null";var t=typeof e;return"object"===t||"array"===t||"function"===t?e.toString():""+e};function we(e,t){if(null===t)return this.isReference&&re("null is not a valid "+this.name),0;t.$$||re(`Cannot pass "${ye(t)}" as a ${this.name}`),t.$$.ptr||re("Cannot pass deleted object as a pointer of type "+this.name);var r=t.$$.ptrType.registeredClass;return ge(t.$$.ptr,r,this.registeredClass)}function be(e,t){var r;if(null===t)return this.isReference&&re("null is not a valid "+this.name),this.isSmartPointer?(r=this.rawConstructor(),null!==e&&e.push(this.rawDestructor,r),r):0;(!t||!t.$$)&&re(`Cannot pass "${ye(t)}" as a ${this.name}`),t.$$.ptr||re("Cannot pass deleted object as a pointer of type "+this.name),!this.isConst&&t.$$.ptrType.isConst&&re(`Cannot convert argument of type ${t.$$.smartPtrType?t.$$.smartPtrType.name:t.$$.ptrType.name} to parameter type ${this.name}`);var n=t.$$.ptrType.registeredClass;if(r=ge(t.$$.ptr,n,this.registeredClass),this.isSmartPointer)switch(void 0===t.$$.smartPtr&&re("Passing raw pointer to smart pointer is illegal"),this.sharingPolicy){case 0:t.$$.smartPtrType===this?r=t.$$.smartPtr:re(`Cannot convert argument of type ${t.$$.smartPtrType?t.$$.smartPtrType.name:t.$$.ptrType.name} to parameter type ${this.name}`);break;case 1:r=t.$$.smartPtr;break;case 2:if(t.$$.smartPtrType===this)r=t.$$.smartPtr;else{var o=t.clone();r=this.rawShare(r,Ne.toHandle(()=>o.delete())),null!==e&&e.push(this.rawDestructor,r)}break;default:re("Unsupported sharing policy")}return r}function Se(e,t){if(null===t)return this.isReference&&re("null is not a valid "+this.name),0;t.$$||re(`Cannot pass "${ye(t)}" as a ${this.name}`),t.$$.ptr||re("Cannot pass deleted object as a pointer of type "+this.name),t.$$.ptrType.isConst&&re(`Cannot convert argument of type ${t.$$.ptrType.name} to parameter type ${this.name}`);var r=t.$$.ptrType.registeredClass;return ge(t.$$.ptr,r,this.registeredClass)}var Ce=(e,t,r)=>{if(t===r)return e;if(void 0===r.baseClass)return null;var n=Ce(e,t,r.baseClass);return null===n?null:r.downcast(n)},Ee={},_e=(e,t)=>(t=((e,t)=>{for(void 0===t&&re("ptr should not be undefined");e.baseClass;)t=e.upcast(t),e=e.baseClass;return t})(e,t),Ee[t]),Ie=(e,t)=>((!t.ptrType||!t.ptr)&&Y("makeClassHandle requires ptr and ptrType"),!!t.smartPtrType!=!!t.smartPtr&&Y("Both smartPtrType and smartPtr must be specified"),t.count={value:1},Ae(Object.create(e,{$$:{value:t,writable:!0}})));function xe(e){var t=this.getPointee(e);if(!t)return this.destructor(e),null;var r=_e(this.registeredClass,t);if(void 0!==r){if(0===r.$$.count.value)return r.$$.ptr=t,r.$$.smartPtr=e,r.clone();var n=r.clone();return this.destructor(e),n}function o(){return this.isSmartPointer?Ie(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:t,smartPtrType:this,smartPtr:e}):Ie(this.registeredClass.instancePrototype,{ptrType:this,ptr:e})}var i=pe[this.registeredClass.getActualType(t)];if(!i)return o.call(this);var a=this.isConst?i.constPointerType:i.pointerType,u=Ce(t,this.registeredClass,a.registeredClass);return null===u?o.call(this):this.isSmartPointer?Ie(a.registeredClass.instancePrototype,{ptrType:a,ptr:u,smartPtrType:this,smartPtr:e}):Ie(a.registeredClass.instancePrototype,{ptrType:a,ptr:u})}function Te(e,t,r,n,o,i,a,u,c,s,A){this.name=e,this.registeredClass=t,this.isReference=r,this.isConst=n,this.isSmartPointer=o,this.pointeeType=i,this.sharingPolicy=a,this.rawGetPointee=u,this.rawConstructor=c,this.rawShare=s,this.rawDestructor=A,o||void 0!==t.baseClass?this.toWireType=be:n?(this.toWireType=we,this.destructorFunction=null):(this.toWireType=Se,this.destructorFunction=null)}var Me=(e,t,r)=>{n.hasOwnProperty(e)||Y("Replacing nonexistent public symbol"),void 0!==n[e].overloadTable&&void 0!==r?n[e].overloadTable[r]=t:(n[e]=t,n[e].argCount=r)},Re={},Pe=(e,t,r)=>(e=e.replace(/p/g,"i"),(0,Re[e])(t,...r)),Oe=[],ke=e=>{var t=Oe[e];return t||(Oe[e]=t=Ot.get(e)),t},De=function(e,t){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];if(e.includes("j"))return Pe(e,t,r);var n=ke(t)(...r);return n},Be=function(e,t){let r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return function(){return De(e,t,[...arguments],r)}},Ue=function(e,t){function r(){return e.includes("j")?Be(e,t):ke(t)}e=ee(e);var n=r();return"function"!=typeof n&&re(`unknown function pointer with signature ${e}: ${t}`),n};class Ve extends Error{}var Fe=e=>{var t=gt(e),r=ee(t);return yt(t),r},je=(e,t)=>{var r=[],n={};throw t.forEach((function e(t){if(!n[t]&&!J[t]){if(Z[t])return void Z[t].forEach(e);r.push(t),n[t]=!0}})),new Ve(e+": "+r.map(Fe).join([", "]))},Qe=(e,t)=>{for(var r=[],n=0;n>2]);return r};function We(e,t,r,n,o,i){var a=t.length;a<2&&re("argTypes array size mismatch! Must at least get return value and 'this' types!");var u=null!==t[1]&&null!==r,c=function(e){for(var t=1;t{let t=(e=e.trim()).indexOf("(");return-1===t?e:e.slice(0,t)},qe=[],Le=[0,1,,1,null,1,!0,1,!1,1],Ge=e=>{e>9&&0==--Le[e+1]&&(Le[e]=void 0,qe.push(e))},Ne={toValue:e=>(e||re("Cannot use deleted val. handle = "+e),Le[e]),toHandle:e=>{switch(e){case void 0:return 2;case null:return 4;case!0:return 6;case!1:return 8;default:{let t=qe.pop()||Le.length;return Le[t]=e,Le[t+1]=1,t}}}},He={name:"emscripten::val",fromWireType:e=>{var t=Ne.toValue(e);return Ge(e),t},toWireType:(e,t)=>Ne.toHandle(t),readValueFromPointer:H,destructorFunction:null},Ke=(e,t)=>{switch(t){case 4:return function(e){return this.fromWireType(x[e>>2])};case 8:return function(e){return this.fromWireType(T[e>>3])};default:throw TypeError(`invalid float width (${t}): ${e}`)}},Je=(e,t,r)=>{switch(t){case 1:return r?e=>I[e]:e=>P[e];case 2:return r?e=>E[e>>1]:e=>M[e>>1];case 4:return r?e=>_[e>>2]:e=>R[e>>2];default:throw TypeError(`invalid integer width (${t}): ${e}`)}},Ze=(e,t,r)=>{let n=(e,t)=>{let r=0;return{next(){if(r>=e)return{done:!0};let n=r;return r++,{value:t(n),done:!1}},[Symbol.iterator](){return this}}};e[Symbol.iterator]||(e[Symbol.iterator]=function(){return n(this[t](),e=>this[r](e))})},ze=Object.assign({optional:!0},He),Ye=(e,t,r)=>((e,t,r,n)=>{if(!(n>0))return 0;for(var o=r,i=r+n-1,a=0;a=i)break;t[r++]=u}else if(u<=2047){if(r+1>=i)break;t[r++]=192|u>>6,t[r++]=128|63&u}else if(u<=65535){if(r+2>=i)break;t[r++]=224|u>>12,t[r++]=128|u>>6&63,t[r++]=128|63&u}else{if(r+3>=i)break;t[r++]=240|u>>18,t[r++]=128|u>>12&63,t[r++]=128|u>>6&63,t[r++]=128|63&u,a++}}return t[r]=0,r-o})(e,P,t,r),Xe=e=>{for(var t=0,r=0;r=55296&&n<=57343?(t+=4,++r):t+=3}return t},et=globalThis.TextDecoder&&new TextDecoder,tt=(e,t,r,n)=>{var o=t+r;if(n)return o;for(;e[t]&&!(t>=o);)++t;return t},rt=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,r=arguments.length>2?arguments[2]:void 0,n=arguments.length>3?arguments[3]:void 0;var o=tt(e,t,r,n);if(o-t>16&&e.buffer&&et)return et.decode(e.subarray(t,o));for(var i="";t>10,56320|1023&s)}}else i+=String.fromCharCode((31&a)<<6|u)}else i+=String.fromCharCode(a)}return i},nt=globalThis.TextDecoder?new TextDecoder("utf-16le"):void 0,ot=(e,t,r)=>{var n=e>>1,o=tt(M,n,t/2,r);if(o-n>16&&nt)return nt.decode(M.subarray(n,o));for(var i="",a=n;a{if(null!=r||(r=2147483647),r<2)return 0;for(var n=t,o=(r-=2)<2*e.length?r/2:e.length,i=0;i>1]=a,t+=2}return E[t>>1]=0,t-n},at=e=>2*e.length,ut=(e,t,r)=>{for(var n="",o=e>>2,i=0;!(i>=t/4);i++){var a=R[o+i];if(!a&&!r)break;n+=String.fromCodePoint(a)}return n},ct=(e,t,r)=>{if(null!=r||(r=2147483647),r<4)return 0;for(var n=t,o=n+r-4,i=0;i65535&&i++,_[t>>2]=a,(t+=4)+4>o)break}return _[t>>2]=0,t-n},st=e=>{for(var t=0,r=0;r65535&&r++,t+=4;return t},At=[],lt=(e,t)=>{var r=J[e];return void 0===r&&re(`${t} has unknown type ${Fe(e)}`),r},ft={},dt=e=>{var t=ft[e];return void 0===t?ee(e):t},pt=(e,t)=>Math.ceil(e/t)*t,ht=e=>{var t=(e-Pt.buffer.byteLength+65535)/65536|0;try{return Pt.grow(t),y(),1}catch{}},mt={},vt=()=>{if(!vt.strings){var e,t,r={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:(null==(e=null==(t=globalThis.navigator)?void 0:t.language)?"C":e).replace("-","_")+".UTF-8",_:s||"./this.program"};for(var n in mt)void 0===mt[n]?delete r[n]:r[n]=mt[n];var o=[];for(var n in r)o.push(`${n}=${r[n]}`);vt.strings=o}return vt.strings};var gt,yt,wt,bt,St,Ct,Et,_t,It,xt,Tt,Mt,Rt,Pt,Ot,kt=[null,[],[]],Dt=(e,t)=>{var r=kt[e];0===t||10===t?((1===e?h:m)(rt(r)),r.length=0):r.push(t)};if((()=>{let e=fe.prototype;Object.assign(e,{isAliasOf(e){if(!(this instanceof fe&&e instanceof fe))return!1;var t=this.$$.ptrType.registeredClass,r=this.$$.ptr;e.$$=e.$$;for(var n=e.$$.ptrType.registeredClass,o=e.$$.ptr;t.baseClass;)r=t.upcast(r),t=t.baseClass;for(;n.baseClass;)o=n.upcast(o),n=n.baseClass;return t===n&&r===o},clone(){if(this.$$.ptr||ae(this),this.$$.preservePointerOnDelete)return this.$$.count.value+=1,this;var e=Ae(Object.create(Object.getPrototypeOf(this),{$$:{value:ie(this.$$)}}));return e.$$.count.value+=1,e.$$.deleteScheduled=!1,e},delete(){this.$$.ptr||ae(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&re("Object already scheduled for deletion"),ce(this),se(this.$$),this.$$.preservePointerOnDelete||(this.$$.smartPtr=void 0,this.$$.ptr=void 0)},isDeleted(){return!this.$$.ptr},deleteLater(){return this.$$.ptr||ae(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&re("Object already scheduled for deletion"),le.push(this),le.length,this.$$.deleteScheduled=!0,this}});let t=Symbol.dispose;t&&(e[t]=e.delete)})(),Object.assign(Te.prototype,{getPointee(e){return this.rawGetPointee&&(e=this.rawGetPointee(e)),e},destructor(e){var t;null==(t=this.rawDestructor)||t.call(this,e)},readValueFromPointer:H,fromWireType:xe}),n.noExitRuntime&&n.noExitRuntime,n.print&&(h=n.print),n.printErr&&(m=n.printErr),n.wasmBinary&&(l=n.wasmBinary),n.arguments&&n.arguments,n.thisProgram&&(s=n.thisProgram),n.preInit)for("function"==typeof n.preInit&&(n.preInit=[n.preInit]);n.preInit.length>0;)n.preInit.shift()();var Bt={s:e=>{var t=new $(e);return t.get_caught()||(t.set_caught(!0),Q--),t.set_rethrown(!1),j.push(t),bt(e)},x:()=>{St(0,0);var e=j.pop();It(e.excPtr),W=0},a:()=>L([]),i:e=>L([e]),m:(e,t)=>L([e,t]),Q:()=>{var e=j.pop();e||w("no exception to throw");var t=e.excPtr;throw e.get_rethrown()||(j.push(e),e.set_rethrown(!0),e.set_caught(!1),Q++),xt(t),W=t},q:(e,t,r)=>{throw new $(e).init(t,r),xt(e),Q++,W=e},fa:()=>Q,d:e=>{throw W||(W=e),W},ba:()=>w(""),wa:e=>{var t=G[e];delete G[e];var r=t.rawConstructor,n=t.rawDestructor,o=t.fields,i=o.map(e=>e.getterReturnType).concat(o.map(e=>e.setterArgumentType));X([e],i,e=>{var i={};{let t=o;for(let r=0;ra.fromWireType(u(c,e)),write:(e,t)=>{var r=[];A(l,e,s.toWireType(r,t)),N(r)},optional:a.optional}}}return[{name:t.name,fromWireType:e=>{var t={};for(var r in i)t[r]=i[r].read(e);return n(e),t},toWireType:(e,t)=>{for(var o in i)if(!(o in t)&&!i[o].optional)throw TypeError(`Missing field: "${o}"`);var a=r();for(o in i)i[o].write(a,t[o]);return null!==e&&e.push(n,a),a},readValueFromPointer:H,destructorFunction:n}]})},aa:(e,t,r,n,o)=>{},qa:(e,t,r,n)=>{oe(e,{name:t=ee(t),fromWireType:function(e){return!!e},toWireType:function(e,t){return t?r:n},readValueFromPointer:function(e){return this.fromWireType(P[e])},destructorFunction:null})},ua:(e,t,r,n,o,i,a,u,c,s,A,l,f)=>{A=ee(A),i=Ue(o,i),u&&(u=Ue(a,u)),s&&(s=Ue(c,s)),f=Ue(l,f);var d=(e=>{var t=(e=e.replace(/[^a-zA-Z0-9_]/g,"$")).charCodeAt(0);return t>=48&&t<=57?"_"+e:e})(A);me(d,(function(){je(`Cannot construct ${A} due to unbound types`,[n])})),X([e,t,r],n?[n]:[],t=>{var r,o;t=t[0],n?o=(r=t.registeredClass).instancePrototype:o=fe.prototype;var a=de(A,(function(){if(Object.getPrototypeOf(this)!==c)throw new te("Use 'new' to construct "+A);if(void 0===p.constructor_body)throw new te(A+" has no accessible constructor");var e=[...arguments],t=p.constructor_body[e.length];if(void 0===t)throw new te(`Tried to invoke ctor of ${A} with invalid number of parameters (${e.length}) - expected (${Object.keys(p.constructor_body).toString()}) parameters instead!`);return t.apply(this,e)})),c=Object.create(o,{constructor:{value:a}});a.prototype=c;var l,p=new ve(A,a,c,f,r,i,u,s);p.baseClass&&(null!=(l=p.baseClass).__derivedClasses||(l.__derivedClasses=[]),p.baseClass.__derivedClasses.push(p));var h=new Te(A,p,!0,!1,!1),m=new Te(A+"*",p,!1,!1,!1),v=new Te(A+" const*",p,!1,!0,!1);return pe[e]={pointerType:m,constPointerType:v},Me(d,a),[h,m,v]})},ta:(e,t,r,n,o,i)=>{var a=Qe(t,r);o=Ue(n,o),X([],[e],e=>{var r="constructor "+(e=e[0]).name;if(void 0===e.registeredClass.constructor_body&&(e.registeredClass.constructor_body=[]),void 0!==e.registeredClass.constructor_body[t-1])throw new te(`Cannot register multiple constructors with identical number of parameters (${t-1}) for class '${e.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);return e.registeredClass.constructor_body[t-1]=()=>{je(`Cannot construct ${e.name} due to unbound types`,a)},X([],a,n=>(n.splice(1,0,null),e.registeredClass.constructor_body[t-1]=We(r,n,null,o,i),[])),[]})},F:(e,t,r,n,o,i,a,u,c,s)=>{var A=Qe(r,n);t=ee(t),t=$e(t),i=Ue(o,i,c),X([],[e],e=>{var n=`${(e=e[0]).name}.${t}`;function o(){je(`Cannot call ${n} due to unbound types`,A)}t.startsWith("@@")&&(t=Symbol[t.substring(2)]),u&&e.registeredClass.pureVirtualFunctions.push(t);var c=e.registeredClass.instancePrototype,s=c[t];return void 0===s||void 0===s.overloadTable&&s.className!==e.name&&s.argCount===r-2?(o.argCount=r-2,o.className=e.name,c[t]=o):(he(c,t,n),c[t].overloadTable[r-2]=o),X([],A,o=>{var u=We(n,o,e,i,a);return void 0===c[t].overloadTable?(u.argCount=r-2,c[t]=u):c[t].overloadTable[r-2]=u,[]}),[]})},oa:e=>oe(e,He),X:(e,t,r)=>{oe(e,{name:t=ee(t),fromWireType:e=>e,toWireType:(e,t)=>t,readValueFromPointer:Ke(t,r),destructorFunction:null})},Y:(e,t,r,n,o,i,a,u)=>{var c=Qe(t,r);e=ee(e),e=$e(e),o=Ue(n,o,a),me(e,(function(){je(`Cannot call ${e} due to unbound types`,c)}),t-1),X([],c,r=>{var n=[r[0],null].concat(r.slice(1));return Me(e,We(e,n,null,o,i),t-1),[]})},A:(e,t,r,n,o)=>{t=ee(t);let i=e=>e;if(0===n){var a=32-8*r;i=e=>e<>>a,o=i(o)}oe(e,{name:t,fromWireType:i,toWireType:(e,t)=>t,readValueFromPointer:Je(t,r,0!==n),destructorFunction:null})},sa:(e,t,r,n)=>{r=ee(r),n=ee(n),X([],[e,t],e=>{let t=e[0];return Ze(t.registeredClass.instancePrototype,r,n),[]})},t:(e,t,r)=>{var n=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][t];function o(e){var t=R[e>>2],r=R[e+4>>2];return new n(I.buffer,r,t)}oe(e,{name:r=ee(r),fromWireType:o,readValueFromPointer:o},{ignoreDuplicateRegistrations:!0})},va:(e,t)=>{oe(e,ze)},pa:(e,t)=>{t=ee(t);oe(e,{name:t,fromWireType(e){var t,r=R[e>>2],n=e+4;return t=((e,t,r)=>e?rt(P,e,t,r):"")(n,r,!0),yt(e),t},toWireType(e,t){t instanceof ArrayBuffer&&(t=new Uint8Array(t));var r,n="string"==typeof t;n||ArrayBuffer.isView(t)&&1==t.BYTES_PER_ELEMENT||re("Cannot pass non-string to std::string"),r=n?Xe(t):t.length;var o=wt(4+r+1),i=o+4;(R[o>>2]=r,n)?Ye(t,i,r+1):P.set(t,i);return null!==e&&e.push(yt,o),o},readValueFromPointer:H,destructorFunction(e){yt(e)}})},S:(e,t,r)=>{var n,o,i;r=ee(r),2===t?(n=ot,o=it,i=at):(n=ut,o=ct,i=st),oe(e,{name:r,fromWireType:e=>{var r=R[e>>2],o=n(e+4,r*t,!0);return yt(e),o},toWireType:(e,n)=>{"string"!=typeof n&&re("Cannot pass non-string to C++ string type "+r);var a=i(n),u=wt(4+a+t);return R[u>>2]=a/t,o(n,u+4,a+t),null!==e&&e.push(yt,u),u},readValueFromPointer:H,destructorFunction(e){yt(e)}})},G:(e,t,r,n,o,i)=>{G[e]={name:ee(t),rawConstructor:Ue(r,n),rawDestructor:Ue(o,i),fields:[]}},xa:(e,t,r,n,o,i,a,u,c,s)=>{G[e].fields.push({fieldName:ee(t),getterReturnType:r,getter:Ue(n,o),getterContext:i,setterArgumentType:a,setter:Ue(u,c),setterContext:s})},ra:(e,t)=>{oe(e,{isVoid:!0,name:t=ee(t),fromWireType:()=>{},toWireType:(e,t)=>{}})},N:(e,t,r)=>{var[n,...o]=((e,t)=>{for(var r=Array(e),n=0;n>2],"parameter "+n);return r})(e,t),i=n.toWireType.bind(n),a=o.map(e=>e.readValueFromPointer.bind(e));e--;var u=Array(e);return(e=>{var t=At.length;return At.push(e),t})(de(`methodCaller<(${o.map(e=>e.name)}) => ${n.name}>`,(t,n,o,c)=>{for(var s=0,A=0;A{var n=[],o=e(n,r);return n.length&&(R[t>>2]=Ne.toHandle(n)),o})(i,o,l)}))},ya:Ge,C:e=>e?(e=dt(e),Ne.toHandle(globalThis[e])):Ne.toHandle(globalThis),T:e=>{e>9&&(Le[e+1]+=1)},M:(e,t,r,n,o)=>At[e](t,r,n,o),ka:e=>{N(Ne.toValue(e)),Ge(e)},ca:(e,t,r,n)=>{var o=(new Date).getFullYear(),i=new Date(o,0,1),a=new Date(o,6,1),u=i.getTimezoneOffset(),c=a.getTimezoneOffset(),s=Math.max(u,c);R[e>>2]=60*s,_[t>>2]=Number(u!=c);var A=e=>{var t=e>=0?"-":"+",r=Math.abs(e);return`UTC${t}${String(Math.floor(r/60)).padStart(2,"0")}${String(r%60).padStart(2,"0")}`},l=A(u),f=A(c);c{var t=P.length,r=2147483648;if((e>>>=0)>r)return!1;for(var n=1;n<=4;n*=2){var o=t*(1+.2/n);if(o=Math.min(o,e+100663296),ht(Math.min(r,pt(Math.max(e,o),65536))))return!0}return!1},da:(e,t)=>{var r=0,n=0;for(var o of vt()){var i=t+r;R[e+n>>2]=i,r+=Ye(o,i,1/0)+1,n+=4}return 0},ea:(e,t)=>{var r=vt();R[e>>2]=r.length;var n=0;for(var o of r)n+=Xe(o)+1;return R[t>>2]=n,0},ha:e=>52,_:function(e,t,r,n,o){return((e,t)=>{})(t,r),70},V:(e,t,r,n)=>{for(var o=0,i=0;i>2],u=R[t+4>>2];t+=8;for(var c=0;c>2]=o,0},ma:function(e,t,r){var n=F();try{return ke(e)(t,r)}catch(e){if(V(n),e!==e+0)throw e;St(1,0)}},K:function(e,t,r,n){var o=F();try{return ke(e)(t,r,n)}catch(e){if(V(o),e!==e+0)throw e;St(1,0)}},B:function(e,t,r,n,o,i){var a=F();try{return ke(e)(t,r,n,o,i)}catch(e){if(V(a),e!==e+0)throw e;St(1,0)}},O:function(e,t,r,n,o,i){var a=F();try{return ke(e)(t,r,n,o,i)}catch(e){if(V(a),e!==e+0)throw e;St(1,0)}},U:function(e,t,r,n){var o=F();try{return ke(e)(t,r,n)}catch(e){if(V(o),e!==e+0)throw e;St(1,0)}},p:function(e){var t=F();try{return ke(e)()}catch(e){if(V(t),e!==e+0)throw e;St(1,0)}},b:function(e,t){var r=F();try{return ke(e)(t)}catch(e){if(V(r),e!==e+0)throw e;St(1,0)}},D:function(e,t,r,n){var o=F();try{return ke(e)(t,r,n)}catch(e){if(V(o),e!==e+0)throw e;St(1,0)}},ja:function(e,t,r){var n=F();try{return ke(e)(t,r)}catch(e){if(V(n),e!==e+0)throw e;St(1,0)}},c:function(e,t,r){var n=F();try{return ke(e)(t,r)}catch(e){if(V(n),e!==e+0)throw e;St(1,0)}},ia:function(e,t,r,n,o){var i=F();try{return ke(e)(t,r,n,o)}catch(e){if(V(i),e!==e+0)throw e;St(1,0)}},h:function(e,t,r,n){var o=F();try{return ke(e)(t,r,n)}catch(e){if(V(o),e!==e+0)throw e;St(1,0)}},j:function(e,t,r,n,o){var i=F();try{return ke(e)(t,r,n,o)}catch(e){if(V(i),e!==e+0)throw e;St(1,0)}},r:function(e,t,r,n,o,i){var a=F();try{return ke(e)(t,r,n,o,i)}catch(e){if(V(a),e!==e+0)throw e;St(1,0)}},P:function(e,t,r,n,o,i,a){var u=F();try{return ke(e)(t,r,n,o,i,a)}catch(e){if(V(u),e!==e+0)throw e;St(1,0)}},w:function(e,t,r,n,o,i,a){var u=F();try{return ke(e)(t,r,n,o,i,a)}catch(e){if(V(u),e!==e+0)throw e;St(1,0)}},E:function(e,t,r,n,o,i,a,u){var c=F();try{return ke(e)(t,r,n,o,i,a,u)}catch(e){if(V(c),e!==e+0)throw e;St(1,0)}},L:function(e,t,r,n,o,i,a,u,c){var s=F();try{return ke(e)(t,r,n,o,i,a,u,c)}catch(e){if(V(s),e!==e+0)throw e;St(1,0)}},I:function(e,t,r,n,o,i,a,u,c,s,A,l){var f=F();try{return ke(e)(t,r,n,o,i,a,u,c,s,A,l)}catch(e){if(V(f),e!==e+0)throw e;St(1,0)}},$:function(e,t,r,n,o,i,a){var u=F();try{return Mt(e,t,r,n,o,i,a)}catch(e){if(V(u),e!==e+0)throw e;St(1,0)}},Z:function(e,t,r,n,o){var i=F();try{return Rt(e,t,r,n,o)}catch(e){if(V(i),e!==e+0)throw e;St(1,0)}},f:function(e){var t=F();try{ke(e)()}catch(e){if(V(t),e!==e+0)throw e;St(1,0)}},l:function(e,t){var r=F();try{ke(e)(t)}catch(e){if(V(r),e!==e+0)throw e;St(1,0)}},e:function(e,t,r){var n=F();try{ke(e)(t,r)}catch(e){if(V(n),e!==e+0)throw e;St(1,0)}},W:function(e,t,r,n,o,i,a,u,c){var s=F();try{ke(e)(t,r,n,o,i,a,u,c)}catch(e){if(V(s),e!==e+0)throw e;St(1,0)}},g:function(e,t,r,n){var o=F();try{ke(e)(t,r,n)}catch(e){if(V(o),e!==e+0)throw e;St(1,0)}},J:function(e,t,r,n,o,i,a){var u=F();try{ke(e)(t,r,n,o,i,a)}catch(e){if(V(u),e!==e+0)throw e;St(1,0)}},k:function(e,t,r,n,o){var i=F();try{ke(e)(t,r,n,o)}catch(e){if(V(i),e!==e+0)throw e;St(1,0)}},la:function(e,t,r,n,o,i,a,u){var c=F();try{ke(e)(t,r,n,o,i,a,u)}catch(e){if(V(c),e!==e+0)throw e;St(1,0)}},o:function(e,t,r,n,o,i){var a=F();try{ke(e)(t,r,n,o,i)}catch(e){if(V(a),e!==e+0)throw e;St(1,0)}},y:function(e,t,r,n,o,i,a){var u=F();try{ke(e)(t,r,n,o,i,a)}catch(e){if(V(u),e!==e+0)throw e;St(1,0)}},u:function(e,t,r,n,o,i,a,u){var c=F();try{ke(e)(t,r,n,o,i,a,u)}catch(e){if(V(c),e!==e+0)throw e;St(1,0)}},R:function(e,t,r,n,o,i,a,u,c){var s=F();try{ke(e)(t,r,n,o,i,a,u,c)}catch(e){if(V(s),e!==e+0)throw e;St(1,0)}},v:function(e,t,r,n,o,i,a,u,c,s){var A=F();try{ke(e)(t,r,n,o,i,a,u,c,s)}catch(e){if(V(A),e!==e+0)throw e;St(1,0)}},n:function(e,t,r,n,o,i,a,u,c,s,A){var l=F();try{ke(e)(t,r,n,o,i,a,u,c,s,A)}catch(e){if(V(l),e!==e+0)throw e;St(1,0)}},H:function(e,t,r,n,o,i,a,u,c,s,A,l,f,d,p,h){var m=F();try{ke(e)(t,r,n,o,i,a,u,c,s,A,l,f,d,p,h)}catch(e){if(V(m),e!==e+0)throw e;St(1,0)}},na:function(e,t,r,n,o,i,a,u,c,s,A,l,f,d,p,h,m){var v=F();try{ke(e)(t,r,n,o,i,a,u,c,s,A,l,f,d,p,h,m)}catch(e){if(V(v),e!==e+0)throw e;St(1,0)}},z:e=>e};var Ut=await async function(){function e(e,t){return function(e){gt=e.Ba,yt=n._free=e.Ca,wt=n._malloc=e.Ea,bt=e.Fa,St=e.Ga,Ct=e.Ha,Et=e.Ia,_t=e.Ja,It=e.Ka,xt=e.La,Tt=e.Ma,Re.viijii=e.Na,Mt=Re.iiijj=e.Oa,Re.jiji=e.Pa,Rt=Re.jiiii=e.Qa,Re.iiiiij=e.Ra,Re.iiiiijj=e.Sa,Re.iiiiiijj=e.Ta,Pt=e.za,Ot=e.Da}(Ut=e.exports),y(),Ut}var t={a:Bt};return n.instantiateWasm?new Promise((r,o)=>{n.instantiateWasm(t,(t,n)=>{r(e(t))})}):(null!=p||(p=b()),function(t){return e(t.instance)}(await C(l,p,t)))}();return function(){function e(){var e,t;n.calledRun=!0,!v&&(g=!0,Ut.Aa(),null==(e=f)||e(n),null==(t=n.onRuntimeInitialized)||t.call(n),function(){if(n.postRun)for("function"==typeof n.postRun&&(n.postRun=[n.postRun]);n.postRun.length;)D(n.postRun.shift());O(k)}())}!function(){if(n.preRun)for("function"==typeof n.preRun&&(n.preRun=[n.preRun]);n.preRun.length;)U(n.preRun.shift());O(B)}(),n.setStatus?(n.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>n.setStatus(""),1),e()},1)):e()}(),g?n:new Promise((e,t)=>{f=e,d=t})}function _(e){return S(E,e)}function I(){return function(e){w.delete(e)}(E)}function x(e){_({overrides:e,equalityFn:Object.is,fireImmediately:!1})}var T=[["aztec","Aztec"],["aztec_code","AztecCode"],["aztec_rune","AztecRune"],["code_128","Code128"],["code_39","Code39"],["code_39_standard","Code39Std"],["code_39_extended","Code39Ext"],["code_32","Code32"],["pzn","PZN"],["code_93","Code93"],["codabar","Codabar"],["databar","DataBar"],["databar_omni","DataBarOmni"],["databar_stacked","DataBarStk"],["databar_stacked_omni","DataBarStkOmni"],["databar_expanded","DataBarExp"],["databar_expanded_stacked","DataBarExpStk"],["databar_limited","DataBarLtd"],["data_matrix","DataMatrix"],["dx_film_edge","DXFilmEdge"],["ean_13","EAN13"],["ean_upc","EANUPC"],["isbn","ISBN"],["ean_8","EAN8"],["itf","ITF"],["itf_14","ITF14"],["maxi_code","MaxiCode"],["micro_qr_code","MicroQRCode"],["pdf417","PDF417"],["compact_pdf417","CompactPDF417"],["qr_code","QRCode"],["qr_code_model_1","QRCodeModel1"],["qr_code_model_2","QRCodeModel2"],["rm_qr_code","RMQRCode"],["upc_a","UPCA"],["upc_e","UPCE"],["other_barcode","OtherBarcode"],["linear_codes","AllLinear"],["matrix_codes","AllMatrix"],["gs1_codes","AllGS1"],["retail_codes","AllRetail"],["industrial_codes","AllIndustrial"],["any","All"]],M=[...T,["unknown"]].map(e=>e[0]),R=new Map(T);function P(e){for(let[t,r]of R)if(e===r)return t;return"unknown"}function O(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.HTMLImageElement)}catch{return!1}}function k(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.SVGImageElement)}catch{return!1}}function D(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.HTMLVideoElement)}catch{return!1}}function B(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.HTMLCanvasElement)}catch{return!1}}function U(e){try{return e instanceof ImageBitmap||"[object ImageBitmap]"===Object.prototype.toString.call(e)}catch{return!1}}function V(e){try{return e instanceof OffscreenCanvas||"[object OffscreenCanvas]"===Object.prototype.toString.call(e)}catch{return!1}}function F(e){try{return e instanceof VideoFrame||"[object VideoFrame]"===Object.prototype.toString.call(e)}catch{return!1}}async function j(e){if(O(e)&&!await async function(e){try{return await e.decode(),!0}catch{return!1}}(e))throw new DOMException("Failed to load or decode HTMLImageElement.","InvalidStateError");if(k(e)&&!await async function(e){try{var t;return await(null==(t=e.decode)?void 0:t.call(e)),!0}catch{return!1}}(e))throw new DOMException("Failed to load or decode SVGImageElement.","InvalidStateError");if(F(e)&&function(e){return null===e.format}(e))throw new DOMException("VideoFrame is closed.","InvalidStateError");if(D(e)&&(0===e.readyState||1===e.readyState))throw new DOMException("Invalid element or state.","InvalidStateError");if(U(e)&&function(e){return 0===e.width&&0===e.height}(e))throw new DOMException("The image source is detached.","InvalidStateError");let{width:t,height:r}=function(e){if(O(e))return{width:e.naturalWidth,height:e.naturalHeight};if(k(e))return{width:e.width.baseVal.value,height:e.height.baseVal.value};if(D(e))return{width:e.videoWidth,height:e.videoHeight};if(U(e))return{width:e.width,height:e.height};if(F(e))return{width:e.displayWidth,height:e.displayHeight};if(B(e)||V(e))return{width:e.width,height:e.height};throw TypeError("The provided value is not of type '(Blob or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or ImageData or OffscreenCanvas or SVGImageElement or VideoFrame)'.")}(e);if(0===t||0===r)return null;let n=function(e,t){try{let r=new OffscreenCanvas(e,t);if(r.getContext("2d")instanceof OffscreenCanvasRenderingContext2D)return r;throw void 0}catch{let r=document.createElement("canvas");return r.width=e,r.height=t,r}}(t,r).getContext("2d");n.drawImage(e,0,0);try{return n.getImageData(0,0,t,r)}catch{throw new DOMException("Source would taint origin.","SecurityError")}}async function Q(e){if(function(e){try{return e instanceof Blob||"[object Blob]"===Object.prototype.toString.call(e)}catch{return!1}}(e))return await async function(e){let t;try{t=await createImageBitmap(e)}catch{try{if(!globalThis.Image)return e;{t=new Image;let r="";try{r=URL.createObjectURL(e),t.src=r,await t.decode()}finally{URL.revokeObjectURL(r)}}}catch{throw new DOMException("Failed to load or decode Blob.","InvalidStateError")}}return await j(t)}(e);if(function(e){try{return e instanceof ImageData||"[object ImageData]"===Object.prototype.toString.call(e)}catch{return!1}}(e)){if(function(e){return 0===e.data.buffer.byteLength}(e))throw new DOMException("The image data has been detached.","InvalidStateError");return e}return B(e)||V(e)?function(e){let{width:t,height:r}=e;if(0===t||0===r)return null;let n=e.getContext("2d");try{return n.getImageData(0,0,t,r)}catch{throw new DOMException("Source would taint origin.","SecurityError")}}(e):await j(e)}function W(e,t){return function(e){return e instanceof DOMException||"[object DOMException]"===Object.prototype.toString.call(e)}(e)?new DOMException(`${t}: ${e.message}`,e.name):function(e){return e instanceof Error||"[object Error]"===Object.prototype.toString.call(e)}(e)?new e.constructor(`${t}: ${e.message}`):Error(`${t}: ${e}`)}function $(e,t,r){(function(e,t){if(t.has(e))throw TypeError("Cannot initialize the same private elements twice on an object")})(e,t),t.set(e,r)}function q(e,t,r){if("function"==typeof e?e===t:e.has(t))return arguments.length<3?t:r;throw TypeError("Private element is not present on this object")}function L(e,t){return e.get(q(e,t))}var G=new WeakMap;Object.defineProperty(t,"a",{enumerable:!0,get:function(){return I}}),Object.defineProperty(t,"i",{enumerable:!0,get:function(){return"98106d24a9bc2c4a24a6e6864e0f5729bd68cf73d6f5b45bb1c824521146370c"}}),Object.defineProperty(t,"n",{enumerable:!0,get:function(){return x}}),Object.defineProperty(t,"o",{enumerable:!0,get:function(){return"3.0.2"}}),Object.defineProperty(t,"r",{enumerable:!0,get:function(){return _}}),Object.defineProperty(t,"s",{enumerable:!0,get:function(){return"b304f6656b865be11b00741d430b7d0027bc0ab4"}}),Object.defineProperty(t,"t",{enumerable:!0,get:function(){return class{constructor(e={}){$(this,G,void 0);try{var t;let r=null==e||null==(t=e.formats)?void 0:t.filter(e=>"unknown"!==e);if(0===(null==r?void 0:r.length))throw TypeError("Hint option provided, but is empty.");for(let e of null==r?[]:r)if(!R.has(e))throw TypeError(`Failed to read the 'formats' property from 'BarcodeDetectorOptions': The provided value '${e}' is not a valid enum value of type BarcodeFormat.`);(function(e,t,r){e.set(q(e,t),r)})(G,this,null==r?[]:r),_({fireImmediately:!0}).catch(()=>{})}catch(e){throw W(e,"Failed to construct 'BarcodeDetector'")}}static async getSupportedFormats(){return M.filter(e=>"unknown"!==e)}async detect(e){try{let t=await Q(e);if(null===t)return[];let r,n={textMode:"Plain",formats:L(G,this).map(e=>R.get(e))};try{r=await async function(e,t){return C(E,e,t)}(t,n)}catch(e){throw console.error(e),new DOMException("Barcode detection service unavailable.","NotSupportedError")}return r.map(e=>{let{topLeft:{x:t,y:r},topRight:{x:n,y:o},bottomLeft:{x:i,y:a},bottomRight:{x:u,y:c}}=e.position,s=Math.min(t,n,i,u),A=Math.min(r,o,a,c),l=Math.max(t,n,i,u),f=Math.max(r,o,a,c);return{boundingBox:new DOMRectReadOnly(s,A,l-s,f-A),rawValue:e.text,format:P(e.format),cornerPoints:[{x:t,y:r},{x:n,y:o},{x:u,y:c},{x:i,y:a}]}})}catch(e){throw W(e,"Failed to execute 'detect' on 'BarcodeDetector'")}}}}})},function(e,t){e.exports="data:audio/ogg;base64,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"},function(e,t,r){"use strict";t.__esModule=!0,t.request=function(e){var t=e.url,r=e.method,a=e.data,u=e.headers,c=e.json,s=e.timeout,A=Object.assign({request_id:(0,o.hex_md5)((0,n.createUUID)()+"_"+Date.now())},a);return new Promise((function(e,n){!function(e){var t,r=e.url||"",n=e.method||"GET",o=e.headers||{},a=e.data||{},u=e.json||!1,c=e.timeout||6e3,s=new XMLHttpRequest;if("GET"==n.toUpperCase())r=(0,i.appendQueryParams)(r,a),t=void 0;else{if("POST"!=n.toUpperCase())return void(e.fail&&e.fail({errMsg:"request:un support "+n}));u?t=JSON.stringify(a):(t=new FormData,Object.keys(a).forEach((function(e){var r=a[e];r instanceof File?t.append(e,r,r.name):t.append(e,r)})))}if(s.timeout=c,s.open(n.toUpperCase(),r,!0),o)for(var A in o)s.setRequestHeader(A,o[A]);u&&s.setRequestHeader("Content-Type","application/json");s.onreadystatechange=function(){if(4==s.readyState){var t=s.getAllResponseHeaders(),r={};if(t)t.split("\n").forEach((function(e){if(e){var t=e.split(": ");t.length>1&&(r[t[0]]=t[1])}}));if(s.status>=200&&s.status<300){var n={errMsg:"request:ok"};try{var o=JSON.parse(s.response);n.data=o}catch(e){n.data=s.response}n.header=r,n.statusCode=s.status,e.success&&e.success(n)}else e.fail&&e.fail({errMsg:"request:fail",data:s.response,header:r})}},s.send(t)}(Object.assign({},{url:t,method:r,data:A,headers:u,json:c,timeout:s},{success:e,fail:n}))})).then((function(e){if(e.statusCode&&200!=e.statusCode)throw e;return e}))};var n=r(1),o=r(23),i=r(24)},function(e,t,r){"use strict";t.__esModule=!0,t.hex_md5=function(e){return d(n(l(e),8*e.length))},t.b64_md5=function(e){return p(n(l(e),8*e.length))},t.str_md5=function(e){return f(n(l(e),8*e.length))},t.hex_hmac_md5=function(e,t){return d(s(e,t))},t.b64_hmac_md5=function(e,t){return p(s(e,t))},t.str_hmac_md5=function(e,t){return f(s(e,t))};function n(e,t){e[t>>5]|=128<>>9<<4)]=t;for(var r=1732584193,n=-271733879,o=-1732584194,s=271733878,l=0;l>>32-u,r);var a,u}function i(e,t,r,n,i,a,u){return o(t&r|~t&n,e,t,i,a,u)}function a(e,t,r,n,i,a,u){return o(t&n|r&~n,e,t,i,a,u)}function u(e,t,r,n,i,a,u){return o(t^r^n,e,t,i,a,u)}function c(e,t,r,n,i,a,u){return o(r^(t|~n),e,t,i,a,u)}function s(e,t){var r=l(e);r.length>16&&(r=n(r,8*e.length));for(var o=Array(16),i=Array(16),a=0;a<16;a++)o[a]=909522486^r[a],i[a]=1549556828^r[a];var u=n(o.concat(l(t)),512+8*t.length);return n(i.concat(u),640)}function A(e,t){var r=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(r>>16)<<16|65535&r}function l(e){for(var t=Array(),r=0;r<8*e.length;r+=8)t[r>>5]|=(255&e.charCodeAt(r/8))<>5]>>>r%32&255);return t}function d(e){for(var t="0123456789abcdef",r="",n=0;n<4*e.length;n++)r+=t.charAt(e[n>>2]>>n%4*8+4&15)+t.charAt(e[n>>2]>>n%4*8&15);return r}function p(e){for(var t="",r=0;r<4*e.length;r+=3)for(var n=(e[r>>2]>>r%4*8&255)<<16|(e[r+1>>2]>>(r+1)%4*8&255)<<8|e[r+2>>2]>>(r+2)%4*8&255,o=0;o<4;o++)8*r+6*o>32*e.length?t+="":t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(n>>6*(3-o)&63);return t}},function(e,t,r){"use strict";t.__esModule=!0,t.stringifyQuery=function(e){return Object.keys(e).map((function(t){var r=e[t];return t+"="+encodeURIComponent(r)})).join("&")},t.decodeQuery=function(e){return Object.keys(e).reduce((function(t,r){var n=e[r];return t[r]=decodeURIComponent(n),t}),{})},t.parseQueryParams=a,t.appendQueryParams=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=a(e),n=r.url,o=r.params;Object.keys(t).forEach((function(e){var r=t[e];null!=r?o[e]=r:delete o[e]}));var i=Object.keys(o).map((function(e){var t=o[e];return e+"="+encodeURIComponent(t)})).join("&");if(!n)return i;if(!i)return n;return n+"?"+i},t.getQueryString=function(e,t){var r=i.default.location.search,n=new RegExp("(^|&)"+e+"=([^&]*)(&|$)"),o=r.substr(1).match(n);if(null!=o)return decodeURIComponent(unescape(o[2]));return t};var n,o=r(2),i=(n=o)&&n.__esModule?n:{default:n};function a(e){var t="",r={};if(!e||"string"!=typeof e)return{url:t,params:r};var n="",o=e.indexOf("?"),i=e.indexOf("#"),a=e.indexOf("=");return o>=0?(t=e.substring(0,o),n=e.substring(o+1,i>0?i:e.length)):a>=0?(t="",n=e):(t=e,n=""),n.split("&").map((function(e){var t=e.indexOf("=");if(t>0){var n=e.substring(0,t),o=e.substring(t+1);r[n]=decodeURIComponent(o)}})),{url:t,params:r}}},function(e,t,r){"use strict";t.__esModule=!0,t.startScanner=function(e){if(!e||"function"!=typeof e)return;var t=c();if(!t)return;if(n=e,"scanning"===o)return;o="scanning",s(),t.addEventListener("keydown",A)},t.stopScanner=function(){if("scanning"!==o)return;o="ready",n=null,s();var e=c();e&&e.removeEventListener("keydown",A)};var n=null,o="ready",i="",a=null,u=0;function c(){return"undefined"==typeof window?null:window}function s(){i="",u=0,a&&(clearTimeout(a),a=null)}function A(e){if("scanning"===o)if(function(){var e=c(),t=e&&e.document&&e.document.activeElement;if(!t||t===e.document.body||t===e.document.documentElement)return!1;var r=t.tagName&&t.tagName.toLowerCase();return"input"===r||"textarea"===r||"select"===r||!0===t.isContentEditable}())s();else if(!(e.ctrlKey||e.metaKey||e.altKey)){if("Enter"===e.key){var t=i.replace(/[\uFF01-\uFF5E]/g,(function(e){return String.fromCharCode(e.charCodeAt(0)-65248)})).replace(/\u3002/g,".").replace(/\u2014/g,"_");return t&&function(e){e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation()}(e),s(),void(t&&n&&n(t))}if(e.key&&1===e.key.length){var r=Date.now();u&&r-u>100&&s(),u=r,i+=e.key,a&&clearTimeout(a),a=setTimeout((function(){s()}),100)}}}},function(e,t,r){"use strict";t.__esModule=!0,t.resolveUseParentProxy=void 0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};t.installEmbedHost=function(e){if(p||"undefined"==typeof window)return;p=!0,(0,A.setEmbedScanResultForwarder)(y),window.addEventListener("message",(function(t){var r=t.data;if(d(r))if("probeWxEnv"!==r.kind)if("scanResultConsumed"!==r.kind)"invoke"===r.kind&&r.id&&r.methodKey&&t.source&&t.source!==window&&(l.add(t.source),function(e,t){var r=t.data,o=r.id,i=r.methodKey,a=function(e,t,r){return e.map((function e(o){if(o&&"object"===(void 0===o?"undefined":n(o))&&o.__IScanEmbedCb__){var i=o.__IScanEmbedCb__;return function(){var e=Array.prototype.slice.call(arguments);t.postMessage({source:"IScanEmbed",v:1,kind:"callback",cbId:i,args:e},r)}}if(null===o||"object"!==(void 0===o?"undefined":n(o)))return o;if(Array.isArray(o))return o.map(e);var a={};return Object.keys(o).forEach((function(t){a[t]=e(o[t])})),a}))}(r.params||[],t.source,t.origin);Promise.resolve().then((function(){return x.apply(void 0,[e,i].concat(a))})).then((function(e){var t=e;return t&&"function"==typeof t.then?t.then((function(e){return t=e})):t})).then((function(e){t.source.postMessage({source:"IScanEmbed",v:1,kind:"invokeResult",id:o,methodKey:i,ok:!0,result:e},t.origin)})).catch((function(e){t.source.postMessage({source:"IScanEmbed",v:1,kind:"invokeResult",id:o,methodKey:i,ok:!1,error:"string"==typeof e?e:String(e&&e.message||e)},t.origin)}))}(e,t));else{if(!t.source||t.source===window)return;"string"==typeof r.result&&(0,s.acknowledgeEmbedScanConsumed)(r.result)}else{if(!t.source||t.source===window)return;var o=(0,u.readWxLikeEnvFromWindow)(window);t.source.postMessage({source:"IScanEmbed",v:1,kind:"probeWxEnvResult",id:r.id,wx:o},t.origin)}}))},t.getEmbedProxyResolved=function(){return(0,o.resolveUseParentProxy)()};var o=r(9);Object.defineProperty(t,"resolveUseParentProxy",{enumerable:!0,get:function(){return o.resolveUseParentProxy}}),t.exportSDK=function(e,t){for(var r=arguments.length,o=Array(r>2?r-2:0),i=2;i=4||(w=!0,b++,_(),window.parent.postMessage({source:"IScanEmbed",v:1,kind:"probeWxEnv",id:(0,c.createUUID)()},"*"),window.setTimeout((function(){w=!1,null===(0,u.getParentWxEnvReport)()&&S()&&C()}),600)))}function E(e){var t=e.data;if(d(t))if("probeWxEnvResult"!==t.kind)if("forwardScanResult"!==t.kind){if("invokeResult"===t.kind){var r=m[t.id];if(!r)return;return delete m[t.id],void(t.ok?r.resolve(t.result):r.reject(new Error(t.error||"[IScan embed]: invoke failed")))}if("callback"===t.kind){var n=v[t.cbId];"function"==typeof n&&n.apply(null,t.args||[])}}else{"string"==typeof t.result&&(0,s.dispatchEmbedScanResult)(t.result)&&(0,o.resolveUseParentProxy)()&&window.parent.postMessage({source:"IScanEmbed",v:1,kind:"scanResultConsumed",result:t.result},"*")}else(0,u.setParentWxEnvReport)(!!t.wx)}function _(){h||"undefined"==typeof window||(h=!0,window.addEventListener("message",E))}function I(e,t){_(),C();var r=(0,c.createUUID)(),n=function(e){for(var t=[],r={},n=0;n1;)r=r[n.shift()];if(r&&1==n.length&&r.hasOwnProperty(n[0])){for(var o,i=arguments.length,a=Array(i>2?i-2:0),u=2;u1&&void 0!==arguments[1]?arguments[1]:"",r={};return Object.keys(e).forEach((function(o){var i=e[o];if("object"===(void 0===i?"undefined":n(i)))Object.assign(r,M(i,""+t+o+"."));else if("function"==typeof i){var a,u=""+t+o;Object.assign(r,((a={})[u]=u,a))}})),r}function R(e){Object.keys(e).forEach((function(t){var r=e[t];"object"===(void 0===r?"undefined":n(r))&&R(r)})),Object.freeze(e)}function P(e,t,r,n){return function(){for(var a=arguments.length,u=Array(a),c=0;c1?r-1:0),o=1;o1?r-1:0),o=1;o1?r-1:0),o=1;o>>a,o=i(o)}oe(e,{name:t,fromWireType:i,toWireType:(e,t)=>t,readValueFromPointer:Ke(t,r,0!==n),destructorFunction:null})},sa:(e,t,r,n)=>{r=ee(r),n=ee(n),X([],[e,t],e=>{let t=e[0];return Je(t.registeredClass.instancePrototype,r,n),[]})},t:(e,t,r)=>{var n=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][t];function o(e){var t=P[e>>2],r=P[e+4>>2];return new n(_.buffer,r,t)}oe(e,{name:r=ee(r),fromWireType:o,readValueFromPointer:o},{ignoreDuplicateRegistrations:!0})},va:(e,t)=>{oe(e,Ze)},pa:(e,t)=>{t=ee(t);oe(e,{name:t,fromWireType(e){var t,r=P[e>>2],n=e+4;return t=((e,t,r)=>e?rt(M,e,t,r):"")(n,r,!0),yt(e),t},toWireType(e,t){t instanceof ArrayBuffer&&(t=new Uint8Array(t));var r,n="string"==typeof t;n||ArrayBuffer.isView(t)&&1==t.BYTES_PER_ELEMENT||re("Cannot pass non-string to std::string"),r=n?Xe(t):t.length;var o=bt(4+r+1),i=o+4;(P[o>>2]=r,n)?Ye(t,i,r+1):M.set(t,i);return null!==e&&e.push(yt,o),o},readValueFromPointer:z,destructorFunction(e){yt(e)}})},S:(e,t,r)=>{var n,o,i;r=ee(r),2===t?(n=ot,o=it,i=at):(n=ut,o=ct,i=st),oe(e,{name:r,fromWireType:e=>{var r=P[e>>2],o=n(e+4,r*t,!0);return yt(e),o},toWireType:(e,n)=>{"string"!=typeof n&&re("Cannot pass non-string to C++ string type "+r);var a=i(n),u=bt(4+a+t);return P[u>>2]=a/t,o(n,u+4,a+t),null!==e&&e.push(yt,u),u},readValueFromPointer:z,destructorFunction(e){yt(e)}})},G:(e,t,r,n,o,i)=>{G[e]={name:ee(t),rawConstructor:Fe(r,n),rawDestructor:Fe(o,i),fields:[]}},xa:(e,t,r,n,o,i,a,u,c,s)=>{G[e].fields.push({fieldName:ee(t),getterReturnType:r,getter:Fe(n,o),getterContext:i,setterArgumentType:a,setter:Fe(u,c),setterContext:s})},ra:(e,t)=>{oe(e,{isVoid:!0,name:t=ee(t),fromWireType:()=>{},toWireType:(e,t)=>{}})},N:(e,t,r)=>{var[n,...o]=((e,t)=>{for(var r=Array(e),n=0;n>2],"parameter "+n);return r})(e,t),i=n.toWireType.bind(n),a=o.map(e=>e.readValueFromPointer.bind(e));e--;var u=Array(e);return(e=>{var t=lt.length;return lt.push(e),t})(de(`methodCaller<(${o.map(e=>e.name)}) => ${n.name}>`,(t,n,o,c)=>{for(var s=0,l=0;l{var n=[],o=e(n,r);return n.length&&(P[t>>2]=Ne.toHandle(n)),o})(i,o,f)}))},ya:Ge,C:e=>e?(e=dt(e),Ne.toHandle(globalThis[e])):Ne.toHandle(globalThis),T:e=>{e>9&&(qe[e+1]+=1)},M:(e,t,r,n,o)=>lt[e](t,r,n,o),ka:e=>{N(Ne.toValue(e)),Ge(e)},ca:(e,t,r,n)=>{var o=(new Date).getFullYear(),i=new Date(o,0,1),a=new Date(o,6,1),u=i.getTimezoneOffset(),c=a.getTimezoneOffset(),s=Math.max(u,c);P[e>>2]=60*s,x[t>>2]=Number(u!=c);var l=e=>{var t=e>=0?"-":"+",r=Math.abs(e);return`UTC${t}${String(Math.floor(r/60)).padStart(2,"0")}${String(r%60).padStart(2,"0")}`},f=l(u),A=l(c);c{var t=M.length,r=2147483648;if((e>>>=0)>r)return!1;for(var n=1;n<=4;n*=2){var o=t*(1+.2/n);if(o=Math.min(o,e+100663296),ht(Math.min(r,pt(Math.max(e,o),65536))))return!0}return!1},da:(e,t)=>{var r=0,n=0;for(var o of gt()){var i=t+r;P[e+n>>2]=i,r+=Ye(o,i,1/0)+1,n+=4}return 0},ea:(e,t)=>{var r=gt();P[e>>2]=r.length;var n=0;for(var o of r)n+=Xe(o)+1;return P[t>>2]=n,0},ha:e=>52,_:function(e,t,r,n,o){return((e,t)=>{})(t,r),70},V:(e,t,r,n)=>{for(var o=0,i=0;i>2],u=P[t+4>>2];t+=8;for(var c=0;c>2]=o,0},ma:function(e,t,r){var n=j();try{return Oe(e)(t,r)}catch(e){if(B(n),e!==e+0)throw e;St(1,0)}},K:function(e,t,r,n){var o=j();try{return Oe(e)(t,r,n)}catch(e){if(B(o),e!==e+0)throw e;St(1,0)}},B:function(e,t,r,n,o,i){var a=j();try{return Oe(e)(t,r,n,o,i)}catch(e){if(B(a),e!==e+0)throw e;St(1,0)}},O:function(e,t,r,n,o,i){var a=j();try{return Oe(e)(t,r,n,o,i)}catch(e){if(B(a),e!==e+0)throw e;St(1,0)}},U:function(e,t,r,n){var o=j();try{return Oe(e)(t,r,n)}catch(e){if(B(o),e!==e+0)throw e;St(1,0)}},p:function(e){var t=j();try{return Oe(e)()}catch(e){if(B(t),e!==e+0)throw e;St(1,0)}},b:function(e,t){var r=j();try{return Oe(e)(t)}catch(e){if(B(r),e!==e+0)throw e;St(1,0)}},D:function(e,t,r,n){var o=j();try{return Oe(e)(t,r,n)}catch(e){if(B(o),e!==e+0)throw e;St(1,0)}},ja:function(e,t,r){var n=j();try{return Oe(e)(t,r)}catch(e){if(B(n),e!==e+0)throw e;St(1,0)}},c:function(e,t,r){var n=j();try{return Oe(e)(t,r)}catch(e){if(B(n),e!==e+0)throw e;St(1,0)}},ia:function(e,t,r,n,o){var i=j();try{return Oe(e)(t,r,n,o)}catch(e){if(B(i),e!==e+0)throw e;St(1,0)}},h:function(e,t,r,n){var o=j();try{return Oe(e)(t,r,n)}catch(e){if(B(o),e!==e+0)throw e;St(1,0)}},j:function(e,t,r,n,o){var i=j();try{return Oe(e)(t,r,n,o)}catch(e){if(B(i),e!==e+0)throw e;St(1,0)}},r:function(e,t,r,n,o,i){var a=j();try{return Oe(e)(t,r,n,o,i)}catch(e){if(B(a),e!==e+0)throw e;St(1,0)}},P:function(e,t,r,n,o,i,a){var u=j();try{return Oe(e)(t,r,n,o,i,a)}catch(e){if(B(u),e!==e+0)throw e;St(1,0)}},w:function(e,t,r,n,o,i,a){var u=j();try{return Oe(e)(t,r,n,o,i,a)}catch(e){if(B(u),e!==e+0)throw e;St(1,0)}},E:function(e,t,r,n,o,i,a,u){var c=j();try{return Oe(e)(t,r,n,o,i,a,u)}catch(e){if(B(c),e!==e+0)throw e;St(1,0)}},L:function(e,t,r,n,o,i,a,u,c){var s=j();try{return Oe(e)(t,r,n,o,i,a,u,c)}catch(e){if(B(s),e!==e+0)throw e;St(1,0)}},I:function(e,t,r,n,o,i,a,u,c,s,l,f){var A=j();try{return Oe(e)(t,r,n,o,i,a,u,c,s,l,f)}catch(e){if(B(A),e!==e+0)throw e;St(1,0)}},$:function(e,t,r,n,o,i,a){var u=j();try{return kt(e,t,r,n,o,i,a)}catch(e){if(B(u),e!==e+0)throw e;St(1,0)}},Z:function(e,t,r,n,o){var i=j();try{return Pt(e,t,r,n,o)}catch(e){if(B(i),e!==e+0)throw e;St(1,0)}},f:function(e){var t=j();try{Oe(e)()}catch(e){if(B(t),e!==e+0)throw e;St(1,0)}},l:function(e,t){var r=j();try{Oe(e)(t)}catch(e){if(B(r),e!==e+0)throw e;St(1,0)}},e:function(e,t,r){var n=j();try{Oe(e)(t,r)}catch(e){if(B(n),e!==e+0)throw e;St(1,0)}},W:function(e,t,r,n,o,i,a,u,c){var s=j();try{Oe(e)(t,r,n,o,i,a,u,c)}catch(e){if(B(s),e!==e+0)throw e;St(1,0)}},g:function(e,t,r,n){var o=j();try{Oe(e)(t,r,n)}catch(e){if(B(o),e!==e+0)throw e;St(1,0)}},J:function(e,t,r,n,o,i,a){var u=j();try{Oe(e)(t,r,n,o,i,a)}catch(e){if(B(u),e!==e+0)throw e;St(1,0)}},k:function(e,t,r,n,o){var i=j();try{Oe(e)(t,r,n,o)}catch(e){if(B(i),e!==e+0)throw e;St(1,0)}},la:function(e,t,r,n,o,i,a,u){var c=j();try{Oe(e)(t,r,n,o,i,a,u)}catch(e){if(B(c),e!==e+0)throw e;St(1,0)}},o:function(e,t,r,n,o,i){var a=j();try{Oe(e)(t,r,n,o,i)}catch(e){if(B(a),e!==e+0)throw e;St(1,0)}},y:function(e,t,r,n,o,i,a){var u=j();try{Oe(e)(t,r,n,o,i,a)}catch(e){if(B(u),e!==e+0)throw e;St(1,0)}},u:function(e,t,r,n,o,i,a,u){var c=j();try{Oe(e)(t,r,n,o,i,a,u)}catch(e){if(B(c),e!==e+0)throw e;St(1,0)}},R:function(e,t,r,n,o,i,a,u,c){var s=j();try{Oe(e)(t,r,n,o,i,a,u,c)}catch(e){if(B(s),e!==e+0)throw e;St(1,0)}},v:function(e,t,r,n,o,i,a,u,c,s){var l=j();try{Oe(e)(t,r,n,o,i,a,u,c,s)}catch(e){if(B(l),e!==e+0)throw e;St(1,0)}},n:function(e,t,r,n,o,i,a,u,c,s,l){var f=j();try{Oe(e)(t,r,n,o,i,a,u,c,s,l)}catch(e){if(B(f),e!==e+0)throw e;St(1,0)}},H:function(e,t,r,n,o,i,a,u,c,s,l,f,A,d,p,h){var m=j();try{Oe(e)(t,r,n,o,i,a,u,c,s,l,f,A,d,p,h)}catch(e){if(B(m),e!==e+0)throw e;St(1,0)}},na:function(e,t,r,n,o,i,a,u,c,s,l,f,A,d,p,h,m){var g=j();try{Oe(e)(t,r,n,o,i,a,u,c,s,l,f,A,d,p,h,m)}catch(e){if(B(g),e!==e+0)throw e;St(1,0)}},z:e=>e};var Ft=await async function(){function e(e,t){return function(e){vt=e.Ba,yt=n._free=e.Ca,bt=n._malloc=e.Ea,wt=e.Fa,St=e.Ga,Ct=e.Ha,Et=e.Ia,xt=e.Ja,_t=e.Ka,It=e.La,Tt=e.Ma,Pe.viijii=e.Na,kt=Pe.iiijj=e.Oa,Pe.jiji=e.Pa,Pt=Pe.jiiii=e.Qa,Pe.iiiiij=e.Ra,Pe.iiiiijj=e.Sa,Pe.iiiiiijj=e.Ta,Mt=e.za,Rt=e.Da}(Ft=e.exports),y(),Ft}var t={a:Ut};return n.instantiateWasm?new Promise((r,o)=>{n.instantiateWasm(t,(t,n)=>{r(e(t))})}):(null!=p||(p=w()),function(t){return e(t.instance)}(await C(f,p,t)))}();return function(){function e(){var e,t;n.calledRun=!0,!g&&(v=!0,Ft.Aa(),null==(e=A)||e(n),null==(t=n.onRuntimeInitialized)||t.call(n),function(){if(n.postRun)for("function"==typeof n.postRun&&(n.postRun=[n.postRun]);n.postRun.length;)D(n.postRun.shift());R(O)}())}!function(){if(n.preRun)for("function"==typeof n.preRun&&(n.preRun=[n.preRun]);n.preRun.length;)F(n.preRun.shift());R(U)}(),n.setStatus?(n.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>n.setStatus(""),1),e()},1)):e()}(),v?n:new Promise((e,t)=>{A=e,d=t})}function x(e){return S(E,e)}function _(){return function(e){b.delete(e)}(E)}function I(e){x({overrides:e,equalityFn:Object.is,fireImmediately:!1})}var T=[["aztec","Aztec"],["aztec_code","AztecCode"],["aztec_rune","AztecRune"],["code_128","Code128"],["code_39","Code39"],["code_39_standard","Code39Std"],["code_39_extended","Code39Ext"],["code_32","Code32"],["pzn","PZN"],["code_93","Code93"],["codabar","Codabar"],["databar","DataBar"],["databar_omni","DataBarOmni"],["databar_stacked","DataBarStk"],["databar_stacked_omni","DataBarStkOmni"],["databar_expanded","DataBarExp"],["databar_expanded_stacked","DataBarExpStk"],["databar_limited","DataBarLtd"],["data_matrix","DataMatrix"],["dx_film_edge","DXFilmEdge"],["ean_13","EAN13"],["ean_upc","EANUPC"],["isbn","ISBN"],["ean_8","EAN8"],["itf","ITF"],["itf_14","ITF14"],["maxi_code","MaxiCode"],["micro_qr_code","MicroQRCode"],["pdf417","PDF417"],["compact_pdf417","CompactPDF417"],["qr_code","QRCode"],["qr_code_model_1","QRCodeModel1"],["qr_code_model_2","QRCodeModel2"],["rm_qr_code","RMQRCode"],["upc_a","UPCA"],["upc_e","UPCE"],["other_barcode","OtherBarcode"],["linear_codes","AllLinear"],["matrix_codes","AllMatrix"],["gs1_codes","AllGS1"],["retail_codes","AllRetail"],["industrial_codes","AllIndustrial"],["any","All"]],k=[...T,["unknown"]].map(e=>e[0]),P=new Map(T);function M(e){for(let[t,r]of P)if(e===r)return t;return"unknown"}function R(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.HTMLImageElement)}catch{return!1}}function O(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.SVGImageElement)}catch{return!1}}function D(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.HTMLVideoElement)}catch{return!1}}function U(e){try{var t;return e instanceof(null==e||null==(t=e.ownerDocument)||null==(t=t.defaultView)?void 0:t.HTMLCanvasElement)}catch{return!1}}function F(e){try{return e instanceof ImageBitmap||"[object ImageBitmap]"===Object.prototype.toString.call(e)}catch{return!1}}function B(e){try{return e instanceof OffscreenCanvas||"[object OffscreenCanvas]"===Object.prototype.toString.call(e)}catch{return!1}}function j(e){try{return e instanceof VideoFrame||"[object VideoFrame]"===Object.prototype.toString.call(e)}catch{return!1}}async function V(e){if(R(e)&&!await async function(e){try{return await e.decode(),!0}catch{return!1}}(e))throw new DOMException("Failed to load or decode HTMLImageElement.","InvalidStateError");if(O(e)&&!await async function(e){try{var t;return await(null==(t=e.decode)?void 0:t.call(e)),!0}catch{return!1}}(e))throw new DOMException("Failed to load or decode SVGImageElement.","InvalidStateError");if(j(e)&&function(e){return null===e.format}(e))throw new DOMException("VideoFrame is closed.","InvalidStateError");if(D(e)&&(0===e.readyState||1===e.readyState))throw new DOMException("Invalid element or state.","InvalidStateError");if(F(e)&&function(e){return 0===e.width&&0===e.height}(e))throw new DOMException("The image source is detached.","InvalidStateError");let{width:t,height:r}=function(e){if(R(e))return{width:e.naturalWidth,height:e.naturalHeight};if(O(e))return{width:e.width.baseVal.value,height:e.height.baseVal.value};if(D(e))return{width:e.videoWidth,height:e.videoHeight};if(F(e))return{width:e.width,height:e.height};if(j(e))return{width:e.displayWidth,height:e.displayHeight};if(U(e)||B(e))return{width:e.width,height:e.height};throw TypeError("The provided value is not of type '(Blob or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or ImageData or OffscreenCanvas or SVGImageElement or VideoFrame)'.")}(e);if(0===t||0===r)return null;let n=function(e,t){try{let r=new OffscreenCanvas(e,t);if(r.getContext("2d")instanceof OffscreenCanvasRenderingContext2D)return r;throw void 0}catch{let r=document.createElement("canvas");return r.width=e,r.height=t,r}}(t,r).getContext("2d");n.drawImage(e,0,0);try{return n.getImageData(0,0,t,r)}catch{throw new DOMException("Source would taint origin.","SecurityError")}}async function W(e){if(function(e){try{return e instanceof Blob||"[object Blob]"===Object.prototype.toString.call(e)}catch{return!1}}(e))return await async function(e){let t;try{t=await createImageBitmap(e)}catch{try{if(!globalThis.Image)return e;{t=new Image;let r="";try{r=URL.createObjectURL(e),t.src=r,await t.decode()}finally{URL.revokeObjectURL(r)}}}catch{throw new DOMException("Failed to load or decode Blob.","InvalidStateError")}}return await V(t)}(e);if(function(e){try{return e instanceof ImageData||"[object ImageData]"===Object.prototype.toString.call(e)}catch{return!1}}(e)){if(function(e){return 0===e.data.buffer.byteLength}(e))throw new DOMException("The image data has been detached.","InvalidStateError");return e}return U(e)||B(e)?function(e){let{width:t,height:r}=e;if(0===t||0===r)return null;let n=e.getContext("2d");try{return n.getImageData(0,0,t,r)}catch{throw new DOMException("Source would taint origin.","SecurityError")}}(e):await V(e)}function Q(e,t){return function(e){return e instanceof DOMException||"[object DOMException]"===Object.prototype.toString.call(e)}(e)?new DOMException(`${t}: ${e.message}`,e.name):function(e){return e instanceof Error||"[object Error]"===Object.prototype.toString.call(e)}(e)?new e.constructor(`${t}: ${e.message}`):Error(`${t}: ${e}`)}function L(e,t,r){(function(e,t){if(t.has(e))throw TypeError("Cannot initialize the same private elements twice on an object")})(e,t),t.set(e,r)}function $(e,t,r){if("function"==typeof e?e===t:e.has(t))return arguments.length<3?t:r;throw TypeError("Private element is not present on this object")}function q(e,t){return e.get($(e,t))}var G=new WeakMap;Object.defineProperty(t,"a",{enumerable:!0,get:function(){return _}}),Object.defineProperty(t,"i",{enumerable:!0,get:function(){return"98106d24a9bc2c4a24a6e6864e0f5729bd68cf73d6f5b45bb1c824521146370c"}}),Object.defineProperty(t,"n",{enumerable:!0,get:function(){return I}}),Object.defineProperty(t,"o",{enumerable:!0,get:function(){return"3.0.2"}}),Object.defineProperty(t,"r",{enumerable:!0,get:function(){return x}}),Object.defineProperty(t,"s",{enumerable:!0,get:function(){return"b304f6656b865be11b00741d430b7d0027bc0ab4"}}),Object.defineProperty(t,"t",{enumerable:!0,get:function(){return class{constructor(e={}){L(this,G,void 0);try{var t;let r=null==e||null==(t=e.formats)?void 0:t.filter(e=>"unknown"!==e);if(0===(null==r?void 0:r.length))throw TypeError("Hint option provided, but is empty.");for(let e of null==r?[]:r)if(!P.has(e))throw TypeError(`Failed to read the 'formats' property from 'BarcodeDetectorOptions': The provided value '${e}' is not a valid enum value of type BarcodeFormat.`);(function(e,t,r){e.set($(e,t),r)})(G,this,null==r?[]:r),x({fireImmediately:!0}).catch(()=>{})}catch(e){throw Q(e,"Failed to construct 'BarcodeDetector'")}}static async getSupportedFormats(){return k.filter(e=>"unknown"!==e)}async detect(e){try{let t=await W(e);if(null===t)return[];let r,n={textMode:"Plain",formats:q(G,this).map(e=>P.get(e))};try{r=await async function(e,t){return C(E,e,t)}(t,n)}catch(e){throw console.error(e),new DOMException("Barcode detection service unavailable.","NotSupportedError")}return r.map(e=>{let{topLeft:{x:t,y:r},topRight:{x:n,y:o},bottomLeft:{x:i,y:a},bottomRight:{x:u,y:c}}=e.position,s=Math.min(t,n,i,u),l=Math.min(r,o,a,c),f=Math.max(t,n,i,u),A=Math.max(r,o,a,c);return{boundingBox:new DOMRectReadOnly(s,l,f-s,A-l),rawValue:e.text,format:M(e.format),cornerPoints:[{x:t,y:r},{x:n,y:o},{x:u,y:c},{x:i,y:a}]}})}catch(e){throw Q(e,"Failed to execute 'detect' on 'BarcodeDetector'")}}}}})},function(e,t,r){"use strict";t.__esModule=!0,t.request=function(e){var t=e.url,r=e.method,a=e.data,u=e.headers,c=e.json,s=e.timeout,l=Object.assign({request_id:(0,o.hex_md5)((0,n.createUUID)()+"_"+Date.now())},a);return new Promise((function(e,n){!function(e){var t,r=e.url||"",n=e.method||"GET",o=e.headers||{},a=e.data||{},u=e.json||!1,c=e.timeout||6e3,s=new XMLHttpRequest;if("GET"==n.toUpperCase())r=(0,i.appendQueryParams)(r,a),t=void 0;else{if("POST"!=n.toUpperCase())return void(e.fail&&e.fail({errMsg:"request:un support "+n}));u?t=JSON.stringify(a):(t=new FormData,Object.keys(a).forEach((function(e){var r=a[e];r instanceof File?t.append(e,r,r.name):t.append(e,r)})))}if(s.timeout=c,s.open(n.toUpperCase(),r,!0),o)for(var l in o)s.setRequestHeader(l,o[l]);u&&s.setRequestHeader("Content-Type","application/json");s.onreadystatechange=function(){if(4==s.readyState){var t=s.getAllResponseHeaders(),r={};if(t)t.split("\n").forEach((function(e){if(e){var t=e.split(": ");t.length>1&&(r[t[0]]=t[1])}}));if(s.status>=200&&s.status<300){var n={errMsg:"request:ok"};try{var o=JSON.parse(s.response);n.data=o}catch(e){n.data=s.response}n.header=r,n.statusCode=s.status,e.success&&e.success(n)}else e.fail&&e.fail({errMsg:"request:fail",data:s.response,header:r})}},s.send(t)}(Object.assign({},{url:t,method:r,data:l,headers:u,json:c,timeout:s},{success:e,fail:n}))})).then((function(e){if(e.statusCode&&200!=e.statusCode)throw e;return e}))};var n=r(2),o=r(22),i=r(23)},function(e,t,r){"use strict";t.__esModule=!0,t.hex_md5=function(e){return d(n(f(e),8*e.length))},t.b64_md5=function(e){return p(n(f(e),8*e.length))},t.str_md5=function(e){return A(n(f(e),8*e.length))},t.hex_hmac_md5=function(e,t){return d(s(e,t))},t.b64_hmac_md5=function(e,t){return p(s(e,t))},t.str_hmac_md5=function(e,t){return A(s(e,t))};function n(e,t){e[t>>5]|=128<>>9<<4)]=t;for(var r=1732584193,n=-271733879,o=-1732584194,s=271733878,f=0;f>>32-u,r);var a,u}function i(e,t,r,n,i,a,u){return o(t&r|~t&n,e,t,i,a,u)}function a(e,t,r,n,i,a,u){return o(t&n|r&~n,e,t,i,a,u)}function u(e,t,r,n,i,a,u){return o(t^r^n,e,t,i,a,u)}function c(e,t,r,n,i,a,u){return o(r^(t|~n),e,t,i,a,u)}function s(e,t){var r=f(e);r.length>16&&(r=n(r,8*e.length));for(var o=Array(16),i=Array(16),a=0;a<16;a++)o[a]=909522486^r[a],i[a]=1549556828^r[a];var u=n(o.concat(f(t)),512+8*t.length);return n(i.concat(u),640)}function l(e,t){var r=(65535&e)+(65535&t);return(e>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(e){for(var t=Array(),r=0;r<8*e.length;r+=8)t[r>>5]|=(255&e.charCodeAt(r/8))<>5]>>>r%32&255);return t}function d(e){for(var t="0123456789abcdef",r="",n=0;n<4*e.length;n++)r+=t.charAt(e[n>>2]>>n%4*8+4&15)+t.charAt(e[n>>2]>>n%4*8&15);return r}function p(e){for(var t="",r=0;r<4*e.length;r+=3)for(var n=(e[r>>2]>>r%4*8&255)<<16|(e[r+1>>2]>>(r+1)%4*8&255)<<8|e[r+2>>2]>>(r+2)%4*8&255,o=0;o<4;o++)8*r+6*o>32*e.length?t+="":t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(n>>6*(3-o)&63);return t}},function(e,t,r){"use strict";t.__esModule=!0,t.stringifyQuery=function(e){return Object.keys(e).map((function(t){var r=e[t];return t+"="+encodeURIComponent(r)})).join("&")},t.decodeQuery=function(e){return Object.keys(e).reduce((function(t,r){var n=e[r];return t[r]=decodeURIComponent(n),t}),{})},t.parseQueryParams=a,t.appendQueryParams=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=a(e),n=r.url,o=r.params;Object.keys(t).forEach((function(e){var r=t[e];null!=r?o[e]=r:delete o[e]}));var i=Object.keys(o).map((function(e){var t=o[e];return e+"="+encodeURIComponent(t)})).join("&");if(!n)return i;if(!i)return n;return n+"?"+i},t.getQueryString=function(e,t){var r=i.default.location.search,n=new RegExp("(^|&)"+e+"=([^&]*)(&|$)"),o=r.substr(1).match(n);if(null!=o)return decodeURIComponent(unescape(o[2]));return t};var n,o=r(4),i=(n=o)&&n.__esModule?n:{default:n};function a(e){var t="",r={};if(!e||"string"!=typeof e)return{url:t,params:r};var n="",o=e.indexOf("?"),i=e.indexOf("#"),a=e.indexOf("=");return o>=0?(t=e.substring(0,o),n=e.substring(o+1,i>0?i:e.length)):a>=0?(t="",n=e):(t=e,n=""),n.split("&").map((function(e){var t=e.indexOf("=");if(t>0){var n=e.substring(0,t),o=e.substring(t+1);r[n]=decodeURIComponent(o)}})),{url:t,params:r}}},function(e,t){e.exports="data:audio/ogg;base64,T2dnUwACAAAAAAAAAAC833vVAAAAAHm1GSUBHgF2b3JiaXMAAAAAAkSsAAAAAAAAgLUBAAAAAAC4AU9nZ1MAAAAAAAAAAAAAvN971QEAAADhrlSJEUD///////////////////8HA3ZvcmJpcw0AAABMYXZmNTguNDEuMTAwAQAAAB8AAABlbmNvZGVyPUxhdmM1OC43NS4xMDAgbGlidm9yYmlzAQV2b3JiaXMlQkNWAQBAAAAkcxgqRqVzFoQQGkJQGeMcQs5r7BlCTBGCHDJMW8slc5AhpKBCiFsogdCQVQAAQAAAh0F4FISKQQghhCU9WJKDJz0IIYSIOXgUhGlBCCGEEEIIIYQQQgghhEU5aJKDJ0EIHYTjMDgMg+U4+ByERTlYEIMnQegghA9CuJqDrDkIIYQkNUhQgwY56ByEwiwoioLEMLgWhAQ1KIyC5DDI1IMLQoiag0k1+BqEZ0F4FoRpQQghhCRBSJCDBkHIGIRGQViSgwY5uBSEy0GoGoQqOQgfhCA0ZBUAkAAAoKIoiqIoChAasgoAyAAAEEBRFMdxHMmRHMmxHAsIDVkFAAABAAgAAKBIiqRIjuRIkiRZkiVZkiVZkuaJqizLsizLsizLMhAasgoASAAAUFEMRXEUBwgNWQUAZAAACKA4iqVYiqVoiueIjgiEhqwCAIAAAAQAABA0Q1M8R5REz1RV17Zt27Zt27Zt27Zt27ZtW5ZlGQgNWQUAQAAAENJpZqkGiDADGQZCQ1YBAAgAAIARijDEgNCQVQAAQAAAgBhKDqIJrTnfnOOgWQ6aSrE5HZxItXmSm4q5Oeecc87J5pwxzjnnnKKcWQyaCa0555zEoFkKmgmtOeecJ7F50JoqrTnnnHHO6WCcEcY555wmrXmQmo21OeecBa1pjppLsTnnnEi5eVKbS7U555xzzjnnnHPOOeec6sXpHJwTzjnnnKi9uZab0MU555xPxunenBDOOeecc84555xzzjnnnCA0ZBUAAAQAQBCGjWHcKQjS52ggRhFiGjLpQffoMAkag5xC6tHoaKSUOggllXFSSicIDVkFAAACAEAIIYUUUkghhRRSSCGFFGKIIYYYcsopp6CCSiqpqKKMMssss8wyyyyzzDrsrLMOOwwxxBBDK63EUlNtNdZYa+4555qDtFZaa621UkoppZRSCkJDVgEAIAAABEIGGWSQUUghhRRiiCmnnHIKKqiA0JBVAAAgAIAAAAAAT/Ic0REd0REd0REd0REd0fEczxElURIlURIt0zI101NFVXVl15Z1Wbd9W9iFXfd93fd93fh1YViWZVmWZVmWZVmWZVmWZVmWIDRkFQAAAgAAIIQQQkghhRRSSCnGGHPMOegklBAIDVkFAAACAAgAAABwFEdxHMmRHEmyJEvSJM3SLE/zNE8TPVEURdM0VdEVXVE3bVE2ZdM1XVM2XVVWbVeWbVu2dduXZdv3fd/3fd/3fd/3fd/3fV0HQkNWAQASAAA6kiMpkiIpkuM4jiRJQGjIKgBABgBAAACK4iiO4ziSJEmSJWmSZ3mWqJma6ZmeKqpAaMgqAAAQAEAAAAAAAACKpniKqXiKqHiO6IiSaJmWqKmaK8qm7Lqu67qu67qu67qu67qu67qu67qu67qu67qu67qu67qu67quC4SGrAIAJAAAdCRHciRHUiRFUiRHcoDQkFUAgAwAgAAAHMMxJEVyLMvSNE/zNE8TPdETPdNTRVd0gdCQVQAAIACAAAAAAAAADMmwFMvRHE0SJdVSLVVTLdVSRdVTVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTdM0TRMIDVkJAJABAJAQUy0txpoJiyRi0mqroGMMUuylsUgqZ7W3yjGFGLVeGoeUURB7qSRjikHMLaTQKSat1lRChRSkmGMqFVIOUiA0ZIUAEJoB4HAcQLIsQLIsAAAAAAAAAJA0DdA8D7A0DwAAAAAAAAAkTQMsTwM0zwMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQNI0QPM8QPM8AAAAAAAAANA8D/A8EfBEEQAAAAAAAAAszwM00QM8UQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQNI0QPM8QPM8AAAAAAAAALA8D/BEEdA8EQAAAAAAAAAszwM8UQQ80QMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAABDgAAAQYCEUGrIiAIgTAHBIEiQJkgTNA0iWBU2DpsE0AZJlQdOgaTBNAAAAAAAAAAAAACRNg6ZB0yCKAEnToGnQNIgiAAAAAAAAAAAAAJKmQdOgaRBFgKRp0DRoGkQRAAAAAAAAAAAAAM80IYoQRZgmwDNNiCJEEaYJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAABhwAAAIMKEMFBqyIgCIEwBwOIplAQCA4ziWBQAAjuNYFgAAWJYligAAYFmaKAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAGHAAAAgwoQwUGrISAIgCAHAoimUBx7Es4DiWBSTJsgCWBdA8gKYBRBEACAAAKHAAAAiwQVNicYBCQ1YCAFEAAAbFsSxNE0WSpGmaJ4okSdM8TxRpmud5nmnC8zzPNCGKomiaEEVRNE2YpmmqKjBNVRUAAFDgAAAQYIOmxOIAhYasBABCAgAcimJZmuZ5nieKpqmaJEnTPE8URdE0TVNVSZKmeZ4oiqJpmqaqsixN8zxRFEXTVFVVhaZ5niiKommqqurC8zxPFEXRNFXVdeF5nieKomiaquq6EEVRNE3TVE1VdV0giqZpmqqqqq4LRE8UTVNVXdd1geeJommqqqu6LhBN01RVVXVdWQaYpmmqquvKMkBVVdV1XVeWAaqqqq7rurIMUFXXdV1ZlmUAruu6sizLAgAADhwAAAKMoJOMKouw0YQLD0ChISsCgCgAAMAYphRTyjAmIaQQGsYkhBRCJiWl0lKqIKRSUikVhFRKKiWjlFJqKVUQUimplApCKiWVUgAA2IEDANiBhVBoyEoAIA8AgDBGKcYYc04ipBRjzjknEVKKMeeck0ox5pxzzkkpGXPMOeeklM4555xzUkrmnHPOOSmlc84555yUUkrnnHNOSiklhM5BJ6WU0jnnnBMAAFTgAAAQYKPI5gQjQYWGrAQAUgEADI5jWZrmeaJompYkaZrneZ4omqYmSZrmeZ4niqrJ8zxPFEXRNFWV53meKIqiaaoq1xVF0zRNVVVdsiyKpmmaquq6ME3TVFXXdV2Ypmmqquu6LmxbVVXVdWUZtq2qquq6sgxc13Vl2ZaBLLuu7NqyAADwBAcAoAIbVkc4KRoLLDRkJQCQAQBAGIOQQgghZRBCCiGElFIICQAAGHAAAAgwoQwUGrISAEgFAACMsdZaa6211kBnrbXWWmutgMxaa6211lprrbXWWmuttdZSa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprrbXWWmuttdZaa6211lprLaWUUkoppZRSSimllFJKKaWUUkoFAPpVOAD4P9iwOsJJ0VhgoSErAYBwAADAGKUYcwxCKaVUCDHmnHRUWouxQogx5ySk1FpsxXPOQSghldZiLJ5zDkIpKcVWY1EphFJSSi22WItKoaOSUkqt1ViMMamk1lqLrcZijEkptNRaizEWI2xNqbXYaquxGGNrKi20GGOMxQhfZGwtptpqDcYII1ssLdVaazDGGN1bi6W2mosxPvjaUiwx1lwAAHeDAwBEgo0zrCSdFY4GFxqyEgAICQAgEFKKMcYYc84556RSjDnmnHMOQgihVIoxxpxzDkIIIZSMMeaccxBCCCGEUkrGnHMQQgghhJBS6pxzEEIIIYQQSimdcw5CCCGEEEIppYMQQgghhBBKKKWkFEIIIYQQQgippJRCCCGEUkIoIZWUUgghhBBCKSWklFIKIYRSQgihhJRSSimFEEIIpZSSUkoppRJKCSWEElIpKaUUSgghlFJKSimlVEoJoYQSSiklpZRSSiGEEEopBQAAHDgAAAQYQScZVRZhowkXHoBCQ1YCAGQAAJCilFIpLUWCIqUYpBhLRhVzUFqKqHIMUs2pUs4g5iSWiDGElJNUMuYUQgxC6hx1TCkGLZUYQsYYpNhyS6FzDgAAAEEAgICQAAADBAUzAMDgAOFzEHQCBEcbAIAgRGaIRMNCcHhQCRARUwFAYoJCLgBUWFykXVxAlwEu6OKuAyEEIQhBLA6ggAQcnHDDE294wg1O0CkqdSAAAAAAAA0A8AAAkFwAERHRzGFkaGxwdHh8gISIjJAIAAAAAAAZAHwAACQlQERENHMYGRobHB0eHyAhIiMkAQCAAAIAAAAAIIAABAQEAAAAAAACAAAABARPZ2dTAASbDgAAAAAAALzfe9UCAAAAgk2QtRE2PS40OTo8Pci/ODk3ODU+NqzKUzmvVuSprFdbPwnTTgHompxUm0VYr2dPHZfQNgFrggAyjp4sb3fsHBqRJYUpI9VaXHVFALzIU7D07kWeqpXFfYB+qIMCUCZgXnbSvF8jZNJDjaw1GDAsrB4MGSLAcTSIUKXHXFftqgF5X/ivlZlYOxvESOv02ouR1umx/wAkWApAbQKsA0lqYKtSWl2SQEsglA4t+JALVymQXd0jZCEABM1jOZX8oXmYVan/AhAjALBTAMoETAWKyI+HpU5xJSQoTm7FcimMAp2+683IQIicCHhnAATRs/mxH0TP8jfuBeiFZAEoA0jSOz7WXhqXlaoyNEk7jVTYV16UsYWitDGufZ9f/+9f9rVz+G9bARTTi2B/XjE9O/bXegE2diEsCEA1Ac1E1kQzaDTJwjF6hFAlrPSe7ZyqeorHfrGTnQtpND3Y0jr5wgD82KthBvgfezXMBzjrVRXoA2KHALAaLUYUYuOjhkAKYoaPS0xi4gBJaKttu+qIKYhE4uIqyIBWdXuuLAAU64ulhPxifbGUkL8PYNOeAABqB6AA1AaIiRgoQJaGZKMwaFQhFUGUKh6+OW+AwFX6kEYGqhmJha04LgYAGpoeGp8fvXYQ/PvbfpvRqaHpofH50WsHwb+/7bcZnfqpqyQyVMqyKLPM6K0eh50mU1wQADdgAEIAhhMkAQQAIAGwIMYqqtbJxlgDU+xiw2q1gsUxGUABgJrhYIpaTVUDVQBwjOKDmBIbRGIjkZptBDZBNJGIwcFKXViRRYaJIT4SFUJFYN2yj0I0hApBsgOFhEIIoQFfLnZkAcSSuBMxYZCr4A5opQMjG2QaC6lUnH7bTVNTAOIhMAAIAGjQgKAUCKDABkSnKQI2qkb90DsHcRA9v1s2a3JaqRqOq74DyIvs+T2yWVPTfWuDzMgURVnNorZMZGRmZka2GTZhDUi1AWBFAABWAkgAAIDhhAAAQALw1FobrDcmWT1GvYMiQcWosY43qqqqalQwIgIAKACK06TbdtuePfXsNm2bDmyFYIdxqklCYMYG2QrkUABABAS2IytEkpEYJSRVIko13UU33Rd5kATblf9kYCABGforqwIEWgEbCQUAAIivwUo8Pg0AAIBWgLYbADTrFaud2G/WK1Y6sb8nwD5AAkCBHSAAlACgSEMABW8zU6nVC22nBihSg1AAGBaiAOHQoWCQTlMANOtjKGUMc836GEoZw9xKB3gBAAGuIAACQBkJgKwAqCloLc2EVmo0g0cEQlX0SmIiABak2xOSkZ4CLOtD5sjesl6x0ph7AF4AAAWAWAADUAcAWTdRzI0oRm0AAbSQQpBI9+MgXiAMoDAe0unZs8QrAzTpY6wjc036GMvI/B4A1gP11JMAUOAKEiAAVAMwWAQLBgIqoIxSU1RLvVQUjR5ZAUDDccAh3R4ADOWztXl/KJ/NzfsPwAmi3gIQYAcIAA0HAIq1EYOpIxXFqo/lCMsJABQCmp5RgPg4QUDSMwAc2d3klrkju5vc0n2AfYAAsoMAVAMAWZQhLiggHGGQ0tbH7nHpio1El8G0EwJUj94oox8E0Zh4OBl9i/llAPTQW+id6HroLfROdOvqrZGwD5AAKAuAWmPFiAWyYjooCvoq9F+A0KbSyj3bOXUqjz7TSaV+DQ=="},function(e,t,r){"use strict";t.__esModule=!0,t.startScanner=function(e){if(!e||"function"!=typeof e)return;var t=c();if(!t)return;if(n=e,"scanning"===o)return;o="scanning",s(),t.addEventListener("keydown",l)},t.stopScanner=function(){if("scanning"!==o)return;o="ready",n=null,s();var e=c();e&&e.removeEventListener("keydown",l)};var n=null,o="ready",i="",a=null,u=0;function c(){return"undefined"==typeof window?null:window}function s(){i="",u=0,a&&(clearTimeout(a),a=null)}function l(e){if("scanning"===o)if(function(){var e=c(),t=e&&e.document&&e.document.activeElement;if(!t||t===e.document.body||t===e.document.documentElement)return!1;var r=t.tagName&&t.tagName.toLowerCase();return"input"===r||"textarea"===r||"select"===r||!0===t.isContentEditable}())s();else if(!(e.ctrlKey||e.metaKey||e.altKey)){if("Enter"===e.key){var t=i.replace(/[\uFF01-\uFF5E]/g,(function(e){return String.fromCharCode(e.charCodeAt(0)-65248)})).replace(/\u3002/g,".").replace(/\u2014/g,"_");return t&&function(e){e.preventDefault&&e.preventDefault(),e.stopPropagation&&e.stopPropagation()}(e),s(),void(t&&n&&n(t))}if(e.key&&1===e.key.length){var r=Date.now();u&&r-u>100&&s(),u=r,i+=e.key,a&&clearTimeout(a),a=setTimeout((function(){s()}),100)}}}},function(e,t,r){"use strict";t.__esModule=!0,t.resolveUseParentProxy=void 0;var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};t.installEmbedHost=function(e){if(p||"undefined"==typeof window)return;p=!0,(0,l.setEmbedScanResultForwarder)(b),(0,l.setEmbedScanErrorForwarder)(y),window.addEventListener("message",(function(t){var r=t.data;if(d(r))if("probeWxEnv"!==r.kind)if("scanResultConsumed"!==r.kind)"invoke"===r.kind&&r.id&&r.methodKey&&t.source&&t.source!==window&&(f.add(t.source),function(e,t){var r=t.data,o=r.id,i=r.methodKey,a=function(e,t,r){return e.map((function e(o){if(o&&"object"===(void 0===o?"undefined":n(o))&&o.__IScanEmbedCb__){var i=o.__IScanEmbedCb__;return function(){var e=Array.prototype.slice.call(arguments);t.postMessage({source:"IScanEmbed",v:1,kind:"callback",cbId:i,args:e},r)}}if(null===o||"object"!==(void 0===o?"undefined":n(o)))return o;if(Array.isArray(o))return o.map(e);var a={};return Object.keys(o).forEach((function(t){a[t]=e(o[t])})),a}))}(r.params||[],t.source,t.origin);Promise.resolve().then((function(){return T.apply(void 0,[e,i].concat(a))})).then((function(e){var t=e;return t&&"function"==typeof t.then?t.then((function(e){return t=e})):t})).then((function(e){t.source.postMessage({source:"IScanEmbed",v:1,kind:"invokeResult",id:o,methodKey:i,ok:!0,result:e},t.origin)})).catch((function(e){t.source.postMessage({source:"IScanEmbed",v:1,kind:"invokeResult",id:o,methodKey:i,ok:!1,error:"string"==typeof e?e:String(e&&e.message||e)},t.origin)}))}(e,t));else{if(!t.source||t.source===window)return;"string"==typeof r.result&&(0,s.acknowledgeEmbedScanConsumed)(r.result)}else{if(!t.source||t.source===window)return;var o=(0,u.readWxLikeEnvFromWindow)(window);t.source.postMessage({source:"IScanEmbed",v:1,kind:"probeWxEnvResult",id:r.id,wx:o},t.origin)}}))},t.getEmbedProxyResolved=function(){return(0,o.resolveUseParentProxy)()};var o=r(12);Object.defineProperty(t,"resolveUseParentProxy",{enumerable:!0,get:function(){return o.resolveUseParentProxy}}),t.exportSDK=function(e,t){for(var r=arguments.length,o=Array(r>2?r-2:0),i=2;i=4||(w=!0,S++,_(),window.parent.postMessage({source:"IScanEmbed",v:1,kind:"probeWxEnv",id:(0,c.createUUID)()},"*"),window.setTimeout((function(){w=!1,null===(0,u.getParentWxEnvReport)()&&C()&&E()}),600)))}function x(e){var t=e.data;if(d(t))if("probeWxEnvResult"!==t.kind)if("forwardScanResult"!==t.kind)if("forwardScanError"!==t.kind){if("invokeResult"===t.kind){var r=m[t.id];if(!r)return;return delete m[t.id],void(t.ok?r.resolve(t.result):r.reject(new Error(t.error||"[IScan embed]: invoke failed")))}if("callback"===t.kind){var n=g[t.cbId];"function"==typeof n&&n.apply(null,t.args||[])}}else"string"==typeof t.error&&(0,s.dispatchEmbedScanError)(t.error);else"string"==typeof t.result&&(0,s.dispatchEmbedScanResult)(t.result)&&(0,o.resolveUseParentProxy)()&&window.parent.postMessage({source:"IScanEmbed",v:1,kind:"scanResultConsumed",result:t.result},"*");else(0,u.setParentWxEnvReport)(!!t.wx)}function _(){h||"undefined"==typeof window||(h=!0,window.addEventListener("message",x))}function I(e,t){_(),E();var r=(0,c.createUUID)(),n=function(e){for(var t=[],r={},n=0;n1;)r=r[n.shift()];if(r&&1==n.length&&r.hasOwnProperty(n[0])){for(var o,i=arguments.length,a=Array(i>2?i-2:0),u=2;u1&&void 0!==arguments[1]?arguments[1]:"",r={};return Object.keys(e).forEach((function(o){var i=e[o];if("object"===(void 0===i?"undefined":n(i)))Object.assign(r,P(i,""+t+o+"."));else if("function"==typeof i){var a,u=""+t+o;Object.assign(r,((a={})[u]=u,a))}})),r}function M(e){Object.keys(e).forEach((function(t){var r=e[t];"object"===(void 0===r?"undefined":n(r))&&M(r)})),Object.freeze(e)}function R(e,t,r,n){return function(){for(var a=arguments.length,u=Array(a),c=0;c 微信 -> Web 摄像头 -> 图片识别 IScan.startScan(); -// 仅打开 Web 视频扫码 -IScan.scanVideo(); - // 仅选择图片识别 IScan.scanImage(); @@ -126,6 +123,11 @@ interface ScanConfigOptions { | `webScanImageFallbackOnVideoError` | 摄像头不可用或打开失败时,是否自动弹出拍照/选图(适用于部分安卓内置浏览器) | `true` | | `webScanVideoAccessTimeout` | 打开摄像头超时(毫秒),超时后走图片回退 | `10000` | | `webScanVideoReadyTimeout` | 摄像头已开但无画面超时(毫秒),超时后走图片回退 | `8000` | +| `webScanCameraPermissionDialogEnabled` | `startScan` 走 Web 摄像头前是否先展示权限说明弹窗 | `true` | +| `webScanCameraPermissionTitle` | 权限说明弹窗标题 | `需要使用摄像头` | +| `webScanCameraPermissionMessage` | 权限说明弹窗正文 | 见类型定义默认值 | +| `webScanCameraPermissionConfirmText` | 确认按钮文案 | `继续` | +| `webScanCameraPermissionCancelText` | 取消按钮文案 | `取消` | | `scanBeepAudio` | 扫码成功提示音地址(任意模式匹配成功时播放) | 内置提示音 | | `scanBeepEnabled` | 扫码成功是否播放提示音 | `true` | | `initWechatJssdk` | 微信 JSSDK 初始化配置,仅微信环境生效 | 无 | @@ -292,14 +294,6 @@ console.log(IScan.getStatus()); IScan.startScan(); ``` -### `scanVideo(): void` - -直接开启 Web 摄像头扫码。扫码结果通过 `onScanListener` 回调。 - -```js -IScan.scanVideo(); -``` - ### `scanImage(): void` 直接选择图片进行识别。识别结果通过 `onScanListener` 回调。 diff --git a/src/_core.js b/src/_core.js index 49f86a1..dd6aed1 100644 --- a/src/_core.js +++ b/src/_core.js @@ -1,12 +1,19 @@ import './polyfill'; import { supportList, - onScanListener, offScanListener, setStatusListener, getStatus, - startScan, stopScan, scanVideo, scanImage, clear + onScanListener, offScanListener, + onScanErrorListener, offScanErrorListener, + setStatusListener, getStatus, + startScan, stopScan, scanImage, scanImageFromFile, clear } from './services/provider/scan'; import { setConfig, getVersion } from './services/config'; import { initWxJssdk } from './services/wx'; -import { printDebug } from './utils/logger'; +import { + isSupportWebScan, + prepareWebScanBarcodeDetector, + isSupportImageScan +} from './services/web'; +import { printDebug, printWarn } from './utils/logger'; let _readyPromise = null; let _calledReady = false; @@ -23,18 +30,25 @@ function config(config) { return _readyPromise; } _readyPromise = Promise.resolve().then(() => { + return initWxJssdk().catch(err => { + printDebug('init wx jssdk failed:', err && err.message ? err.message : err); + }); + }).then(() => { printDebug('-------------------------------------'); printDebug('sdk_version:', getVersion()); printDebug('support_list:', supportList.map(item => item.name + ':' + item.support).join(', ')); printDebug('-------------------------------------'); - initWxJssdk(); - return Promise.resolve().then(() => { - _calledReady = true; - }).catch(err => { - _readyPromise = null; - throw err; - }); - }) + if (isSupportWebScan() || isSupportImageScan()) { + return prepareWebScanBarcodeDetector().catch(err => { + printWarn('prepare barcode detector failed:', err); + }); + } + }).then(() => { + _calledReady = true; + }).catch(err => { + _readyPromise = null; + throw err; + }); return _readyPromise; } @@ -42,11 +56,13 @@ export default Object.assign({}, { config, onScanListener, offScanListener, + onScanErrorListener, + offScanErrorListener, setStatusListener, getStatus, startScan, stopScan, - scanVideo, scanImage, + scanImageFromFile, clear, }); \ No newline at end of file diff --git a/src/_export.js b/src/_export.js index 33058cc..917abb9 100644 --- a/src/_export.js +++ b/src/_export.js @@ -13,8 +13,12 @@ import { createUUID } from "./utils/uuid"; import { dispatchEmbedScanResult, acknowledgeEmbedScanConsumed, + dispatchEmbedScanError, } from "./services/provider/scan"; -import { setEmbedScanResultForwarder } from "./services/embedScanBridge"; +import { + setEmbedScanResultForwarder, + setEmbedScanErrorForwarder, +} from "./services/embedScanBridge"; const EMBED_SOURCE = "IScanEmbed"; const EMBED_V = 1; @@ -25,6 +29,8 @@ const embedChildSources = new Set(); const EMBED_LISTENER_METHODS = new Set([ "onScanListener", "offScanListener", + "onScanErrorListener", + "offScanErrorListener", "clear", ]); @@ -105,6 +111,26 @@ function hydrateEmbedParams(params, messageSource, targetOrigin) { return params.map(walk); } +function broadcastScanErrorToEmbedChildren(error) { + if (embedChildSources.size === 0 || error == null || error === "") { + return; + } + embedChildSources.forEach((source) => { + try { + source.postMessage( + { + source: EMBED_SOURCE, + v: EMBED_V, + kind: "forwardScanError", + error, + }, + "*" + ); + } catch (e) { + } + }); +} + function broadcastScanResultToEmbedChildren(result) { if (embedChildSources.size === 0 || result == null || result === "") { return; @@ -198,6 +224,12 @@ function embedChildOnMessage(ev) { } return; } + if (data.kind === "forwardScanError") { + if (typeof data.error === "string") { + dispatchEmbedScanError(data.error); + } + return; + } if (data.kind === "invokeResult") { const pending = pendingInvokes[data.id]; if (!pending) { @@ -307,6 +339,7 @@ export function installEmbedHost(lib) { } embedHostInstalled = true; setEmbedScanResultForwarder(broadcastScanResultToEmbedChildren); + setEmbedScanErrorForwarder(broadcastScanErrorToEmbedChildren); window.addEventListener("message", (ev) => { const data = ev.data; if (!isEmbedMessage(data)) { diff --git a/src/index.js b/src/index.js index 63010fc..8e38c1f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,15 @@ +import './polyfill'; import core from "./_core"; import _global from './polyfill/_global'; import { exportSDK, installEmbedHost } from './_export'; +import { setSdkScriptSrc } from './services/web'; + +if (typeof document !== 'undefined' && document.currentScript && document.currentScript.src) { + setSdkScriptSrc(document.currentScript.src); +} const IScan = exportSDK(core, null, "config", "setStatusListener", "onScanListener", - "offScanListener", "stopScan", "startScan", "scanImage", "clear"); + "offScanListener", "onScanErrorListener", "offScanErrorListener", "stopScan", "startScan", "scanImage", "scanImageFromFile", "clear"); installEmbedHost(core); diff --git a/src/polyfill/_es6.js b/src/polyfill/_es6.js index da00dbd..c670e79 100644 --- a/src/polyfill/_es6.js +++ b/src/polyfill/_es6.js @@ -1,5 +1,12 @@ import { polyfill } from 'es6-promise'; +// Object.hasOwn (ES2022) — barcode-detector / ZXing 依赖,旧版 WebView 无此方法 +if (typeof Object.hasOwn !== 'function') { + Object.hasOwn = function hasOwn(object, key) { + return Object.prototype.hasOwnProperty.call(object, key); + }; +} + // Object.assign if (typeof Object.assign != 'function') { // Must be writable: true, enumerable: false, configurable: true diff --git a/src/services/embedScanBridge.js b/src/services/embedScanBridge.js index 1954445..b420869 100644 --- a/src/services/embedScanBridge.js +++ b/src/services/embedScanBridge.js @@ -1,12 +1,24 @@ /** 父页识别到扫码结果时,向嵌入 iframe 转发的回调(由 installEmbedHost 注册) */ let embedScanResultForwarder = null; +/** 父页图片识别失败时,向嵌入 iframe 转发的回调 */ +let embedScanErrorForwarder = null; export function setEmbedScanResultForwarder(fn) { embedScanResultForwarder = typeof fn === "function" ? fn : null; } +export function setEmbedScanErrorForwarder(fn) { + embedScanErrorForwarder = typeof fn === "function" ? fn : null; +} + export function forwardEmbedScanResultIfNeeded(result) { if (embedScanResultForwarder && result != null && result !== "") { embedScanResultForwarder(result); } } + +export function forwardEmbedScanErrorIfNeeded(error) { + if (embedScanErrorForwarder && error != null && error !== "") { + embedScanErrorForwarder(error); + } +} diff --git a/src/services/provider/scan.js b/src/services/provider/scan.js index d83106b..c53703a 100644 --- a/src/services/provider/scan.js +++ b/src/services/provider/scan.js @@ -7,28 +7,83 @@ import { startScanForImage, unlockScanBeep, playScanBeep, - isWebScanImageFallbackEnabled + isWebScanImageFallbackEnabled, + canUseWebCameraScan, + shouldSkipWebCameraProbe, + cleanupWebScanResiduals, + detectImageFileForScan } from "../web"; -import { isSupportWxScan, startScanForWx } from "../wx"; +import { isSupportWxScan, startScanForWx, isWxEnv } from "../wx"; import { startScanner, stopScanner } from "../scanner"; import { getConfig } from "../config"; import { toAny } from "../../utils/toany"; -import { printDebug } from "../../utils/logger"; -import { forwardEmbedScanResultIfNeeded } from "../embedScanBridge"; +import { printDebug, printWarn } from "../../utils/logger"; +import { forwardEmbedScanResultIfNeeded, forwardEmbedScanErrorIfNeeded } from "../embedScanBridge"; let _scan_status = "ready"; let _scan_status_listener = null; let _scan_listener_list = []; +let _scan_error_listener_list = []; let _scan_resolve = null; let _scan_closing = false; let _scan_next_start_time = 0; const SCAN_RESTART_DELAY = 500; +const BRIDGE_SCAN_TIMEOUT = 5000; +const SCAN_SESSION_TIMEOUT = 90000; function getScanRestartDelay() { return toAny(getConfig("scanRestartDelay"), SCAN_RESTART_DELAY); } +function getBridgeScanTimeout() { + const timeout = getConfig("bridgeScanTimeout"); + return typeof timeout === "number" && timeout > 0 ? timeout : BRIDGE_SCAN_TIMEOUT; +} + +function getScanSessionTimeout() { + const timeout = getConfig("scanSessionTimeout"); + return typeof timeout === "number" && timeout > 0 ? timeout : SCAN_SESSION_TIMEOUT; +} + +function withScanSessionTimeout(scanPromise) { + return Promise.race([ + scanPromise, + new Promise(resolve => { + setTimeout(() => { + printWarn("scan session timeout"); + resolve({ cancel: 1, scanTimeout: true }); + }, getScanSessionTimeout()); + }) + ]); +} + +function __fallbackScanAfterBridgeFailure(err) { + if (!isScanning()) { + throw err; + } + printWarn("bridge scan unavailable, fallback:", err); + return __startNonBridgeScan(err); +} + +function __fallbackScanAfterWxFailure(err) { + if (!isScanning()) { + throw err; + } + printWarn("wx scan unavailable, fallback to web/image scan:", err); + return __startNonBridgeScan(err); +} + +function __startNonBridgeScan(err) { + if (isSupportWebScan()) { + return __startWebScan(); + } + if (isSupportImageScan()) { + return __startImageScan(); + } + throw err; +} + function parseBarcodeString(input) { // 标准化的类型映射表:将各种变体映射到统一标识 // 这样即使传入 EAN_13、EAN-13、EAN13 都能匹配成功 @@ -120,6 +175,68 @@ function __result(result) { return matched; } +function normalizeScanError(raw) { + if (typeof raw === "string") { + return raw; + } + if (raw && raw.error != null && raw.error !== "") { + return String(raw.error); + } + if (raw && raw.message) { + return String(raw.message); + } + if (raw == null || raw === "") { + return ""; + } + return String(raw); +} + +function __scanError(raw, meta) { + const error = normalizeScanError(raw); + if (!error) { + return false; + } + forwardEmbedScanErrorIfNeeded(error); + let matched = false; + for (let i = 0; i < _scan_error_listener_list.length; i++) { + const item = _scan_error_listener_list[i]; + if (item.listener && __match(error, item.match)) { + matched = true; + item.listener(Object.assign({ + error, + key: item.key + }, meta || {})); + break; + } + } + return matched; +} + +function __notifyImageScanFailure(raw, meta) { + if (raw && raw.cancel) { + return false; + } + const error = normalizeScanError(raw); + const notified = __scanError(raw, Object.assign({ source: "image" }, meta || {})); + if (!notified && error) { + printWarn("image scan failed:", error); + } + return notified; +} + +function __notifyWebScanFailure(raw, meta) { + if (raw && raw.cancel) { + return false; + } + const payload = raw && raw.error != null ? raw.error : raw; + const error = normalizeScanError(payload); + const notified = __scanError(payload, Object.assign({ source: "web" }, meta || {})); + if (!notified && error) { + printWarn("web scan failed:", error); + } + return notified; +} + function __hasMatchedListener(result) { for (let i = 0; i < _scan_listener_list.length; i++) { const item = _scan_listener_list[i]; @@ -178,6 +295,15 @@ export function dispatchEmbedScanResult(raw) { return __scannerResult(result); } +/** + * 父页通过 postMessage 将识别错误投递到嵌入 iframe 时调用。 + * @returns {boolean} 是否有监听消费了该错误 + */ +export function dispatchEmbedScanError(raw) { + const error = normalizeScanError(raw); + return __scanError(error, { source: "image" }); +} + /** * 嵌入 iframe 已消费扫码结果时通知父页结束当前识别(关闭摄像头/UI 等)。 */ @@ -222,7 +348,7 @@ function __scannerResult(result) { function __startBridgeScan() { return bridgeAsync("startScan", { closeable: true - }).then(resp => { + }, getBridgeScanTimeout()).then(resp => { if (!isScanning()) { return resp; } @@ -238,10 +364,10 @@ function __startBridgeScan() { return resp; }).catch(err => { if (!isScanning()) { - return err; + throw err; } if (!err || !err.result) { - return err; + throw err; } if (__result(err.result)) { return err; @@ -261,6 +387,9 @@ function __startWxScan() { if (!isScanning()) { return resp; } + if (resp && resp.error && !resp.result) { + throw resp.error; + } if (!resp || !resp.result) { return resp; } @@ -270,43 +399,50 @@ function __startWxScan() { return resp; }).catch(err => { if (!isScanning()) { + throw err; + } + if (err && err.result) { + if (__result(err.result)) { + return err; + } return err; } - if (!err || !err.result) { - return err; - } - if (__result(err.result)) { - return err; - } - return err; + return __fallbackScanAfterWxFailure(err); }); } -function __startWebScan() { - return startScanForWeb(__result).then(resp => { +function __startWebScan(useImageScan = false) { + return startScanForWeb(__result, __scanError).then(resp => { if (!isScanning()) { return resp; } if (!resp || !resp.result) { + if (resp && resp.success === false) { + __notifyWebScanFailure(resp); + } return resp; } - if (__result(resp.result)) { - return resp; - } - if (isScanning()) { - return __startWebScan(); - } + __result(resp.result); return resp; }).catch(err => { if (!isScanning()) { return err; } - if (err && err.cancel || err && err.imageFallbackUsed) { + if (err && err.cancel) { return err; } - if (isWebScanImageFallbackEnabled()) { + if (err && err.scanTimeout) { + return err; + } + if (err && err.imageFallbackUsed) { + __notifyWebScanFailure(err); + return err; + } + if (isWebScanImageFallbackEnabled() && useImageScan) { return __startImageScan(); } + __notifyWebScanFailure(err); + printWarn("web scan failed:", err); return err; }); } @@ -316,29 +452,27 @@ function __startImageScan() { if (!isScanning()) { return resp; } + if (resp && resp.cancel) { + return resp; + } if (!resp || !resp.result) { + __notifyImageScanFailure(resp); return resp; } - if (__result(resp.result)) { - return resp; - } - if (isScanning()) { - return __startImageScan(); - } + __result(resp.result); return resp; }).catch(err => { if (!isScanning()) { return err; } - if (!err || !err.result) { + if (err && err.cancel) { return err; } - if (__result(err.result)) { + if (err && err.result) { + __result(err.result); return err; } - if (isScanning()) { - return __startImageScan(); - } + __notifyImageScanFailure(err); return err; }); } @@ -353,6 +487,11 @@ export function clear() { item.cancel(); } _scan_listener_list.length = 0; + for (let i = 0; i < _scan_error_listener_list.length; i++) { + const item = _scan_error_listener_list[i]; + item.cancel(); + } + _scan_error_listener_list.length = 0; __checkScanner(); } @@ -416,6 +555,68 @@ export function offScanListener(listener) { __checkScanner(); } +function createScanErrorListenerItem(listener, key, match, level) { + const item = { + key, + match: match || "", + level: level || 0, + listener: listener, + cancel: () => { + const index = _scan_error_listener_list.indexOf(item); + if (index !== -1) { + const items = _scan_error_listener_list.splice(index, 1); + for (let i = 0; i < items.length; i++) { + const removed = items[i]; + removed.listener && removed.listener({ cancel: 1, key: removed.key }); + } + } + } + }; + return item; +} + +export function onScanErrorListener(listener, key, match, level) { + if (!key || typeof key !== 'string') { + return; + } + if (typeof listener !== 'function') { + return; + } + let item = null; + for (let i = 0; i < _scan_error_listener_list.length; i++) { + const _i = _scan_error_listener_list[i]; + if (_i.key === key) { + item = _i; + break; + } + } + if (item) { + item.level = level; + item.match = match; + item.listener = listener; + } else { + item = createScanErrorListenerItem(listener, key, match, level); + _scan_error_listener_list.push(item); + } + _scan_error_listener_list.sort((a, b) => b.level - a.level); + return item; +} + +export function offScanErrorListener(listener) { + for (let i = 0; i < _scan_error_listener_list.length; i++) { + const _i = _scan_error_listener_list[i]; + if (typeof listener === 'string') { + if (_i.key === listener) { + _i.cancel(); + break; + } + } else if (_i.listener === listener) { + _i.cancel(); + break; + } + } +} + export function setStatusListener(listener) { if (typeof listener !== 'function') { return; @@ -428,11 +629,15 @@ export function getStatus() { } export function stopScan() { + cleanupWebScanResiduals(); if (!isScanning()) { return; } + const resolve = __finishScan(); + _scan_closing = true; __stopCurrentScan().then(() => { - __closed(); + resolve && resolve({ cancel: 1 }); + _scan_closing = false; }); } @@ -448,45 +653,23 @@ export function startScan() { }); let scanPromise = Promise.resolve(); if (inRuntime()) { - scanPromise = __startBridgeScan(); + scanPromise = __startBridgeScan().catch(__fallbackScanAfterBridgeFailure); } else if (isSupportWxScan()) { scanPromise = __startWxScan(); } else if (isSupportWebScan()) { - scanPromise = __startWebScan(); + scanPromise = __startWebScan(true); } else if (isSupportImageScan()) { scanPromise = __startImageScan(); } else { - printDebug("Not support scanner"); + printWarn("Not support scanner"); } - return Promise.race([scanPromise, scannerPromise]); + return withScanSessionTimeout(Promise.race([scanPromise, scannerPromise])); }).finally(() => { _scan_resolve = null; __closed(); }); } -export function scanVideo() { - if (!isSupportWebScan()) { - printDebug("Not support video scanner"); - return; - } - if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) { - return; - } - unlockScanBeep(); - Promise.resolve().then(() => { - __scanning(); - return startScanForWeb(__result).then(resp => { - if (resp && resp.result) { - __result(resp.result); - } - throw resp.error; - }).catch(err => { }); - }).finally(() => { - __closed(); - }); -} - export function scanImage() { if (!isSupportImageScan()) { printDebug("Not support image scanner"); @@ -496,14 +679,49 @@ export function scanImage() { return; } unlockScanBeep(); - Promise.resolve().then(() => { - __scanning(); - return startScanForImage().then(resp => { - if (resp && resp.result) { - __result(resp.result); + __scanning(); + withScanSessionTimeout(__startImageScan()).catch(err => { + if (err && err.cancel) { + return; + } + __notifyImageScanFailure(err); + }).finally(() => { + __closed(); + }); +} + +/** 由原生/业务传入已选图片 File,避免 WebView 无法从 input.files 取文件 */ +export function scanImageFromFile(file) { + if (!isSupportImageScan()) { + printDebug("Not support image scanner"); + return; + } + if (isScanning() || _scan_closing || Date.now() < _scan_next_start_time) { + return; + } + unlockScanBeep(); + cleanupWebScanResiduals(); + __scanning(); + withScanSessionTimeout( + detectImageFileForScan(file).then(resp => { + if (!isScanning()) { + return resp; } - throw resp.error; - }).catch(err => { }); + if (resp && resp.cancel) { + return resp; + } + if (!resp || !resp.result) { + __notifyImageScanFailure(resp); + return resp; + } + __result(resp.result); + return resp; + }) + ).catch(err => { + if (err && err.cancel) { + return; + } + __notifyImageScanFailure(err); }).finally(() => { __closed(); }); @@ -512,19 +730,30 @@ export function scanImage() { export const supportList = [ { name: "bridge", - support: !!inRuntime() + get support() { + return !!inRuntime(); + } }, { name: "wx", - support: !!isSupportWxScan() + get support() { + return !!isSupportWxScan(); + } }, { name: "web", - support: !!isSupportWebScan() + get support() { + if (shouldSkipWebCameraProbe()) { + return false; + } + return !!canUseWebCameraScan(); + } }, { name: "image", - support: !!isSupportImageScan() + get support() { + return !!isSupportImageScan(); + } }, { name: "scanner", diff --git a/src/services/web/index.js b/src/services/web/index.js index 85c7eaf..4f17d42 100644 --- a/src/services/web/index.js +++ b/src/services/web/index.js @@ -1,19 +1,31 @@ +import '../../polyfill'; import { BarcodeDetector as BarcodeDetectorPonyfill, prepareZXingModule } from "barcode-detector/dist/cjs/ponyfill.js"; import { createUUID } from "../../utils/uuid"; import { getConfig } from "../config"; +import { inRuntime } from "../bridge"; +import { isWxEnv, isSupportWxScan } from "../wx"; +import { printWarn, printDebug } from "../../utils/logger"; import scanBeepAudio from "../../../res/scan_beep.ogg"; const scanWeb = { uuid: null, finish: true, stream: null, - videoEl: null + videoEl: null, + cancelSession: null } +let activeImageScanCancel = null; +let activeChooseImageCancel = null; + +const HIDDEN_FILE_INPUT_STYLE = "position:fixed;left:-10000px;top:0;width:1px;height:1px;opacity:0;pointer-events:none;z-index:-1;border:0;padding:0;margin:0;"; + const DEFAULT_SCAN_BEEP_AUDIO = scanBeepAudio; const ZXING_READER_WASM_PATH = "lib/reader.wasm"; const WEBSCAN_CLOSE_BUTTON_ID = "__webscan_close_button__"; const WEBSCAN_PICK_IMAGE_BUTTON_ID = "__webscan_pick_image_button__"; +const WEBSCAN_IMAGE_PICKER_OVERLAY_ID = "__webscan_image_picker_overlay__"; +const WEBSCAN_CAMERA_PERMISSION_OVERLAY_ID = "__webscan_camera_permission_overlay__"; const WEBSCAN_CLOSE_ICON_SVG = ""; const WEBSCAN_PICK_IMAGE_ICON_SVG = ""; const WEBSCAN_OVERLAY_BUTTON_SIZE = 40; @@ -23,9 +35,47 @@ const WEBSCAN_OVERLAY_BUTTON_GAP = 10; function getDefaultWebScanOverlayButtonStyle() { return "width: " + WEBSCAN_OVERLAY_BUTTON_SIZE + "px; height: " + WEBSCAN_OVERLAY_BUTTON_SIZE + "px; padding: 0; border: 0; border-radius: 50%; background: rgba(0, 0, 0, 0.55); color: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 10000;"; } -const currentScriptSrc = typeof document !== "undefined" +let sdkScriptSrc = typeof document !== "undefined" && document.currentScript - && document.currentScript.src; + && document.currentScript.src + || ""; + +/** 在 SDK 入口脚本执行时写入,避免 async/defer 导致 currentScript 为空 */ +export function setSdkScriptSrc(src) { + if (src && typeof src === "string") { + sdkScriptSrc = src; + } +} + +function resolveSdkScriptSrc() { + const configured = getConfig("webScanWasmBaseUrl"); + if (configured && typeof configured === "string") { + return configured; + } + if (sdkScriptSrc) { + return sdkScriptSrc; + } + if (typeof document === "undefined") { + return ""; + } + if (document.currentScript && document.currentScript.src) { + return document.currentScript.src; + } + const scripts = document.getElementsByTagName("script"); + for (let i = scripts.length - 1; i >= 0; i--) { + const src = scripts[i].src; + if (src && /(?:^|\/)index\.js(?:\?|$)/.test(src)) { + return src; + } + } + for (let i = scripts.length - 1; i >= 0; i--) { + const src = scripts[i].src; + if (src) { + return src; + } + } + return ""; +} let barcodeDetectorPreparePromise = null; let scanBeepAudioEl = null; @@ -40,10 +90,19 @@ const SILENT_BEEP_UNLOCK_AUDIO = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAA function removeEl(id, uuid) { try { let el = document.getElementById(id); - if (uuid && el && el.uuid !== uuid) { + if (!el) { return; } - document.body.removeChild(el); + if (uuid && el.uuid !== uuid) { + return; + } + if (el.remove) { + el.remove(); + return; + } + if (el.parentNode) { + el.parentNode.removeChild(el); + } } catch (error) { } } @@ -71,8 +130,185 @@ function stopMediaStream(stream) { } } -function stopActiveWebScan() { +function cancelActiveImageScan() { + if (activeImageScanCancel) { + const cancel = activeImageScanCancel; + activeImageScanCancel = null; + cancel(); + } +} + +function cancelActiveChooseImage() { + if (activeChooseImageCancel) { + const cancel = activeChooseImageCancel; + activeChooseImageCancel = null; + cancel(); + } +} + +function removeImagePickerOverlay() { + removeEl(WEBSCAN_IMAGE_PICKER_OVERLAY_ID); +} + +function getWebScanImagePickerMode() { + const mode = getConfig("webScanImagePickerMode"); + if (mode === "auto" || mode === "button") { + return mode; + } + if (isAndroid() || isWechatBrowser()) { + return "button"; + } + return "auto"; +} + +/** 清理残留选图 input / 轮询,避免全屏透明层拦截点击 */ +let activeCameraPermissionCancel = null; + +function removeCameraPermissionOverlay() { + if (activeCameraPermissionCancel) { + const cancel = activeCameraPermissionCancel; + activeCameraPermissionCancel = null; + cancel(); + return; + } + removeEl(WEBSCAN_CAMERA_PERMISSION_OVERLAY_ID); +} + +function queryCameraPermissionState() { + if (typeof navigator === "undefined" || !navigator.permissions || typeof navigator.permissions.query !== "function") { + return Promise.resolve(null); + } + return navigator.permissions.query({ name: "camera" }).then(status => { + return status && status.state ? status.state : null; + }).catch(() => null); +} + +function shouldTrustCameraPermissionQuery() { + // 微信等 WebView 的 Permissions API 常与 getUserMedia 实际行为不一致,仅信任本会话已成功开流 + return !isWechatBrowser(); +} + +/** 是否可跳过说明弹窗(不保证不调起系统授权,仅用于是否展示 SDK 说明层) */ +function isWebCameraPermissionGranted() { + if (webCameraPermissionGrantedCache === true) { + return Promise.resolve(true); + } + if (!shouldTrustCameraPermissionQuery() || webCameraPermissionApiMismatch) { + return Promise.resolve(false); + } + return queryCameraPermissionState().then(state => state === "granted"); +} + +let webCameraPermissionDialogSkipped = false; + +function ensureWebScanCameraPermissionBeforeAccess() { + webCameraPermissionDialogSkipped = false; + return isWebCameraPermissionGranted().then(granted => { + if (granted) { + webCameraPermissionDialogSkipped = true; + printDebug("web camera permission: trusted granted, skip dialog"); + return; + } + return showWebScanCameraPermissionDialog(); + }); +} + +function isCameraAccessDeniedError(err) { + if (!err) { + return false; + } + const name = err.name || ""; + return name === "NotAllowedError" || name === "PermissionDeniedError" || name === "SecurityError"; +} + +function markWebCameraPermissionApiMismatch(err) { + if (!webCameraPermissionDialogSkipped || !isCameraAccessDeniedError(err)) { + return; + } + webCameraPermissionApiMismatch = true; + webCameraPermissionGrantedCache = null; + printDebug("web camera permission: API granted but getUserMedia denied, will show dialog next time"); +} + +/** 申请摄像头前展示说明,用户确认后再触发系统授权(仅 startScan 流程调用) */ +function showWebScanCameraPermissionDialog() { + if (getConfig("webScanCameraPermissionDialogEnabled") === false) { + return Promise.resolve(); + } + if (typeof document === "undefined") { + return Promise.resolve(); + } + removeCameraPermissionOverlay(); + return new Promise((resolve, reject) => { + const overlay = document.createElement("div"); + overlay.id = WEBSCAN_CAMERA_PERMISSION_OVERLAY_ID; + overlay.style.cssText = "position:fixed;left:0;top:0;right:0;bottom:0;z-index:100001;background:rgba(0,0,0,0.55);display:flex;align-items:center;justify-content:center;padding:20px;box-sizing:border-box;"; + const panel = document.createElement("div"); + panel.style.cssText = "width:100%;max-width:300px;background:#fff;border-radius:12px;padding:22px 20px;box-shadow:0 8px 28px rgba(0,0,0,0.22);"; + const title = document.createElement("h3"); + title.textContent = getConfig("webScanCameraPermissionTitle") || "需要使用摄像头"; + title.style.cssText = "margin:0 0 12px;font-size:17px;font-weight:600;color:#222;line-height:1.35;text-align:center;"; + const message = document.createElement("p"); + message.textContent = getConfig("webScanCameraPermissionMessage") + || "为了扫描条形码或二维码,需要您授权使用摄像头。请点击「继续」后,在系统弹窗中选择「允许」。"; + message.style.cssText = "margin:0 0 20px;font-size:14px;color:#555;line-height:1.55;text-align:left;"; + const confirmBtn = document.createElement("button"); + confirmBtn.type = "button"; + confirmBtn.textContent = getConfig("webScanCameraPermissionConfirmText") || "继续"; + confirmBtn.style.cssText = "display:block;width:100%;padding:12px;border:0;background:#1b63f4;color:#fff;border-radius:8px;font-size:16px;line-height:1.4;cursor:pointer;"; + const cancelBtn = document.createElement("button"); + cancelBtn.type = "button"; + cancelBtn.textContent = getConfig("webScanCameraPermissionCancelText") || "取消"; + cancelBtn.style.cssText = "display:block;width:100%;margin-top:10px;padding:10px;border:0;background:#f0f0f0;border-radius:8px;font-size:15px;color:#666;line-height:1.4;cursor:pointer;"; + const finish = (fn, value) => { + activeCameraPermissionCancel = null; + removeEl(WEBSCAN_CAMERA_PERMISSION_OVERLAY_ID); + fn(value); + }; + activeCameraPermissionCancel = () => finish(reject, { cancel: 1 }); + confirmBtn.onclick = event => { + event.preventDefault && event.preventDefault(); + finish(resolve); + }; + cancelBtn.onclick = event => { + event.preventDefault && event.preventDefault(); + finish(reject, { cancel: 1 }); + }; + panel.appendChild(title); + panel.appendChild(message); + panel.appendChild(confirmBtn); + panel.appendChild(cancelBtn); + overlay.appendChild(panel); + document.body.appendChild(overlay); + }); +} + +export function cleanupWebScanResiduals() { + cancelActiveChooseImage(); + removeCameraPermissionOverlay(); + removeEl("__webscan_image_input__"); + removeImagePickerOverlay(); +} + +function stopActiveWebScan(options) { + options = options || {}; + if (options.cleanupChooseImage !== false) { + cleanupWebScanResiduals(); + } + if (scanWeb.cancelSession) { + const cancel = scanWeb.cancelSession; + scanWeb.cancelSession = null; + if (options.invokeCancel !== false) { + cancel(); + } + } + if (options.cancelImageScan !== false) { + cancelActiveImageScan(); + } scanWeb.uuid = null; + if (options.keepScanFinish !== true) { + scanWeb.finish = true; + } stopMediaStream(scanWeb.stream); try { if (scanWeb.videoEl) { @@ -114,6 +350,126 @@ function isMobile() { && /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent || ""); } +function isAndroid() { + return typeof navigator !== 'undefined' + && /Android/i.test(navigator.userAgent || ""); +} + +function isIOS() { + return typeof navigator !== 'undefined' + && /iPhone|iPad|iPod/i.test(navigator.userAgent || ""); +} + +function isWechatBrowser() { + return isWxEnv(); +} + +let webCameraSupportProbed = null; +/** 本页已成功 getUserMedia 后为 true,用于跳过说明弹窗 */ +let webCameraPermissionGrantedCache = null; +/** Permissions API 报 granted 但 getUserMedia 仍失败时置 true,不再信任 API */ +let webCameraPermissionApiMismatch = false; + +function hasGetUserMediaSupport() { + if (typeof navigator === "undefined") { + return false; + } + if (navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === "function") { + return true; + } + const legacy = navigator.getUserMedia + || navigator.webkitGetUserMedia + || navigator.mozGetUserMedia; + return typeof legacy === "function"; +} + +function invokeGetUserMedia(constraints) { + if (typeof navigator === "undefined") { + return Promise.reject(new Error("navigator is not available")); + } + if (navigator.mediaDevices && typeof navigator.mediaDevices.getUserMedia === "function") { + return navigator.mediaDevices.getUserMedia(constraints); + } + const legacy = navigator.getUserMedia + || navigator.webkitGetUserMedia + || navigator.mozGetUserMedia; + if (typeof legacy === "function") { + return new Promise((resolve, reject) => { + legacy.call(navigator, constraints, resolve, reject); + }); + } + return Promise.reject(new Error("getUserMedia is not supported")); +} + +function getWebScanCameraProbeTimeout() { + const timeout = getConfig("webScanCameraProbeTimeout"); + return typeof timeout === "number" && timeout > 0 ? timeout : 3000; +} + +function resolveWebCameraConfigOverride() { + if (getConfig("webScanCameraEnabled") === false || getConfig("webScanCameraInWechat") === false) { + return false; + } + if (getConfig("webScanCameraEnabled") === true || getConfig("webScanCameraInWechat") === true) { + return true; + } + return null; +} + +/** bridge / 微信扫一扫实际可用时跳过 H5 摄像头探测,避免 config 阶段申请权限弹窗 */ +export function shouldSkipWebCameraProbe() { + if (inRuntime()) { + return true; + } + return !!isSupportWxScan(); +} + +/** + * 同步判断是否具备 Web 摄像头扫码条件(不申请权限)。 + * @deprecated 请用 canUseWebCameraScan;保留兼容,不再调用 getUserMedia + */ +export function probeWebCameraScan() { + if (shouldSkipWebCameraProbe()) { + return Promise.resolve(false); + } + const supported = canUseWebCameraScan(); + printDebug("web camera capability (sync):", supported); + return Promise.resolve(supported); +} + +export function resetWebCameraSupportProbe() { + webCameraSupportProbed = null; + webCameraPermissionGrantedCache = null; + webCameraPermissionApiMismatch = false; + webCameraPermissionDialogSkipped = false; +} + +/** 是否支持 Web 摄像头连续扫码(同步能力判断,不触发权限弹窗) */ +export function canUseWebCameraScan() { + if (getConfig("webScanEnabled") === false) { + return false; + } + if (!getBarcodeDetectorClass()) { + return false; + } + const override = resolveWebCameraConfigOverride(); + if (override === false) { + return false; + } + if (override === true) { + return hasGetUserMediaSupport(); + } + if (webCameraSupportProbed !== null) { + return webCameraSupportProbed; + } + return hasGetUserMediaSupport(); +} + +/** 安卓 WebView/Chrome 对 display:none 的 video 可能不解码帧,需保持可播放但不可见 */ +function getHiddenVideoStyle() { + return "position: fixed; width: 2px; height: 2px; opacity: 0.01; pointer-events: none; z-index: -1; left: 0; top: 0;"; +} + function getBarcodeFormats(scanType) { let formats = []; if (!scanType) { @@ -140,27 +496,109 @@ function getBarcodeFormats(scanType) { return formats; } -function getBarcodeDetectorClass() { +function resolveBarcodeDetectorClass(forcePonyfill) { + if (forcePonyfill || shouldPreferPonyfillBarcodeDetector()) { + return BarcodeDetectorPonyfill; + } if (typeof BarcodeDetector !== 'undefined') { return BarcodeDetector; } return BarcodeDetectorPonyfill; } +function getBarcodeDetectorClass() { + return resolveBarcodeDetectorClass(false); +} + +function shouldPreferPonyfillBarcodeDetector() { + if (getConfig("webScanPreferPonyfill") === true) { + return true; + } + // 微信/部分 WebView 的原生 BarcodeDetector 不完整,getSupportedFormats 常为空 + if (isWechatBrowser()) { + return true; + } + return false; +} + +function needsWasmPrepare(BarcodeDetectorClass) { + return BarcodeDetectorClass === BarcodeDetectorPonyfill && !!prepareZXingModule; +} + +const BARCODE_FORMAT_ALIASES = { + qrcode: "qr_code", + "qr-code": "qr_code", + QRCode: "qr_code", + ean13: "ean_13", + "ean-13": "ean_13", + ean8: "ean_8", + code128: "code_128", + code39: "code_39", + upca: "upc_a", + upce: "upc_e", + datamatrix: "data_matrix", + pdf417: "pdf417" +}; + +function normalizeBarcodeFormatName(format) { + if (!format || typeof format !== "string") { + return format; + } + if (BARCODE_FORMAT_ALIASES[format]) { + return BARCODE_FORMAT_ALIASES[format]; + } + const lower = format.toLowerCase().replace(/-/g, "_"); + return BARCODE_FORMAT_ALIASES[lower] || lower; +} + +function resolveSupportedBarcodeFormats(requestedFormats, reportedFormats) { + const reported = (reportedFormats || []).map(normalizeBarcodeFormatName); + const requested = (requestedFormats || []).map(normalizeBarcodeFormatName); + const supported = requested.filter(format => reported.indexOf(format) !== -1); + if (supported.length) { + return supported; + } + if (requestedFormats && requestedFormats.length) { + printWarn( + "barcode format filter empty, use configured formats:", + requestedFormats, + "reported:", + reportedFormats + ); + return requestedFormats; + } + return []; +} + function getZXingReaderWasmUrl() { - if (currentScriptSrc) { - return new URL(ZXING_READER_WASM_PATH, currentScriptSrc).href; + const configuredWasmUrl = getConfig("webScanWasmUrl"); + if (configuredWasmUrl && typeof configuredWasmUrl === "string") { + return configuredWasmUrl; + } + const scriptSrc = resolveSdkScriptSrc(); + if (scriptSrc) { + const base = getConfig("webScanWasmBaseUrl") || scriptSrc; + return new URL(ZXING_READER_WASM_PATH, base).href; } return "./" + ZXING_READER_WASM_PATH; } -function prepareBarcodeDetector() { - const BarcodeDetectorClass = getBarcodeDetectorClass(); - if (typeof BarcodeDetector !== 'undefined' || !prepareZXingModule) { +function prepareBarcodeDetectorWithTimeout(options) { + return promiseWithTimeout( + prepareBarcodeDetector(options), + getWebScanPrepareTimeout(), + "prepare barcode detector" + ); +} + +function prepareBarcodeDetector(options) { + options = options || {}; + const BarcodeDetectorClass = resolveBarcodeDetectorClass(options.forcePonyfill); + if (!needsWasmPrepare(BarcodeDetectorClass)) { return Promise.resolve(BarcodeDetectorClass); } - if (!barcodeDetectorPreparePromise) { - barcodeDetectorPreparePromise = prepareZXingModule({ + if (!barcodeDetectorPreparePromise || options.forcePonyfill) { + const preparePromise = prepareZXingModule({ fireImmediately: true, overrides: { locateFile: path => { @@ -170,27 +608,150 @@ function prepareBarcodeDetector() { return path; } } - }).then(() => BarcodeDetectorClass); + }).then(() => BarcodeDetectorPonyfill).catch(err => { + if (!options.forcePonyfill) { + barcodeDetectorPreparePromise = null; + } + printWarn("prepare barcode detector failed:", err, "wasm:", getZXingReaderWasmUrl()); + throw err; + }); + if (!options.forcePonyfill) { + barcodeDetectorPreparePromise = preparePromise; + } + return preparePromise; } return barcodeDetectorPreparePromise; } -function createBarcodeDetector(scanType) { - return prepareBarcodeDetector().then(BarcodeDetectorClass => { +/** config 阶段预加载 WASM,避免选图后才首次加载失败 */ +export function prepareWebScanBarcodeDetector() { + return prepareBarcodeDetector(); +} + +function getWebScanDetectTimeout() { + const timeout = getConfig("webScanDetectTimeout"); + return typeof timeout === "number" && timeout > 0 ? timeout : 15000; +} + +function getWebScanPrepareTimeout() { + const timeout = getConfig("webScanPrepareTimeout"); + return typeof timeout === "number" && timeout > 0 ? timeout : 20000; +} + +function getChooseImageTimeout() { + const timeout = getConfig("webScanChooseImageTimeout"); + return typeof timeout === "number" && timeout > 0 ? timeout : 120000; +} + +function promiseWithTimeout(promise, timeoutMs, label) { + return new Promise((resolve, reject) => { + let settled = false; + const timer = setTimeout(() => { + if (settled) { + return; + } + settled = true; + reject(new Error((label || "operation") + " timeout")); + }, timeoutMs); + Promise.resolve(promise).then(value => { + if (settled) { + return; + } + settled = true; + clearTimeout(timer); + resolve(value); + }).catch(err => { + if (settled) { + return; + } + settled = true; + clearTimeout(timer); + reject(err); + }); + }); +} + +function detectWithTimeout(detector, source, timeoutMs) { + timeoutMs = timeoutMs || getWebScanDetectTimeout(); + return new Promise((resolve, reject) => { + let settled = false; + const timer = setTimeout(() => { + if (settled) { + return; + } + settled = true; + reject(new Error("barcode detect timeout")); + }, timeoutMs); + Promise.resolve(detector.detect(source)).then(barcodes => { + if (settled) { + return; + } + settled = true; + clearTimeout(timer); + resolve(barcodes); + }).catch(err => { + if (settled) { + return; + } + settled = true; + clearTimeout(timer); + reject(err); + }); + }); +} + +function createImageBarcodeDetector(scanType) { + const preferPonyfill = getConfig("webScanImagePreferPonyfill") === true; + const avoidNativeOnMobile = isAndroid() || isWechatBrowser(); + printDebug("image scan: create detector, preferPonyfill:", preferPonyfill, "avoidNative:", avoidNativeOnMobile); + if (preferPonyfill || avoidNativeOnMobile) { + return createBarcodeDetector(scanType, { forcePonyfill: true }).catch(err => { + printWarn("image scan ponyfill unavailable, fallback native:", err); + return createBarcodeDetector(scanType, { useNativeFormats: true }); + }); + } + return createBarcodeDetector(scanType, { useNativeFormats: true }); +} + +function createBarcodeDetector(scanType, options) { + options = options || {}; + return prepareBarcodeDetectorWithTimeout(options).then(BarcodeDetectorClass => { if (!BarcodeDetectorClass) { throw new Error("BarcodeDetector is not supported"); } const formats = getBarcodeFormats(scanType); + if (!formats.length) { + throw new Error("No supported barcode formats, requested formats: " + formats.join(', ')); + } + const createInstance = resolvedFormats => new BarcodeDetectorClass({ formats: resolvedFormats }); + if (options.useNativeFormats) { + return createInstance(formats); + } if (BarcodeDetectorClass.getSupportedFormats) { - return BarcodeDetectorClass.getSupportedFormats().then(supportedFormats => { - const supported = formats.filter(format => supportedFormats.indexOf(format) !== -1); - if (!supported.length) { - throw new Error("No supported barcode formats"); + return Promise.resolve(BarcodeDetectorClass.getSupportedFormats()).then(reportedFormats => { + if (!reportedFormats || !reportedFormats.length) { + // 部分 WebView 原生 getSupportedFormats 为空但 detect 仍可用,不做交集过滤 + return createInstance(formats); } - return new BarcodeDetectorClass({ formats: supported }); + const resolved = resolveSupportedBarcodeFormats(formats, reportedFormats); + if (!resolved.length) { + if (!options.forcePonyfill && typeof BarcodeDetector !== 'undefined' && BarcodeDetectorClass !== BarcodeDetectorPonyfill) { + return createBarcodeDetector(scanType, { forcePonyfill: true }); + } + throw new Error("No supported barcode formats, reported formats: " + reportedFormats.join(', ')); + } + return createInstance(resolved); + }).catch(err => { + if (!options.forcePonyfill && typeof BarcodeDetector !== 'undefined' && BarcodeDetectorClass !== BarcodeDetectorPonyfill) { + return createBarcodeDetector(scanType, { forcePonyfill: true }); + } + if (options.forcePonyfill && typeof BarcodeDetector !== 'undefined') { + return createBarcodeDetector(scanType, { useNativeFormats: true }); + } + throw err; }); } - return new BarcodeDetectorClass({ formats }); + return createInstance(formats); }); } @@ -433,11 +994,7 @@ export function unlockScanBeep() { } export function isSupportWebScan() { - return typeof navigator !== 'undefined' - && navigator.mediaDevices - && navigator.mediaDevices.getUserMedia - && !!getBarcodeDetectorClass() - && getConfig("webScanEnabled") !== false; + return canUseWebCameraScan(); } export function isSupportImageScan() { @@ -452,12 +1009,43 @@ export function isWebScanImageFallbackEnabled() { function getWebScanVideoAccessTimeout() { const timeout = getConfig("webScanVideoAccessTimeout"); - return typeof timeout === "number" && timeout > 0 ? timeout : 10000; + if (typeof timeout === "number" && timeout > 0) { + return timeout; + } + return isWechatBrowser() ? 3000 : 10000; } function getWebScanVideoReadyTimeout() { const timeout = getConfig("webScanVideoReadyTimeout"); - return typeof timeout === "number" && timeout > 0 ? timeout : 8000; + if (typeof timeout === "number" && timeout > 0) { + return timeout; + } + return isWechatBrowser() ? 3000 : 8000; +} + +function needsDeferredFileRead() { + return isAndroid() || isWechatBrowser(); +} + +function getDeferredFileReadDelay() { + const delay = getConfig("webScanFileReadDelay"); + if (typeof delay === "number" && delay >= 0) { + return delay; + } + if (isAndroid() || isWechatBrowser()) { + return 300; + } + return 0; +} + +function getFilePollInterval() { + const interval = getConfig("webScanFilePollInterval"); + return typeof interval === "number" && interval > 0 ? interval : 250; +} + +function getMaxDeferredFileReadAttempts() { + const max = getConfig("webScanFileReadMaxAttempts"); + return typeof max === "number" && max > 0 ? max : 8; } function getUserMediaWithTimeout(constraints, timeoutMs) { @@ -470,7 +1058,7 @@ function getUserMediaWithTimeout(constraints, timeoutMs) { settled = true; reject(new Error("getUserMedia timeout")); }, timeoutMs); - navigator.mediaDevices.getUserMedia(constraints).then(stream => { + invokeGetUserMedia(constraints).then(stream => { if (settled) { stopMediaStream(stream); return; @@ -489,32 +1077,62 @@ function getUserMediaWithTimeout(constraints, timeoutMs) { }); } -function runWebScanImageFallback(onResult, resolve, reject) { - stopActiveWebScan(); - unlockScanBeep(); - return createBarcodeDetector(getConfig("webScanType")).then(detector => { - return chooseImageFile({ preferCapture: isMobile() }).then(file => { - if (!file) { - return Promise.reject({ cancel: 1 }); - } +function notifyImageScanError(onError, error) { + if (!onError || error == null || error === "") { + return; + } + if (typeof error === "string") { + onError(error); + return; + } + onError(error.error || error.message || String(error)); +} + +function pickImageThenDetect(fileOptions) { + return chooseImageFile(fileOptions).then(file => { + if (!file) { + return Promise.reject({ cancel: 1 }); + } + printDebug("pickImageThenDetect: file selected", file.name); + return createImageBarcodeDetector(getConfig("webScanType")).then(detector => { + printDebug("pickImageThenDetect: detector ready"); return detectImageFile(detector, file); - }).then(code => { - if (code && code.rawValue) { - if (!onResult || !onResult(code.rawValue)) { - return Promise.reject({ cancel: 1 }); - } - scanWeb.finish = true; - resolve({ - result: code.rawValue - }); - return; - } - return Promise.reject({ - success: false, - error: "未识别到二维码或条形码", - imageFallbackUsed: true - }); }); + }); +} + +function runWebScanImageFallback(onResult, onError, resolve, reject) { + // 仅停摄像头,不触发 cancelSession(否则选图前 Promise 已被 reject 为 cancel:1) + stopActiveWebScan({ invokeCancel: false, cancelImageScan: false, cleanupChooseImage: true, keepScanFinish: true }); + scanWeb.finish = false; + unlockScanBeep(); + const preferCapture = getConfig("webScanImagePreferCapture") === true && isMobile(); + printDebug("image fallback: pick image, mode:", getWebScanImagePickerMode()); + return pickImageThenDetect({ preferCapture: preferCapture }).then(code => { + if (code && code.rawValue) { + if (!onResult || !onResult(code.rawValue)) { + const scanError = { + success: false, + error: "扫码结果未被监听消费", + imageFallbackUsed: true + }; + notifyImageScanError(onError, scanError.error); + return Promise.reject(scanError); + } + scanWeb.uuid = null; + scanWeb.finish = true; + resolve({ + result: code.rawValue + }); + return; + } + const scanError = { + success: false, + error: "未识别到二维码或条形码", + imageFallbackUsed: true + }; + notifyImageScanError(onError, scanError.error); + return Promise.reject(scanError); }).catch(err => { if (err && err.cancel) { reject({ cancel: 1, imageFallbackUsed: true }); @@ -524,14 +1142,17 @@ function runWebScanImageFallback(onResult, resolve, reject) { reject(Object.assign({ imageFallbackUsed: true }, err)); return; } - reject({ + printWarn("image fallback detect failed:", err); + const scanError = { imageFallbackUsed: true, - error: err && err.error ? err.error : err - }); + error: err && err.error ? err.error : (err && err.message ? err.message : err) + }; + notifyImageScanError(onError, scanError.error); + reject(scanError); }); } -function tryWebScanImageFallback(onResult, resolve, reject, state) { +function tryWebScanImageFallback(onResult, onError, resolve, reject, state) { if (!isWebScanImageFallbackEnabled()) { return false; } @@ -541,7 +1162,7 @@ function tryWebScanImageFallback(onResult, resolve, reject, state) { if (state) { state.imageFallbackStarted = true; } - runWebScanImageFallback(onResult, resolve, reject); + runWebScanImageFallback(onResult, onError, resolve, reject); return true; } @@ -551,58 +1172,334 @@ export function stopScanForWeb() { }) } -function chooseImageFile(options) { +function bindChooseImageInput(input, resolve, options) { + options = options || {}; + const autoOpen = options.autoOpen === true; + let finished = false; + let pickerOpenedAt = 0; + let pollTimer = null; + let chooseTimer = null; + let deferredReadTimer = null; + let deferredReadAttempts = 0; + const detachInput = () => { + try { + if (input.remove) { + input.remove(); + } else if (input.parentNode) { + input.parentNode.removeChild(input); + } + } catch (_e) { } + removeEl("__webscan_image_input__"); + }; + const cleanup = () => { + window.removeEventListener("focus", onWindowFocus); + document.removeEventListener("visibilitychange", onVisibilityChange); + if (pollTimer) { + clearInterval(pollTimer); + pollTimer = null; + } + if (chooseTimer) { + clearTimeout(chooseTimer); + chooseTimer = null; + } + if (deferredReadTimer) { + clearTimeout(deferredReadTimer); + deferredReadTimer = null; + } + activeChooseImageCancel = null; + removeImagePickerOverlay(); + detachInput(); + }; + const finish = file => { + if (finished) { + return; + } + finished = true; + cleanup(); + printDebug("chooseImageFile:", file ? (file.name + " " + file.size) : "cancelled"); + resolve(file); + }; + activeChooseImageCancel = () => finish(null); + const tryReadFile = source => { + if (finished) { + return true; + } + const file = input.files && input.files[0]; + if (file) { + printDebug("chooseImageFile: got file via", source || "unknown"); + finish(file); + return true; + } + return false; + }; + const scheduleDeferredRead = source => { + if (finished) { + return; + } + if (deferredReadTimer) { + clearTimeout(deferredReadTimer); + } + deferredReadTimer = setTimeout(() => { + deferredReadTimer = null; + if (tryReadFile(source)) { + return; + } + if (!needsDeferredFileRead()) { + if (source === "change" || source === "input") { + finish(null); + } + return; + } + if (deferredReadAttempts < getMaxDeferredFileReadAttempts()) { + deferredReadAttempts += 1; + scheduleDeferredRead(source); + } + }, getDeferredFileReadDelay()); + }; + const handleChange = () => { + unlockScanBeep(); + if (autoOpen && Date.now() - pickerOpenedAt < 400) { + return; + } + deferredReadAttempts = 0; + if (tryReadFile("change")) { + return; + } + if (!needsDeferredFileRead()) { + finish(null); + return; + } + scheduleDeferredRead("change"); + }; + const onWindowFocus = () => { + if (finished || !pickerOpenedAt) { + return; + } + deferredReadAttempts = 0; + scheduleDeferredRead("focus"); + }; + const onVisibilityChange = () => { + if (finished || document.visibilityState !== "visible") { + return; + } + deferredReadAttempts = 0; + scheduleDeferredRead("visibility"); + }; + input.id = "__webscan_image_input__"; + input.addEventListener("change", handleChange); + if (!isAndroid() && !isWechatBrowser()) { + input.addEventListener("input", handleChange); + } + input.oncancel = () => { + finish(null); + }; + pickerOpenedAt = Date.now(); + window.addEventListener("focus", onWindowFocus); + document.addEventListener("visibilitychange", onVisibilityChange); + pollTimer = setInterval(() => { + if (finished) { + return; + } + tryReadFile("poll"); + }, getFilePollInterval()); + chooseTimer = setTimeout(() => { + if (!finished) { + printWarn("chooseImageFile: timeout"); + finish(null); + } + }, getChooseImageTimeout()); + if (autoOpen) { + printDebug("chooseImageFile: opening picker (auto)"); + try { + if (typeof input.showPicker === "function" && !isAndroid()) { + input.showPicker(); + } else { + input.click(); + } + } catch (e) { + printWarn("chooseImageFile: open picker failed:", e); + try { + input.click(); + } catch (e2) { + finish(null); + } + } + input.style.cssText = HIDDEN_FILE_INPUT_STYLE; + } else { + printDebug("chooseImageFile: tap the button to pick image"); + } +} + +function chooseImageFileAuto(options) { options = options || {}; return new Promise(resolve => { + cleanupWebScanResiduals(); const input = document.createElement("input"); input.type = "file"; input.accept = "image/*"; + input.multiple = false; if (options.preferCapture) { input.setAttribute("capture", options.captureMode || "environment"); } - input.style.display = "none"; - let finished = false; - let finish = file => { - if (finished) { - return; - } - finished = true; - removeEl("__webscan_image_input__"); - resolve(file); - }; - input.id = "__webscan_image_input__"; - input.onchange = () => { - unlockScanBeep(); - finish(input.files && input.files[0]); - }; - input.oncancel = () => { - finish(null); - }; + input.style.cssText = HIDDEN_FILE_INPUT_STYLE; document.body.appendChild(input); - input.click(); + bindChooseImageInput(input, resolve, { autoOpen: true }); }); } -function detectImageFile(detector, file) { +function chooseImageFileWithButton(options) { + options = options || {}; + return new Promise(resolve => { + cleanupWebScanResiduals(); + const overlay = document.createElement("div"); + overlay.id = WEBSCAN_IMAGE_PICKER_OVERLAY_ID; + overlay.style.cssText = "position:fixed;left:0;top:0;right:0;bottom:0;z-index:100000;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center;padding:16px;box-sizing:border-box;"; + const panel = document.createElement("div"); + panel.style.cssText = "width:100%;max-width:280px;background:#fff;border-radius:12px;padding:20px;text-align:center;box-shadow:0 8px 24px rgba(0,0,0,0.2);"; + const title = document.createElement("p"); + title.textContent = getConfig("webScanImagePickerTitle") || "请选择图片识别"; + title.style.cssText = "margin:0 0 16px;font-size:16px;color:#333;line-height:1.4;"; + const label = document.createElement("label"); + label.style.cssText = "display:block;position:relative;padding:12px 20px;background:#1b63f4;color:#fff;border-radius:8px;font-size:16px;line-height:1.4;cursor:pointer;"; + const input = document.createElement("input"); + input.type = "file"; + input.accept = "image/*"; + input.multiple = false; + if (options.preferCapture) { + input.setAttribute("capture", options.captureMode || "environment"); + } + input.style.cssText = "position:absolute;left:0;top:0;width:100%;height:100%;opacity:0;cursor:pointer;font-size:0;"; + const labelText = document.createElement("span"); + labelText.textContent = getConfig("webScanImagePickerButtonText") || "选择图片"; + const cancelBtn = document.createElement("button"); + cancelBtn.type = "button"; + cancelBtn.textContent = getConfig("webScanImagePickerCancelText") || "取消"; + cancelBtn.style.cssText = "display:block;width:100%;margin-top:12px;padding:10px;border:0;background:#f0f0f0;border-radius:8px;font-size:15px;color:#666;cursor:pointer;"; + cancelBtn.onclick = event => { + event.preventDefault && event.preventDefault(); + if (activeChooseImageCancel) { + activeChooseImageCancel(); + } + }; + label.appendChild(input); + label.appendChild(labelText); + panel.appendChild(title); + panel.appendChild(label); + panel.appendChild(cancelBtn); + overlay.appendChild(panel); + document.body.appendChild(overlay); + bindChooseImageInput(input, resolve, { autoOpen: false }); + }); +} + +function chooseImageFile(options) { + options = options || {}; + if (options.mode === "auto") { + return chooseImageFileAuto(options); + } + if (options.mode === "button") { + return chooseImageFileWithButton(options); + } + if (getWebScanImagePickerMode() === "button") { + return chooseImageFileWithButton(options); + } + return chooseImageFileAuto(options); +} + +/** 业务侧已有 File/Blob 时直接识别(绕过 WebView input.files 异常) */ +export function detectImageFileForScan(file) { if (!file) { - return Promise.resolve(null); - } - if (typeof createImageBitmap !== 'undefined') { - return createImageBitmap(file).then(image => { - return detector.detect(image).then(barcodes => { - image.close && image.close(); - return barcodes && barcodes[0]; - }).catch(err => { - image.close && image.close(); - throw err; - }); - }); + return Promise.resolve({ cancel: 1 }); } + return createImageBarcodeDetector(getConfig("webScanType")).then(detector => { + return detectImageFile(detector, file); + }).then(code => { + if (code && code.rawValue) { + return { result: code.rawValue }; + } + return { + success: false, + error: "未识别到二维码或条形码" + }; + }).catch(err => { + if (err && err.cancel) { + return err; + } + return { + success: false, + error: err && err.message ? err.message : (err || "图片识别失败") + }; + }); +} + +function detectWithCanvas(detector, file) { return new Promise((resolve, reject) => { const image = new Image(); const url = URL.createObjectURL(file); + let loaded = false; + const loadTimer = setTimeout(() => { + if (loaded) { + return; + } + URL.revokeObjectURL(url); + reject(new Error("image load timeout")); + }, getWebScanDetectTimeout()); image.onload = () => { - detector.detect(image).then(barcodes => { + loaded = true; + clearTimeout(loadTimer); + try { + const canvas = document.createElement("canvas"); + let width = image.naturalWidth || image.width; + let height = image.naturalHeight || image.height; + const maxSide = 2048; + if (width > maxSide || height > maxSide) { + const scale = maxSide / Math.max(width, height); + width = Math.round(width * scale); + height = Math.round(height * scale); + } + canvas.width = Math.max(1, width); + canvas.height = Math.max(1, height); + const ctx = canvas.getContext("2d"); + if (!ctx) { + URL.revokeObjectURL(url); + reject(new Error("canvas context unavailable")); + return; + } + ctx.drawImage(image, 0, 0, canvas.width, canvas.height); + URL.revokeObjectURL(url); + detectWithTimeout(detector, canvas).then(barcodes => { + resolve(barcodes && barcodes[0]); + }).catch(reject); + } catch (e) { + URL.revokeObjectURL(url); + reject(e); + } + }; + image.onerror = err => { + clearTimeout(loadTimer); + URL.revokeObjectURL(url); + reject(err); + }; + image.src = url; + }); +} + +function detectWithImageElement(detector, file) { + return new Promise((resolve, reject) => { + const image = new Image(); + const url = URL.createObjectURL(file); + let loaded = false; + const loadTimer = setTimeout(() => { + if (loaded) { + return; + } + URL.revokeObjectURL(url); + reject(new Error("image load timeout")); + }, getWebScanDetectTimeout()); + image.onload = () => { + loaded = true; + clearTimeout(loadTimer); + detectWithTimeout(detector, image).then(barcodes => { URL.revokeObjectURL(url); resolve(barcodes && barcodes[0]); }).catch(err => { @@ -611,6 +1508,7 @@ function detectImageFile(detector, file) { }); }; image.onerror = err => { + clearTimeout(loadTimer); URL.revokeObjectURL(url); reject(err); }; @@ -618,41 +1516,110 @@ function detectImageFile(detector, file) { }); } -export function startScanForImage() { - return chooseImageFile().then(file => { - if (!file) { - return null; - } - return createBarcodeDetector(getConfig("webScanType")).then(detector => { - return detectImageFile(detector, file); +function detectWithImageBitmap(detector, file) { + const bitmapOptions = (isAndroid() || isWechatBrowser()) ? { imageOrientation: "from-image" } : undefined; + const bitmapPromise = typeof createImageBitmap === "function" + ? createImageBitmap(file, bitmapOptions) + : Promise.reject(new Error("createImageBitmap unavailable")); + return promiseWithTimeout(bitmapPromise, getWebScanDetectTimeout(), "createImageBitmap").then(image => { + return detectWithTimeout(detector, image).then(barcodes => { + image.close && image.close(); + return barcodes && barcodes[0]; + }).catch(err => { + image.close && image.close(); + throw err; }); - }).then(code => { - if (code && code.rawValue) { - return { - result: code.rawValue - }; - } - return { - success: false, - error: "未识别到二维码或条形码" - }; }); } -export function startScanForWeb(onResult) { +function detectImageFile(detector, file) { + if (!file) { + return Promise.resolve(null); + } + printDebug("detectImageFile:", file.name, file.size); + const tryCanvas = () => detectWithCanvas(detector, file); + const tryImageElement = () => detectWithImageElement(detector, file); + const tryBitmap = () => detectWithImageBitmap(detector, file); + const detectTimeout = getWebScanDetectTimeout() + 5000; + const run = chain => promiseWithTimeout(chain(), detectTimeout, "image detect"); + if (isAndroid() || isWechatBrowser() || getConfig("webScanImageDetectPreferCanvas") === true) { + return run(() => tryCanvas().catch(() => tryImageElement().catch(tryBitmap))); + } + if (typeof createImageBitmap === "function") { + return run(() => tryBitmap().catch(() => tryCanvas().catch(tryImageElement))); + } + return run(() => tryCanvas().catch(tryImageElement)); +} + +export function startScanForImage() { + return new Promise((resolve, reject) => { + let settled = false; + const finish = (type, value) => { + if (settled) { + return; + } + settled = true; + activeImageScanCancel = null; + type(value); + }; + activeImageScanCancel = () => finish(reject, { cancel: 1 }); + printDebug("startScanForImage: begin, open file picker first"); + pickImageThenDetect().then(code => { + if (settled) { + return; + } + printDebug("startScanForImage: detect done", code && code.rawValue); + if (code && code.rawValue) { + finish(resolve, { + result: code.rawValue + }); + return; + } + finish(resolve, { + success: false, + error: "未识别到二维码或条形码" + }); + }).catch(err => { + if (settled) { + return; + } + if (err && err.cancel) { + finish(resolve, err); + return; + } + printWarn("startScanForImage: failed:", err); + finish(resolve, { + success: false, + error: err && err.message ? err.message : (err || "图片识别失败") + }); + }); + }); +} + +export function startScanForWeb(onResult, onError) { let currentUuid = null; const fallbackState = { imageFallbackStarted: false }; return new Promise((resolve, reject) => { + let settled = false; + const settle = (type, value) => { + if (settled) { + return; + } + settled = true; + scanWeb.cancelSession = null; + type(value); + }; try { stopActiveWebScan(); scanWeb.uuid = createUUID(); scanWeb.finish = false; currentUuid = scanWeb.uuid; + scanWeb.cancelSession = () => settle(reject, { cancel: 1 }); let canvasStyle = getConfig("webScanCanvasStyle"); let canvasClass = getConfig("webScanCanvasClass"); let videoEl = createEl("video", "__webscan_video__", - "display: none", false); + getHiddenVideoStyle(), false); let canvasEnabled = getConfig("webScanCanvasEnabled") !== false; let canvasDisplay = ""; let useDefaultCanvasLayout = !canvasStyle && !canvasClass; @@ -700,22 +1667,34 @@ export function startScanForWeb(onResult) { videoEl.uuid = scanWeb.uuid; canvasEl.uuid = scanWeb.uuid; createBarcodeDetector(getConfig("webScanType")).then(detector => { - return getUserMediaWithTimeout({ - video: { - facingMode: "environment" + return ensureWebScanCameraPermissionBeforeAccess().then(() => { + return getUserMediaWithTimeout({ + video: { + facingMode: "environment" + } + }, getWebScanVideoAccessTimeout()).then(stream => { + webCameraSupportProbed = true; + webCameraPermissionGrantedCache = true; + printDebug("web camera access: granted"); + return { + detector, + stream + }; + }); + }).catch(err => { + if (!(err && err.cancel)) { + webCameraSupportProbed = false; + markWebCameraPermissionApiMismatch(err); + printDebug("web camera access: denied or failed", err && err.message ? err.message : err); } - }, getWebScanVideoAccessTimeout()).then(stream => { - return { - detector, - stream - }; + throw err; }); }).then(function (options) { const detector = options.detector; const stream = options.stream; if (scanWeb.uuid !== currentUuid) { stopMediaStream(stream); - reject({ cancel: 1 }); + settle(reject, { cancel: 1 }); return; } scanWeb.stream = stream; @@ -723,7 +1702,12 @@ export function startScanForWeb(onResult) { const mirrorVideo = shouldMirrorWebVideo(stream); const mirrorVideoVertical = shouldMirrorWebVideoVertical(); videoEl.srcObject = stream; - videoEl.setAttribute("playsinline", true); // iOS使用 + videoEl.setAttribute("playsinline", true); + videoEl.setAttribute("webkit-playsinline", true); + videoEl.muted = true; + if (!videoEl.isConnected) { + document.body.appendChild(videoEl); + } canvasEl.style.display = "none"; let detecting = false; let displayed = false; @@ -746,7 +1730,7 @@ export function startScanForWeb(onResult) { } closed = true; close(); - tryWebScanImageFallback(onResult, resolve, reject, fallbackState); + tryWebScanImageFallback(onResult, onError, value => settle(resolve, value), value => settle(reject, value), fallbackState); }, getWebScanVideoReadyTimeout()); }; scheduleVideoReadyTimeout(); @@ -779,7 +1763,7 @@ export function startScanForWeb(onResult) { return; } close(); - tryWebScanImageFallback(onResult, resolve, reject, fallbackState); + tryWebScanImageFallback(onResult, onError, value => settle(resolve, value), value => settle(reject, value), fallbackState); }); } if (pickImageButtonEl) { @@ -795,7 +1779,11 @@ export function startScanForWeb(onResult) { return; } detectImageFile(detector, file).then(code => { - if (!code || !code.rawValue || scanWeb.uuid !== currentUuid || closed) { + if (scanWeb.uuid !== currentUuid || closed) { + return; + } + if (!code || !code.rawValue) { + notifyImageScanError(onError, "未识别到二维码或条形码"); return; } if (!onResult || !onResult(code.rawValue)) { @@ -804,17 +1792,20 @@ export function startScanForWeb(onResult) { scanWeb.uuid = null; scanWeb.finish = true; close(); - resolve({ + settle(resolve, { result: code.rawValue }); - }).catch(() => { + }).catch(err => { + notifyImageScanError(onError, err); }); }); }; } let tick = () => { try { - if (videoEl.readyState === videoEl.HAVE_ENOUGH_DATA && !detecting) { + const minReadyState = videoEl.HAVE_CURRENT_DATA || 2; + const videoReady = videoEl.readyState >= minReadyState && videoEl.videoWidth > 0; + if (videoReady && !detecting) { clearVideoReadyTimer(); canvasEl.width = canvasDisplaySize.width; canvasEl.height = canvasDisplaySize.height; @@ -841,7 +1832,7 @@ export function startScanForWeb(onResult) { } } detecting = true; - detector.detect(videoEl).then(barcodes => { + detectWithTimeout(detector, videoEl).then(barcodes => { const code = barcodes && barcodes[0]; if (code && code.rawValue && scanWeb.uuid == currentUuid) { if (!onResult || !onResult(code.rawValue)) { @@ -851,7 +1842,7 @@ export function startScanForWeb(onResult) { scanWeb.uuid = null; scanWeb.finish = true; close(); - resolve({ + settle(resolve, { result: code.rawValue }) } @@ -868,11 +1859,11 @@ export function startScanForWeb(onResult) { tick() }); } else { - if (!scanWeb.finish) { - reject({ cancel: 1 }); + close(); + if (!scanWeb.finish && !fallbackState.imageFallbackStarted) { + settle(reject, { cancel: 1 }); scanWeb.finish = true; } - close(); } if (scanWeb.finish) { close(); @@ -882,14 +1873,16 @@ export function startScanForWeb(onResult) { tick(); }); }).catch(err => { - if (!tryWebScanImageFallback(onResult, resolve, reject, fallbackState)) { - reject({ error: err }); + if (!tryWebScanImageFallback(onResult, onError, value => settle(resolve, value), value => settle(reject, value), fallbackState)) { + settle(reject, { error: err }); } }); } catch (e) { - reject({ error: e }); + settle(reject, { error: e }); } }).finally(() => { + scanWeb.cancelSession = null; + cleanupWebScanResiduals(); removeEl("__webscan_video__", currentUuid); removeEl("__webscan_canvas__", currentUuid); removeEl(WEBSCAN_CLOSE_BUTTON_ID, currentUuid); diff --git a/types/index.d.ts b/types/index.d.ts index 560ca55..a5b6f3e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -45,6 +45,58 @@ interface ScanConfigOptions { * 2. 结束扫码的方法名称为:stopScan */ bridgeName?: string, + /** + * 桥接扫码超时(毫秒),超时后回退 Web/图片识别,默认 5000 + */ + bridgeScanTimeout?: number, + /** + * 是否允许 H5 摄像头扫码:true 强制开启(仍需有媒体 API),false 强制关闭 + */ + webScanCameraEnabled?: boolean, + /** + * @deprecated 请用 webScanCameraEnabled;保留兼容 + */ + webScanCameraInWechat?: boolean, + /** + * @deprecated 摄像头权限已后置到 startScan,请用 webScanVideoAccessTimeout + */ + webScanCameraProbeTimeout?: number, + /** + * startScan 走 Web 摄像头前是否展示权限说明弹窗,默认 true + */ + webScanCameraPermissionDialogEnabled?: boolean, + /** + * 摄像头权限说明弹窗标题 + */ + webScanCameraPermissionTitle?: string, + /** + * 摄像头权限说明弹窗正文 + */ + webScanCameraPermissionMessage?: string, + /** + * 摄像头权限说明弹窗确认按钮文案 + */ + webScanCameraPermissionConfirmText?: string, + /** + * 摄像头权限说明弹窗取消按钮文案 + */ + webScanCameraPermissionCancelText?: string, + /** + * 选图后延迟读取 file 对象(毫秒),微信/安卓 WebView 默认 100 + */ + webScanFileReadDelay?: number, + /** + * 强制使用 WASM ponyfill 识别(微信/部分 WebView 建议开启,默认微信内自动开启) + */ + webScanPreferPonyfill?: boolean, + /** + * WASM 文件完整 URL;未配置时相对 SDK 脚本地址解析 lib/reader.wasm + */ + webScanWasmUrl?: string, + /** + * WASM 基准路径(SDK 脚本 URL 或目录);用于 async/defer 加载时修正 reader.wasm 路径 + */ + webScanWasmBaseUrl?: string, /** * webScan是否启用,默认启用 */ @@ -101,6 +153,41 @@ interface ScanConfigOptions { * 摄像头已打开但长时间无画面时触发图片回退(毫秒),默认 8000 */ webScanVideoReadyTimeout?: number, + /** + * 图片/回退识别时 detect 超时(毫秒),默认 15000 + */ + webScanDetectTimeout?: number, + /** + * 图片识别是否优先使用 ZXing ponyfill(原生 detect 在部分 WebView 可能卡住),默认 true + */ + webScanImagePreferPonyfill?: boolean, + /** + * 移动端图片回退是否使用 capture 拍照(false 为相册选图,兼容性更好),默认 false + */ + webScanImagePreferCapture?: boolean, + /** + * 图片识别是否优先 canvas 解码(安卓 WebView 建议开启),默认在安卓/微信内自动开启 + */ + webScanImageDetectPreferCanvas?: boolean, + /** + * ZXing WASM 加载超时(毫秒),默认 20000 + */ + webScanPrepareTimeout?: number, + /** + * 选图等待超时(毫秒),默认 120000 + */ + webScanChooseImageTimeout?: number, + /** + * 选图方式:button=显示「选择图片」按钮(安卓/微信默认,需用户点击);auto=自动弹出系统选图 + */ + webScanImagePickerMode?: 'auto' | 'button', + webScanImagePickerTitle?: string, + webScanImagePickerButtonText?: string, + webScanImagePickerCancelText?: string, + /** + * 单次扫码会话超时(毫秒),超时后状态恢复 ready,默认 90000 + */ + scanSessionTimeout?: number, /** * 扫码成功提示音地址,默认使用内置提示音;任意识别模式匹配成功时播放 */ @@ -161,6 +248,16 @@ interface ScanResult { key: string } +/** + * 扫码错误 + */ +interface ScanErrorInfo { + error: string, + key: string, + source?: string, + cancel?: number +} + /** * 监听key */ @@ -197,6 +294,22 @@ type ScanStatus = "scanning" | "ready"; */ type ScanResultCallback = (result: ScanResult) => any; +/** + * 监听扫码错误回调 + */ +type ScanErrorCallback = (error: ScanErrorInfo) => any; + +/** + * 扫码错误监听信息 + */ +interface ScanErrorListenerInfo { + key?: string; + match?: string; + level?: number; + listener: ScanErrorCallback; + cancel: () => void; +} + /** * 监听状态回调 */ @@ -227,6 +340,19 @@ interface IScan { * @param callback 监听回调,或监听key */ offScanListener(callback: ScanResultCallback | string): void; + /** + * 添加监听扫码错误(如图片识别失败) + * @param callback 错误回调 + * @param key 监听 key + * @param match 可选正则,匹配 error 文本后回调 + * @param level 优先级 + */ + onScanErrorListener(callback: ScanErrorCallback, key: string, match?: string, level?: number): ScanErrorListenerInfo; + /** + * 取消监听扫码错误 + * @param callback 监听回调,或监听 key + */ + offScanErrorListener(callback: ScanErrorCallback | string): void; /** * 获取扫码状态 * @returns ScanStatus @@ -240,14 +366,12 @@ interface IScan { * 开启扫码 */ startScan(): void; - /** - * 开启视频扫码 - */ - scanVideo(): void; /** * 选择图片进行识别 */ scanImage(): void; + /** 由业务/原生传入已选图片 File 识别(WebView input.files 异常时使用) */ + scanImageFromFile(file: File | Blob): void; /** * 清除全部监听 */