JavaScript の Canvas で画像を扱うとき、ImageBitmap にすることで描画の遅延を減らすことができます。
ただし、ImageBitmap はメモリ消費が大きい場合があるため、注意が必要です (※具体的な扱い方は後述) 。
ImageData は CORS によって取得できないことがありますが、ImageBitmap は取得できます。
参考「ImageBitmap - Web API | MDN」
参考「OffscreenCanvas: transferToImageBitmap() method - Web APIs | MDN」
1. 生成
1.1. createImageBitmap() 関数
一般的な画像ソースから ImageBitmap を生成するには createImageBitmap() 関数を用います。
const offscreenCanvas = new OffscreenCanvas(300, 150);
// ...
const imageBitmap = await createImageBitmap(offscreenCanvas);
const canvas = document.createElement('canvas');
// ...
const imageBitmap = await createImageBitmap(canvas);
※他にも createImageBitmap() 関数が使える型があります。
位置や大きさ等を指定することもできます。
const offscreenCanvas = new OffscreenCanvas(300, 150);
// ...
const imageBitmap = await createImageBitmap(offscreenCanvas, 100, 0, 100, 75);
※他の操作に関しては公式ドキュメント等参照。
参考「createImageBitmap() - Web API | MDN」
1.2. transferToImageBitmap() メソッド
OffscreenCanvas から ImageBitmap を取得して OffscreenCanvas を初期化するには transferToImageBitmap() メソッドを用います。
const offscreenCanvas = new OffscreenCanvas(300, 150);
// ...
const imageBitmap = offscreenCanvas.transferToImageBitmap();
参考「OffscreenCanvas: transferToImageBitmap() method - Web APIs | MDN」
※後述する transferFromImageBitmap() メソッドは transferToImageBitmap() メソッドと異なり、通常の HTMLCanvasElement でも使用可能です。
※ transferToImageBitmap() は OffscreenCanvas 型のメソッドですが、transferFromImageBitmap() は ImageBitmapRenderingContext 型のメソッドです。
1.3. createImageBitmap() 関数と transferToImageBitmap() メソッドの違い
OffscreenCanvas に関しては createImageBitmap() 関数でも transferToImageBitmap() メソッドでも ImageBitmap を得ることができますが、以下の表のような違いがあります。
createImageBitmap() 関数 |
transferToImageBitmap() メソッド |
|
|---|---|---|
| 画像ソースの型 |
HTMLImageElementSVGImageElementHTMLVideoElementHTMLCanvasElementBlobImageDataImageBitmapOffscreenCanvas
|
OffscreenCanvas |
| 画像ソースの扱い | そのまま | 初期化 |
| 位置や大きさ等を指定 | 可 | 不可 |
| 処理方法 | 非同期 | 同期 |
2. 描画および破棄
2.1. transferFromImageBitmap() メソッド
HTMLCanvasElement または OffscreenCanvas に ImageBitmap 全体を描画して ImageBitmap を破棄するには transferFromImageBitmap() メソッドを用います。
const context = canvas.getContext('bitmaprenderer');
context.transferFromImageBitmap(imageBitmap);
const offscreenContext = offscreenCanvas.getContext('bitmaprenderer');
offscreenContext.transferFromImageBitmap(imageBitmap);
ちなみに、Canvas と大きさが一致しない ImageBitmap を transferFromImageBitmap() メソッドで描画すると内部的には ImageBitmap の大きさで扱われますが、Canvas の width および height は更新されないため注意が必要です。
//
const offscreenCanvasA = new OffscreenCanvas(300, 300);
const imageBitmapA = await createImageBitmap(offscreenCanvasA);
console.log(imageBitmapA.width, imageBitmapA.height);
//
const offscreenCanvasB = new OffscreenCanvas(300, 150);
const offscreenContextB = offscreenCanvasB.getContext('bitmaprenderer');
offscreenContextB.transferFromImageBitmap(imageBitmapA);
console.log(offscreenCanvasB.width, offscreenCanvasB.height);
const imageBitmapB = await createImageBitmap(offscreenCanvasB);
console.log(imageBitmapB.width, imageBitmapB.height);
300 300
300 150
300 300
※ transferFromImageBitmap() メソッドは transferToImageBitmap() メソッドと異なり、通常の HTMLCanvasElement でも使用可能です。
※ transferToImageBitmap() は OffscreenCanvas 型のメソッドですが、transferFromImageBitmap() は ImageBitmapRenderingContext 型のメソッドです。
参考「ImageBitmapRenderingContext: transferFromImageBitmap() method - Web APIs | MDN」
2.2. close() メソッド
drawImage() メソッド等、transferFromImageBitmap() メソッド以外でも ImageBitmap を描画することができますが、その場合は ImageBitmap が破棄されないため、close() メソッドを呼ぶことで明示的に破棄します。
const context = canvas.getContext('2d');
context.drawImage(imageBitmap, 0, 0);
imageBitmap.close();
const offscreenContext = offscreenCanvas.getContext('2d');
offscreenContext.drawImage(imageBitmap, 0, 0);
imageBitmap.close();
参考「CanvasRenderingContext2D: drawImage() メソッド - Web API | MDN」
参考「WebGLRenderingContext: texImage2D() method - Web APIs | MDN」
参考「ImageBitmap.close() - Web API | MDN」
2.3. transferFromImageBitmap() メソッドと drawImage() メソッドの違い
transferFromImageBitmap() メソッドでも drawImage() メソッドでも ImageBitmap を描画することができますが、以下の表のような違いがあります。
transferFromImageBitmap() メソッド |
drawImage() メソッド |
|
|---|---|---|
| Context の型 | ImageBitmapRenderingContext |
CanvasRenderingContext2D |
| 画像ソースの型 | ImageBitmap |
HTMLImageElementSVGImageElementHTMLVideoElementHTMLCanvasElementImageBitmapOffscreenCanvasVideoFrame
|
| 画像ソースの扱い | 破棄 | そのまま |
| 位置や大きさ等を指定 | 不可 | 可 |
3. ImageBitmap を使うべきでない状況
頻繁に ImageBitmap を生成しつつ drawImage() メソッドで描画するような使い方だと ImageBitmap の恩恵を得にくいため、直接 Canvas を drawImage() メソッドで描画した方が良いです。
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const offscreenCanvas = new OffscreenCanvas(300, 150);
// ...
context.drawImage(offscreenCanvas, 0, 0);
参考「CanvasRenderingContext2D: drawImage() メソッド - Web API | MDN」
参考「WebGLRenderingContext: texImage2D() method - Web APIs | MDN」