📘

画像処理サービスimgixのAutomatic機能が便利

2021/12/03に公開

今回は小ネタです。

マナリンクではimgixという画像処理サービスを使っているのですが、先日とても便利な機能を見つけたので記事にしました。

imgixの概要

できること

imgixを簡単に言うと、「画像にアクセスするURLに規定のクエリパラメータを付与することで、様々な処理済みの画像が得られるサービス」です。

たとえば、以下の画像について考えてみます。この画像のURLはhttps://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.pngです。

元画像

URLの末尾にサイズを操作するパラメータを付けて、思い切り小さくしてみましょう。

https://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.png?w=100&h=100&fit=clip

縦横最大100pxに変更

このように、クエリパラメータを末尾に付けてアクセスすると、画像処理後の画像が得られる、というのがimgixの基本思想です。

なにがうれしいか

あくまで元画像はストレージに保有したまま、表示したいページに応じて、最適なサイズの画像を<img>タグで指定して表示できることです。

そして、それを非常に少ない工数で実装することができます。

本来こういった要件を満たそうと思ったら、画像のアップロードをフックにして、あらかじめ複数サイズの画像を生成してストレージに保有する必要があります。

しかしimgixを利用していると、あくまでその画像を表示したい側がクエリパラメータを末尾に付けるだけで欲しい画像サイズで得ることができるので、ストレージのコストや実装工数を削減できます。

最適なサイズの画像をWeb上で利用することで、パフォーマンスを向上させることができます。

imgixは画像処理を高速で行ってくれる上で、一度処理した画像はCDN上にキャッシュしておいてくれるため、2回目以降のアクセスはリサイズ後の画像のダウンロード時間しか掛からないため非常に高速です。

簡単にcurlコマンドを実行してチェックしてみました。

curl "https://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.png" -I            HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 132238
...中略
X-Served-By: cache-sjc10058-SJC, cache-tyo11970-TYO
X-Cache: MISS, MISS
curl "https://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.png" -I
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 132238
...中略
X-Served-By: cache-sjc10058-SJC, cache-tyo11957-TYO
X-Cache: MISS, HIT

まったく同じ画像ですが、2回めの実行はより速くレスポンスが返ってきました。また、X-Cacheヘッダを見るとキャッシュヒットしていることが伺えます。

どうやって使うのか

Amazon S3などのストレージサービスと連携することで、そこに上がっているリソースをimgixのドメイン経由で利用することができます。

https://docs.imgix.com/setup/creating-sources

マナリンクはAWSを使っていて、かねてから画像はS3にあげているので、S3と連携しました。

もともとS3の前段にCloudFrontを置いていて、assets.manalink.jpドメインでアクセスできるようにしていたのですが、このままのURLだと画像処理は噛ますことができません。

https://assets.manalink.jp/images/202112/guest/webeng-bosyu.png

あくまでprod-manalink-images.imgix.netといったimgixのドメインでアクセスすることで、機能が利用できます。

料金は?

最低月額10ドルから始めることができます。そこから従量課金ですが、マナリンクでは現状ずっと10ドルのままです。imgixがお得だなぁという気持ちと、トラフィックもっと増やしたいなぁという複雑な気持ちになりますw

Automatic機能

ここから本題なのですが、Automaticという機能にようやく気がついたという話をします。

https://docs.imgix.com/apis/rendering/auto/auto

auto=formatというパラメータを付けると、WebP対応ブラウザから開かれた場合はWebPを、そうでない場合は(おそらく)元画像のフォーマットで返してくれます。

実は、fm=webpというオプションがあって、これを付けることでWebPを得ることができるのは以前から知っていました。

curl "https://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.png?fm=webp" -I
HTTP/1.1 200 OK
Connection: keep-alive
...
Content-Type: image/webp
...
X-Cache: MISS, MISS

Content-Typeがimage/webpになっていることが分かると思います。

しかし強制的にWebPを得られるということは、このURLでは一部のブラウザで画像がそもそも開くことができません。

https://caniuse.com/webp

なので僕はつい先日まで、<picture>を使ってフォールバック可能になるようにマークアップしていました。

しかしauto=formatを使えば、WebP対応しているかしていないかで返ってくる画像がそもそも異なるので、WebP未対応ブラウザのことは考えずに画像を表示できます。

おそらくAcceptヘッダとUser-Agentヘッダを見ることによって、ブラウザの判定をしているものと考えられます(Varyヘッダから推察。ドキュメントのどこかにロジックが書いてあるかもしれませんが見つけられていません)。

curl "https://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.png?auto=format" -I
HTTP/1.1 200 OK
...
Content-Type: image/png
...
X-Cache: MISS, HIT
Vary: Accept, User-Agent
curl "https://prod-manalink-images.imgix.net/images/202112/guest/webeng-bosyu.png?auto=format" -I -H 'Accept: image/webp'
HTTP/1.1 200 OK
...
Content-Type: image/webp
...
X-Cache: MISS, HIT
Vary: Accept, User-Agent

以上のように、Acceptヘッダによって返ってくるContent-Typeが異なるのは少なくとも確認できました。

同様にauto=compressというクエリパラメータもあり、こちらは画質などを少し下げながら画像サイズの削減をしてくれます。

これまでフロントエンドでコンポーネントごとにwidth/heightの設定をやってきたのですが、それらに加えてformat/compressを使うことでより画像サイズが削れそうです。

実際に、マナリンク上でのとあるページで2MB以上の画像が複数枚表示されてしまっているページがあったのですが、imgixのホスト名に置換してクエリパラメータをつけるように実装したところ、それぞれ70KB前後にまで抑えられました。
これがユーザーさんにも社内メンバーにも一切の手間なく実現できたのが大きいです。

マナリンクでは以下のように、登録している先生が自由に指導コースを作ることができます。本文中にさまざまなオンライン指導のイメージ画像を挿入いただくことも多く、こういった画像を全部imgixに置換してからブラウザに表示することで、パフォーマンスと自由度の両立ができたと思います。

https://manalink.jp/teacher/11804/courses/2286

CleanShot 2021-12-03 at 18 24 02

データベースにはassets.manalink.jpドメインのURLでデータを入れつつ、出力時のPresentation層での処理でimgixへの置換やクエリパラメータへの付与を行っているので、ページごとにクオリティ調整もできるし、万が一imgixをやめたいとなったときもリスクが低いです。

まとめ

  • imgixはいいぞ
  • パフォーマンスは大事だぞ
  • 便利なサービスはどんどん使っていきたい
マナリンク Tech Blog

Discussion