JS30 day19 - Webcam Fun
作業內容
今天的難度又突然提升了,主要內容在玩弄攝影機的畫面,並改造成類似靈異現象的效果,像下面這張圖這樣
學到什麼
-
JS
1. 如何拿到 live 的攝影畫面
要使用攝影機有一個內建的 js 方法
navigator.mediaDevices.getUserMedia
,要注意的是他回傳的是 Promise 物件,詳細內容可以直接看下面參考資料
除此之外要注意localMediaStream
是一個物件,我們必須利用一些特定方法把這個物件轉成 url 才能使用,在這裡使用的方法是設定 video 的srcObject
屬性,等於把這個物件設成 url 的型態1
2
3
4
5
6
7
8
9
10
11function getVideo(){
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(localMediaStream => {
video.srcObject = localMediaStream;
video.play()
})
// 使用 catch 來捕捉例外
.catch(err => {
console.log('Oh No!!', err);
})
}srcObject
navigator.mediaDevices.getUserMedia2. 拍照功能:
toDataURL()
是只有 HTMLCanvasElement 這個元素可以使用的方法,他可以把圖片轉換成Base64編碼,裡面可以放兩個值,第一個是圖像格式,預設為image/png
,第二個是圖像品質,介於 0 - 1之間,兩個都是非必填參數
轉 Base64 通常用在小圖片,因為大圖片編碼起來會很長,好處是可以把編碼包到 HTML / CSS /JS 中,比較方便,壞處是圖片不會被快取起來
超連結有個屬性叫做 download<a href="..." download="檔名.txt">點選下載</a>
如果有這個屬性就會強迫下載1
2
3
4
5
6
7
8
9
10
11
12
13
14function takePhoto(){
// 發出聲音
snap.currentTime = 0
snap.play()
// 拍照
// 利用toDataURL把canvas的內容轉為base64的圖檔資訊
const data = canvas.toDataURL('image/jpeg')
const link = document.createElement('a')
link.href = data
link.setAttribute('download', 'hansome')
link.textContent = 'Download Image'
//insertBefore 在 Jquery 等同於 prepend
strip.insertBefore(link, strip.firstChild)
}3. 把畫面呈現在畫布上
之前有說過,畫圖不是直接畫在 canvas 而是畫在他的 context 上,所以這邊選擇的節點是 ctx 不是 canvas
drawImage()
裡的參數為 image, x, y, width, height,最後兩個參數是縮放參數,非必填
getImageData()
回傳的值為 ImageDate 物件,它代表著這個 canvas 上某部分的像素,這個像素使用 debugger 抓出來會長的像下面那樣,每個數字分別代表 RGBA 的數值:第一個數字代表紅色,第二個是綠色,第三個是藍色,第四個是 alpha 值,第五個是紅色… 以此類推1
2
3
4
5
6
7
8
9
10
11
12
13function paintToCanvas(){
const width = video.videoWidth
const height = video.videoHeight
canvas.width = width
canvas.height = height
return setInterval(function(){
ctx.drawImage(video, 0, 0, width, height)
const pixels = ctx.getImageData(0, 0, width, height)
console.log(pixels)
debugger
}, 16)
}
了解 pixels 排列方式之後,就可以來改變輸出的影像了!
不管怎麼改造,其實做的順序都一樣:把 pixels 取出,讓他經過 function 變化之後再把改造完的 pixels 放回去1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20function paintToCanvas(){
const width = video.videoWidth
const height = video.videoHeight
canvas.width = width
canvas.height = height
return setInterval(function(){
ctx.drawImage(video, 0, 0, width, height);
//把 pixels 取出
let pixels = ctx.getImageData(0, 0, width, height);
// 用 function redEffect處裡
// pixels = redEffect(pixels);
// 用 function rgbSplit處裡
pixels = rgbSplit(pixels);
// 用 globalAlpha 屬性改變透明度
ctx.globalAlpha = 0.8
// 放回去
ctx.putImageData(pixels, 0, 0);
}, 16)
}其實最後有個 greenScreen 的效果還沒摸透怎麼回事 XD,等之後更熟悉前端之後再回來看可能會好點!
參考資料:
https://github.com/wesbos/JavaScript30
code 內容:
HTML:
1 | <div class="photobooth"> |
CSS:
1 | html { |
JS:
1 | const video = document.querySelector('.player'); |