【JavaScript】 Canvasの画像をPNG/JPEGとして保存(ダウンロード)する
更新日:2022/08/01
直接保存できない
Canvasはブラウザ上で動作するAPIです。
ブラウザのAPIは、PCやスマホのファイルシステムを操作できません。
そのため、疑似的にリンククリックしてファイルのダウンロードとして、保存します。
一時的にリンクを作成して疑似的にクリック
const a = document.createElement("a"); // a要素の作成
a.href = url; // href属性のセット
a.download = "image.jpg"; // ファイル名のセット
a.click(); // 疑似的にクリック
このとき、href属性にCanvas画像をPNGやJPEGに変換した画像のURLをセットします。
URLを生成する方法は、CanvasのtoDataURL()を呼び出す方法と、toBlob()を使う方法の2種類あります。
toDataURL()を使う
次のようにtoDataURL()を使うと、Canvasの画像をPNGやJPEGで保存できます。
const a = document.createElement("a");
a.href = canvas.toDataURL("image/jpeg", 0.75); // PNGなら"image/png"
a.download = "image.jpg";
a.click();
toDataURL()の書式
canvas.toDataURL( MIMEタイプ , 品質 )
第一引数は、"image/png"や"image/jpeg"などのMIMEタイプを指定します。
指定がないと"image/png"とみなされます。
第二引数は画像の品質で0から1で指定します。
これは、圧縮率と解釈してよさそうです。
toDataURLは、内部でPNGやJPEGのバイナリイメージを作成します。
次に、バイナリをBase64という方式で文字列に変換します。
そして、この文字列の前に、次の文字列を配置します。
data:[タイプ];base64,
[タイプ]はtoDataURLの第一引数です。
toDataURLに対応していないMIMEタイプを指定すると、"image/png"で処理されます。
そのため、戻り値に指定したMIMEタイプが含まれているかどうかで、対応しているかどうか判断できます。
リンクがクリックされると、base64がバイナリに展開されてダウンロードされます。
ここで、えっ!と思う人は多いはず。
バイナリ→テキスト→バイナリと、ムダな手間をかけていますね。
また、Base64は元のデータよりも1.3から1.4倍になります。
ただし、これは一文字1バイトとして計算したものです。
実はJavaScriptは一文字2バイトです。
そのため、メモリサイズは2.6から2.8倍に膨らみます。
手間だけでなく、メモリ消費も大きいですね。
toBlob()を使う
toBlob()は、toDataURL()よりも効率がいいです。
canvas.toBlob( blob =>{
const a = document.createElement("a");
a.src = URL.createObjectURL(blob);
a.download = "image.jpg";
a.click();
URL.revokeObjectURL(link.href);
},types[type],0.7);
toBlob()の書式
canvas.toBlob( コールバック , MIMEタイプ , 品質 )
第一引数は、生成されたblobオブジェクトを引数とするコールバック関数です。
第二引数は、"image/png"や"image/jpeg"などのMIMEタイプを指定します。
指定がないと"image/png"とみなされます。
第三引数は画像の品質で0から1で指定します。
これは、圧縮率と解釈してよさそうです。
createObjectURLは、blobオブジェクトを指し示す内部的なURLを生成します。
そして、リンクがクリックされるとblobオブジェクトが参照されてダウンロードされます。
生成されたバイナリが、そのままダウンロードされるので効率がいいです。
なお、createObjectURLを呼び出したら、revokeObjectURLを呼び出す必要があります。
どちらがいいのか
細かいことまで気にするならtoBlobが良さそうですが、個人的には今はPCやスマホの性能が高いので、どちらでもいいと思います。
更新日:2022/08/01
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。