0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PNG・JPEGをブラウザだけでWebPに変換して軽量化する(Canvas / Python Pillow)

0
Posted at

画像を軽くしたいとき、いまは WebP が定番の選択肢です。同じ見た目でもPNGやJPEGよりファイルが小さくなりやすく、表示速度やCore Web Vitalsにも効きます。でも「どうやって変換するの?」「透明は保持されるの?」「古いブラウザは大丈夫?」あたりで手が止まりがちです。

この記事では、**PNG / JPEG を、アップロードせずブラウザの中だけで WebP に変換する(そして必要なら戻す)**方法を、Canvas と少しのPythonでまとめます。

ゴール:画像を選ぶだけで、透明を保ったまま WebP に変換して軽くできるようになること。


そもそも WebP はなぜ軽いのか

WebP は Google が作った画像フォーマットで、非可逆(lossy)と可逆(lossless)の両方を扱えます。

  • 非可逆:JPEG のように情報を間引いて圧縮。写真系で強い。
  • 可逆:PNG のように劣化なしで圧縮。イラストやロゴ、スクショ系で強い。
  • アルファ(透明)対応:PNG のような透明を保ったまま、非可逆でも圧縮できる(PNGだと透明を残すと重くなりがち)。

ざっくり「JPEGの軽さとPNGの透明を、いいとこ取りできる」フォーマットだと思っておくと使いどころが分かりやすいです。


基本:Canvas で PNG/JPEG を WebP に変換する

ブラウザには画像を再エンコードする仕組みが標準で入っています。画像を Canvas に描いて、toBlob で image/webp を指定するだけです。

async function toWebP(file, quality = 0.8) {
  // 画像を読み込む
  const bitmap = await createImageBitmap(file);

  // 同じサイズの canvas に描画
  const canvas = document.createElement("canvas");
  canvas.width = bitmap.width;
  canvas.height = bitmap.height;
  const ctx = canvas.getContext("2d");
  ctx.drawImage(bitmap, 0, 0);

  // WebP として書き出す(quality は 0〜1)
  return await new Promise((resolve) => {
    canvas.toBlob(resolve, "image/webp", quality);
  });
}

呼び出し側はこれだけです。

input.addEventListener("change", async (e) => {
  const file = e.target.files[0];
  const webpBlob = await toWebP(file, 0.8);

  console.log(`${file.size} → ${webpBlob.size} バイト`);

  // ダウンロードさせる
  const a = document.createElement("a");
  a.href = URL.createObjectURL(webpBlob);
  a.download = file.name.replace(/\.\w+$/, "") + ".webp";
  a.click();
});

quality は非可逆のときの画質です。写真なら 0.75〜0.85 あたりが、見た目とサイズのバランスが取りやすいです。


透明(アルファ)を保持したいとき

ここがPNGユーザーの一番の関心事だと思います。結論、特別なことは不要です。

canvas.getContext("2d") は既定で透明を保持するので、上のコードで PNGの透明はそのまま WebP に引き継がれます。逆に「白背景で塗りつぶしたい」場合だけ、描画前に背景を敷きます。

// 透明を白で埋めたいとき(JPEG化の前処理などで有効)
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(bitmap, 0, 0);

なお toBlob の quality 指定は非可逆WebPとして書き出します。ブラウザのCanvas経由では可逆(lossless)WebPを明示的に選ぶAPIが無いため、「劣化ゼロで可逆圧縮したい」ときは後述のPython(Pillow)やツールを使うのが確実です。


WebP を PNG に戻す

「WebPで受け取ったけど、PNGしか受け付けない場所に貼りたい」——逆変換も同じ要領です。出力の MIME を image/png にするだけ。

async function webpToPng(file) {
  const bitmap = await createImageBitmap(file);
  const canvas = document.createElement("canvas");
  canvas.width = bitmap.width;
  canvas.height = bitmap.height;
  canvas.getContext("2d").drawImage(bitmap, 0, 0);
  return await new Promise((r) => canvas.toBlob(r, "image/png"));
}

PNGは可逆なので、quality 引数は無視されます(指定しても効きません)。


複数ファイルをまとめて変換する

Canvasは1枚ずつの処理ですが、Promise.all で並べれば複数枚も手早く回せます。

const files = [...input.files];
const results = await Promise.all(files.map((f) => toWebP(f, 0.8)));
// results[i] が各ファイルの WebP Blob

大量に処理するとメモリを食うので、数百枚規模なら「1枚変換→保存→次へ」と逐次にした方が安定します。


つまずきやすいところ

  • 対応ブラウザ。 WebPの表示は主要ブラウザで対応済みですが、canvas.toBlob(..., "image/webp") での書き出し対応は環境差があります。未対応だと勝手にPNGで書き出されることがあるので、blob.type が image/webp か確認すると安全です。
  • 写真は非可逆・イラストは可逆が基本。 ブラウザCanvasは非可逆WebPになりがちなので、ロゴやスクショで劣化を避けたいときはPillowやツール側で可逆指定を。
  • 必ず小さくなるとは限らない。 元がすでに最適化済みPNGだと、WebP化しても大きくなる場合があります。変換後にサイズを比較して、増えていたら元を使う判断を入れると親切です。
  • アニメーションPNG/GIF。 単純なCanvas変換では静止画になります。アニメーションWebPは別処理が必要です。
  • EXIF。 Canvasを通すと位置情報などのメタデータは基本的に落ちます(プライバシー面ではむしろ利点になることも)。

Python でやる場合

サーバーやバッチで処理するなら Pillow が手軽で、可逆・非可逆も選べます。

from PIL import Image

img = Image.open("input.png")

# 非可逆(写真向け・quality 0〜100)
img.save("output.webp", "WEBP", quality=80)

# 可逆(イラスト・ロゴ向け・劣化なし)
img.save("output_lossless.webp", "WEBP", lossless=True)

透明を保ったまま変換したいときは、img.convert("RGBA") してから保存すると確実です。


まとめ

  • WebP は「JPEGの軽さ」と「PNGの透明」を両取りできるフォーマット
  • ブラウザだけなら Canvas + toBlob("image/webp", quality) で変換できる
  • 透明は特別な処理なしで保持される(白埋めしたいときだけ背景を描く)
  • 戻すのも同じ要領(出力MIMEを image/png に)
  • 可逆WebPで劣化ゼロにしたいときは Pillow(lossless=True) が確実
  • 変換後はサイズを比較して、増えていたら元を使うと安全

「画像をもう少し軽くしたい」に、WebP × ブラウザ完結はよく効きます。参考になれば嬉しいです。


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?