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,也就是說,您現在可以在任何地方解碼圖片。如果您有許多非必要的圖片需要解碼,請將這些圖片的網址傳送至 Web 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 中試用這項功能,並告訴我們使用心得!