调用摄像头拍照对于网页来说用的不多,在手机上 file 表单直接就可以选择相机拍照,PC 上也是直接选择文件上传。最近对于调用传感器之类的比较感兴趣,之前写了调用麦克风录音,这里继续来写调用摄像头。

拍摄照片

下面简单实现预览摄像头画面、拍照、显示拍摄的照片、导出照片。

点击 拍摄照片demo 可以预览效果。

HTML:

<button type="button" id="start-camera">打开摄像头</button>
<button type="button" id="snapshot-btn">拍照</button>
<button type="button" id="export-btn">导出照片</button>
<video id="preview-box" width="640" height="480" autoplay></video>
<canvas width="640" height="480"></canvas>
<a href="https://www.misterma.com/">Mr. Ma's Blog misterma.com</a>

video 用来显示摄像头画面,canvas 用来显示拍摄的照片,Mr. Ma's Blog 链接可以忽略。

下面是 JavaScript:

const startCameraBtn = document.querySelector('#start-camera');  // 打开摄像头按钮
const snapshotBtn = document.querySelector('#snapshot-btn');  // 拍照按钮
const exportBtn = document.querySelector('#export-btn');  // 导出照片按钮
const previewBox = document.querySelector('#preview-box');  // 预览区
const canvas = document.querySelector('canvas');  // canvas用来显示拍摄的照片
let imgData = null;  // 存储图片数据

// 打开摄像头按钮点击
startCameraBtn.addEventListener('click', () => {
  // 申请摄像头权限
  navigator.mediaDevices.getUserMedia({video: true, audio: false}).then(stream => {
    // 把媒体流直接传给 video 的 srcObject
    previewBox.srcObject = stream;
  }).catch(info => {
    alert('无法获取摄像头权限:' + info);
  });
});

// 拍照按钮点击
snapshotBtn.addEventListener('click', () => {
  // 绘制 2D 图像
  canvas.getContext('2d').drawImage(previewBox, 0, 0, previewBox.width, previewBox.height);
  // 把 canvas 的图像转换为 dataURL 数据
  imgData = canvas.toDataURL('image/jpeg');
});

// 导出照片按钮点击
exportBtn.addEventListener('click', () => {
  if (imgData === null) return false;
  // 创建一个链接
  const link = document.createElement('a');
  link.href = imgData;
  link.download = 'image.jpg';
  link.click();
});

点击 打开摄像头 按钮浏览器就会弹出摄像头授权的对话框,授权后 video 就能显示摄像头画面,点击 拍照 按钮 canvas 就可以截取 video 的画面,点击 导出照片 按钮就能导出 JPG 图片。

详细说明

上面的拍照可分为几个步骤:

  1. 申请摄像头权限
  2. 显示摄像头画面
  3. 截取画面显示在 canvas
  4. 获取图像数据
  5. 导出照片

申请摄像头权限

navigator.mediaDevices.getUserMedia 可以申请媒体输入许可,需要传入一个 constraints 对象,媒体类型可以是 video 视频输入设备,例如摄像头,audio 音频输入设备,例如麦克风,因为我只是拍摄照片,所以只需要 video

用户选择完成后会返回一个 Promise,如果成功 then 会返回一个媒体流,失败 catch 会返回错误信息。

显示摄像头画面

使用 navigator.mediaDevices.getUserMedia 申请摄像头成功后会返回一个媒体流,把媒体流传给 videosrcObject 就可以显示摄像头画面了。

默认传回的画面尺寸不同的设备可能会不一样,如果需要约束画面尺寸,在使用 navigator.mediaDevices.getUserMedia 申请摄像头的时候可以设置 video 尺寸,如下:

const constraints = {
  audio: false,
  video: {
    width: 400,
    height: 400
  }
};
navigator.mediaDevices.getUserMedia(constraints)

截取照片

使用 canvasgetContext('2d').drawImage() 方法可以在 canvas 上绘制 2D 图像。我这里用到了 5 个参数:

  • image 图像源,我使用的是 video 元素
  • dx 横向起始位置
  • dy 纵向起始位置
  • dw 绘制宽度,我使用的是 video 元素的宽度
  • dh 绘制高度,我使用的是 video 元素的高度

截取完成后把 canvas 图像转换为 dataURL 数据,可以设置图片格式,我使用的是 jpeg,如果省略会使用 png

转换后的 dataURL 可以传给 imgsrc 直接显示,也可以封装到 FormData 上传,也可以传给 a 链接的 href 导出。

导出照片

导出照片就比较简单了,上面已经把 canvas 的图像转成了 jpeg 的 dataURL ,直接把 dataURL 传给链接的 href ,然后设置一下链接的 download 下载文件名,点击链接就会弹出下载。

类似文章: