emblemscanner: native wasm works
This commit is contained in:
parent
431f81faad
commit
7c7c94fa7b
@ -27,7 +27,6 @@
|
||||
// Import utility functions from library
|
||||
const {
|
||||
get_system_info,
|
||||
get_phone_model,
|
||||
get_camera_rule,
|
||||
make_query,
|
||||
fetch_real_ip,
|
||||
@ -40,7 +39,6 @@ const {
|
||||
load_qrtool,
|
||||
is_qrtool_ready,
|
||||
process_frame,
|
||||
process_frame_with_debug,
|
||||
make_hint_text
|
||||
} = require('./qrprocessor.js');
|
||||
|
||||
@ -72,30 +70,28 @@ Page({
|
||||
tenant_id: '', // Tenant identifier
|
||||
debug_msgs: [],
|
||||
debug_image_data_url: '',
|
||||
debug_last_result: null,
|
||||
qrtool_ready: false,
|
||||
frame_processing_started: false,
|
||||
// Frame processing statistics
|
||||
frames_processed: 0,
|
||||
frames_skipped: 0,
|
||||
total_processing_time: 0,
|
||||
avg_processing_time: 0,
|
||||
last_frame_time: 0,
|
||||
avg_processing_time_ms: 0,
|
||||
last_frame_time_ms: 0,
|
||||
rule_zoom: -1,
|
||||
camera_rule: null,
|
||||
use_web_view: false,
|
||||
emblem_camera_url: null,
|
||||
// State machine: loading -> scanning -> verifying -> result
|
||||
app_state: 'loading', // 'loading', 'scanning_camera', 'scanning_webview', 'verifying', 'result'
|
||||
// State machine: initializing -> loading -> scanning -> verifying -> result
|
||||
app_state: 'initializing', // 'initializing', 'loading', 'scanning_camera', 'scanning_webview', 'verifying', 'result'
|
||||
scan_mode: 'unknown', // 'camera', 'webview'
|
||||
no_web_view: false // Override web-view rule, force native camera
|
||||
},
|
||||
|
||||
/**
|
||||
* Lifecycle function--Called when page load
|
||||
*/
|
||||
onLoad(options) {
|
||||
console.log('QR Scanner module loaded', options);
|
||||
|
||||
// Store query parameters
|
||||
const no_web_view = options.no_web_view === '1' || options.no_web_view === 'true';
|
||||
|
||||
this.setData({
|
||||
@ -103,54 +99,38 @@ Page({
|
||||
no_web_view: no_web_view
|
||||
});
|
||||
|
||||
// Initialize image data storage
|
||||
this.image_data_urls = [];
|
||||
|
||||
// Handle debug mode locally
|
||||
options = options || {};
|
||||
const enable_debug = options.debug || options.scene == 'debug' || false;
|
||||
|
||||
// Get system information
|
||||
this.initializeSystem(enable_debug);
|
||||
|
||||
// Initialize QRTool WASM
|
||||
this.initializeQRTool();
|
||||
|
||||
// Fetch IP address and tenant info, then load camera rules
|
||||
this.fetchRealIP();
|
||||
this.fetchTenantID();
|
||||
this.loadCameraRules();
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch real IP address
|
||||
*/
|
||||
fetchRealIP() {
|
||||
fetch_real_ip((err, ip) => {
|
||||
this.setData({ real_ip: ip });
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch tenant ID (can be customized based on app logic)
|
||||
*/
|
||||
fetchTenantID() {
|
||||
const tenant_id = get_tenant_id();
|
||||
this.setData({ tenant_id });
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize QRTool WASM module
|
||||
*/
|
||||
initializeQRTool() {
|
||||
load_qrtool();
|
||||
|
||||
// Check readiness periodically
|
||||
const checkReady = () => {
|
||||
if (is_qrtool_ready()) {
|
||||
this.setData({ qrtool_ready: true });
|
||||
this.addDebugMessage('QRTool WASM loaded and ready');
|
||||
this.startFrameProcessing();
|
||||
this.transitionToState('loading');
|
||||
this.startFrameProcessingMaybe();
|
||||
} else {
|
||||
setTimeout(checkReady, 100);
|
||||
}
|
||||
@ -158,9 +138,6 @@ Page({
|
||||
checkReady();
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize system information and device detection
|
||||
*/
|
||||
initializeSystem(enable_debug) {
|
||||
const systemInfo = get_system_info();
|
||||
const phone_model = systemInfo.model;
|
||||
@ -175,18 +152,13 @@ Page({
|
||||
console.log(`Phone model: ${phone_model}, Using native camera mode`);
|
||||
},
|
||||
|
||||
/**
|
||||
* Load camera rules from API
|
||||
*/
|
||||
loadCameraRules() {
|
||||
get_camera_rule(null, (rule) => {
|
||||
console.log('Camera rule loaded:', rule);
|
||||
|
||||
// Check for no_web_view override
|
||||
const should_use_webview = rule.web_view && !this.data.no_web_view;
|
||||
let emblem_camera_url = null;
|
||||
|
||||
// Set up web-view URL if needed
|
||||
if (should_use_webview) {
|
||||
emblem_camera_url = "https://themblem.com/camera-5.1/?" + make_query(rule.zoom, this.data.return_page, this.data.real_ip, this.data.tenant_id);
|
||||
this.addDebugMessage(`Using web-view camera: ${emblem_camera_url}`);
|
||||
@ -203,10 +175,8 @@ Page({
|
||||
emblem_camera_url: emblem_camera_url
|
||||
});
|
||||
|
||||
// Add rule info to debug messages
|
||||
this.addDebugMessage(`Camera rule: zoom=${rule.zoom}, web_view=${rule.web_view}${this.data.no_web_view ? ' (NO_WEB_VIEW)' : ''}`);
|
||||
|
||||
// Transition to appropriate scanning state
|
||||
if (should_use_webview) {
|
||||
this.startWebviewScanning();
|
||||
} else {
|
||||
@ -215,19 +185,13 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Camera ready callback
|
||||
*/
|
||||
onCameraReady(e) {
|
||||
console.log('Camera ready', e);
|
||||
this.camera_context = wx.createCameraContext();
|
||||
this.addDebugMessage('Camera initialized for WASM processing');
|
||||
// State transition is handled in loadCameraRules
|
||||
this.startFrameProcessingMaybe();
|
||||
},
|
||||
|
||||
/**
|
||||
* Camera error callback
|
||||
*/
|
||||
onCameraError(e) {
|
||||
console.error('Camera error', e);
|
||||
this.addDebugMessage(`Camera error: ${JSON.stringify(e.detail)}`);
|
||||
@ -237,11 +201,6 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Toggle torch/flash
|
||||
*/
|
||||
toggle_torch() {
|
||||
const newFlash = this.data.camera_flash === 'torch' ? 'off' : 'torch';
|
||||
this.setData({
|
||||
@ -250,9 +209,6 @@ Page({
|
||||
console.log('Torch toggled to:', newFlash);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show scan guide
|
||||
*/
|
||||
show_scanguide() {
|
||||
this.setData({
|
||||
show_modal: 'scanguide',
|
||||
@ -260,34 +216,22 @@ Page({
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show service modal
|
||||
*/
|
||||
show_service() {
|
||||
this.setData({
|
||||
show_modal: 'service'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Close modal and restart camera (legacy method name for WXML compatibility)
|
||||
*/
|
||||
restart_camera() {
|
||||
this.restartScanning();
|
||||
},
|
||||
|
||||
/**
|
||||
* Close any modal
|
||||
*/
|
||||
close_modal() {
|
||||
this.setData({
|
||||
show_modal: ''
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Debug tap handler
|
||||
*/
|
||||
debug_tap() {
|
||||
const count = (this.debug_tap_count || 0) + 1;
|
||||
this.debug_tap_count = count;
|
||||
@ -299,7 +243,6 @@ Page({
|
||||
this.debug_tap_count = 0;
|
||||
}
|
||||
|
||||
// Clear count after 3 seconds
|
||||
setTimeout(() => {
|
||||
this.debug_tap_count = 0;
|
||||
}, 3000);
|
||||
@ -331,11 +274,19 @@ Page({
|
||||
},
|
||||
|
||||
/**
|
||||
* Start frame processing - sets up camera frame listener
|
||||
* Start frame processing if both QRTool and camera are ready
|
||||
*/
|
||||
startFrameProcessing() {
|
||||
startFrameProcessingMaybe() {
|
||||
// Already started, nothing to do
|
||||
if (this.data.frame_processing_started) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if both are ready
|
||||
if (!this.data.qrtool_ready || !this.camera_context) {
|
||||
this.addDebugMessage('QRTool or camera not ready, skipping frame processing');
|
||||
const qrStatus = this.data.qrtool_ready ? 'ready' : 'not ready';
|
||||
const cameraStatus = this.camera_context ? 'ready' : 'not ready';
|
||||
this.addDebugMessage(`Cannot start frame processing - QRTool: ${qrStatus}, Camera: ${cameraStatus}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -349,6 +300,9 @@ Page({
|
||||
|
||||
// Start the listener
|
||||
this.listener.start();
|
||||
|
||||
// Mark as started
|
||||
this.setData({ frame_processing_started: true });
|
||||
},
|
||||
|
||||
/**
|
||||
@ -371,28 +325,27 @@ Page({
|
||||
this.lastFrameTime = now;
|
||||
|
||||
// Start timing frame processing
|
||||
const processStart = performance.now();
|
||||
const processStart = Date.now();
|
||||
|
||||
// Process frame data directly
|
||||
try {
|
||||
const result = this.data.enable_debug ?
|
||||
process_frame_with_debug(frame.width, frame.height, frame.data, this.data.camera_sensitivity) :
|
||||
process_frame(frame.width, frame.height, frame.data, this.data.camera_sensitivity);
|
||||
const result = process_frame(frame.width, frame.height, frame.data, this.data.camera_sensitivity, this.data.enable_debug);
|
||||
|
||||
// Calculate processing time
|
||||
const processEnd = performance.now();
|
||||
const processEnd = Date.now();
|
||||
const processingTime = processEnd - processStart;
|
||||
|
||||
// Update statistics
|
||||
const newFramesProcessed = this.data.frames_processed + 1;
|
||||
const newTotalTime = this.data.total_processing_time + processingTime;
|
||||
const newAvgTime = newTotalTime / newFramesProcessed;
|
||||
const newAvgTime = Math.round(newTotalTime / newFramesProcessed);
|
||||
|
||||
this.setData({
|
||||
frames_processed: newFramesProcessed,
|
||||
total_processing_time: newTotalTime,
|
||||
avg_processing_time: newAvgTime,
|
||||
last_frame_time: processingTime
|
||||
avg_processing_time_ms: newAvgTime,
|
||||
last_frame_time_ms: Math.round(processingTime),
|
||||
debug_last_result: result
|
||||
});
|
||||
|
||||
if (result) {
|
||||
@ -401,18 +354,19 @@ Page({
|
||||
} catch (error) {
|
||||
this.addDebugMessage(`Frame processing error: ${error.message}`);
|
||||
// Still count failed processing attempts
|
||||
const processEnd = performance.now();
|
||||
const processEnd = Date.now();
|
||||
const processingTime = processEnd - processStart;
|
||||
|
||||
const newFramesProcessed = this.data.frames_processed + 1;
|
||||
const newTotalTime = this.data.total_processing_time + processingTime;
|
||||
const newAvgTime = newTotalTime / newFramesProcessed;
|
||||
const newAvgTime = Math.round(newTotalTime / newFramesProcessed);
|
||||
|
||||
this.setData({
|
||||
frames_processed: newFramesProcessed,
|
||||
total_processing_time: newTotalTime,
|
||||
avg_processing_time: newAvgTime,
|
||||
last_frame_time: processingTime
|
||||
avg_processing_time_ms: newAvgTime,
|
||||
last_frame_time_ms: Math.round(processingTime),
|
||||
debug_last_result: null
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -507,24 +461,31 @@ Page({
|
||||
* State: Any -> Loading (restart)
|
||||
*/
|
||||
restartScanning() {
|
||||
this.transitionToState('loading');
|
||||
// Go to initializing if QRTool isn't ready, otherwise loading
|
||||
const newState = this.data.qrtool_ready ? 'loading' : 'initializing';
|
||||
this.transitionToState(newState);
|
||||
|
||||
const hintText = this.data.qrtool_ready ? '初始化相机...' : '初始化QR工具...';
|
||||
this.setData({
|
||||
show_modal: '',
|
||||
hint_text: '初始化相机...',
|
||||
hint_text: hintText,
|
||||
busy: true,
|
||||
// Reset frame processing statistics
|
||||
frames_processed: 0,
|
||||
frames_skipped: 0,
|
||||
total_processing_time: 0,
|
||||
avg_processing_time: 0,
|
||||
last_frame_time: 0
|
||||
avg_processing_time_ms: 0,
|
||||
last_frame_time_ms: 0,
|
||||
frame_processing_started: false
|
||||
});
|
||||
|
||||
// Reset frame timing
|
||||
this.lastFrameTime = 0;
|
||||
|
||||
// Reload camera rules to restart the flow
|
||||
// Reload camera rules to restart the flow (only if QRTool is ready)
|
||||
if (this.data.qrtool_ready) {
|
||||
this.loadCameraRules();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -537,7 +498,7 @@ Page({
|
||||
const debugMsg = `${timestamp}: ${message}`;
|
||||
|
||||
this.setData({
|
||||
debug_msgs: [...this.data.debug_msgs, debugMsg].slice(-10) // Keep last 10 messages
|
||||
debug_msgs: [debugMsg, ...this.data.debug_msgs].slice(0, 5) // Keep first 5 messages (newest on top)
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
<view class="wrapper">
|
||||
<!-- STATE: INITIALIZING -->
|
||||
<view wx:if="{{ app_state == 'initializing' }}" class="loading-spinner">
|
||||
<view class="spinner"></view>
|
||||
<text>初始化QR工具...</text>
|
||||
</view>
|
||||
|
||||
<!-- STATE: LOADING -->
|
||||
<view wx:if="{{ app_state == 'loading' }}" class="loading-spinner">
|
||||
<view class="spinner"></view>
|
||||
@ -31,7 +37,7 @@
|
||||
<camera class="camera"
|
||||
flash="{{ camera_flash }}"
|
||||
frame-size="medium"
|
||||
bindready="onCameraReady"
|
||||
bindinitdone="onCameraReady"
|
||||
binderror="onCameraError">
|
||||
</camera>
|
||||
</block>
|
||||
@ -46,60 +52,97 @@
|
||||
|
||||
<!-- Debug overlay (available in all states) -->
|
||||
<view class="debug" wx:if="{{ enable_debug }}">
|
||||
<view><image src="{{ debug_image_data_url }}"></image></view>
|
||||
<view class="debug-messages">
|
||||
<text wx:for="{{ debug_msgs }}" class="debug-msg">{{ item }}</text>
|
||||
</view>
|
||||
<view class="debug-top-row">
|
||||
<view class="debug-info-panel">
|
||||
<view class="debug-items">
|
||||
<!-- Application State -->
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">state:</text>
|
||||
<text class="debug-value">{{ app_state }}</text>
|
||||
</view>
|
||||
|
||||
<!-- System Info -->
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">model:</text>
|
||||
<text class="debug-value">{{ phone_model }}</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">zoom:</text>
|
||||
<text class="debug-value">{{ zoom }}/{{ max_zoom }}</text>
|
||||
</view>
|
||||
<view class="debug-item debug-flag-box" wx:if="{{ no_web_view }}">
|
||||
<text class="debug-flag">no_web_view</text>
|
||||
</view>
|
||||
|
||||
<!-- Camera Configuration -->
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">rule:</text>
|
||||
<text class="debug-value">{{ camera_rule.model || 'default' }}</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">web_view:</text>
|
||||
<text class="debug-value">{{ use_web_view }}</text>
|
||||
<text class="debug-label">zoom:</text>
|
||||
<text class="debug-value-number">{{ zoom }}/{{ max_zoom }}</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">sensitivity:</text>
|
||||
<text class="debug-value">{{ camera_sensitivity }}</text>
|
||||
<text class="debug-value-number">{{ camera_sensitivity }}</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">web_view:</text>
|
||||
<text class="debug-value">{{ use_web_view }}</text>
|
||||
</view>
|
||||
<view class="debug-item debug-flag-box" wx:if="{{ no_web_view }}">
|
||||
<text class="debug-flag">no_web_view</text>
|
||||
</view>
|
||||
|
||||
<!-- Processing Status -->
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">qrtool:</text>
|
||||
<text class="debug-value">{{ qrtool_ready ? 'ready' : 'loading' }}</text>
|
||||
</view>
|
||||
|
||||
<!-- Frame Statistics -->
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">frames:</text>
|
||||
<text class="debug-value">{{ frames_processed }}/{{ frames_processed + frames_skipped }}</text>
|
||||
<text class="debug-value-number">{{ frames_processed }}</text>
|
||||
<text class="debug-value">/</text>
|
||||
<text class="debug-value-number">{{ frames_processed + frames_skipped }}</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">skipped:</text>
|
||||
<text class="debug-value">{{ frames_skipped }}</text>
|
||||
<text class="debug-value-number">{{ frames_skipped }}</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">avg:</text>
|
||||
<text class="debug-value">{{ avg_processing_time.toFixed(2) }}ms</text>
|
||||
<text class="debug-value-number">{{ avg_processing_time_ms }}ms</text>
|
||||
</view>
|
||||
<view class="debug-item">
|
||||
<text class="debug-label">last:</text>
|
||||
<text class="debug-value">{{ last_frame_time.toFixed(2) }}ms</text>
|
||||
<text class="debug-value-number">{{ last_frame_time_ms }}ms</text>
|
||||
</view>
|
||||
|
||||
<!-- QR Detection Results -->
|
||||
<view class="debug-item" wx:if="{{ debug_last_result }}">
|
||||
<text class="debug-label">qr:</text>
|
||||
<text class="debug-value">{{ debug_last_result.qrcode || 'none' }}</text>
|
||||
</view>
|
||||
<view class="debug-item" wx:if="{{ debug_last_result }}">
|
||||
<text class="debug-label">ok:</text>
|
||||
<text class="debug-value">{{ debug_last_result.ok ? 'yes' : 'no' }}</text>
|
||||
</view>
|
||||
<view class="debug-item" wx:if="{{ debug_last_result && debug_last_result.err }}">
|
||||
<text class="debug-label">err:</text>
|
||||
<text class="debug-value">{{ debug_last_result.err }}</text>
|
||||
</view>
|
||||
|
||||
<!-- Legacy Result -->
|
||||
<view class="debug-item" wx:if="{{ result }}">
|
||||
<text class="debug-label">result:</text>
|
||||
<text class="debug-value">{{ result }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="debug-image-box">
|
||||
<image src="{{ debug_image_data_url }}"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="debug-messages">
|
||||
<text wx:for="{{ debug_msgs }}" class="debug-msg">{{ item }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Bottom action controls (only for camera scanning) -->
|
||||
<view wx:if="{{ app_state == 'scanning_camera' }}" class="bottomfixed">
|
||||
|
||||
@ -198,23 +198,37 @@ view.debug {
|
||||
background-color: rgba(100, 100, 100, 0.5);
|
||||
z-index: 1000;
|
||||
font-size: 10px;
|
||||
overflow-y: auto;
|
||||
opacity: 0.75;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
view.debug image {
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
.debug-top-row {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.debug-image-box {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debug-image-box image {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border: 1px solid rgba(239, 72, 35, 0.8);
|
||||
}
|
||||
|
||||
.debug-info-panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Debug messages section */
|
||||
.debug-messages {
|
||||
margin-bottom: 4px;
|
||||
margin-top: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debug-msg {
|
||||
@ -222,6 +236,8 @@ view.debug image {
|
||||
margin: 1px 0;
|
||||
line-height: 1.2;
|
||||
color: #ffffff;
|
||||
font-family: monospace;
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
/* Debug items container */
|
||||
@ -257,6 +273,13 @@ view.debug image {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.debug-value-number {
|
||||
color: #99ff99;
|
||||
font-family: monospace;
|
||||
min-width: 32px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Special styling for no_web_view flag box */
|
||||
.debug-item.debug-flag-box {
|
||||
border: 1px solid rgba(255, 0, 0, 0.6);
|
||||
|
||||
@ -26,91 +26,90 @@ function is_qrtool_ready() {
|
||||
/**
|
||||
* Process camera frame for QR code detection
|
||||
*/
|
||||
function process_frame(width, height, image_data, camera_sensitivity) {
|
||||
function process_frame(width, height, image_data, camera_sensitivity, enable_debug = false) {
|
||||
if (!qrtool_ready) {
|
||||
console.log("qrtool not ready");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Allocate buffer for image data
|
||||
var buf = qrtool._malloc(image_data.length * image_data.BYTES_PER_ELEMENT);
|
||||
qrtool.HEAPU8.set(image_data, buf);
|
||||
console.log('process_frame called:', {
|
||||
width,
|
||||
height,
|
||||
data_type: typeof image_data,
|
||||
data_constructor: image_data ? image_data.constructor.name : 'undefined',
|
||||
data_length: image_data ? image_data.length : 'undefined',
|
||||
data_byteLength: image_data ? image_data.byteLength : 'undefined',
|
||||
bytes_per_element: image_data ? image_data.BYTES_PER_ELEMENT : 'undefined',
|
||||
camera_sensitivity,
|
||||
enable_debug
|
||||
});
|
||||
|
||||
try {
|
||||
// Copy frame data to avoid TOCTOU
|
||||
var uca1 = new Uint8ClampedArray(image_data);
|
||||
var uca = new Uint8ClampedArray(uca1);
|
||||
|
||||
console.log('Frame data copied:', {
|
||||
uca_length: uca.length,
|
||||
uca_bytes_per_element: uca.BYTES_PER_ELEMENT
|
||||
});
|
||||
|
||||
var buf = qrtool._malloc(uca.length * uca.BYTES_PER_ELEMENT);
|
||||
qrtool.HEAPU8.set(uca, buf);
|
||||
|
||||
console.log('Buffer allocated:', {
|
||||
buffer_size: uca.length * uca.BYTES_PER_ELEMENT
|
||||
});
|
||||
|
||||
var dot_area_buf = 0;
|
||||
var debug_data_url = null;
|
||||
|
||||
if (enable_debug) {
|
||||
const dot_area_size = 32;
|
||||
const da_len = dot_area_size * dot_area_size * uca.BYTES_PER_ELEMENT * 4;
|
||||
dot_area_buf = qrtool._malloc(da_len);
|
||||
}
|
||||
|
||||
// Process QR code detection with angle
|
||||
var result_str = qrtool.ccall('qrtool_angle', 'string',
|
||||
['number', 'number', 'number', 'number', 'number'],
|
||||
[buf, width, height, 0, camera_sensitivity || 1.0]
|
||||
[buf, width, height, dot_area_buf, camera_sensitivity || 1]
|
||||
);
|
||||
|
||||
// Clean up buffer
|
||||
console.log('qrtool_angle result:', result_str);
|
||||
|
||||
if (enable_debug && dot_area_buf) {
|
||||
const dot_area_size = 32;
|
||||
const da_len = dot_area_size * dot_area_size * uca.BYTES_PER_ELEMENT * 4;
|
||||
var debug_view = qrtool.HEAPU8.subarray(dot_area_buf, dot_area_buf + da_len);
|
||||
debug_data_url = data_url_from_frame(dot_area_size, dot_area_size, debug_view);
|
||||
}
|
||||
qrtool._free(buf);
|
||||
if (dot_area_buf) {
|
||||
qrtool._free(dot_area_buf);
|
||||
}
|
||||
|
||||
// Parse result
|
||||
var result = JSON.parse(result_str);
|
||||
|
||||
return {
|
||||
var returnValue = {
|
||||
qrcode: result.qrcode || '',
|
||||
angle: result.angle || 0,
|
||||
ok: result.ok || false,
|
||||
err: result.err || '',
|
||||
valid_pattern: is_emblem_qr_pattern(result.qrcode || '')
|
||||
};
|
||||
|
||||
if (enable_debug && debug_data_url) {
|
||||
returnValue.debug_data_url = debug_data_url;
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
} catch (error) {
|
||||
console.error('QR processing error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process frame with dot area extraction (for debug visualization)
|
||||
*/
|
||||
function process_frame_with_debug(width, height, image_data, camera_sensitivity) {
|
||||
if (!qrtool_ready) {
|
||||
console.log("qrtool not ready");
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Allocate buffer for image data
|
||||
var buf = qrtool._malloc(image_data.length * image_data.BYTES_PER_ELEMENT);
|
||||
qrtool.HEAPU8.set(image_data, buf);
|
||||
|
||||
// Allocate buffer for debug dot area
|
||||
const dot_area_size = 32;
|
||||
const da_len = dot_area_size * dot_area_size * image_data.BYTES_PER_ELEMENT * 4;
|
||||
var dot_area_buf = qrtool._malloc(da_len);
|
||||
|
||||
// Process QR code detection with debug output
|
||||
var result_str = qrtool.ccall('qrtool_angle', 'string',
|
||||
['number', 'number', 'number', 'number', 'number'],
|
||||
[buf, width, height, dot_area_buf, camera_sensitivity || 1.0]
|
||||
);
|
||||
|
||||
// Extract debug image
|
||||
var debug_view = qrtool.HEAPU8.subarray(dot_area_buf, dot_area_buf + da_len);
|
||||
var debug_data_url = data_url_from_frame(dot_area_size, dot_area_size, debug_view);
|
||||
|
||||
// Clean up buffers
|
||||
qrtool._free(buf);
|
||||
qrtool._free(dot_area_buf);
|
||||
|
||||
// Parse result
|
||||
var result = JSON.parse(result_str);
|
||||
|
||||
return {
|
||||
qrcode: result.qrcode || '',
|
||||
angle: result.angle || 0,
|
||||
ok: result.ok || false,
|
||||
err: result.err || '',
|
||||
valid_pattern: is_emblem_qr_pattern(result.qrcode || ''),
|
||||
debug_data_url: debug_data_url
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('QR processing error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create offscreen canvas for debug image generation
|
||||
@ -179,7 +178,6 @@ module.exports = {
|
||||
load_qrtool,
|
||||
is_qrtool_ready,
|
||||
process_frame,
|
||||
process_frame_with_debug,
|
||||
data_url_from_frame,
|
||||
is_emblem_qr_pattern,
|
||||
make_hint_text
|
||||
|
||||
@ -34,7 +34,7 @@ var performance = {
|
||||
};
|
||||
Module["instantiateWasm"] = (info, receiveInstance) => {
|
||||
console.log("loading wasm...", info);
|
||||
WebAssembly.instantiate("assets/qrtool.wx.wasm.br", info).then(result => {
|
||||
WebAssembly.instantiate("pages/emblemscanner/assets/qrtool.wx.wasm.br", info).then(result => {
|
||||
console.log("result:", result);
|
||||
var inst = result["instance"];
|
||||
receiveInstance(inst);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user