- 著者
- app-hacks
- 公開日
- 更新日
- 確認日
Canvas API / WebP / JavaScript
Canvas APIによるブラウザ内WebP変換・圧縮
WebP変換ツールを基に、画像読込、Canvas変換、品質指定、透過、Blobダウンロードをブラウザ内で行う方法を解説します。
Canvas APIによるブラウザ内WebP変換・圧縮
ブラウザ内で画像をWebPへ変換する場合、画像をサーバーへ送らずにCanvas APIで処理できます。ただし、ファイル選択、画像の読み込み、Canvasへの描画、Blobの生成、Object URLの解放を別々に扱わないと、壊れたプレビューやメモリリークにつながります。
この記事では、JPG・PNGを受け取り、ブラウザ内でWebPを生成してダウンロードする基本の流れを説明します。実際の変換は画像WebP変換・圧縮ツールで試せます。
画像ファイルだけを受け付ける
ファイル入力のaccept属性は選択画面の補助にはなりますが、処理側でもMIMEタイプを確認します。対象外のファイルをCanvasへ渡す前に止め、利用者に選び直しを案内します。
function isSupportedImage(file: File) {
return file.type === 'image/jpeg' || file.type === 'image/png';
}
入力形式と出力形式は分けて考えます。この例ではJPGとPNGを入力として受け、出力をimage/webpに固定します。SVG、GIF、アニメーション、複数ページ画像は、同じ処理で対応できると仮定しません。
Object URLで画像を読み込む
選択されたファイルからURL.createObjectURL()で一時URLを作り、Imageへ読み込みます。画像の表示サイズではなく、naturalWidthとnaturalHeightをCanvasサイズに使うことで、元画像のピクセル寸法で変換できます。
const sourceUrl = URL.createObjectURL(file);
const image = new Image();
await new Promise<void>((resolve, reject) => {
image.onload = () => resolve();
image.onerror = () => reject(new Error('画像を読み込めませんでした。'));
image.src = sourceUrl;
});
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
context.drawImage(image, 0, 0);
読み込みに失敗した場合も、作成したObject URLは不要になります。新しい画像を選んだときや処理をやり直すときは、前のURLを解放します。
CanvasからWebPのBlobを作る
canvas.toBlob()へimage/webpと品質を渡すと、変換後のBlobを非同期で受け取れます。画面の品質入力が0〜100なら、APIへ渡す前に0〜1へ変換します。
function toWebp(canvas: HTMLCanvasElement, quality: number) {
return new Promise<Blob>((resolve, reject) => {
canvas.toBlob((blob) => {
if (!blob || blob.type !== 'image/webp') {
reject(new Error('WebPを生成できませんでした。'));
return;
}
resolve(blob);
}, 'image/webp', quality / 100);
});
}
戻り値がnullの場合やMIMEタイプが期待と異なる場合は、プレビューやダウンロードを有効にしません。CanvasとWebPの対応はブラウザ環境に依存するため、失敗を成功扱いにしないことが重要です。
プレビューとダウンロードのURLを管理する
生成したBlobにもObject URLを作り、<img>のsrcやダウンロードリンクへ使えます。新しい変換結果に置き換える前に古い結果URLをURL.revokeObjectURL()で解放します。元画像用と結果用のURLを別々に管理すると、どのURLを解放すべきかが明確になります。
ダウンロード名は元のファイル名から拡張子を外し、.webpを付けます。名前がない場合のフォールバックも用意します。
const baseName = file.name.replace(/\.[^.]+$/, '') || 'image';
downloadLink.download = `${baseName}.webp`;
品質とファイルサイズを混同しない
品質を下げれば必ずファイルが小さくなるわけではありません。元画像の内容、寸法、透過、エンコーダーの実装で結果は変わります。品質の数値は視覚的な劣化と容量のバランスを調整する入力であり、特定の圧縮率を保証する値ではありません。
PNGの透過はCanvas描画とWebP出力が対応する範囲で扱えますが、実際の利用先で透明背景が期待どおりかは確認が必要です。変換後は表示だけでなく、ダウンロードしたファイルを対象ブラウザや利用先で開き、寸法・透明度・画質を確認してください。