首页
/ MDN Web API 教程:使用 getUserMedia() 拍摄静态照片

MDN Web API 教程:使用 getUserMedia() 拍摄静态照片

2025-07-07 01:21:10作者:卓艾滢Kingsley

本文将详细介绍如何利用 WebRTC 技术中的 navigator.mediaDevices.getUserMedia() API 访问用户设备的图像采集设备,并实现拍照功能。这是一个非常实用的功能,可以应用于各种需要用户上传照片的 Web 应用中。

功能概述

我们将创建一个简单的拍照应用,主要功能包括:

  1. 访问用户设备的图像采集设备
  2. 实时显示采集的画面
  3. 点击按钮拍摄静态照片
  4. 显示拍摄的照片

准备工作

HTML 结构

首先,我们需要设置基本的 HTML 结构:

<div class="content-area">
  <h1>拍照功能演示</h1>
  
  <div class="camera">
    <video id="video">视频流不可用</video>
    <button id="start-button">拍照</button>
  </div>
  
  <canvas id="canvas"></canvas>
  
  <div class="output">
    <img id="photo" alt="拍摄的照片将显示在这里">
  </div>
</div>

这个结构包含三个主要部分:

  1. 视频显示区域 (<video>)
  2. 拍照按钮
  3. 照片显示区域 (<img>)

注意我们还包含了一个隐藏的 <canvas> 元素,它将在拍照过程中作为中间处理环节使用。

JavaScript 实现

初始化变量

首先定义一些全局变量:

const width = 320;  // 照片宽度
let height = 0;     // 高度将根据视频流计算
let streaming = false;  // 标记视频流状态

// 获取DOM元素
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const photo = document.getElementById('photo');
const startButton = document.getElementById('start-button');

获取图像采集设备访问权限

核心是调用 getUserMedia() 方法请求访问图像采集设备:

navigator.mediaDevices.getUserMedia({ video: true, audio: false })
  .then((stream) => {
    video.srcObject = stream;
    video.play();
  })
  .catch((err) => {
    console.error(`发生错误: ${err}`);
  });

这个方法返回一个 Promise:

  • 成功时:将视频流赋给 <video> 元素并开始播放
  • 失败时:打印错误信息(可能是用户拒绝授权或没有设备)

视频准备就绪处理

我们需要监听视频的 canplay 事件,当视频可以播放时进行初始化:

video.addEventListener('canplay', (ev) => {
  if (!streaming) {
    // 根据视频宽高比计算高度
    height = video.videoHeight / (video.videoWidth / width);
    
    // 设置视频和画布尺寸
    video.setAttribute('width', width);
    video.setAttribute('height', height);
    canvas.setAttribute('width', width);
    canvas.setAttribute('height', height);
    
    streaming = true;
  }
}, false);

拍照功能实现

当用户点击拍照按钮时:

startButton.addEventListener('click', (ev) => {
  takePicture();
  ev.preventDefault();
}, false);

拍照的核心函数 takePicture()

function takePicture() {
  const context = canvas.getContext('2d');
  if (width && height) {
    // 设置画布尺寸
    canvas.width = width;
    canvas.height = height;
    
    // 将视频帧绘制到画布上
    context.drawImage(video, 0, 0, width, height);
    
    // 将画布内容转为图片数据
    const data = canvas.toDataURL('image/png');
    
    // 显示拍摄的照片
    photo.setAttribute('src', data);
  } else {
    clearPhoto();
  }
}

清除照片

我们还需要一个清除照片的函数:

function clearPhoto() {
  const context = canvas.getContext('2d');
  
  // 用灰色填充画布
  context.fillStyle = '#AAA';
  context.fillRect(0, 0, canvas.width, canvas.height);
  
  // 将空白画布转为图片并显示
  const data = canvas.toDataURL('image/png');
  photo.setAttribute('src', data);
}

添加滤镜效果

我们可以扩展功能,为拍摄的照片添加滤镜效果:

function takePicture() {
  const context = canvas.getContext('2d');
  if (width && height) {
    canvas.width = width;
    canvas.height = height;
    
    // 获取视频元素应用的CSS滤镜
    const videoStyles = window.getComputedStyle(video);
    const filterValue = videoStyles.getPropertyValue('filter');
    
    // 将同样的滤镜应用到画布
    context.filter = filterValue !== 'none' ? filterValue : 'none';
    
    context.drawImage(video, 0, 0, width, height);
    
    const dataUrl = canvas.toDataURL('image/png');
    photo.setAttribute('src', dataUrl);
  } else {
    clearPhoto();
  }
}

这样,如果视频元素应用了CSS滤镜(如灰度、模糊等),拍摄的照片也会应用相同的效果。

选择特定设备

如果需要指定使用某个特定的图像采集设备:

// 首先枚举所有可用设备
navigator.mediaDevices.enumerateDevices()
  .then((devices) => {
    // 筛选出视频输入设备
    const videoDevices = devices.filter(device => device.kind === 'videoinput');
    
    // 使用第一个视频设备
    if (videoDevices.length > 0) {
      return navigator.mediaDevices.getUserMedia({
        video: {
          deviceId: videoDevices[0].deviceId
        },
        audio: false
      });
    }
  })
  .then((stream) => {
    // 处理视频流
    video.srcObject = stream;
    video.play();
  })
  .catch((err) => {
    console.error(`发生错误: ${err}`);
  });

注意事项

  1. 用户权限:浏览器会要求用户授权访问图像采集设备,用户必须同意才能继续
  2. HTTPS:在生产环境中,此API只能在安全上下文(HTTPS)中工作
  3. 错误处理:需要妥善处理用户拒绝授权或没有设备的情况
  4. 性能考虑:高分辨率视频流可能会影响性能,特别是移动设备

总结

通过本文,我们学习了如何使用WebRTC API实现浏览器中的拍照功能。这个功能可以广泛应用于各种Web应用,如:

  • 用户头像上传
  • 证件照拍摄
  • 产品展示
  • 在线考试监考系统等

关键点在于理解视频流、画布和图像数据之间的转换过程。通过扩展这个基础功能,你可以实现更复杂的效果,如实时滤镜、人脸识别等高级特性。