[程式碼&DEMO] [HackMD完整筆記]
驅動webcam來紀錄影像資訊,再用cavas達成拍照與濾鏡效果。
預設的配置:
STEP0.建立一個localhost服務器
STEP1 取得影像
function getVideo() {
   // 取得視訊裝置,回傳Promise狀態
  navigator.mediaDevices.getUserMedia({ video: true, audio: false })
  
    //允許就把回傳的MediaStream寫進html的video tag中進行播放
    .then(localMediaStream => {
      console.log(localMediaStream);   
      video.srcObject = localMediaStream;
      video.play();
    })
    
    //失敗就印出錯誤結果
    .catch(err => {
      console.error(`OH NO!!!`, err);
    });
}
navigator.mediaDevices.getUserMedia()取得攝影鏡頭的權限。
返回一個promise對象。
STEP2 擷取視訊影像放到canvas中
function paintToCanvas() {
  //設定畫布大小
  const width = video.videoWidth;
  const height = video.videoHeight;
  canvas.width = width;
  canvas.height = height;
  /// 用setInterval來不斷地取得目前影像資訊
  return setInterval(() => {
    //將畫面擷取下來
    ctx.drawImage(video, 0, 0, width, height);
    //獲取canvas區域內的像素數據存進pixels變數中
    let pixels = ctx.getImageData(0, 0, width, height);
    //呼叫rgbSplit()把rgb像素分離
    pixels = rgbSplit(pixels);
    //將ImageData的數據繪製到圖像上
    ctx.putImageData(pixels, 0, 0);
  }, 16);
}
STEP3 製作拍照功能
function takePhoto() {
  // 拍照的音效
  snap.currentTime = 0;//音效從第0秒開始播放
  snap.play();
  // 用.toDataURL把canvas內容轉成base64的圖檔資訊
  const data = canvas.toDataURL('image/jpeg');
  //建立一個新的<a>元素
  const link = document.createElement('a');
  //設置連結位置為轉圖檔後的base64位置
  link.href = data;
  // 設置連結屬性為下載
  link.setAttribute('download', 'handsome');
  // 新增一個預覽圖
  link.innerHTML = `<img src="${data}" alt="Handsome Man" />`;
  //在圖片區插入新圖片(在第一筆的位置)
  strip.insertBefore(link, strip.firstChild);
}
STEP4 製作濾鏡效果
function redEffect(pixels) {
//用迴圈將取回的所有像素資料全部跑一次,四個一組(r,g,b,alpha)
  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;
}
把紅的項目加深處理,藍綠的項目-50及減半。
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) {
      // take it out!
      pixels.data[i + 3] = 0;
    }
  }
  return pixels;
}
語法:var promise = navigator.mediaDevices.getUserMedia(constraints);
建立一個帶有URL的DOMString,代表參數值中傳入的物件。此URL的生命週期與創造它的window一樣。