前端h5调用摄像头拍照&扫码。

发布于 2024-08-30  108 次阅读


技术拆解

  1. getUserMedia API
    • 用于访问设备摄像头,获取视频流并在网页上实时显示。它是实现拍照和扫码功能的核心技术。
  2. canvas 元素
    • 用于捕捉和绘制摄像头的当前视频帧,以实现拍照功能。通过 canvas 可以将视频帧转换为静态图像。
  3. jsQR
    • 轻量级的 JavaScript 库,用于解析二维码。它能够从视频帧中提取二维码信息,实现扫码功能。

这些技术共同实现了前端拍照和扫码的核心功能,是开发类似应用的关键技术基础。

1. 设计前端页面的代码


<h2>调用摄像头拍照</h2>
<video id="video" autoplay></video>
<button id="snap">拍照</button>
<canvas id="canvas"></canvas>

<h2>扫码功能</h2>
<video id="qr-video" autoplay></video>
<p id="qr-result">二维码结果将在此显示...</p>

2. 获取节点、初始化摄像头的代码

// 获取 HTML 元素节点
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const snapButton = document.getElementById('snap');
const context = canvas.getContext('2d');

const qrVideo = document.getElementById('qr-video');
const qrResult = document.getElementById('qr-result');

初始化摄像头的代码

// 初始化摄像头,显示在视频元素中
navigator.mediaDevices.getUserMedia({ video: true })
    .then(stream => {
        video.srcObject = stream;
    })
    .catch(err => {
        console.error("Error accessing the camera: ", err);
    });

// 初始化扫码摄像头
navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
    .then(stream => {
        qrVideo.srcObject = stream;
        qrVideo.setAttribute('playsinline', true); // 兼容iOS
        qrVideo.play();
        requestAnimationFrame(scanQR);
    })
    .catch(err => {
        console.error("Error accessing the camera for QR scanning: ", err);
    });

扫码功能的代码

<script src="https://cdn.jsdelivr.net/npm/jsqr/dist/jsQR.js"></script>

扫码功能的代码

// 扫描二维码
function scanQR() {
    if (qrVideo.readyState === qrVideo.HAVE_ENOUGH_DATA) {
        const qrCanvas = document.createElement('canvas');
        const qrContext = qrCanvas.getContext('2d');
        qrCanvas.height = qrVideo.videoHeight;
        qrCanvas.width = qrVideo.videoWidth;
        qrContext.drawImage(qrVideo, 0, 0, qrCanvas.width, qrCanvas.height);

        const imageData = qrContext.getImageData(0, 0, qrCanvas.width, qrCanvas.height);
        const code = jsQR(imageData.data, qrCanvas.width, qrCanvas.height);
        if (code) {
            qrResult.textContent = `QR Code detected: ${code.data}`;
        } else {
            qrResult.textContent = "未检测到二维码,请稍后再试...";
        }
    }
    requestAnimationFrame(scanQR);
}

拍照功能的代码

// 拍照并将图像显示在 canvas 中
snapButton.addEventListener('click', () => {
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    context.drawImage(video, 0, 0, canvas.width, canvas.height);
});

效果展示

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>H5 调用摄像头拍照 & 扫码</title>
    <style>
        video, canvas {
            width: 100%;
            max-width: 500px;
            margin: 10px 0;
        }
    </style>
</head>
<body>

<h2>调用摄像头拍照</h2>
<video id="video" autoplay></video>
<button id="snap">拍照</button>
<canvas id="canvas"></canvas>

<h2>扫码功能</h2>
<video id="qr-video" autoplay></video>
<p id="qr-result">二维码结果将在此显示...</p>

<script src="https://cdn.jsdelivr.net/npm/jsqr/dist/jsQR.js"></script>
<script>
    // 拍照功能
    const video = document.getElementById('video');
    const canvas = document.getElementById('canvas');
    const snapButton = document.getElementById('snap');
    const context = canvas.getContext('2d');

    navigator.mediaDevices.getUserMedia({ video: true })
        .then(stream => {
            video.srcObject = stream;
        })
        .catch(err => {
            console.error("Error accessing the camera: ", err);
        });

    snapButton.addEventListener('click', () => {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
    });

    // 扫码功能
    const qrVideo = document.getElementById('qr-video');
    const qrResult = document.getElementById('qr-result');

    navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
        .then(stream => {
            qrVideo.srcObject = stream;
            qrVideo.setAttribute('playsinline', true); // 兼容iOS
            qrVideo.play();
            requestAnimationFrame(scanQR);
        })
        .catch(err => {
            console.error("Error accessing the camera for QR scanning: ", err);
        });

    function scanQR() {
        if (qrVideo.readyState === qrVideo.HAVE_ENOUGH_DATA) {
            const qrCanvas = document.createElement('canvas');
            const qrContext = qrCanvas.getContext('2d');
            qrCanvas.height = qrVideo.videoHeight;
            qrCanvas.width = qrVideo.videoWidth;
            qrContext.drawImage(qrVideo, 0, 0, qrCanvas.width, qrCanvas.height);

            const imageData = qrContext.getImageData(0, 0, qrCanvas.width, qrCanvas.height);
            const code = jsQR(imageData.data, qrCanvas.width, qrCanvas.height);
            if (code) {
                qrResult.textContent = `QR Code detected: ${code.data}`;
            } else {
                qrResult.textContent = "未检测到二维码,请稍后再试...";
            }
        }
        requestAnimationFrame(scanQR);
    }
</script>

</body>
</html>