Posted at

canvasの図形を画像として出力する時のブラウザ毎の処理

More than 1 year has passed since last update.

canvasに描かれた図形を画像として出力する方法としてデータURIスキームの方法もありますがBlobを使用した出力方法もあるので、それぞれのブラウザ毎に出力を分けてローカルに保存できるようにしてみます。


canvasの図形を画像出力する

既に何か描かれているcanvas要素から画像を出力するコードです。

var

// canvas要素
canvas = document.querySelector('#canvas'),

// 出力した画像を表示するimg要素
image = document.querySelector('#outputImg'),

// 画像のダウンロードリンク
link = document.querySelector('#downloadLink'),

blob, imageURL;

// リンクにdownload属性を設定
link.download = 'canvas.png';

if (canvas.toBlob) {
// HTMLCanvasElement.toBlob() が使用できる場合

// canvasの図形をPNG形式のBlobオブジェクトに変換
canvas.toBlob(function (blob) {
// BlobオブジェクトにアクセスできるURLを生成
imageURL = URL.createObjectURL(blob);

// 要素にURLを適用
image.src = imageURL;
link.href = imageURL;
});

} else if (canvas.msToBlob) {
// IE10以降やEDGEで使えるメソッド

// canvasの図形からPNG形式のBlobオブジェクトを取得
blob = canvas.msToBlob();

// BlobオブジェクトにアクセスできるURLを生成
imageURL = URL.createObjectURL(blob);

// 要素にURLを適用
image.src = imageURL;
link.href = imageURL;

// IEとEDGEの場合 navigator.msSaveBlob() でBlobオブジェクトを保存できるメソッドがある
link.addEventListener('click', function (ev) {
ev.preventDefault();
navigator.msSaveBlob(blob, 'canvas.png');
});

} else {
// Blobオブジェクトに変換できない場合はPNG形式のデータURIスキームとして出力
imageURL = canvas.toDataURL();

// 要素にURLを適用
image.src = imageURL;
link.href = imageURL;
}

Blobオブジェクト用のURLは blob:https://example.com/12345678-1234-5678-9012-123456789012blob:12345678-1234-5678-9012-123456789012 といったような特殊なものになっています。

実際にサーバーにこのファイルがあるわけではなく、ブラウザ内部で持っているバイナリデータにアクセスするためのURLみたいなものですね。

このURLは URL.revokeObjectURL(blobURL) を使用したり、他のページへ遷移した時に破棄されます。

HTMLCanvasElement.toBlob() が非同期処理なのに対し、IE・EDGE独自実装の HTMLCanvasElement.msToBlob() は非同期処理ではないので大きな図形を扱う場合 msToBlob() では変換が終わるまで他のコードが実行できない事になります。

HTMLCanvasElement.toBlob() - Web API インターフェイス | MDN

MDNに HTMLCanvasElement.toBlob() のポリフィルもありますが、あくまでこういう処理でできるよ程度のものなので、パフォーマンスを考えると実用的ではありません。


Blobオブジェクトのメリット

Blobオブジェクトであれば blob.size のように出力後のファイルサイズを取得することができます。

他にもimg要素に出力する時、データURIスキームだと画像のデータがテキストデータとして存在することになるので大き目の画像の場合ブラウザ側の動作が重くなる可能性がありますが、Blobオブジェクトの場合はブラウザ内部にバイナリデータとして持っているので動作は軽いです。

Blob - Web API インターフェイス | MDN