首先,这里说一下,Chrome 56 以上,已经提供了相应的 API,允许纯前端开发人员使用摄像头并且进行拍照图片抓取了。
getUserMedia(打开摄像头)
首先,我们先设置srcObject,这个对象提供了HTMLMediaElement的媒体源,通常是MediaStream,所以这里我们通过getUserMedia拿到mediaStream。
然后我们再通过getVideoTracks拿到媒体流中视频轨道的对象序列。
再通过ImageCapture,获取到刚才视频流对象序列中的图像信息。
let imageCapture = null;
navigator.mediaDevices.getUserMedia({video: true})
.then(mediaStream => {
video.srcObject = mediaStream;
const track = mediaStream.getVideoTracks()[0];
imageCapture = new ImageCapture(track);
})
takePhoto
我们可以通过该方法获取视频设备捕捉的图像信息,返回一个Blob类型的Promise对象。
然后我们通过createImageBitmap方法生成一个ImageBitmap,这样就可以在Canvas上来画下我们捕捉到的照片啦。
imageCapture.takePhoto()
.then(blob => createImageBitmap(blob))
.then(imageBitmap => {
const takePhotoCanvas = document.getElementById('takePhotoCanvas');
// drawImage 为Util方法,往下看,有解释
drawImage(takePhotoCanvas, imageBitmap)
})
grabFrame
前端拍照不止takePhoto一种方法,还有grabFrame也很常用。
他会截取快照,并直接返回ImageBitmap的一个Promise对象。比上边的方法更加简洁。
imageCapture.grabFrame()
.then(imageBitmap => {
const grabFrameCanvas = document.getElementById('grabFrameCanvas');
drawImage(grabFrameCanvas, imageBitmap)
})
到了这里,有人可能就好奇,takePhoto 和 grabFrame 都能实现拍照,那他们有什么区别呢?
看到MDN上的解说,还有上述的描述,很明显可以看到,grabFrame更简单方便,可以直接拿到imageBitmap然后来画图。虽然takePhoto没有那么一步到位呢,但是我们可以看到它会返回一个Blob对象,可以通过浏览器下载,同时它也可以支持更高的分辨率。
drawImage
此方法可以在Canvas上任意绘图,并且第一个参数绘图对象可是是任意图像源,视频也可,也是非常强大的,其余参数看文档查看。
上边呢,都是拿到ImageBitmap后绘图的,我们来直接绘图看一下
function drawImage(canvas, image) {
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
}
方法中我们直接绘图,可以看到渲染出来的图片并非我们所需要的那样,哪里不太对呢?我们还需要算出drawImage所需要的宽、高、缩放比、x、y轴,还有要在canvas上绘制的宽高等信息。
function drawImage(canvas, image) {
canvas.width = getComputedStyle(canvas).width.split('px')[0];
canvas.height = getComputedStyle(canvas).height.split('px')[0];
const ctx = canvas.getContext('2d');
const radio = Math.min(canvas.width / image.width, canvas.height / image.height);
const x = (canvas.width - image.width * radio) / 2;
const y = (canvas.height - image.height * radio) / 2;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(image, 0, 0, image.width, image.height, x, y, image.width * radio, image.height * radio);
}
clearRect 可以擦出来一个透明的矩形出来,距离左上角的距离还有宽高都是根据传参取的。然后我们再在这块儿矩形区域画出我们捕捉的到的图像。当然,也可以不用clearRect的,直接画出来。
下边就是上述代码的效果,查看源码请点击
Comments | NOTHING