本文详解如何在 web 端通过 navigator.mediadevices.getusermedia 正确启用摄像头自动对焦(focusmode),解决近距离扫描小尺寸 qr 码时图像模糊、识别失败的核心问题。
本文详解如何在 web 端通过 navigator.mediadevices.getusermedia 正确启用摄像头自动对焦(focusmode),解决近距离扫描小尺寸 qr 码时图像模糊、识别失败的核心问题。
在基于 HTML5 的 Web 端 QR 码扫描应用中,摄像头无法自动对焦是导致小尺寸或近距离二维码识别率骤降的常见瓶颈。尽管 MediaStreamTrack.applyConstraints() 支持 focusMode,但其实际生效依赖于设备能力、浏览器兼容性与约束设置方式——直接在 getUserMedia 中写入 advanced: [{ focusMode: "continuous" }] 并不能保证生效,甚至可能被忽略。
先获取媒体流,再动态应用约束
focusMode 属于高级约束(Advanced Constraint),必须在获得 MediaStreamTrack 后,通过 track.applyConstraints() 单独设置,且需确保该约束已被设备支持。
验证设备是否支持 focusMode
使用 navigator.mediaDevices.getSupportedConstraints() 检查当前环境是否支持 focusMode:
const supported = navigator.mediaDevices.getSupportedConstraints();console.log('focusMode supported:', !!supported.focusMode); // 必须为 true
{ advanced: [{ focusMode: "continuous" }] }
✅ 正确写法(直接作为顶层约束项):
const focusConstraints = { focusMode: { ideal: "continuous" } // 或 "auto"};await track.applyConstraints(focusConstraints);
<!DOCTYPE html><html><head> <title>QR Scanner with Auto-Focus</title> <meta charset="utf-8"> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jsQR.min.js"></script></head><body> <video id="video" width="640" height="480" autoplay muted></video> <canvas id="canvas" width="640" height="480" style="display:none;"></canvas> <p id="result">Initializing...</p> <script> const video = document.getElementById("video"); const canvas = document.getElementById("canvas"); const ctx = canvas.getContext("2d"); const resultEl = document.getElementById("result"); async function initScanner() { try { // Step 1: 请求摄像头权限(仅视频) const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment", width: { ideal: 1280 }, height: { ideal: 720 }, frameRate: { ideal: 15 } } }); video.srcObject = stream; await video.play(); // Step 2: 获取视频轨道并检查 focusMode 支持 const track = stream.getVideoTracks()[0]; const supported = navigator.mediaDevices.getSupportedConstraints(); if (!supported.focusMode) { resultEl.textContent = "⚠️ focusMode not supported on this device"; return; } // Step 3: 应用对焦约束(关键!) try { await track.applyConstraints({ focusMode: { ideal: "continuous" } }); console.log("✅ Auto-focus enabled successfully"); } catch (e) { console.warn("❌ Failed to set focusMode:", e.name, e.message); // 降级尝试:部分 Android 设备需用 "auto" try { await track.applyConstraints({ focusMode: "auto" }); console.log("✅ Fallback to 'auto' mode"); } catch (e2) { console.error("❌ Focus mode not available", e2); } } // Step 4: 启动扫码循环 const scanInterval = setInterval(() => { ctx.drawImage(video, 0, 0, canvas.width, canvas.height); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const code = jsQR(imageData.data, imageData.width, imageData.height, { inversionAttempts: "dontInvert", }); if (code) { clearInterval(scanInterval); resultEl.textContent = `✅ Scanned: ${code.data}`; alert(`QR Code: ${code.data}`); } }, 500); } catch (err) { resultEl.textContent = `❌ Error: ${err.message}`; console.error(err); } } // 延迟启动,确保 DOM 加载完成 window.addEventListener("load", initScanner); </script></body></html>
Web 端实现可靠对焦并非“设置即生效”,而是需结合能力检测、分步约束、错误降级与用户体验引导。虽然 GitHub 上多数开源扫码库未封装对焦逻辑(因其设备依赖性强),但通过上述标准化流程,可在支持设备上显著提升小码识别成功率。若目标用户以 iOS 为主,建议同步提供「手动对焦辅助线」UI 或调用 MediaStreamTrack.getSettings() 动态反馈当前对焦状态,构建更鲁棒的扫码体验。
立即学习“前端免费学习笔记(深入)”;