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