こんにちは、21新卒エンジニアの柳です。
この度、プレスリリースのサムネイル画像とプレスリリース詳細ページ内で掲載されている画像の画質改善を行いました。

今回行った画質改善の対象となる条件は以下の通りです。
- 12月中旬以降にアップロードして頂いた画像
- サイズが十分に大きい画像
- トップページ(https://prtimes.jp) で表示されているプレスリリースのサムネイル画像
- プレスリリース詳細ページで表示されている画像

画質改善前のプレスリリース画像の問題点
PR TIMESでは画像をエディタからアップロードしたときに、実際に画面に表示されるサイズと同じサイズにリサイズ処理をして、生成したサムネイル画像や詳細ページの画像をそのまま配信していました。PR TIMESのサービス開始時点であれば、画面に表示されるサイズと同じサイズの画像を配信することが画像の最適化として良い対応でした。
しかし昨今、Retinaディスプレイに代表されるような高解像度ディスプレイが採用され、画面に表示するサイズの2倍や3倍のサイズの画像でなければ、綺麗に表示されないようになりました。
そのため、従来のプレスリリース画像では初めにお見せした改善前の画像のように文字の輪郭がぼやけるなどの現象が発生していました。
この問題を解決するために表示されるサイズよりも大きい画像を用意する必要がありました。しかし、プレスリリース画像は以下の記事でも説明されているように、オンプレミスのストレージサーバーに保存されており、大きい画像を保存することで容量の枯渇が早まる可能性がありました。

また、PR TIMESではJPEGやPNG、GIFといったフォーマットの画像を配信しており、大きい画像をそのまま配信してしまうと、Webページの表示速度の低下や、転送量の増加によりCDNのコストが増加してしまうなどのデメリットが発生してしまいます。
そのため、圧縮率の高い画像形式であるWebPを用いて、大きい画像でもファイルサイズを抑えて配信し、ユーザー体験を高めつつ、転送量の増加を抑えようと考えました。
WebPについては弊社CTOの金子が以前紹介しているのでそちらをご参照ください。

プレスリリース画像をS3へアップロードする
まずはオンプレミスのストレージサーバーの容量を圧迫しないようにするために、画質改善用の大きな画像を一枚だけS3へアップロードするようにしました。この大きな画像を用いて、サムネイル画像やプレスリリース内掲載画像の画質改善を行います。なぜ一枚だけで良いのかは後ほど説明します。


いきなりS3からのみ画像を配信することは難しかったため、新しい構成においても、これまで通りオンプレミスへ画像をアップロードするようにし、徐々にS3の画像を使用するようにしています。
S3へのアップロードはAPI Gatewayから直接S3にアップロードする構成にしました。理由として、PR TIMESで使用されているPHPのバージョンが古くAWS SDKやライブラリを使用が難しいため、PHPのcURLだけでS3へアップロードをすることが可能なこの構成を選択しました。
今回使用したAPI GatewayとS3はTerraformを用いて構築・管理しており、インターン生の西さんに構築して頂きました。

Fastly Image Optimizerを用いた画像の最適化
S3にアップロードされた大きな画像を表示する場所に合わせて動的に最適化を行うためにFastly Image Optimizerを利用しました。
Fastly Image OptimizerはURLのクエリパラメーターを用いて、動的に画像のサイズ・形式・品質などを調整することができます。そのため、S3には大きな画像を一枚だけアップロードし、その画像を元にサムネイルや詳細ページ用のサイズに調整するようにしました。
また、元々PR TIMESではFastlyを契約していませんでしたが、今回の画質改善を機に契約・導入を行いました。FastlyはImage Optimizer以外にも優れた機能がたくさんあるため、今後様々な場面で利用していきたいと思っています。
各プレスリリース画像で付与しているFastly Image Optimizerのパラメーター
Fastly Image Optimizerの各パラメーターについての詳しい説明は以下をご参照ください。
サムネイル画像のパラメーター
- width=295
- height=195
- fit=bounds
- format=jpeg
- auto=webp
- quality=85,75
- canvas=118:78
- bg-color=fff
本来表示するサムネイル画像のサイズは118x78pxですが、295x195pxと2.5倍のサイズの画像を配信するようにし、画質改善を行っています。また、縦と横のサイズを指定すると画像のアスペクト比が崩れてしまうためfit=boundsを指定し、元のアスペクト比を崩さずに画像をリサイズしています。
画像の形式はJPEGを指定(format=jpeg)し、WebPに対応している端末・ブラウザであればWebPで配信する(auto=webp)ようにしています。JPEGを指定することでPNGやGIF形式の画像をWebP非対応ブラウザに配信する際の転送量をある程度抑えられます。また、PNGやGIF形式の画像をauto=webpでWebPに変換しても、その画像はWebP Losslessとなってしまい、後述するパラメーターのquality=85,75で品質調整を行うことができません。そのため、format=jpegで一度JPEGに変換した後に、auto=webpにかけることでPNG、GIF形式でもWebP Lossyにすることができ、品質を調整できるようにしています。
画像の品質(quality=85,75)は、WebP非対応端末・ブラウザの場合は85、WebP対応端末・ブラウザの場合は75にしています。WebPで画像を配信するだけでもファイルサイズの削減をすることができますが、WebPはJPEGよりも品質を下げた際の画像劣化が起こりにくく、逆に品質が高いとJPEGよりもファイルサイズが大きくなる可能性があるため、JPEGよりも品質を低く設定しています。
canvas=118:78とbg-color=fffのパラメーターは画像の背景色を白くするためで画質改善前の画像仕様に合わせるために付与しています。
詳細ページの画像
- width=1950
- height=1350
- fit=bounds
- format=jpeg
- auto=webp
- quality=85,65(オリジナル画像が十分なサイズの場合)
詳細ページもサムネイル画像と同じようなパラメーターを付与していますが、一点注意するパラメーターがあります。それは、画像の品質を調整するパラメーター(quality=85,65)です。
画像のサイズを1950x1350pxと指定していますが、オリジナル画像がこのサイズよりも小さい場合はそのままのサイズで配信されます。そのため、ただ品質の悪い画像(quality=65)を配信することになってしまいます。この問題を解決するために、ファイル名に画像のwidthとheightを付与し、そのサイズに合わせて、quality=85,75、quality=85,85のようにWebPの品質を上げるようにしています。
画質改善後の結果
上記の取り組みによりプレスリリース画像の画質改善を行うことができました。

また、改善前の画像よりも大きい画像(2.5~3倍)を配信しているにも関わらず、改善前と比べてファイルサイズがほとんど変わらない、また逆にファイルサイズが下がった画像を数多く確認することができました。
上記の画像に関して言えば、改善前はファイルサイズが33.2KBであったのに対し、改善後は16.8KBと半分近く削減することができています。
これは画像形式をWebPにし品質の調整を行ったことが要因だと考えられ、特にPNG形式の画像はWebPに変換することで大幅なファイルサイズの削減を行うことができました。
以上が、今回の画質改善の取り組み・結果になります。
次にFastlyの管理・運用についてご紹介します。
TerraformによるFastlyの管理・構築
画質改善で使用しているFastlyの設定はTerraformを用いて管理・構築しました。
Terraformで管理することにより、Fastlyのコンソールをぽちぽちする必要がなくなることはもちろんのこと、似たような環境(開発環境と本番環境)を作成する際にコードをコピペすることで、すぐに環境構築を行うことができました。また、設定を変更する際にコードレビューをしてもらうことが可能になり、設定ミスなどを減らすことができています。
Terraformのディレクトリ構成は現状では以下のようなシンプルな構成で運用しています。また、現状は開発用と本番用の設定の差はありませんが、これから運用していく中で開発用と本番用で差が出てくることがあると思ったため、各環境の共通化は今のところ行っていません。
root
├── [develop] <-- 開発用
│ ├── vcl
│ │ └── main.vcl
│ └── main.tf
│
└── [production] <-- 本番用
├── vcl
│ └── main.vcl
└── main.tf
New Relicを用いてFastlyをモニタリングする
New Relicでは以下の指標をモニタリングしています。
FastlyとNew Relicの連携についてはこちらの記事を参考にさせて頂きました。

Response Body Sizes

このグラフはFastlyから配信されたレスポンスのボディサイズの分布を表しています。このグラフを見ることで、ファイルサイズが大きい画像が大量に配信されていないかや、今後Fastly Image Optimizerのパラメーターを変更した際にファイルサイズにどのような変化が起こるかを確認することができます。
また、500KB以上のレスポンスの数が一定以上の割合を超えた時にSlackにアラートを通知するようにしています。
Response Status

このグラフはタイトル通りレスポンスのステータスコードをモニタリングしています。これもアラート設定を行なっており、エラーコードの数や全体比の割合を閾値にしています。
Cache Hit Ratio

このグラフはキャッシュヒット率を表しており、オリジンシールドのキャッシュヒットも含んで算出しています。Fastly Statsでもキャッシュヒット率を確認することができますが、オリジンシールドでのキャッシュヒットを含まずに算出されています。この仕様については、以下の記事で詳しく書かれているため、気になる方はぜひご参照ください。

まとめ
今回、PR TIMESのトップページのサムネイル画像とプレスリリース詳細ページの画像の画質を行いました。また、その中でプレスリリース画像をS3へアップロードする機能やFastlyの導入を行い、今後のPR TIMESの発展に寄与できるようなプロジェクトとなりました。
新卒一年目とインターン生というとても若いチームで、Fastlyの導入からプレスリリース画像をS3へアップロードする仕組み、Terraformによるリソース管理、New Relicでのモニタリングなどを行い、とても貴重な経験をさせて頂きました。
PR TIMESでは今後AWSやFastlyなどを活用し、開発スピードを上げ、様々な改善・新機能の実装を行う予定なので、ぜひ注目して頂けると嬉しいです。