2025-10-29 21:27:29 +00:00

186 lines
4.7 KiB
JavaScript

// QR Processing Module for EmblemScanner
// Self-contained WASM-based QR code processing
var qrtool = null;
var qrtool_ready = false;
/**
* Load qrtool WASM module
*/
function load_qrtool() {
var m = require('./qrtool.wx.js');
m.onRuntimeInitialized = () => {
console.log("QRTool runtime initialized");
qrtool_ready = true;
qrtool = m;
}
}
/**
* Check if qrtool is ready for processing
*/
function is_qrtool_ready() {
return qrtool_ready;
}
/**
* Process camera frame for QR code detection
*/
function process_frame(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);
// 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]
);
// Clean up buffer
qrtool._free(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 || '')
};
} 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
*/
const offscreenCanvas = wx.createOffscreenCanvas({
type: '2d',
width: 100,
height: 100,
});
/**
* Convert raw frame data to data URL for debug visualization
*/
function data_url_from_frame(width, height, image_data) {
offscreenCanvas.width = width;
offscreenCanvas.height = height;
var ctx = offscreenCanvas.getContext('2d');
var imgd = ctx.createImageData(width, height);
imgd.data.set(image_data);
ctx.putImageData(imgd, 0, 0);
return offscreenCanvas.toDataURL("image/jpeg", 1.0);
}
/**
* Check if QR code matches Emblem pattern
*/
function is_emblem_qr_pattern(p) {
if (!p) return false;
if (p.search(/code=[0-9a-zA-Z]+/) >= 0) return true;
if (p.search(/id=[0-9a-zA-Z]+/) >= 0) return true;
if (p.search(/c=[0-9a-zA-Z]+/) >= 0) return true;
if (p.search(/https:\/\/xy\.ltd\/v\/[0-9a-zA-Z]+/) >= 0) return true;
return false;
}
/**
* Generate hint text based on QR processing result
*/
function make_hint_text(result) {
if (!result) {
return "查找二维码";
}
if (result.qrcode && result.qrcode.length > 0) {
if (!result.valid_pattern) {
return "无效编码";
}
if (result.ok) {
return "识别成功";
}
// Check specific error conditions
var err = result.err || "";
if (err.includes("margin too small")) {
return "对齐定位点";
} else if (err.includes("energy check failed") || err.includes("cannot detect angle")) {
return "移近一点";
}
}
return "对齐定位点";
}
module.exports = {
load_qrtool,
is_qrtool_ready,
process_frame,
process_frame_with_debug,
data_url_from_frame,
is_emblem_qr_pattern,
make_hint_text
};