emblemscanner: native upload works
This commit is contained in:
parent
55d2ccb8fc
commit
4b10ad335a
@ -40,16 +40,15 @@ const {
|
|||||||
} = require('./upload.js');
|
} = require('./upload.js');
|
||||||
|
|
||||||
// Import precheck utilities for image processing
|
// Import precheck utilities for image processing
|
||||||
const {
|
// Note: We now use our own data_url_from_frame from qrprocessor.js
|
||||||
data_url_from_frame
|
|
||||||
} = require('../../precheck.js');
|
|
||||||
|
|
||||||
// Import QR processing module
|
// Import QR processing module
|
||||||
const {
|
const {
|
||||||
load_qrtool,
|
load_qrtool,
|
||||||
is_qrtool_ready,
|
is_qrtool_ready,
|
||||||
process_frame,
|
process_frame,
|
||||||
make_hint_text
|
make_hint_text,
|
||||||
|
data_url_from_frame
|
||||||
} = require('./qrprocessor.js');
|
} = require('./qrprocessor.js');
|
||||||
|
|
||||||
Page({
|
Page({
|
||||||
@ -74,17 +73,19 @@ Page({
|
|||||||
qrarc_class: 'sm',
|
qrarc_class: 'sm',
|
||||||
qrmarkers_class: 'hidden',
|
qrmarkers_class: 'hidden',
|
||||||
frame_upload_interval_ms: 2000,
|
frame_upload_interval_ms: 2000,
|
||||||
return_page: '', // Page to navigate to after successful scan
|
return_page: '/pages/test_result_page/test_result_page', // Page to navigate to after successful scan
|
||||||
server_url: 'https://themblem.com', // Default server URL
|
server_url: 'https://themblem.com', // Default server URL
|
||||||
real_ip: '', // User's real IP address
|
real_ip: '', // User's real IP address
|
||||||
tenant_id: '', // Tenant identifier
|
tenant_id: '', // Tenant identifier
|
||||||
debug_msgs: [],
|
debug_msgs: [],
|
||||||
debug_image_data_url: '',
|
debug_image_data_url: '',
|
||||||
debug_last_result: null,
|
debug_last_result: null,
|
||||||
|
debug_current_frame_url: '', // Current frame being processed
|
||||||
qrtool_ready: false,
|
qrtool_ready: false,
|
||||||
// Frame processing statistics
|
// Frame processing statistics
|
||||||
frames_processed: 0,
|
frames_processed: 0,
|
||||||
frames_skipped: 0,
|
frames_skipped: 0,
|
||||||
|
ok_frames: 0,
|
||||||
total_processing_time: 0,
|
total_processing_time: 0,
|
||||||
avg_processing_time_ms: 0,
|
avg_processing_time_ms: 0,
|
||||||
last_frame_time_ms: 0,
|
last_frame_time_ms: 0,
|
||||||
@ -93,6 +94,7 @@ Page({
|
|||||||
use_web_view: false,
|
use_web_view: false,
|
||||||
use_worker: false,
|
use_worker: false,
|
||||||
emblem_camera_url: null,
|
emblem_camera_url: null,
|
||||||
|
first_qr_found: false, // Track if first QR has been detected to trigger zoom-in
|
||||||
// State machine: loading_rules -> loading_qrtool -> init_camera -> scanning -> verifying -> result
|
// State machine: loading_rules -> loading_qrtool -> init_camera -> scanning -> verifying -> result
|
||||||
app_state: 'loading_rules', // 'loading_rules', 'loading_qrtool', 'init_camera', 'scanning', 'webview_scanning', 'verifying', 'result'
|
app_state: 'loading_rules', // 'loading_rules', 'loading_qrtool', 'init_camera', 'scanning', 'webview_scanning', 'verifying', 'result'
|
||||||
scan_mode: 'unknown', // 'camera', 'webview'
|
scan_mode: 'unknown', // 'camera', 'webview'
|
||||||
@ -105,7 +107,7 @@ Page({
|
|||||||
const no_web_view = options.no_web_view === '1' || options.no_web_view === 'true';
|
const no_web_view = options.no_web_view === '1' || options.no_web_view === 'true';
|
||||||
|
|
||||||
this.setData({
|
this.setData({
|
||||||
return_page: options.return_page || '',
|
return_page: options.return_page || '/pages/test_result_page/test_result_page',
|
||||||
no_web_view: no_web_view
|
no_web_view: no_web_view
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -202,17 +204,18 @@ Page({
|
|||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
// For worker, we need to trigger image collection when we find a good QR
|
// For worker, we need to trigger image collection when we find a good QR
|
||||||
if (result.ok && result.qrcode && result.valid_pattern && is_emblem_qr_pattern(result.qrcode)) {
|
if (result.qrcode && result.valid_pattern && is_emblem_qr_pattern(result.qrcode)) {
|
||||||
this.addDebugMessage(`Worker QR detected: ${result.qrcode}`);
|
this.addDebugMessage(`Worker QR detected: ${result.qrcode}`);
|
||||||
|
|
||||||
// Trigger zoom-in if function is set up
|
// Trigger zoom-in if function is set up
|
||||||
if (this.on_qr_found && !this.data.qr_found) {
|
if (this.on_first_qr_found && !this.data.first_qr_found) {
|
||||||
this.on_qr_found();
|
this.on_first_qr_found();
|
||||||
this.setData({ qr_found: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request worker to submit image data
|
if (result.ok) {
|
||||||
this.worker.postMessage({ type: "ready_to_submit" });
|
// Request worker to submit image data
|
||||||
|
this.worker.postMessage({ type: "ready_to_submit" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.handleQRResult(result, this.lastWorkerFrame);
|
this.handleQRResult(result, this.lastWorkerFrame);
|
||||||
@ -222,14 +225,20 @@ Page({
|
|||||||
const result = msg.res;
|
const result = msg.res;
|
||||||
const imageData = msg.image_data;
|
const imageData = msg.image_data;
|
||||||
if (imageData) {
|
if (imageData) {
|
||||||
const dataUrl = data_url_from_frame(imageData.width, imageData.height, new Uint8ClampedArray(imageData.data));
|
// Worker now sends data URL directly, no need to convert
|
||||||
this.image_data_urls.push(dataUrl);
|
this.image_data_urls.push(imageData.data);
|
||||||
|
|
||||||
|
// Update ok frames counter
|
||||||
|
this.setData({
|
||||||
|
ok_frames: this.image_data_urls.length
|
||||||
|
});
|
||||||
|
|
||||||
if (this.image_data_urls.length >= 3) {
|
if (this.image_data_urls.length >= 3) {
|
||||||
this.addDebugMessage('3 good images collected via worker, starting verification');
|
this.addDebugMessage('3 good images collected via worker, starting verification');
|
||||||
this.startVerifying();
|
this.startVerifying();
|
||||||
this.submitImageForVerification(this.image_data_urls, result.qrcode);
|
this.submitImageForVerification(this.image_data_urls, result.qrcode);
|
||||||
this.image_data_urls = []; // Reset for next scan
|
this.image_data_urls = []; // Reset for next scan
|
||||||
|
this.setData({ ok_frames: 0 }); // Reset counter
|
||||||
} else {
|
} else {
|
||||||
this.addDebugMessage(`Collected ${this.image_data_urls.length}/3 worker images`);
|
this.addDebugMessage(`Collected ${this.image_data_urls.length}/3 worker images`);
|
||||||
}
|
}
|
||||||
@ -382,8 +391,9 @@ Page({
|
|||||||
this.camera_context.setZoom({ zoom: initial_zoom });
|
this.camera_context.setZoom({ zoom: initial_zoom });
|
||||||
|
|
||||||
// Set up zoom-in behavior when QR is found
|
// Set up zoom-in behavior when QR is found
|
||||||
this.on_qr_found = () => {
|
this.on_first_qr_found = () => {
|
||||||
this.addDebugMessage(`QR found, zoom to ${zoom}x`);
|
this.setData({ first_qr_found: true });
|
||||||
|
this.addDebugMessage(`First QR found, zoom to ${zoom}x`);
|
||||||
this.camera_context.setZoom({ zoom: zoom });
|
this.camera_context.setZoom({ zoom: zoom });
|
||||||
this.setData({
|
this.setData({
|
||||||
zoom: zoom,
|
zoom: zoom,
|
||||||
@ -465,10 +475,22 @@ Page({
|
|||||||
if (this.data.use_worker && this.worker) {
|
if (this.data.use_worker && this.worker) {
|
||||||
// Worker processing (iPhone)
|
// Worker processing (iPhone)
|
||||||
this.lastWorkerFrame = frame; // Store for handleQRResult
|
this.lastWorkerFrame = frame; // Store for handleQRResult
|
||||||
|
|
||||||
|
// Copy frame data to avoid TOCTOU race condition (like camera.js)
|
||||||
|
var uca1 = new Uint8ClampedArray(frame.data);
|
||||||
|
var uca = new Uint8ClampedArray(uca1);
|
||||||
|
|
||||||
|
// Generate debug frame data URL if debug is enabled
|
||||||
|
if (this.data.enable_debug) {
|
||||||
|
const frameDataUrl = data_url_from_frame(frame.width, frame.height, uca);
|
||||||
|
this.updateDebugFrameUrls(frameDataUrl);
|
||||||
|
}
|
||||||
|
|
||||||
this.worker.postMessage({
|
this.worker.postMessage({
|
||||||
type: 'frame',
|
type: 'frame',
|
||||||
width: frame.width,
|
width: frame.width,
|
||||||
height: frame.height,
|
height: frame.height,
|
||||||
|
data: uca, // Pass actual frame data
|
||||||
camera_sensitivity: this.data.camera_sensitivity
|
camera_sensitivity: this.data.camera_sensitivity
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -484,7 +506,17 @@ Page({
|
|||||||
const processStart = Date.now();
|
const processStart = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = process_frame(frame.width, frame.height, frame.data, this.data.camera_sensitivity, this.data.enable_debug);
|
// Copy frame data to avoid TOCTOU race condition (like camera.js)
|
||||||
|
var uca1 = new Uint8ClampedArray(frame.data);
|
||||||
|
var uca = new Uint8ClampedArray(uca1);
|
||||||
|
|
||||||
|
// Generate debug frame data URL if debug is enabled
|
||||||
|
if (this.data.enable_debug) {
|
||||||
|
const frameDataUrl = data_url_from_frame(frame.width, frame.height, uca);
|
||||||
|
this.updateDebugFrameUrls(frameDataUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = process_frame(frame.width, frame.height, uca, this.data.camera_sensitivity, this.data.enable_debug);
|
||||||
|
|
||||||
// Calculate processing time
|
// Calculate processing time
|
||||||
const processEnd = Date.now();
|
const processEnd = Date.now();
|
||||||
@ -504,7 +536,7 @@ Page({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
this.handleQRResult(result, frame);
|
this.handleQRResult(result, frame, uca);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.addDebugMessage(`Frame processing error: ${error.message}`);
|
this.addDebugMessage(`Frame processing error: ${error.message}`);
|
||||||
@ -529,7 +561,7 @@ Page({
|
|||||||
/**
|
/**
|
||||||
* Handle QR processing result
|
* Handle QR processing result
|
||||||
*/
|
*/
|
||||||
handleQRResult(result, frame) {
|
handleQRResult(result, frame, copiedFrameData = null) {
|
||||||
// Update debug info if available
|
// Update debug info if available
|
||||||
if (result.debug_data_url) {
|
if (result.debug_data_url) {
|
||||||
this.setData({
|
this.setData({
|
||||||
@ -543,18 +575,17 @@ Page({
|
|||||||
// Check if we have a valid QR code that's ready for upload (like camera.js)
|
// Check if we have a valid QR code that's ready for upload (like camera.js)
|
||||||
// don't require ok as we only care about the view has a valid qrcode in it
|
// don't require ok as we only care about the view has a valid qrcode in it
|
||||||
// zooming in so that it's more likely to be clear enough for upload
|
// zooming in so that it's more likely to be clear enough for upload
|
||||||
if (!this.data.qr_found && result.qrcode && result.valid_pattern && is_emblem_qr_pattern(result.qrcode)) {
|
if (result.qrcode && result.valid_pattern && is_emblem_qr_pattern(result.qrcode)) {
|
||||||
this.addDebugMessage(`QR detected and ready: ${result.qrcode}`);
|
this.addDebugMessage(`QR detected and ready: ${result.qrcode}`);
|
||||||
|
|
||||||
// Trigger zoom-in if function is set up
|
// Trigger zoom-in if function is set up
|
||||||
if (this.on_qr_found) {
|
if (!this.data.first_qr_found && this.on_first_qr_found) {
|
||||||
this.on_qr_found();
|
this.on_first_qr_found();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onQRCodeDetected(result.qrcode, frame);
|
if (result.ok) {
|
||||||
this.setData({
|
this.onQRCodeDetected(result.qrcode, frame, copiedFrameData); // Pass the copied frame data
|
||||||
qr_found: true
|
}
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Update hint for user guidance
|
// Update hint for user guidance
|
||||||
this.setData({ hint_text: hint });
|
this.setData({ hint_text: hint });
|
||||||
@ -566,23 +597,38 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle successful QR code detection - collect images from "ok" frames and verify
|
* Handle successful QR code detection - collect images from "ok" frames and verify (non-worker case)
|
||||||
*/
|
*/
|
||||||
onQRCodeDetected(qrCode, frameData) {
|
onQRCodeDetected(qrCode, frameData, copiedFrameData = null) {
|
||||||
// Convert frame data to data URL for upload (only called for "ok" frames)
|
// Only collect images for non-worker case (worker handles its own image collection)
|
||||||
if (frameData) {
|
if (!this.data.use_worker && frameData && copiedFrameData) {
|
||||||
const dataUrl = data_url_from_frame(frameData.width, frameData.height, frameData.data);
|
// Convert frame data to data URL for upload (only called for "ok" frames)
|
||||||
|
// Use the copied frame data instead of original frameData.data to avoid corruption
|
||||||
|
const dataUrl = data_url_from_frame(frameData.width, frameData.height, copiedFrameData);
|
||||||
this.image_data_urls.push(dataUrl);
|
this.image_data_urls.push(dataUrl);
|
||||||
this.addDebugMessage(`Collected ${this.image_data_urls.length}/3 good images`);
|
|
||||||
}
|
// Update ok frames counter
|
||||||
|
this.setData({
|
||||||
// Need 3 "ok" frames before verification (like camera.js)
|
ok_frames: this.image_data_urls.length
|
||||||
if (this.image_data_urls.length >= 3) {
|
});
|
||||||
this.addDebugMessage('3 good images collected, starting verification');
|
|
||||||
this.startVerifying();
|
this.addDebugMessage(`Collected ${this.image_data_urls.length}/3 good images (direct) - using copied data`);
|
||||||
this.submitImageForVerification(this.image_data_urls, qrCode);
|
|
||||||
this.image_data_urls = []; // Reset for next scan
|
// Add debug info about the submitted image
|
||||||
|
if (this.data.enable_debug) {
|
||||||
|
this.addDebugMessage(`Submitted image preview: ${dataUrl.substring(0, 50)}...`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need 3 "ok" frames before verification (like camera.js)
|
||||||
|
if (this.image_data_urls.length >= 3) {
|
||||||
|
this.addDebugMessage('3 good images collected, starting verification');
|
||||||
|
this.startVerifying();
|
||||||
|
this.submitImageForVerification(this.image_data_urls, qrCode);
|
||||||
|
this.image_data_urls = []; // Reset for next scan
|
||||||
|
this.setData({ ok_frames: 0 }); // Reset counter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// For worker case, image collection is handled in setupWorker() message handler
|
||||||
// If less than 3 images, continue scanning to collect more
|
// If less than 3 images, continue scanning to collect more
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -671,25 +717,20 @@ Page({
|
|||||||
goToResult(qrCode, serialCode) {
|
goToResult(qrCode, serialCode) {
|
||||||
this.transitionToState('result');
|
this.transitionToState('result');
|
||||||
|
|
||||||
if (this.data.return_page) {
|
// Pass both qr_code and serial_code parameters like camera-5.1 does
|
||||||
// Pass both qr_code and serial_code parameters like camera-5.1 does
|
// serialCode comes from server verification response
|
||||||
// serialCode comes from server verification response
|
const url = `${this.data.return_page}?qr_code=${encodeURIComponent(qrCode)}&serial_code=${encodeURIComponent(serialCode)}`;
|
||||||
const url = `${this.data.return_page}?qr_code=${encodeURIComponent(qrCode)}&serial_code=${encodeURIComponent(serialCode)}`;
|
|
||||||
|
wx.redirectTo({
|
||||||
wx.redirectTo({
|
url: url,
|
||||||
url: url,
|
success: () => {
|
||||||
success: () => {
|
this.addDebugMessage(`Navigated to: ${this.data.return_page}`);
|
||||||
this.addDebugMessage(`Navigated to: ${this.data.return_page}`);
|
},
|
||||||
},
|
fail: (err) => {
|
||||||
fail: (err) => {
|
this.addDebugMessage(`Navigation failed: ${err.errMsg}`);
|
||||||
this.addDebugMessage(`Navigation failed: ${err.errMsg}`);
|
this.restartScanning();
|
||||||
this.restartScanning();
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.addDebugMessage('No return page specified');
|
|
||||||
this.restartScanning();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -708,9 +749,11 @@ Page({
|
|||||||
// Reset frame processing statistics
|
// Reset frame processing statistics
|
||||||
frames_processed: 0,
|
frames_processed: 0,
|
||||||
frames_skipped: 0,
|
frames_skipped: 0,
|
||||||
|
ok_frames: 0,
|
||||||
total_processing_time: 0,
|
total_processing_time: 0,
|
||||||
avg_processing_time_ms: 0,
|
avg_processing_time_ms: 0,
|
||||||
last_frame_time_ms: 0
|
last_frame_time_ms: 0,
|
||||||
|
first_qr_found: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reset frame timing
|
// Reset frame timing
|
||||||
@ -736,6 +779,18 @@ Page({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update debug frame URLs for visualization
|
||||||
|
*/
|
||||||
|
updateDebugFrameUrls(frameDataUrl) {
|
||||||
|
if (!this.data.enable_debug) return;
|
||||||
|
|
||||||
|
// Just show the current frame
|
||||||
|
this.setData({
|
||||||
|
debug_current_frame_url: frameDataUrl
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log function for debugging
|
* Log function for debugging
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -71,6 +71,14 @@
|
|||||||
<!-- Debug overlay (available in all states) -->
|
<!-- Debug overlay (available in all states) -->
|
||||||
<view class="debug" wx:if="{{ enable_debug }}">
|
<view class="debug" wx:if="{{ enable_debug }}">
|
||||||
<view class="debug-top-row">
|
<view class="debug-top-row">
|
||||||
|
<view class="debug-image-box">
|
||||||
|
<image src="{{ debug_image_data_url }}"></image>
|
||||||
|
<view class="debug-label">Processed Frame</view>
|
||||||
|
</view>
|
||||||
|
<view class="debug-frame-box">
|
||||||
|
<image src="{{ debug_current_frame_url }}"></image>
|
||||||
|
<view class="debug-label">Raw Frame</view>
|
||||||
|
</view>
|
||||||
<view class="debug-info-panel">
|
<view class="debug-info-panel">
|
||||||
<view class="debug-items">
|
<view class="debug-items">
|
||||||
<!-- Application State -->
|
<!-- Application State -->
|
||||||
@ -84,34 +92,18 @@
|
|||||||
<text class="debug-label">model:</text>
|
<text class="debug-label">model:</text>
|
||||||
<text class="debug-value">{{ phone_model }}</text>
|
<text class="debug-value">{{ phone_model }}</text>
|
||||||
</view>
|
</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">
|
<view class="debug-item">
|
||||||
<text class="debug-label">zoom:</text>
|
<text class="debug-label">zoom:</text>
|
||||||
<text class="debug-value-number">{{ zoom }}/{{ max_zoom }}</text>
|
<text class="debug-value-number">{{ zoom }}/{{ max_zoom }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="debug-item">
|
<view class="debug-item">
|
||||||
<text class="debug-label">sensitivity:</text>
|
<text class="debug-label">sensitivity:</text>
|
||||||
<text class="debug-value-number">{{ camera_sensitivity }}</text>
|
<text class="debug-value">{{ 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>
|
||||||
<view class="debug-item debug-flag-box" wx:if="{{ no_web_view }}">
|
<view class="debug-item debug-flag-box" wx:if="{{ no_web_view }}">
|
||||||
<text class="debug-flag">no_web_view</text>
|
<text class="debug-flag">no_web_view</text>
|
||||||
</view>
|
</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 -->
|
<!-- Frame Statistics -->
|
||||||
<view class="debug-item">
|
<view class="debug-item">
|
||||||
<text class="debug-label">frames:</text>
|
<text class="debug-label">frames:</text>
|
||||||
@ -120,17 +112,14 @@
|
|||||||
<text class="debug-value-number">{{ frames_processed + frames_skipped }}</text>
|
<text class="debug-value-number">{{ frames_processed + frames_skipped }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="debug-item">
|
<view class="debug-item">
|
||||||
<text class="debug-label">skipped:</text>
|
<text class="debug-label">ok:</text>
|
||||||
<text class="debug-value-number">{{ frames_skipped }}</text>
|
<text class="debug-value">{{ ok_frames }}</text>
|
||||||
|
<text class="debug-value">/3</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="debug-item">
|
<view class="debug-item">
|
||||||
<text class="debug-label">avg:</text>
|
<text class="debug-label">avg:</text>
|
||||||
<text class="debug-value-number">{{ avg_processing_time_ms }}ms</text>
|
<text class="debug-value-number">{{ avg_processing_time_ms }}ms</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="debug-item">
|
|
||||||
<text class="debug-label">last:</text>
|
|
||||||
<text class="debug-value-number">{{ last_frame_time_ms }}ms</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- QR Detection Results -->
|
<!-- QR Detection Results -->
|
||||||
<view class="debug-item" wx:if="{{ debug_last_result }}">
|
<view class="debug-item" wx:if="{{ debug_last_result }}">
|
||||||
@ -153,9 +142,6 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="debug-image-box">
|
|
||||||
<image src="{{ debug_image_data_url }}"></image>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
<view class="debug-messages">
|
<view class="debug-messages">
|
||||||
<text wx:for="{{ debug_msgs }}" class="debug-msg">{{ item }}</text>
|
<text wx:for="{{ debug_msgs }}" class="debug-msg">{{ item }}</text>
|
||||||
|
|||||||
@ -219,6 +219,25 @@ view.debug {
|
|||||||
border: 1px solid rgba(239, 72, 35, 0.8);
|
border: 1px solid rgba(239, 72, 35, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.debug-frame-box {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-frame-box image {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border: 1px solid rgba(35, 150, 239, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-frame-box .debug-label,
|
||||||
|
.debug-image-box .debug-label {
|
||||||
|
font-size: 8px;
|
||||||
|
color: #ffffff;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 2px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.debug-info-panel {
|
.debug-info-panel {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -291,6 +310,7 @@ view.debug {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Tooltip */
|
/* Tooltip */
|
||||||
view.tooltip {
|
view.tooltip {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@ -89,23 +89,31 @@ function process_frame(width, height, image_data, camera_sensitivity, enable_deb
|
|||||||
/**
|
/**
|
||||||
* Create offscreen canvas for debug image generation
|
* Create offscreen canvas for debug image generation
|
||||||
*/
|
*/
|
||||||
const offscreenCanvas = wx.createOffscreenCanvas({
|
let offscreenCanvas = null;
|
||||||
type: '2d',
|
|
||||||
width: 100,
|
function getOffscreenCanvas() {
|
||||||
height: 100,
|
if (!offscreenCanvas) {
|
||||||
});
|
offscreenCanvas = wx.createOffscreenCanvas({
|
||||||
|
type: '2d',
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return offscreenCanvas;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert raw frame data to data URL for debug visualization
|
* Convert raw frame data to data URL for image visualization
|
||||||
*/
|
*/
|
||||||
function data_url_from_frame(width, height, image_data) {
|
function data_url_from_frame(width, height, image_data) {
|
||||||
offscreenCanvas.width = width;
|
const canvas = getOffscreenCanvas();
|
||||||
offscreenCanvas.height = height;
|
canvas.width = width;
|
||||||
var ctx = offscreenCanvas.getContext('2d');
|
canvas.height = height;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
var imgd = ctx.createImageData(width, height);
|
var imgd = ctx.createImageData(width, height);
|
||||||
imgd.data.set(image_data);
|
imgd.data.set(image_data);
|
||||||
ctx.putImageData(imgd, 0, 0);
|
ctx.putImageData(imgd, 0, 0);
|
||||||
return offscreenCanvas.toDataURL("image/jpeg", 1.0);
|
return canvas.toDataURL("image/jpeg", 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
function upload_image_data_urls(image_data_urls, success, fail, log) {
|
|
||||||
do_upload(image_data_urls, success, fail, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
function check_auto_torch(qrcode, cb) {
|
function check_auto_torch(qrcode, cb) {
|
||||||
var gd = getApp().globalData;
|
var gd = getApp().globalData;
|
||||||
var url = gd.server_url + '/api/v1/check-auto-torch/?qrcode=' + encodeURIComponent(qrcode);
|
var url = gd.server_url + '/api/v1/check-auto-torch/?qrcode=' + encodeURIComponent(qrcode);
|
||||||
@ -33,7 +29,7 @@ function check_auto_torch(qrcode, cb) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function do_upload(image_data_urls, success, fail, log) {
|
function upload_image_data_urls(image_data_urls, success, fail, log) {
|
||||||
var ui = wx.getStorageSync('userinfo');
|
var ui = wx.getStorageSync('userinfo');
|
||||||
var gd = getApp().globalData;
|
var gd = getApp().globalData;
|
||||||
var fd = {
|
var fd = {
|
||||||
|
|||||||
@ -2,6 +2,34 @@ console.log("hello from emblemscanner worker");
|
|||||||
|
|
||||||
let qrtool = require('../qrtool.wx.js');
|
let qrtool = require('../qrtool.wx.js');
|
||||||
|
|
||||||
|
// Create offscreen canvas for image generation (self-contained)
|
||||||
|
let offscreenCanvas = null;
|
||||||
|
|
||||||
|
function getOffscreenCanvas() {
|
||||||
|
if (!offscreenCanvas) {
|
||||||
|
offscreenCanvas = wx.createOffscreenCanvas({
|
||||||
|
type: '2d',
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return offscreenCanvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert raw frame data to data URL for image visualization
|
||||||
|
*/
|
||||||
|
function data_url_from_frame(width, height, image_data) {
|
||||||
|
const canvas = getOffscreenCanvas();
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var imgd = ctx.createImageData(width, height);
|
||||||
|
imgd.data.set(image_data);
|
||||||
|
ctx.putImageData(imgd, 0, 0);
|
||||||
|
return canvas.toDataURL("image/jpeg", 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
var qrtool_ready = false;
|
var qrtool_ready = false;
|
||||||
|
|
||||||
qrtool.onRuntimeInitialized = () => {
|
qrtool.onRuntimeInitialized = () => {
|
||||||
@ -23,7 +51,7 @@ function handle_frame(data, width, height, camera_sensitivity) {
|
|||||||
ok: false,
|
ok: false,
|
||||||
err: "qrtool not ready",
|
err: "qrtool not ready",
|
||||||
},
|
},
|
||||||
processing_time: Date.now() - begin,
|
processing_time: 0,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -43,10 +71,11 @@ function handle_frame(data, width, height, camera_sensitivity) {
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
// Since image_data takes seconds to serialize, send it in a separate
|
// Since image_data takes seconds to serialize, send it in a separate
|
||||||
// message to the UI can update with the good news
|
// message to the UI can update with the good news
|
||||||
|
const dataUrl = data_url_from_frame(width, height, uca);
|
||||||
submit_message = {
|
submit_message = {
|
||||||
type: "submit",
|
type: "submit",
|
||||||
res,
|
res,
|
||||||
image_data: { data, width, height },
|
image_data: { data: dataUrl, width, height },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,9 +85,9 @@ worker.onMessage((msg) => {
|
|||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case "frame":
|
case "frame":
|
||||||
try {
|
try {
|
||||||
const data = worker.getCameraFrameData();
|
// Use frame data from message instead of getCameraFrameData()
|
||||||
if (data) {
|
if (msg.data) {
|
||||||
handle_frame(data, msg.width, msg.height, msg.camera_sensitivity);
|
handle_frame(msg.data, msg.width, msg.height, msg.camera_sensitivity);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
@ -68,6 +97,6 @@ worker.onMessage((msg) => {
|
|||||||
worker.postMessage(submit_message);
|
worker.postMessage(submit_message);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log("Unknown message type:", msg.data.type);
|
console.log("Unknown message type:", msg.type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -129,7 +129,7 @@ Page({
|
|||||||
goto_camera: function () {
|
goto_camera: function () {
|
||||||
this.getUserProfile(() => {
|
this.getUserProfile(() => {
|
||||||
wx.navigateTo({
|
wx.navigateTo({
|
||||||
url: '/pages/emblemscanner/emblemscanner?return_page=/pages/test_result_page/test_result_page'
|
url: '/pages/emblemscanner/emblemscanner?return_page=/pages/productinfo/productinfo'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
{
|
{
|
||||||
"name": "emblemscanner force camera",
|
"name": "emblemscanner force camera",
|
||||||
"pathName": "pages/emblemscanner/emblemscanner",
|
"pathName": "pages/emblemscanner/emblemscanner",
|
||||||
"query": "debug=1&no_web_view=1",
|
"query": "debug=1&no_web_view=1&return_page=/pages/test_result_page/test_result_page",
|
||||||
"scene": null,
|
"scene": null,
|
||||||
"launchMode": "default"
|
"launchMode": "default"
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user