- A+
WebRTC从摄像头获取图片传入canvas
前面我们已经能够利用WebRTC的功能,通过浏览器打开摄像头,并把预览的图像显示在video元素中。
接下来我们尝试从视频中截取某一帧,显示在界面上。
html
先准备一下界面,摆上控件。下面是关键部分的代码。
<video playsinline autoplay></video> <button id="showVideo">打开摄像头</button> <button id="takeSnapshot">截取</button> <button id="clearList">清除记录</button> <canvas id="mainCanvas"></canvas> <div id="list" style="display: grid; grid-template-columns: repeat(auto-fill, 100px); column-gap: 20px; row-gap: 20px;"></div>
- video 用来预览视频
- 3个button,分别拿来打开摄像头,截取图片和清除记录
- canvas 用来显示截取的图片
- 下面的div是拿来存放多个截取图片记录的。给它指定了grid,显示多个图片时候比较好看一些
照例,需要引入adapter-latest.js
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
js
准备实现功能。
打开摄像头并预览
和之前的打开摄像头类似,还是要用到getUserMedia
方法。拿到视频流后交给video去播放。
const video = document.querySelector('video'); const constraints = { audio: false, video: true }; // .... function openCamera(e) { navigator.mediaDevices.getUserMedia(constraints).then(gotStream).catch(onError); } function gotStream(stream) { window.stream = stream; video.srcObject = stream; } function onError(error) { console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name); }
截取图片
拿到界面中的canvas,先预定一个尺寸(不预定也行)。
const mCanvas = window.canvas = document.querySelector('#mainCanvas'); mCanvas.width = 480; mCanvas.height = 360; // 开始截取 mCanvas.width = video.videoWidth; mCanvas.height = video.videoHeight; mCanvas.getContext('2d').drawImage(video, 0, 0, mCanvas.width, mCanvas.height);
发起截取后,使用getContext
获取到CanvasRenderingContext2D对象。然后调用它的drawImage
方法。
把video中的视频帧绘制进去。
除了绘制这一个canvas,我们可以在每次发起(点击按钮)的时候创建新的canvas,把它们像相册一样展示出来。
const list = document.querySelector('#list'); // 拿来存放多个元素 // 新增1张 var divItem = document.createElement("div"); divItem.style.display = "block"; divItem.width = 100; divItem.height = divItem.width * video.videoHeight / video.videoWidth; // 计算一下比例 divItem.style.width = divItem.width + "px"; divItem.style.height = divItem.height + "px"; console.log("div item size: ", divItem.width, divItem.height); var c1 = document.createElement("canvas"); c1.width = divItem.width; c1.height = divItem.height; c1.getContext('2d').drawImage(video, 0, 0, mCanvas.width, mCanvas.height, 0, 0, c1.width, c1.height); divItem.appendChild(c1); list.appendChild(divItem);
子项的存放方式是div包裹canvas。先用document.createElement("div")
创建divItem
。
按照视频的宽高,计算调整divItem
的大小,并设置style。
document.createElement("canvas")
创建c1
,它的宽高设置为前面divItem
的宽高。然后把图片绘制进去。
drawImage
时,前面传入的是视频(源)的范围,后面的4个参数是自己的绘制范围。
这样一个子项就生成完毕了。添加到我们准备好的列表(div)中。
清除记录
清除div(list
)里的子项。用一个循环获取并移除子项。
var child = list.lastElementChild; while (child) { list.removeChild(child); child = list.lastElementChild; }
小结
打开摄像头,显示视频。把视频绘制到canvas上。创建多个canvas,做成历史记录的效果。
主要利用的还是canvas的绘制方法。绘制的时候注意传入的参数,能够指定绘制的边界。
也就是说只绘制视频大小中的一部分也是可行的。
示例中用到的关键方法
getUserMedia
getContext
drawImage
createElement
预览
简易的预览链接