iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 20
2
Modern Web

用 Javascript 當個影像魔術師系列 第 20

Day 20 - Canvas 效能調整 - OffscreenCanvas 及 ImageBitmap (上)

API 介紹

這次主要會實作 ImageBitmap 以及 OffscreenCanvas 兩個新的 API,這兩個目前支持度最好的目前只有最新版的 chrome,所以目前在使用上請記得相容性問題。那就繼續往下吧!

ImageBitmap

還記得上章說過在主線程跟 worker 中傳遞的資料會在兩邊都被複製一份,所以在資料大時會造成額外的開銷,除了有實作 Transferable 介面的ArrayBufferMessagePortImageBitmapOffscreenCanvas 這幾種類型,傳遞上可以想像成物件類型的傳遞,是使用址來做為傳遞,所以不會在進行複製。

所以我們現在要做的事情就是將從 video 取回來的影像轉為 ImageBitmap 傳遞給 worker,並且將濾鏡在裡面計算完畢。我們先在 play 成功之後進行下列動作,

  1. 使用 captureStream ,這個將會回傳一個 MediaStream 物件,可以讓我們獲得即時的資料
  2. 接著使用 getVideoTracks 來獲得目前的影像 ( getVideoTracks 會回傳目前所有軌道的影像,因為我們目前只有一軌,所以直接拿第一個, MediaStream 也可以增加軌道或者音頻,如果要做編輯或混音的時候可能會用到 )
  3. 接著將拿到的 videoImageCapture 使用, ImageCapture 提供了一些方法可以將目前的影片保存下來,將下來我們會使用其中一個。
 video
    .play()
    .then(() => {
      console.log('play video start')
      const stream = video.captureStream()
      const track = stream.getVideoTracks()[0]
      this.capture = new ImageCapture(track)
      this.drawCanvas()
    })

做完上面的初始化之後,接著在原本更新畫面的方法裡面做一些改變,主要就是使用 grabFrame,這個將會回傳一個 ImageBitmap,所以我們就可以使用 postMessage 傳遞,要注意的是第二個參數我們使用了 [imageBitmap] ,有實作 Transferable 的物件類型,可以通過此方法,將資料不需透過複製就傳給 worker,但要注意的是在傳遞過後,主線程就喪失了這個資料的使用權。

this.capture
    .grabFrame()
    .then(imageBitmap => {
      worker.postMessage(
        {
          imageBitmap,
          sliderValue: this.sliderValue,
          type: 'process'
        },
        [imageBitmap]
      )
    })
    .catch(err => {
      // 目前發現不會每次都成功,似乎跟原本影片 fps 沒有達到瀏覽器更新頻率有關
      // console.log('play video error', err)
    })

接著在 worker 裡接收

let imageBitmapTmp
let sliderValueTmp

onmessage = function(e) {
 if (e.data.type === 'process' && context) {
    const { imageBitmap, sliderValue } = e.data
    imageBitmapTmp = imageBitmap
    sliderValueTmp = sliderValue
  }
}

到這裡我們就成功將圖像送給 worker ,接下來遇到的問題就是我們平時是使用 Canvas 去獲得最後要修改的 ImageData ,但是在 worker 裡面卻無法獲得 DOM,明天來看要如何解決吧!

小結

拉達克的首都最熱鬧的一條街,雖然是首都但也是電力不穩,不過已經是這趟旅程裡面生活機能最好的地方了

今天提到了 ImageBitmap ,其實他的創造來源可以有很多種,圖片、SVG等都可以當作來源。在使用上 MDN 表示使用在 CavasWebGL 上會更有效率。而且在 worker 中也可以使用,所以如果以後有圖片需要載入的動作就可以透過 worker 進行。那就明天見囉!


上一篇
Day 19 - Canvas 效能調整 - Web Worker
下一篇
Day 21 - Canvas 效能調整 - OffscreenCanvas 及 ImageBitmap (下)
系列文
用 Javascript 當個影像魔術師30

尚未有邦友留言

立即登入留言