186 lines
4.7 KiB
JavaScript
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
|
|
}; |