MediaStream Image Capture API 的 ImageCapture 接口提供了从相机或其他摄影设备捕获图像或照片的方法。 它提供了一个接口,用于从通过有效的 MediaStreamTrack 引用的摄影设备捕获图像。
什么是ImageCapture?图片来自https://www.freepik.com/的marcovector并加工
ImageCapture 对象是使用 MediaStreamTrack 作为源构建的。 API 有两个捕获方法 takePhoto() 和 grabFrame() 以及检索相机功能和设置,同时提供了更改设置的诸多方法。
takePhoto() 将单次摄影曝光的结果作为 Blob 返回,该 Blob 可以下载、由浏览器存储或显示在 img 元素中。 此方法使用可用的最高摄影相机分辨率。
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);
}
注意:要在不同的摄像头之间进行选择,例如手机上的前置摄像头和后置摄像头,可以通过
navigator.mediaDevices.enumerateDevices() 方法获取可用设备列表,然后在 getUserMedia() 约束中设置 deviceId(具体查看文末链接代码)。如下调用takePhoto方法:
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() 将 theTrack 中的实时视频快照作为 ImageBitmap 对象返回,该对象可以绘制在画布上,然后进行后期处理以有选择地更改颜色值。
请注意,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));
照片的选项、设置与 theImageCapturer 或 MediaStreamTrack 相关联,具体取决于给定的功能/设置是否对 MediaStreamTrack 具有立即可识别的效果,即是否“实时”。 例如,更改缩放级别会立即反映在 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) {
// 获取zoom级别
zoomSlider.min = capabilities.zoom.min;
zoomSlider.max = capabilities.zoom.max;
zoomSlider.step = capabilities.zoom.step;
zoomSlider.value = settings.zoom;
}
“非实时”相机功能和设置通过 ImageCapture 对象进行操作:
ImageCapture.getPhotoCapabilities() 返回一个 PhotoCapabilities 对象,该对象提供对“非实时”可用相机功能的访问。
var widthSlider = document.querySelector('input[type=range]');
// 获取目标DOM
imageCapture.getPhotoCapabilities()
.then(function(photoCapabilities) {
// 获取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));
“实时”相机设置可以通过 MediaStreamTrack 的 ApplyConstrAInts() constraints 配置,例如:
//applyConstraints设置实时属性
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]');
//takePhoto方法参数设置非实时属性
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));
如下图所示,Chrome从59版本、Edge从79版本开始已经支持ImageCapture,Firefox从35版本开始也作为试验属性添加。Safari依然是特例,即使最新的16.3版本也没有支持这个属性。
整体来看,浏览器支持大约75.06%。不可以可幸的是,对于不支持的浏览器来说google Chrome实验室提供了ImageCapture的polyfill,只需要按照如下方式集成项目即可。
npm install --save image-capture
安装项目后就可以直接在JS中使用:
let videoDevice;
let canvas = document.getElementById('canvas');
let photo = document.getElementById('photo');
navigator.mediaDevices.getUserMedia({video: true}).then(gotMedia).catch(failedToGetMedia);
function gotMedia(mediaStream) {
// Extract video track.
videoDevice = mediaStream.getVideoTracks()[0];
// Check if this device supports a picture mode...
let captureDevice = new ImageCapture(videoDevice);
if (captureDevice) {
captureDevice.takePhoto().then(processPhoto).catch(stopCamera);
captureDevice.grabFrame().then(processFrame).catch(stopCamera);
}
}
function processPhoto(blob) {
photo.src = window.URL.createObjectURL(blob);
}
// 绘制到Canvas中
function processFrame(imageBitmap) {
canvas.width = imageBitmap.width;
canvas.height = imageBitmap.height;
canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
}
function stopCamera(error) {
console.error(error);
if (videoDevice) videoDevice.stop(); // turn off the camera
}
photo.addEventListener('load', function () {
// 图片加载完成后,丢弃图片对象释放内存
window.URL.revokeObjectURL(this.src);
});
本文主要和大家介绍MediaStream Image Capture API 的 ImageCapture 接口,其提供了从相机或其他摄影设备捕获图像或照片的方法,文章没有就ImageCapture过多的展开。但是文末的参考资料提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。
https://chromium.googlesource.com/chromium/src/third_party/+/master/blink/renderer/modules/imagecapture/README.md
https://developer.chrome.com/blog/imagecapture/
https://Github.com/GoogleChromeLabs/imagecapture-polyfill
https://webrtc.github.io/samples/src/content/devices/input-output/