Happylab Logo
發布於

Day19: Webcam Fun

Authors

簡介: 如何使用 JavaScript 和 HTML5 的 getUserMedia API 來實現網頁攝影功能。

作品頁面:https://iris1114.github.io/javascript30/19_Webcam-Fun/

HTML

  • 包含一個 div 容器,內部有控制按鈕、canvas 元素、video 元素和一個顯示拍攝照片的區域。
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Get User Media Code Along!</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="photobooth">
      <div class="controls">
        <button onClick="takePhoto()">Take Photo</button>
        <!--
      <div class="rgb">
        <label for="rmin">Red Min:</label>
        <input type="range" min=0 max=255 name="rmin">
        <label for="rmax">Red Max:</label>
        <input type="range" min=0 max=255 name="rmax">

        <br>

        <label for="gmin">Green Min:</label>
        <input type="range" min=0 max=255 name="gmin">
        <label for="gmax">Green Max:</label>
        <input type="range" min=0 max=255 name="gmax">

        <br>

        <label for="bmin">Blue Min:</label>
        <input type="range" min=0 max=255 name="bmin">
        <label for="bmax">Blue Max:</label>
        <input type="range" min=0 max=255 name="bmax">
      </div>
      --></div>

      <canvas class="photo"></canvas>
      <video class="player"></video>
      <div class="strip"></div>
    </div>

    <audio class="snap" src="./snap.mp3" hidden></audio>

    <script src="scripts.js"></script>
  </body>
</html>

JavaScript

  • 使用 JavaScript 來獲取使用者的攝影機影像,並將影像顯示在 video 元素中。
  • video 元素中的影像繪製到 canvas 元素上,並進行像素處理。
  • 拍攝照片並將照片顯示在頁面上。
const video = document.querySelector('.player')
const canvas = document.querySelector('.photo')
const ctx = canvas.getContext('2d')
const strip = document.querySelector('.strip')
const snap = document.querySelector('.snap')

// 獲取使用者的攝影機影像
function getVideo() {
  navigator.mediaDevices
    .getUserMedia({ video: true, audio: false })
    .then((localMediaStream) => {
      console.log(localMediaStream)
      video.srcObject = localMediaStream
      video.play()
    })
    .catch((err) => {
      console.error(`OH NO!!!`, err)
    })
}

// 將影像繪製到 canvas 上
function paintToCanvas() {
  const width = video.videoWidth
  const height = video.videoHeight
  canvas.width = width
  canvas.height = height

  return setInterval(() => {
    ctx.drawImage(video, 0, 0, width, height)
    let pixels = ctx.getImageData(0, 0, width, height)
    // 可以在這裡應用不同的效果
    pixels = rgbSplit(pixels)
    ctx.putImageData(pixels, 0, 0)
  }, 16)
}

// 拍攝照片並顯示在頁面上
function takePhoto() {
  // 播放拍照聲音
  snap.currentTime = 0
  snap.play()

  // 從 canvas 中獲取影像數據
  const data = canvas.toDataURL('image/jpeg')
  const link = document.createElement('a')
  link.href = data
  link.setAttribute('download', 'handsome')
  link.innerHTML = `<img src="${data}" alt="Handsome Man" />`
  strip.insertBefore(link, strip.firstChild)
}

// 紅色效果
function redEffect(pixels) {
  for (let i = 0; i < pixels.data.length; i += 4) {
    pixels.data[i + 0] = pixels.data[i + 0] + 200 // RED
    pixels.data[i + 1] = pixels.data[i + 1] - 50 // GREEN
    pixels.data[i + 2] = pixels.data[i + 2] * 0.5 // Blue
  }
  return pixels
}

// RGB 分裂效果
function rgbSplit(pixels) {
  for (let i = 0; i < pixels.data.length; i += 4) {
    pixels.data[i - 150] = pixels.data[i + 0] // RED
    pixels.data[i + 500] = pixels.data[i + 1] // GREEN
    pixels.data[i - 550] = pixels.data[i + 2] // Blue
  }
  return pixels
}

// 綠幕效果
function greenScreen(pixels) {
  const levels = {}

  document.querySelectorAll('.rgb input').forEach((input) => {
    levels[input.name] = input.value
  })

  for (i = 0; i < pixels.data.length; i = i + 4) {
    red = pixels.data[i + 0]
    green = pixels.data[i + 1]
    blue = pixels.data[i + 2]
    alpha = pixels.data[i + 3]

    if (
      red >= levels.rmin &&
      green >= levels.gmin &&
      blue >= levels.bmin &&
      red <= levels.rmax &&
      green <= levels.gmax &&
      blue <= levels.bmax
    ) {
      // 將像素透明度設為 0
      pixels.data[i + 3] = 0
    }
  }

  return pixels
}

// 啟動攝影機
getVideo()

// 當 video 可以播放時,開始將影像繪製到 canvas 上
video.addEventListener('canplay', paintToCanvas)

Note

  • 使用 navigator.mediaDevices.getUserMedia 來獲取使用者的攝影機影像。
  • 使用 canvas 元素來繪製和處理影像。
  • 使用 setInterval 來定期更新 canvas 上的影像。
  • 提供多種像素處理效果,如紅色效果、RGB 分裂效果和綠幕效果。