前言

哈喽,大家好,我是海怪。

最近一直在看 WebRTC 的用法,也学了一下音视频流的东西,今天就跟大家分享一个好玩的小实战吧——给自己拍照。

如何用 WebRTC 给自己拍照?

**项目已上传至 Github,Repo

接口文档址:github.com/haixiangyan…**

页面结构

首先,我们要拆分一下实现步骤:

  • 打开摄像头,获取视频流
  • 需要一个 <video> 来播放摄html网页制作像头的画面
  • 点击按钮,生成画面,并展示在 <img>

因此,我们apple需要 <vidgithub官网eo>, <img> 以及 <button>

<head>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
  <link rel="stylesheet" href="styles.css">
</head>
<body>
<main>
  <video id="video">浏览器不支持 Video</video>
  <canvas id="canvas">
    <img id="photo" alt="拍照后的照片">
  </canvas>
</main>
<div class="actions">
  <button id="takePhotoButton" type="button" class="btn btn-primary">拍照</button>
  <button id="downloadButton" type="button" class="btn btn-success">下载</button>
  <button id="clearButton" type="button" class="btn btn-danger">清空</button>
</div>
<script src="./main.js"></script>
</body>

再加上点 CSS,让整个 App 好看一点~

main {
    padding: 24px 24px 16px;
    display: flex;
}
video {
    margin-right: 16px;
    box-sizing: content-box;
    border: 4px solid #ffaabb;
}
canvas {
    box-sizing: content-box;
    border: 4px solid #aabbff;
}
.actions {
    padding: 0 24px;
}
.actions button {
    margin-right: 16px;
}

如何用 WebRTC 给自己拍照?

左边为摄像头的 <video>,右边apple则是拍照的图片html文件怎么打开

打开摄像头

打开摄像头这一步,其实是调用了 WebRTC 的一个重要接口 navigator.mcanvas可画官网ediaDevices.getUserMgithub直播平台永久回家edia,通过这个接口不仅可以完成用户对摄像头的使用授权,还可以从返回值里直接拿到视频流:

const start = async () => {
  video = document.getElementById('video');
  canvas = document.getElementById('canvas');
  photo = document.getElementById('photo');
  takePhotoButton = document.getElementById('takePhotoButton');
  downloadButton = document.getElementById('downloadButton');
  // 获取摄像头的视频流
  try {
    video.srcObject = await navigator.mediaDevices.getUserMedia({video: true, audio: false})
    video.play()
  } catch (e) {
    console.error(e)
  }
}
start().then()

将视频流接到 <video> 元素的 srcObject 上,再调用一下 video.play() 就可以展示视频流了:

如何用 WebRTC 给自己拍照?

拍照

HTML 结构里我们可github汤姆以看到 <canvas> 里面还藏着一个 <img>。这里 <canvas> 的作用是负责从视频流中生成图片数据,再将这个数据放到 <img>src 上,这样就完成了我们的拍照功能了。

const takePhoto = () => {
  const context = canvas.getContext('2d')
  if (width && height) {
    // 将 video 元素的 width 和 height 拿过来
    canvas.width = width;
    canvas.height = height;
    context.drawImage(video, 0, 0, width, height);
    // 生成图片
    const data = canvas.toDataURL('image/png');
    photo.setAttribute('src', data);
  } else {
    clearPhoto()
  }
}

不过在调用 drawImaggithub打不开e 的时候要传入对应的宽和高,这里的宽和高可以从 <video> 元素中的 widthhecanvas英语ight 获得。

const start = async () => {
  video = document.getElementById('video');
  canvas = document.getElementById('canvas');
  photo = document.getElementById('photo');
  takePhotoButton = document.getElementById('takePhotoButton');
  downloadButton = document.getElementById('downloadButton');
  // 获取摄像头的视频流
  try {
    video.srcObject = await navigator.mediaDevices.getUserMedia({video: true, audio: false})
    video.play()
  } catch (e) {
    console.error(e)
  }
  video.addEventListener('canplay', (event) => {
    if (!streaming) {
      // 按比例放大 videoHeight
      height = video.videoHeight / (video.videoWidth / width);
      // 设置 video 的宽高
      video.setAttribute('width', width);
      video.setAttribute('height', height);
      // 设置 canvas 的宽高
      canvas.setAttribute('width', width);
      canvas.setAttribute('height', height);
      streaming = true;
    }
  }, false)
  takePhotoButton.addEventListener('click', (event) => {
    // 拍照
    takePhoto()
  }, false)
}
start().then()

这样一来就能生github是干什么的成视频中定格后的某一个画面了。

如何用 WebRTC 给自己拍照?

从上面可以看到这里的 <img> 里的 srcdata:xxx 的图片数据。

清空图片

如果要重清除已经拍好的照片呢?我们可github开放私库以利用 <canvas>fillRect 来生成一个空白图html个人网页完整代码片,然后再转化成图片数据html代码,放到 src 里就可以了:

// 清空操作
const clearPhoto = () => {
  const context = canvas.getContext('2d')
  // 生成空白图片
  context.fillStyle = "#AAA";
  context.fillRect(0, 0, canvas.width, canvas.height);
  const data = canvas.toDataURL('image/png');
  photo.setAttribute('src', data);
}
// 开始
const start = async () => {
  // ...
  clearButton.addEventListener('click', (event) => {
    clearPhoto();
  })
  // 生成默认空白图片
  clearPhoto();
}
start().then()

或许有的人会觉得:我把图片 v-if=falsedisplay: nonevisgithub官网ibility: hidden 不也可以嘛?

当然可以!这里我只是想再分享另一种思路嘛~ 因为像canvas2七彩的素描这种调用 fillRect 来做重置功能的是比较常用github打不开的,比较画板里的重置就appreciate可以这样来清空画布。

下载

下载则比较简单了,也是面试常考的一道技巧题。

先生成一个GitHub &lhtml个人网页完整代码t;aapple苹果官网> 标签,然后通过 <canvas> 生成 URL,将这个 URL 放到 href 里,用 JS 出发 c接口英文lick 事件,就github是干什么的可模拟下载了:

// 下载操作
const downloadPhoto = () => {
  const link = document.createElement('a');
  link.download = '你的帅照.png';
  link.href = canvas.toDataURL();
  link.click();
}
const start = async () => {
  // ...
  downloadButton.addEventListener('click', (event) => {
    // 下载
    downloadPhoto()
  })
}
start().then()

总结

到这里,这个小实战就结束啦,并没有什么难度,这里稍微做下总结吧。

WebRTC 最重要的 API 就是 await navigator.mediaDevices.getUserhtml文件怎么打开Media({video: true, audio: fhtml网页制作alse}),通过返回值可以获取当前摄像头github中文社区、麦克风的音视频流。

通过 <video> 元素的 srcObject 属性可以直接接上视频流,这在直播、P2P、视频聊天的场景都可以这样使用。

通过 <canvas>drawImage 以及 fillRect 来生成视频图片以及空白图片数据,再把这些数据放到 <img> 就可以实现 JS 生成画面的效果。

如果你也喜欢我的文章,也可以关注我,你的三连是我最大的动力~