無論是讓使用者自訂顯示圖片、裁剪圖片,或是只是放大圖片,解碼圖片以便與畫布搭配使用都是相當常見的做法。解碼圖片的問題在於可能會耗用大量 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,讓後者在有時間時下載並解碼。然後將其轉移回主執行緒,以便繪製至畫布。

這麼做的程式碼可能如下所示:
// 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 中試用這項功能,並告訴我們使用心得!