---
# System prepended metadata

title: '[JS30] Day.19 Unreal Webcam Fun'
tags: [JS30]

---

# [JS30] Day.19 Unreal Webcam Fun
###### tags: `JS30`
## 任務 Task
控制鏡頭相機顯示在 `canvas` 上，並能套上濾鏡呈現效果。

==完成時間：2hr==
## 步驟 Step
1. 使用瀏覽器物件（BOM）的 `navigator` 取得 `mediaDevice` 。
2. 再 `getUserMedia` 取得 `promise` 物件，丟給  `video.srcObject`，就可以播放螢幕畫面。
```javascript=
navigator.mediaDevices
    .getUserMedia({ video: true, audio: false })//只取螢幕畫面，而不取聲音
    .then((localMediaStream) => {
        video.srcObject = localMediaStream;
        video.play();
        })
    .catch((err) => {
        console.error("OH NO", err);
        });
```
3. 建立一個 `paintToCanvas function` 設定畫布尺寸同影像尺寸。
4. 將影像用 `ctx.drawImage` 的方式渲染到畫布上，但因為是圖片，所以需要包在時間函數 `setInterval` 每隔 16 毫秒重新渲染，就會呈現出影片。
```javascript=+
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);
    }, 16);
}
```
5. 監聽影像當可以播放時，就執行 `paintToCanvas()`
```javascript=
video.addEventListener("canplay", paintToCanvas);
```
6. 建立 `takePhoto function` 可以擷取影像並下載。
7. 使用 `canvas.toDataURL` 取得影像網址，放入 `anchor tag href` 裡，並在裡面放入擷取的圖片。
```javascript=
function takePhoto() {
    snap.currentTime = 0;
    snap.play();
    const data = canvas.toDataURL();
    const link = document.createElement("a");
    link.href = data;
    // link.setAttribute("download", "handsome");
    link.download = "he";
    link.innerHTML = `<img src="${data}" alt="Handsome Man" />`;
    strip.appendChild(link);
}
```
8. 濾鏡效果，是讀取每個螢幕像素的顏色，去做更改調色。
```javascript=
let pixels = ctx.getImageData(0, 0, width, height);//取得每個 pixel 的 rgba 
function redEffect(pixels) {
    for (let i = 0; i < pixels.data.length; i += 4) {
        pixels.data[i + 0] = pixels.data[i + 0] + 10;
        pixels.data[i + 1] = pixels.data[i + 1] - 50;
        pixels.data[i + 2] = pixels.data[i + 2] * 0.5;
    }
    return pixels;
}
//更改每個像素的 rgba 呈現不同顏色的效果。
```
9. 建立 `greenScreen function` 呈現去背效果。
10. 概念是當像素顏色介於制定的 `max` 跟 `min` 之間時，就將透明度變成 `0` ，就可把該像素顏色去掉。
## 筆記 Note
### <font color=#337EA9>JS Navigator.mediaDevices</font>
* 語法：
```javascript=
navigator.mediaDevices
  .getUserMedia(/** setting media constraints */)
  .then(/** handle Success */)
  .catch(/** handle Error */)
```
* `Navigator` 允許讀取用戶的瀏覽器資料，包含：設定語言、讀取音訊視訊、當前的座標、用電量等等。
* `navigator.mediaDevices.getUserMedia` 回傳的是 `promise` 物件，可以使用 `then` 及 `catch` 來處理。
### <font color=#337EA9>JS debugger</font>
* 建立斷點，進行除錯，但不影響後面程式碼的執行。
* 當想檢查特定程式碼時可以透過斷點去檢查，在此專案則是利用 `debugger;` 去讓 `console.log` 不要一直跑，是個很方便的偵錯語法。
### <font color=#337EA9>16毫秒</font>
* 在設定 `setInterval()` 時，是設定成 16 毫秒，原因在於畫面的螢幕更新率。
* 基本上從 `60Hz` `120Hz` `144Hz` 甚至到 `300Hz`都有，而在控制台>顯示器>進階裡就可以看到螢幕的頻率。

    ![](https://i.imgur.com/1NQ5eBs.jpg)
    
    可以看到 ==重新整理頻率(Hz)== 為 60.052Hz，意思是每秒更新 60 次，也就說更新一次是 1000(ms) / 60  = 16.6666 (ms)，也就是說 16 毫秒是最快的螢幕渲染速度了，再更低也不會讓畫面更順暢了。

### <font color=#337EA9>去背</font>
* 一般在拍電影的時候使用的綠幕去背，也是用一樣的道理，將像素內含綠色的像素設成透明的，就可去背了。
* 之所以都是用綠色，是因為綠色跟皮膚的顏色相差最遠，如果使用紅色很容易把人也去掉，而藍幕也是有人在用，不過因為藍色比起綠色所使用的機會較高，所以現在大部分都使用綠幕較多。
