拍摄照片和控制相机设置

Miguel Casas-Sanchez
François Beaufort
François Beaufort

Image Capture 是一个用于拍摄静态图像和配置相机硬件设置的 API。此 API 可在 Android 设备和桌面设备上的 Chrome 59 中使用。我们还发布了 ImageCapture polyfill 库

该 API 支持控制相机功能,例如变焦、亮度、对比度、ISO 和白平衡。最棒的是,借助图片拍摄功能,您可以使用任何可用设备相机或网络摄像头的完整分辨率功能。之前在网络上拍摄照片的技术使用的是视频快照,其分辨率低于静态图片。

ImageCapture 对象是使用 MediaStreamTrack 作为源构建的。然后,该 API 提供了两种拍摄方法 takePhoto()grabFrame(),以及检索相机功能和设置以及更改这些设置的方法。

建筑

Image Capture API 通过从 getUserMedia() 获取的 MediaStreamTrack 访问相机:

navigator.mediaDevices.getUserMedia({video: true})
    .then(gotMedia)
    .catch(error => console.error('getUserMedia() error:', error));

function gotMedia(mediaStream) {
    const mediaStreamTrack = mediaStream.getVideoTracks()[0];
    const imageCapture = new ImageCapture(mediaStreamTrack);
    console.log(imageCapture);
}

您可以在开发者工具控制台中试用此代码。

捕获

拍摄方法有两种:全帧拍摄和快速拍摄快照。takePhoto() 会返回一个 Blob,即单次摄影曝光的结果,可下载、由浏览器存储或显示在 <img> 元素中。此方法使用可用的最高相机分辨率。例如:

const img = document.querySelector('img');
// ...
imageCapture.takePhoto()
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('takePhoto() error:', error));

grabFrame() 会返回一个 ImageBitmap 对象,即直播视频的快照,该对象可以(例如)在 <canvas> 上绘制,然后进行后处理以选择性地更改颜色值。请注意,ImageBitmap 仅具有视频源的分辨率,这通常低于相机的静态图像功能。例如:

const canvas = document.querySelector('canvas');
// ...
imageCapture.grabFrame()
    .then(imageBitmap => {
    canvas.width = imageBitmap.width;
    canvas.height = imageBitmap.height;
    canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
    })
    .catch(error => console.error('grabFrame() error:', error));

功能和设置

您可以通过多种方式操纵拍摄设置,具体取决于更改是反映在 MediaStreamTrack 中,还是只能在 takePhoto() 之后看到。例如,zoom 级别的变化会立即传播到 MediaStreamTrack,而消除红眼(如果设置)仅在拍摄照片时应用。

“实时”相机功能和设置通过预览 MediaStreamTrack 进行操纵:MediaStreamTrack.getCapabilities() 会返回一个 MediaTrackCapabilities 字典,其中包含具体的受支持功能以及范围或允许的值,例如支持的缩放范围或允许的白平衡模式。相应地,MediaStreamTrack.getSettings() 会返回包含具体当前设置的 MediaTrackSettings。缩放、亮度和手电筒模式属于此类别,例如:

var zoomSlider = document.querySelector('input[type=range]');
// ...
const capabilities = mediaStreamTrack.getCapabilities();
const settings = mediaStreamTrack.getSettings();
if (capabilities.zoom) {
    zoomSlider.min = capabilities.zoom.min;
    zoomSlider.max = capabilities.zoom.max;
    zoomSlider.step = capabilities.zoom.step;
    zoomSlider.value = settings.zoom;
}

“非实时”摄像头功能和设置通过 ImageCapture 对象操纵:ImageCapture.getPhotoCapabilities() 会返回一个 PhotoCapabilities 对象,该对象提供对“非实时”可用摄像头功能的访问权限。相应地,从 Chrome 61 开始,ImageCapture.getPhotoSettings() 会返回一个包含具体当前设置的 PhotoSettings 对象。照片分辨率、红眼消除和闪光灯模式(手电筒除外)属于此部分,例如:

var widthSlider = document.querySelector('input[type=range]');
// ...
imageCapture.getPhotoCapabilities()
    .then(function(photoCapabilities) {
    widthSlider.min = photoCapabilities.imageWidth.min;
    widthSlider.max = photoCapabilities.imageWidth.max;
    widthSlider.step = photoCapabilities.imageWidth.step;
    return imageCapture.getPhotoSettings();
    })
    .then(function(photoSettings) {
    widthSlider.value = photoSettings.imageWidth;
    })
    .catch(error => console.error('Error getting camera capabilities and settings:', error));

正在配置

您可以通过预览 MediaStreamTrackapplyConstraints() 限制条件来配置“实时”摄像头设置,例如:

var zoomSlider = document.querySelector('input[type=range]');

mediaStreamTrack.applyConstraints({ advanced: [{ zoom: zoomSlider.value }]})
    .catch(error => console.error('Uh, oh, applyConstraints() error:', error));

“非实时”摄像头设置使用 takePhoto() 的可选 PhotoSettings 字典进行配置,例如:

var widthSlider = document.querySelector('input[type=range]');
imageCapture.takePhoto({ imageWidth : widthSlider.value })
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('Uh, oh, takePhoto() error:', error));

相机功能

如果您运行上面的代码,会注意到 grabFrame()takePhoto() 结果之间的尺寸不同。

takePhoto() 方法提供对相机最大分辨率的访问权限。

grabFrame() 只是获取渲染程序进程内的 MediaStreamTrack 中下一个可用的 VideoFrame,而 takePhoto() 会中断 MediaStream,重新配置相机,拍摄照片(通常采用压缩格式,因此为 Blob),然后恢复 MediaStreamTrack。实质上,这意味着 takePhoto() 可授予对相机的完整静态图像分辨率功能的访问权限。以前,只能通过使用视频作为来源对 canvas 元素调用 drawImage() 来“拍摄照片”(如此处的示例所示)。

如需了解详情,请参阅 README.md 部分

在此演示中,<canvas> 尺寸设置为视频流的分辨率,而 <img> 的自然尺寸是相机的最大静态图片分辨率。当然,CSS 用于设置这两者的显示尺寸。

您可以使用 PhotoCapabilities.imageHeightimageWidthMediaSettingsRange 值来获取和设置静态图像的所有可用相机分辨率。请注意,getUserMedia() 的最小和最大宽度和高度限制适用于视频,其(如上所述)可能与静态图片的相机功能不同。换言之,从 getUserMedia() 保存到画布时,您可能无法使用设备的完整分辨率功能。WebRTC 分辨率约束条件演示展示了如何为分辨率设置 getUserMedia() 约束条件。

还想执行任何其他步骤吗?

  • Shape Detection API 与图片拍摄工具配合良好:可以重复调用 grabFrame(),以将 ImageBitmap 馈送到 FaceDetectorBarcodeDetector。如需详细了解该 API,请参阅 Paul Kinlan 的博文

  • 您可以通过 PhotoCapabilities 中的 FillLightMode 访问相机闪光灯(设备指示灯),但可以在 MediaTrackCapabilities 中找到手电筒模式(闪光灯持续开启)。

演示和代码示例

支持

  • Android 和桌面设备上的 Chrome 59。
  • Android 和桌面版 Chrome 59 之前的版本,并启用实验性 Web 平台功能。

了解详情