「JavaScript 30」學習筆記(十九)

前言

本文為「JavaScript 30」教學影片的學習筆記。

目標

驅動視訊,並輸出到 Canvas 畫布上,對視訊影像進行截圖與濾鏡處理。

筆記

首先使用 gum 套件建立一個本機伺服器。

1
2
npm install
npm start

取得視訊影像的位置元素。

1
const video = document.querySelector('.player');

取得 Canvas 畫布的位置元素。

1
const canvas = document.querySelector('.photo');

取得 Canvas 畫布本身。

1
const ctx = canvas.getContext('2d');

取得產生截圖的位置元素。

1
const strip = document.querySelector('.strip');

取得照相時的音效元素。

1
const snap = document.querySelector('.snap');

設定一個 getVideo() 方法以取得視訊影像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getVideo() {
// 取得視訊的權限,會回傳一個 Promise 物件
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(localMediaStream => {
// 視訊來源是一個帶有 URL 的 DOMString
video.src = window.URL.createObjectURL(localMediaStream);
// 放出視訊影像
video.play();
})
.catch(err => {
// 例外狀況
console.log(`OH NO!!!`, err);
})
}

設定一個 paintToCanvas() 方法以將視訊影像繪製到畫布上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function paintToCanvas() {
// 設定視訊影像寬度
const width = video.videoWidth;
// 設定視訊影像長度
const height = video.videoHeight;
// 設定畫布寬度
canvas.width = width;
// 設定畫布長度
canvas.height = height;

// 設定運行週期是 16 毫秒
return setInterval(() => {
// 在畫布上繪製視訊影像
ctx.drawImage(video, 0, 0, width, height);
// 取出畫布所有像素
let pixels = ctx.getImageData(0, 0, width, height);
// 紅色濾鏡
// pixels = redEffect(pixels);
// RGB 濾鏡
// pixels = rgbSplit(pixels);
// 去背功能
pixels = greenScreen(pixels);
// 放回畫布所有像素
ctx.putImageData(pixels, 0, 0);
}, 16);
}
  • setInterval() 方法可按照指定的週期來調用方法。

設定一個 greenScreen() 方法以配合滑桿達到去背的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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) {
pixels.data[i + 3] = 0;
}
}

return pixels;
}

執行 getVideo() 方法,以取得視訊影像。

1
getVideo();

監聽視訊影像,如果 canplay 事件發生,就觸發 paintToCanvas 方法。

1
video.addEventListener('canplay', paintToCanvas);