Chrome 50 支援在 Chrome 中使用 createImageBitmap()

Paul Lewis

無論是讓使用者自訂顯示圖片、裁剪圖片,或是只是放大圖片,解碼圖片以便與畫布搭配使用都是相當常見的做法。解碼圖片的問題在於,這項作業可能會耗用大量 CPU,有時可能會導致卡頓或顯示格狀圖像。自 Chrome 50 版起 (以及 Firefox 42 以上版本),您現在有另一個選項:createImageBitmap()。這可讓您在背景中解碼圖片,並存取新的 ImageBitmap 基本元素,您可以以與 <img> 元素、另一個畫布或影片相同的方式,將其繪製到畫布中。

使用 createImageBitmap() 繪製圓形

假設您使用 fetch() (或 XHR) 下載 blob 圖片,並想將其繪製到畫布上。如果沒有 createImageBitmap(),您必須建立圖片元素和 Blob 網址,才能將圖片轉換成可用的格式。有了這個功能,您就能更直接地進行繪圖作業:

fetch(url)
    .then(response => response.blob())
    .then(blob => createImageBitmap(blob))
    .then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));

此方法也適用於以 blob 形式儲存在 IndexedDB 中的圖片,讓 blob 成為便捷的中繼格式。Chrome 50 也支援在畫布元素上使用 .toBlob() 方法,這表示您可以從畫布元素產生 Blob。

在網路工作者中使用 createImageBitmap()

createImageBitmap() 最棒的功能之一,就是它也適用於 worker,也就是說,您現在可以在任何地方解碼圖片。如果有大量圖像需要解碼,請將這些圖片寄送到「網路工作處理序」,以便下載並解碼。然後將其轉移回主執行緒,以便繪製至畫布。

使用 createImageBitmap 和網頁工作站的資料流。

這麼做的程式碼可能如下所示:

// In the worker.
fetch(imageURL)
    .then(response => response.blob())
    .then(blob => createImageBitmap(blob))
    .then(imageBitmap => {
    // Transfer the imageBitmap back to main thread.
    self.postMessage({ imageBitmap }, [imageBitmap]);
    }, err => {
    self.postMessage({ err });
    });

// In the main thread.
worker.onmessage = (evt) => {
    if (evt.data.err)
    throw new Error(evt.data.err);

    canvasContext.drawImage(evt.data.imageBitmap, 0, 0);
}

目前,如果您在主執行緒上呼叫 createImageBitmap(),解碼作業就會在該執行緒上執行。不過,我們計畫讓 Chrome 自動在其他執行緒中進行解碼,以減少主要執行緒的工作負載。不過,您也應注意在主執行緒上進行解碼,因為這項工作負擔沉重,可能會阻斷其他重要工作,例如 JavaScript、樣式計算、版面配置、繪圖或合成。

輔助程式庫

為了讓生活更簡單一點,我建立了輔助程式庫,用於處理 worker 上的解碼作業,並將解碼後的圖片傳回至主執行緒,然後將其繪製至畫布。當然,您也可以視需要進行反向工程,將模型應用到自己的應用程式。主要優點是可提供更多控制選項,但與使用 <img> 元素相比,這會產生更多程式碼、需要更多偵錯作業,以及更多邊緣案例需要考量。

如果您需要進一步控制圖片解碼作業,createImageBitmap() 就是您的新好友。快透過 Chrome 50 一探究竟,並請告訴我們最新進展!