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

Paul Lewis

將圖片解碼成畫布使用的做法相當常見,例如可讓使用者自訂顯示圖片、裁剪圖片或單純放大圖片。將圖片解碼時的問題在於可能會耗用大量 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,網頁工作人員會盡可能下載這些圖片並進行解碼。然後將圖片轉移回主執行緒,以便繪圖至畫布。

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 版本,並告訴我們你的使用體驗!