JS30-19-Webcam-Fun

利用視訊鏡頭顯示影片及拍照功能(+濾鏡效果)。

目標

  • 利用視訊鏡頭顯示影片及拍照功能(+濾鏡效果)。

實踐步驟

  1. 取得鏡頭影像
  2. MediaStream影像資料 寫入 canvas
  3. 新增拍照功能
  4. 新增濾鏡效果

成品

[DEMO] | [GitHub]


JS學習紀錄

第一次使用JS來操作鏡頭影像,所以紀錄一下整個過程,方便以後回想。

一、取得鏡頭影像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* step 1. 取得鏡頭影像 */
function getVideo() {
// 取得 user 的視訊裝置,並且回傳 Promise 狀態
navigator.mediaDevices.getUserMedia({
video: true, // 鏡頭
audio: false // 聲音
})
/* 回傳 MediaStream 的資料 */
.then(localMediaStream => {
console.log(localMediaStream);
/* 將 MediaStream 寫進 html的video標籤 */
video.src = window.URL.createObjectURL(localMediaStream);
/* 讓鏡頭持續運作 */
video.play();
})
.catch(err => {
console.error(`!!Error!!`, err);
});
}

// 啟動鏡頭
getVideo();

二、MediaStream影像資料 寫入 canvas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* step 2. MediaStream 寫入 canvas */
function paintToCanvas() {
const width = video.videoWidth;
const height = video.videoHeight;
canvas.width = width;
canvas.height = height;

// 用setInterval來持續取得目前的影像資訊
return setInterval(() => {
// 在 canvas 設置drawImage參數為 (資料來源video, 起始位置X軸, 起始位置Y軸, 長, 寬)
ctx.drawImage(video, 0, 0, width, height);
// ctx.drawImage(video, 0, 0, 200, 200);
}, 16)
}

/* 監聽video事件,是否啟動 鏡頭 了嗎 */
video.addEventListener('canplay', paintToCanvas);

三、新增拍照功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* step 3. 新增拍照功能 */
function takePhoto() {
// 將聲音切到 第0秒 並 播放
snap.currentTime = 0;
snap.play();

// 將 canvas的內容 轉為 base64的圖檔資訊
const data = canvas.toDataURL('image/jpeg');
// console.log(data);

// 用 createElemamnt 來建立一個新的 a 元素
const link = document.createElement('a');
// 設定連結為 base64圖檔
link.href = data;
// 設定屬性為:下載
link.setAttribute('download', 'picture');
// a元素裡新增一個 img
link.innerHTML = `<img src="${data}" alt="picture" />`;

// 將 a元素 新增至 strip圖片區塊(在第一筆的位置)
strip.insertBefore(link, strip.firstChild);
}

四、新增濾鏡效果

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function paintToCanvas() {
// ...略

// 用setInterval來持續取得目前的影像資訊
return setInterval(() => {
// 在 canvas 設置drawImage參數為 (資料來源video, 起始位置X軸, 起始位置Y軸, 長, 寬)
ctx.drawImage(video, 0, 0, width, height);
// ctx.drawImage(video, 0, 0, 200, 200);

+ /* 4. 新增濾鏡效果 */
+ // 透過 getImageData 取得 canvans 中所有的像素點(r,g,b,alpha的資訊)
+ let pixels = ctx.getImageData(0, 0, width, height);
+ // console.log(pixels);

+ // 透用濾鏡效果
+ // pixels = redEffect(pixels); // 4.1濾鏡效果(紅色)
+ pixels = rgbSplit(pixels); // 4.2濾鏡效果(三原色)
+ // ctx.globalAlpha = 0.1; // canvas 透明度
+ // pixels = greenScreen(pixels); // 4.3濾鏡效果(綠色)

+ // 寫入 濾鏡效果
+ ctx.putImageData(pixels, 0, 0);

}, 16)
}



+/* step 4-1. 濾鏡效果(紅色) */
+function redEffect(pixels) {
+ // ...略
+}

+/* step 4-2. 濾鏡效果(三原色) */
+function rgbSplit(pixels) {
+ // ...略
+}

+/* step 4-3. 濾鏡效果(綠色) */
+function greenScreen(pixels) {
+ // ...略
+}
canvas 圖像的資料都是數個陣列所組成,數據為數字,順序皆為 RGBA。