無論是讓使用者自訂顯示圖片、裁剪圖片,或是只是放大圖片,解碼圖片以便與畫布搭配使用都是相當常見的做法。解碼圖片的問題在於,這項作業可能會耗用大量 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,也就是說,您現在可以在任何地方解碼圖片。如果有大量圖像需要解碼,請將這些圖片寄送到「網路工作處理序」,以便下載並解碼。然後將其轉移回主執行緒,以便繪製至畫布。
這麼做的程式碼可能如下所示:
// 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 一探究竟,並請告訴我們最新進展!