目標
我們先來觀察一下html吧
<div class="photobooth">
<div class="controls">
<button onClick="takePhoto()">Take Photo</button>
</div>
<canvas class="photo"></canvas>
<video class="player"></video>
<div class="strip"></div>
</div>
<audio class="snap" src="http://wesbos.com/demos/photobooth/snap.mp3" hidden></audio>
首先我們有一個video.player
,可以用來播放攝像頭拍到的影片
接著我們會將擷取到的影片畫到canvas.photo
上
const video = document.querySelector('.player');
function getVideo() {
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(mediaStream => {
try {
video.srcObject = mediaStream;
} catch (err) {
video.src = window.URL.createObjectURL(mediaStream);
}
video.play();
});
};
getVideo();
我們要如何讀取攝像頭的影片呢?
可以使用navigator.mediaDevices
來麥克風、攝影機或共享螢幕的連結
接著使用.getUserMedia()
來取得許可.getUserMedia(constraints)
的constraints參數有2個video
和audio
用來說明請求media的類型
必須至少一個可以被指定,寫法是
{video: boolean, audio: boolean}
我們這邊給video
屬性值設定true
而audio
屬性值設定false
表示我們只要得到攝像頭的視訊,不需要麥克風的音訊getUserMedia()
會讓我們得到一個Promise物件
再用.then
來得到MediaStream這個物件
原本的寫法是
video.src = window.URL.createObjectURL(mediaStream)
但是這個方法即將在2018的12月被捨棄
所以我們改用另外一個方法
video.srcObject = mediaStream;
為了避免有寫瀏覽器不支援
所以我們使用try{} catch {}
來讓第一種方法不適用時
切換成第二種方法
這種方式寫起來更簡單
將HTMLMediaElement
的srcobject
屬性拿來存放MediaStream
做其來源
最後用.play()
播放video
即可
不要忘了getVideo()
,執行函式
這樣就可以得到攝像頭的影片了
接下來我們要將得到的影片畫到畫布上CanvasRenderingContext2D
提供課多種方式在canvas上繪製圖像
其中一個語法是我們今天可以使用的
ctx.drawImage(image, dx, dy, dWidth, dHeight);
可以放canvas的圖像來源
如果單看MDN上的解釋,可能會一知半解
其實就是「從canvas
的哪裡開始畫」
如果都是0的話
就是從左上角開始畫
在canvas上繪製的寬度/高度,允許對繪製的圖進行縮放
我們使用setInterval
來更新我們的canvas
讓攝像頭拍到的影片能一直更新在canvas上
const canvas = document.querySelector('.photo');
const ctx = canvas.getContext('2d');
function paintToCanvas() {
const width = video.videoWidth;
const height = video.videoHeight;
//使canvas的像素等同於video的像素
canvas.width = width;
canvas.height = height;
//每16ms更新一次canvas
return setInterval(() => {
ctx.drawImage(video, 0, 0, width, height);
}, 16);
}
video.addEventListener('canplay', paintToCanvas);
再來就是拍照功能了
在按鈕被點擊後會觸發takePhoto()
首先先播放「喀嚓」的聲音吧
之前學過要播放聲音時
先設定.currentTime = 0
這樣才可以在短時間拍多張照片時
可以有多次喀嚓的聲音
<button onClick="takePhoto()">Take Photo</button>
const strip = document.querySelector('.strip');
const snap = document.querySelector('.snap');
function takePhoto() {
//play the sound
snap.currentTime = 0;
snap.play();
//設置圖片成dataURL的格式,存在網頁上
const data = canvas.toDataURL('image/jpeg');
//設置連結
const link = document.createElement('a');
link.href = data;
link.setAttribute('download', 'handsome');
link.innerHTML = `<img src="${data}" alt="Handsome Man">`
strip.insertBefore(link, strip.firstChild);
}
可以將圖片儲存在網頁上
語法
canvas.toDataURL(type, encoderOptions);
預設為image/png
,可設定為image/jpeg
在image/jpeg
或image/webp
下,可以設定0~1,調整圖片的畫質
預設是0.92
並給他一個連結link
,href
指定到剛剛存圖片的(toDataURL
)變數data
然後<a>
的屬性download
設置,可以使使用者點擊連結時,下載圖片
其值則是download的預設名稱
最後只要將link
這個<a>
innerHTML
一個img
並使用insertBefore
將他顯示在.strip
上即可
語法
parentNode.insertBefore(newElement, referenceElement);
在參考的element前加入新的element
以上是如何擷取攝像頭的照片到canvas,並拍照下載
明天來替canvas上影像增加效果