纯JS实现拍照并展示

发布于 2020-11-28  169 次阅读 本文共3666个字


首先,这里说一下,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)
})

到了这里,有人可能就好奇,takePhotograbFrame 都能实现拍照,那他们有什么区别呢?

看到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的,直接画出来。

下边就是上述代码的效果,查看源码请点击

纯JS实现拍照并展示

努力,只为遇见更好的自己!