將圖片解碼成畫布使用的做法相當常見,例如可讓使用者自訂顯示圖片、裁剪圖片或單純放大圖片。將圖片解碼時的問題在於可能會耗用大量 CPU,而這有時可能代表資源浪費或檢查畫面。自 Chrome 50 版 (以及 Firefox 42 以上版本) 起,您現在可選擇createImageBitmap()
。這可讓您在背景將圖片解碼,並取得新的 ImageBitmap
原始物件。原始檔案可以繪製在畫布,方法與使用 <img>
元素、其他畫布或影片相同。
使用 createImageBitmap() 繪製 blob
假設您使用 fetch()
(或 XHR) 下載 blob 圖片,並想要將其繪製到畫布上。如果沒有 createImageBitmap()
,您必須建立圖片元素和 Blob 網址,將圖片轉換成可用的格式。如此一來,繪畫路徑就能更加直接:
fetch(url)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));
這個方法也適用於儲存在 IndexedDB 中做為 blob 的圖片,使 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 版本,並告訴我們你的使用體驗!