1.什么是ImageCapture?
MediaStream Image Capture API 的 ImageCapture 接口提供了從相機或其他攝影設備捕獲圖像或照片的方法。 它提供了一個接口,用于從通過有效的 MediaStreamTrack 引用的攝影設備捕獲圖像。
什么是ImageCapture?圖片來自https://www.freepik.com/的marcovector并加工
2.ImageCapture的API 機制
ImageCapture 對象是使用 MediaStreamTrack 作為源構建的。 API 有兩個捕獲方法 takePhoto() 和 grabFrame() 以及檢索相機功能和設置,同時提供了更改設置的諸多方法。
2.1 takePhoto
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));
2.2 grabFrame
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));
3.ImageCapture照片設置和功能
照片的選項、設置與 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));
4.ImageCapture的瀏覽器支持與polyfill
如下圖所示,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);
});
5.本文總結
本文主要和大家介紹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/