如何把 Video 畫在 Canvas 上
Hi 大家好,我是 Johnny,今天這篇來介紹個小玩意,如標題,該怎麼把 Video 畫在 Canvas 上呢?
背景
把 Video 畫在 Canvas 上可以有很多用處,比如我們可以對影像背景進行即時改變,或是給予其他更大的創意操作彈性,但...創意部份就留給大家發想了,本篇會專注在如何轉換的過程上摟~
實際效果
本篇會以 Vue 來實作,不過不會涉及太複雜的使用,只需要大概懂基礎就好
實作前,先實際展示 Canvas 影片效果給大家看~
試著把手機打橫、放直看看效果吧!
實作
首先我們把 video 先正確顯示在網頁上面,如下範例:
<div id="app">
<video playsinline loop>
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4" />
</video>
</div>
應該就能看到我們帥氣的影片出現拉~
接著我們將影片隱藏起來,並添加我們的目標 Canvas,預留兩個 ref 待後續使用
#app {
video {
display: none;
}
canvas {
width: 100%;
}
}
<div id="app">
<video ref="bgVideoRef" crossorigin="anonymous" playsinline loop>
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" type="video/mp4" />
</video>
<canvas ref="videoBg"></canvas>
</div>
接著處理我們的主要邏輯,透過監聽影片 loadeddata
事件,取得影片的實際寬高比例,並將 canvas 的 pixel resolution 設為影片寬高,透過這個方式才能維持原影片的畫質正確,否則預設 canvas 的 pixel 比例會是 300x150
canvas 元素上的 width, height 並不單單只影響 DOM 寬高,而是真正影響畫布的 pixel resolution,用 css style 影響的才是顯示的寬高,所以即使你用 css 去設定 canvas,如果沒有明確去定義 width, height 屬性,那麼內容的 pixel resolution 就仍然是預設的配置
// 為求方便直接用 option API 撰寫瞜~
Vue.createApp({
mounted() {
const vm = this
vm.initCanvas()
vm.initVideo()
},
methods: {
initCanvas() {
const vm = this
var canvas = this._canvas = this.$refs.videoBg;
this._ctx = canvas.getContext('2d');
},
initVideo() {
const canvas = this._canvas;
const ctx = this._ctx;
const videoEl = this.$refs.bgVideoRef;
const _display = videoEl.style.display;
let ratio = 1;
videoEl.style.display = 'block';
videoEl.addEventListener('loadeddata', () => {
// set canvas pixel resolution
canvas.width = videoEl.videoWidth;
canvas.height = videoEl.videoHeight;
// get video ratio
ratio = videoEl.videoHeight / videoEl.videoWidth;
// recover videoEl display
videoEl.style.display = _display;
// create fabric image
drawVideo();
// start
videoEl.play();
});
function drawVideo() {
ctx.drawImage(
videoEl,
0,
0,
canvas.width,
canvas.width * ratio
);
requestAnimationFrame(drawVideo);
}
},
},
}).mount('#app')
如果這時我們希望讓影片能夠自適應,並且始終填滿畫面,而將 CSS 改為如下
#app {
video {
display: none;
}
canvas {
width: 100vw;
height: 100vh;
}
}
這樣寫你會發現,我們的 Canvas 就被拉伸了~NO~~!! 影片內容是有填滿畫面沒錯,但是比例整個跑掉啦~
大家猜猜能怎麼解,5,4,3,2,1...
沒錯,直接在 Canvas 外面再包一層 .canvas-container
並且將內部的 Canvas 設為 object-fit
,搞定!!
#app {
video {
display: none;
}
.canvas-container {
width: 100vw;
height: 100vh;
canvas {
width: 100%;
height: 100%;
object-fit: cover;
}
}
}
那今天的分享就到這邊摟,希望大家會喜歡,也歡迎大家分享給更多人看看玩玩瞜,謝謝大家 =V=~