WebPに変換するだけでは、Web画像は軽くなりません。形式、ピクセル数、圧縮品質を分けて決める必要があります。幅4,000pxのWebPを600pxの枠に表示すれば、余分なデータを送ることになります。
ブログなら、元画像を残し、決めた幅のWebPをアップロード時に作る構成から始めるのが扱いやすいでしょう。

配信形式の判断

- 写真:WebPを第一候補にし、互換用にJPEGを残します。
- 透過画像や文字入りの図:lossless WebPまたはPNGを使います。
- ロゴや単純な図形:拡大しても崩れないSVGが向いています。
WebPは非可逆と可逆の両方に対応し、透過も扱えます。Googleの評価では、非可逆WebPは同等のSSIM品質のJPEGより25〜34%小さく、可逆WebPはPNGより26%小さい結果でした。画像によって結果は変わるため、変換後のバイト数も確認します。
必要な画像幅

Webではdpiより、CSS上の表示幅と端末のDPRを見ます。表示幅640px、DPR 2なら、必要な画像幅の目安は1,280pxです。
必要な画像幅 ≒ CSS表示幅 × DPR480px、960px、1,440pxなどの候補をsrcsetで渡せば、ブラウザが表示条件に合う画像を選びます。詳しい指定方法はUsing responsive images in HTML(MDN)で確認できます。
変換のタイミング

ブログや企業サイトでは、アップロード時に480px、960px、1,440pxなどを生成します。初回アクセスでも変換待ちがなく、費用も読みやすい方法です。
表示サイズを事前に絞れないサービスでは、リクエスト時変換が使えます。ただし、許可する幅と形式を固定し、生成結果をCDNでキャッシュしてください。任意のサイズを作れる公開APIは、処理回数と保存ファイルを簡単に増やされます。
AWSとGoogle Cloud

AWSでは、S3の作成イベントでLambdaを起動し、Sharpなどで変換した画像を出力用S3へ保存します。配信はCloudFrontに任せます。リクエスト時変換には、AWS公式のDynamic Image Transformation for Amazon CloudFrontが参考になります。
Google Cloudでは、Cloud Storageのgoogle.cloud.storage.object.v1.finalizedイベントをEventarcで受け、Cloud Run functionを起動します。変換後の画像は出力用Cloud Storageへ保存します。設定方法はCreate triggers from Cloud Storage eventsにまとまっています。
どちらも入力と出力を分けます。同じイベント対象へ派生画像を書き戻すと、その画像が次のFunctionを起動し、処理が繰り返されるためです。
実装時の確認
- 元画像を残し、派生画像を再生成できるようにする
- 幅、高さ、総ピクセル数、ファイルサイズに上限を設ける
- EXIFの向きを反映し、位置情報など不要なメタデータを削除する
- 出力に正しいContent-TypeとCache-Controlを付ける
- 変換条件を出力キーに含め、同じイベントを再処理しても同じ結果にする
- Sharpなどのネイティブ依存を実行環境に合わせてビルドする
最初から多数のサイズと形式を作る必要はありません。本文幅が680px前後なら、480px、960px、1,440pxのWebPと、必要なJPEGまたはPNGから始めます。公開後にブラウザのNetworkパネルを見て、使われない幅や元画像より大きい派生ファイルを減らしてください。



