emblemscanner: subpackage support
This commit is contained in:
parent
fffc50372e
commit
e68348fbff
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ build
|
||||
/dataset/local
|
||||
/detection/model
|
||||
/api/db.sqlite3
|
||||
/emblemscanner-release
|
||||
|
||||
8
Makefile
8
Makefile
@ -135,8 +135,8 @@ RELEASE_VERSION := $(shell git describe --tags --abbrev=0 | sed 's/^emblemscanne
|
||||
|
||||
emblemscanner-release: build/emblemscanner-$(RELEASE_VERSION).tar.gz
|
||||
|
||||
build/emblemscanner-$(RELEASE_VERSION).tar.gz:
|
||||
# if tree dirty or git head not tagged, error out
|
||||
build/emblemscanner-$(RELEASE_VERSION).tar.gz: FORCE
|
||||
- rm -rf $@
|
||||
git diff --exit-code
|
||||
if test -z "$(RELEASE_VERSION)"; then \
|
||||
echo "RELEASE_VERSION is empty"; \
|
||||
@ -146,4 +146,6 @@ build/emblemscanner-$(RELEASE_VERSION).tar.gz:
|
||||
echo "git head not tagged as $(RELEASE_VERSION)"; \
|
||||
exit 1; \
|
||||
fi
|
||||
tar -czvf build/emblemscanner-$(RELEASE_VERSION).tar.gz -C scanner pages/emblemscanner
|
||||
tar -cf build/emblemscanner-$(RELEASE_VERSION).tar -C scanner pages/emblemscanner
|
||||
cd scanner/pages/emblemscanner && tar -uf ../../../build/emblemscanner-$(RELEASE_VERSION).tar README.md
|
||||
gzip build/emblemscanner-$(RELEASE_VERSION).tar
|
||||
@ -7,7 +7,23 @@ var performance = {
|
||||
};
|
||||
Module['instantiateWasm'] = (info, receiveInstance) => {
|
||||
console.log("loading wasm...", info);
|
||||
WebAssembly.instantiate("pages/emblemscanner/qrtool.wx.wasm.br", info).then((result) => {
|
||||
|
||||
// Use dynamic path from global data if available, otherwise fallback to hardcoded path
|
||||
var wasmPath = "pages/emblemscanner/qrtool.wx.wasm.br";
|
||||
try {
|
||||
// Check if we're in a WeChat miniprogram environment and have access to getApp
|
||||
if (typeof getApp !== 'undefined') {
|
||||
var app = getApp();
|
||||
if (app && app.globalData && app.globalData.wasmFilePath) {
|
||||
wasmPath = app.globalData.wasmFilePath;
|
||||
console.log("Using dynamic WASM path:", wasmPath);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to get dynamic WASM path, using fallback:", e);
|
||||
}
|
||||
|
||||
WebAssembly.instantiate(wasmPath, info).then((result) => {
|
||||
console.log("result:", result);
|
||||
var inst = result['instance'];
|
||||
receiveInstance(inst);
|
||||
|
||||
104
scanner/pages/emblemscanner/README.md
Normal file
104
scanner/pages/emblemscanner/README.md
Normal file
@ -0,0 +1,104 @@
|
||||
|
||||
# EmblemScanner 微信小程序扫码验证模块
|
||||
|
||||
## Release notes
|
||||
- Version 1.0.1: initial release
|
||||
- Version 1.1.0: sub package support
|
||||
|
||||
|
||||
## 概述
|
||||
|
||||
EmblemScanner 是一个专为微信小程序设计的二维码扫描验证模块,集成了先进的 AI 图像识别技术和二维码检测算法,能够快速准确地识别和验证二维码。
|
||||
|
||||
## 集成方式和接口
|
||||
|
||||
### 调用参数
|
||||
|
||||
| 参数 | 说明 | 示例值 |
|
||||
|------|------|--------|
|
||||
| return_page | 扫描完成后跳转的页面路径 | `/pages/scan_result/scan_result` |
|
||||
|
||||
### 扫描结果
|
||||
|
||||
扫描成功后,模块会跳转到指定的 return_page,携带以下参数:
|
||||
- `ok=1` - 扫描成功
|
||||
- `qr_code` - 二维码内容
|
||||
- `serial_code` - 验证序列号(如有)
|
||||
|
||||
扫描失败时:
|
||||
- `ok=0` - 扫描失败
|
||||
|
||||
### 依赖要求
|
||||
|
||||
- 相机权限
|
||||
- 网络访问权限(连接 themblem.com API等)
|
||||
|
||||
## 使用步骤
|
||||
|
||||
### 1. 项目准备
|
||||
创建 JS 版小程序项目。
|
||||
|
||||
### 2. 文件部署
|
||||
解压 emblemscanner 代码到小程序项目目录。
|
||||
|
||||
```
|
||||
pages/emblemscanner/
|
||||
├── assets/ # 静态资源
|
||||
├── emblemscanner.json # 页面配置
|
||||
├── emblemscanner.wxml # 页面结构
|
||||
├── emblemscanner.wxss # 样式文件
|
||||
├── emblemscanner.js # 主页面逻辑
|
||||
├── libemblemscanner.js # 核心库
|
||||
├── qrprocessor.js # 二维码处理器
|
||||
├── qrtool.wx.js # 二维码工具
|
||||
├── qrtool.wx.wasm.br # WebAssembly 二进制
|
||||
├── upload.js # 上传模块
|
||||
└── worker/ # Worker 线程
|
||||
```
|
||||
|
||||
### 3. 项目配置
|
||||
|
||||
在 `app.json` 中添加页面和 worker 配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [
|
||||
"pages/index/index",
|
||||
"pages/emblemscanner/emblemscanner",
|
||||
"pages/logs/logs"
|
||||
],
|
||||
"workers": "pages/emblemscanner/worker"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 域名配置
|
||||
|
||||
参考[微信小程序网络配置指南](https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html),在小程序后台配置合法域名:
|
||||
|
||||
- `themblem.com`
|
||||
|
||||
### 5. 扫码调用
|
||||
|
||||
#### 跳转到扫码页面:
|
||||
```javascript
|
||||
navigateToScanner() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/emblemscanner/emblemscanner?return_page=/pages/scan_result/scan_result'
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### 处理扫码结果:
|
||||
```javascript
|
||||
onLoad(options) {
|
||||
var verify_ok = options['ok']; // ok == 1表示验证通过
|
||||
var qr_code = options['qr_code']; // 二维码内容
|
||||
var serial_code = options['serial_code']; // 序列码
|
||||
|
||||
this.setData({
|
||||
verify_ok,
|
||||
qr_code,
|
||||
serial_code,
|
||||
})
|
||||
}
|
||||
```
|
||||
@ -1,6 +1,12 @@
|
||||
// QR Scanner Module - Self-contained QR scanning page
|
||||
// Adapted from existing camera implementation
|
||||
//
|
||||
// DYNAMIC PATH RESOLUTION:
|
||||
// - The system now dynamically computes the correct WASM file and worker paths based on the current page location
|
||||
// - This allows the emblemscanner to work in both main pages directory and subpackages
|
||||
// - Paths are computed using getCurrentPages() API and stored in global data during page load
|
||||
// - WASM files and workers use these dynamic paths instead of hardcoded absolute paths
|
||||
//
|
||||
// SCANNING MODES:
|
||||
// 1. Web View Mode - Uses external camera-5.1 web interface in web-view component
|
||||
// - Fallback for devices that need special handling
|
||||
@ -31,7 +37,9 @@ const {
|
||||
make_query,
|
||||
fetch_real_ip,
|
||||
get_tenant_id,
|
||||
is_emblem_qr_pattern
|
||||
is_emblem_qr_pattern,
|
||||
get_current_package_path,
|
||||
get_wasm_file_path
|
||||
} = require('./libemblemscanner.js');
|
||||
|
||||
// Import upload functionality for verification (self-contained)
|
||||
@ -115,6 +123,13 @@ Page({
|
||||
no_web_view: no_web_view
|
||||
});
|
||||
|
||||
// Store current package path in global data for dynamic WASM loading
|
||||
const currentPackagePath = get_current_package_path();
|
||||
getApp().globalData.currentPackagePath = currentPackagePath;
|
||||
getApp().globalData.wasmFilePath = get_wasm_file_path('qrtool.wx.wasm.br');
|
||||
console.log('Current package path:', currentPackagePath);
|
||||
console.log('WASM file path:', getApp().globalData.wasmFilePath);
|
||||
|
||||
// Log page load for backend reporting (like camera.js)
|
||||
this.log("emblemscanner page load");
|
||||
this.log("options", JSON.stringify(options));
|
||||
@ -189,8 +204,12 @@ Page({
|
||||
* Set up worker for iPhone processing like camera.js
|
||||
*/
|
||||
setupWorker() {
|
||||
// Create worker with local worker file
|
||||
var worker = wx.createWorker('/pages/emblemscanner/worker/index.js', {
|
||||
// Create worker with dynamic path based on current package location
|
||||
var packagePath = getApp().globalData.currentPackagePath || 'pages/emblemscanner';
|
||||
var workerPath = `${packagePath}/worker/index.js`;
|
||||
console.log('Creating worker with path:', workerPath);
|
||||
|
||||
var worker = wx.createWorker(workerPath, {
|
||||
useExperimentalWorker: true,
|
||||
});
|
||||
|
||||
@ -240,7 +259,10 @@ Page({
|
||||
|
||||
if (this.data.app_state === 'final_scanning' && result.ok) {
|
||||
// Request worker to submit image data
|
||||
this.get_worker().postMessage({ type: "ready_to_submit" });
|
||||
const worker = this.get_worker();
|
||||
if (worker) {
|
||||
worker.postMessage({ type: "ready_to_submit" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,7 +383,6 @@ Page({
|
||||
|
||||
|
||||
show_scanguide() {
|
||||
console.log('show_scanguide');
|
||||
this.setData({
|
||||
show_modal: 'scanguide',
|
||||
show_tip: false
|
||||
@ -420,12 +441,12 @@ Page({
|
||||
});
|
||||
|
||||
this.log(`Camera set initial zoom to ${initial_zoom}x, will zoom in to ${zoom}x when QR is found`);
|
||||
this.camera_context.setZoom({ zoom: 6 });
|
||||
this.camera_context.setZoom({ zoom: initial_zoom });
|
||||
|
||||
// Set up zoom-in behavior when QR is found
|
||||
this.on_first_qr_found = () => {
|
||||
this.log(`First QR found, zoom to ${zoom}x`);
|
||||
this.camera_context.setZoom({ zoom: 6 });
|
||||
this.camera_context.setZoom({ zoom: zoom });
|
||||
this.setData({
|
||||
zoom: zoom,
|
||||
qrmarkers_class: '',
|
||||
@ -479,7 +500,7 @@ Page({
|
||||
});
|
||||
|
||||
// Start the listener with worker if using worker mode
|
||||
var worker = this.get_worker();
|
||||
var worker = this.data.use_worker ? this.get_worker() : null;
|
||||
this.listener.start({
|
||||
worker,
|
||||
});
|
||||
@ -531,12 +552,15 @@ Page({
|
||||
// Set processing flag before sending message
|
||||
this.setData({ worker_processing: true });
|
||||
|
||||
this.get_worker().postMessage({
|
||||
type: 'frame',
|
||||
width: frame.width,
|
||||
height: frame.height,
|
||||
camera_sensitivity: this.data.camera_sensitivity
|
||||
});
|
||||
const worker = this.get_worker();
|
||||
if (worker) {
|
||||
worker.postMessage({
|
||||
type: 'frame',
|
||||
width: frame.width,
|
||||
height: frame.height,
|
||||
camera_sensitivity: this.data.camera_sensitivity
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Direct processing (other devices)
|
||||
this.processFrameDirect(frame);
|
||||
@ -698,7 +722,6 @@ Page({
|
||||
submitImageForVerification(dataUrls, qrCode) {
|
||||
this.log('Submitting images for verification');
|
||||
const begin = Date.now();
|
||||
wx.vibrateShort({ type: "heavy" });
|
||||
|
||||
const success = (res) => {
|
||||
this.log(`Upload success, code: ${res.statusCode}`);
|
||||
@ -1029,6 +1052,7 @@ Page({
|
||||
*/
|
||||
onUnload() {
|
||||
this.cleanupListener();
|
||||
this.terminateWorker();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1053,11 +1077,10 @@ Page({
|
||||
},
|
||||
|
||||
get_worker() {
|
||||
var gd = getApp().globalData;
|
||||
if (!gd.emblemscanner_worker) {
|
||||
gd.emblemscanner_worker = this.setupWorker();
|
||||
if (!this.worker && this.data.use_worker) {
|
||||
this.worker = this.setupWorker();
|
||||
}
|
||||
return gd.emblemscanner_worker;
|
||||
return this.worker;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1075,6 +1098,17 @@ Page({
|
||||
|
||||
this.log('Worker state cleaned up');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Terminate and clean up worker on page unload
|
||||
*/
|
||||
terminateWorker() {
|
||||
if (this.worker) {
|
||||
this.worker.terminate();
|
||||
this.worker = null;
|
||||
this.log('Worker terminated');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@ -1,3 +1,13 @@
|
||||
|
||||
page {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display:none;
|
||||
}
|
||||
|
||||
/* Main container */
|
||||
view.wrapper {
|
||||
width: 100%;
|
||||
|
||||
@ -131,6 +131,83 @@ function is_emblem_qr_pattern(p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current package path for dynamic WASM file loading
|
||||
* This function determines the correct path to WASM files based on the current page location
|
||||
*/
|
||||
function get_current_package_path() {
|
||||
try {
|
||||
// Get current pages stack to determine current page location
|
||||
const pages = getCurrentPages();
|
||||
if (pages && pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1];
|
||||
const route = currentPage.route;
|
||||
|
||||
// Extract package path from route
|
||||
// For example: "bofen/packages/emblemscanner/emblemscanner" -> "bofen/packages/emblemscanner"
|
||||
const pathParts = route.split('/');
|
||||
if (pathParts.length >= 2) {
|
||||
// Remove the page file name and return the package path
|
||||
return pathParts.slice(0, -1).join('/');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to get current package path:', e);
|
||||
}
|
||||
|
||||
// Fallback: assume we're in the main pages directory
|
||||
return 'pages/emblemscanner';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full WASM file path based on current package location
|
||||
*/
|
||||
function get_wasm_file_path(filename) {
|
||||
const packagePath = get_current_package_path();
|
||||
return `${packagePath}/${filename}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test function to verify path resolution works correctly
|
||||
* This can be called in development to test the path resolution logic
|
||||
*/
|
||||
function test_path_resolution() {
|
||||
console.log('Testing path resolution...');
|
||||
|
||||
// Mock getCurrentPages for testing (would normally be available in WeChat miniprogram)
|
||||
const originalGetCurrentPages = global.getCurrentPages;
|
||||
global.getCurrentPages = function() {
|
||||
return [{
|
||||
route: 'bofen/packages/emblemscanner/emblemscanner'
|
||||
}];
|
||||
};
|
||||
|
||||
try {
|
||||
const packagePath = get_current_package_path();
|
||||
const wasmPath = get_wasm_file_path('qrtool.wx.wasm.br');
|
||||
|
||||
console.log('Expected package path: bofen/packages/emblemscanner');
|
||||
console.log('Actual package path:', packagePath);
|
||||
console.log('Expected WASM path: bofen/packages/emblemscanner/qrtool.wx.wasm.br');
|
||||
console.log('Actual WASM path:', wasmPath);
|
||||
|
||||
if (packagePath === 'bofen/packages/emblemscanner' && wasmPath === 'bofen/packages/emblemscanner/qrtool.wx.wasm.br') {
|
||||
console.log('✅ Path resolution test PASSED');
|
||||
return true;
|
||||
} else {
|
||||
console.log('❌ Path resolution test FAILED');
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
// Restore original function
|
||||
if (originalGetCurrentPages) {
|
||||
global.getCurrentPages = originalGetCurrentPages;
|
||||
} else {
|
||||
delete global.getCurrentPages;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get_system_info,
|
||||
get_phone_model,
|
||||
@ -138,5 +215,8 @@ module.exports = {
|
||||
make_query,
|
||||
fetch_real_ip,
|
||||
get_tenant_id,
|
||||
is_emblem_qr_pattern
|
||||
is_emblem_qr_pattern,
|
||||
get_current_package_path,
|
||||
get_wasm_file_path,
|
||||
test_path_resolution
|
||||
};
|
||||
|
||||
@ -34,7 +34,21 @@ var performance = {
|
||||
};
|
||||
Module["instantiateWasm"] = (info, receiveInstance) => {
|
||||
console.log("loading wasm...", info);
|
||||
WebAssembly.instantiate("pages/emblemscanner/qrtool.wx.wasm.br", info).then(result => {
|
||||
// Use dynamic path from global data if available, otherwise fallback to hardcoded path
|
||||
var wasmPath = "pages/emblemscanner/qrtool.wx.wasm.br";
|
||||
try {
|
||||
// Check if we're in a WeChat miniprogram environment and have access to getApp
|
||||
if (typeof getApp !== "undefined") {
|
||||
var app = getApp();
|
||||
if (app && app.globalData && app.globalData.wasmFilePath) {
|
||||
wasmPath = app.globalData.wasmFilePath;
|
||||
console.log("Using dynamic WASM path:", wasmPath);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to get dynamic WASM path, using fallback:", e);
|
||||
}
|
||||
WebAssembly.instantiate(wasmPath, info).then(result => {
|
||||
console.log("result:", result);
|
||||
var inst = result["instance"];
|
||||
receiveInstance(inst);
|
||||
|
||||
@ -34,7 +34,21 @@ var performance = {
|
||||
};
|
||||
Module["instantiateWasm"] = (info, receiveInstance) => {
|
||||
console.log("loading wasm...", info);
|
||||
WebAssembly.instantiate("pages/emblemscanner/qrtool.wx.wasm.br", info).then(result => {
|
||||
// Use dynamic path from global data if available, otherwise fallback to hardcoded path
|
||||
var wasmPath = "pages/emblemscanner/qrtool.wx.wasm.br";
|
||||
try {
|
||||
// Check if we're in a WeChat miniprogram environment and have access to getApp
|
||||
if (typeof getApp !== "undefined") {
|
||||
var app = getApp();
|
||||
if (app && app.globalData && app.globalData.wasmFilePath) {
|
||||
wasmPath = app.globalData.wasmFilePath;
|
||||
console.log("Using dynamic WASM path:", wasmPath);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to get dynamic WASM path, using fallback:", e);
|
||||
}
|
||||
WebAssembly.instantiate(wasmPath, info).then(result => {
|
||||
console.log("result:", result);
|
||||
var inst = result["instance"];
|
||||
receiveInstance(inst);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user