TinyPNG API を使って、画像を最適化してみよう

この記事は Advent Calendar 2019 の25日目の記事となります。さまざまな a-blog cms に関する記事が公開されていますので是非ごらんください。



画像を最適化してファイルサイズを小さくすることでパフォーマンスをよくすることができます。
これを実現するために「ロスレス圧縮」機能が a-blog cms にはありますが、サーバー側で必要なライブラリが入っていないと動作しません。

必要なライブラリ例

  • pngquant
  • optipng
  • pngcrush
  • pngout
  • advpng
  • jpegtran
  • jpegoptim
  • gifsicle
  • svgo

共用のレンタルサーバーなどだと、これらのライブラリが入っている可能性が少なく、対応に困ります。
そこで、画像最適をするサービスで有名な「TinyPNG」のAPIを使い、ライブラリが入っていないサーバーでも画像のロスレス圧縮に対応させる拡張アプリを作ってみたので紹介いたします。

この拡張アプリで実現できること

TinyPNGのAPIを利用して、画像のロスレス圧縮を実現できます。Hook機能を使って画像生成時にすべてロスレス圧縮します。 また校正オプションを用意していて、ロスレス圧縮された状態で画像のリサイズをすることができます。

インストール方法

設置方法

https://github.com/appleple/acms-tiny-png/raw/master/build/TinyPNG.zip のリンクからzipファイルをダウンロードします。zipを解凍すると TinyPNG というディレクトリが出てくるので extension/plugins/ に設置します。

アプリのインストール

設置できたら、管理画面にログインし、拡張アプリ から TinyPNG 拡張アプリをインストールします。

config.server.php

拡張アプリのインストールができたら、config.server.php の HOOK_ENABLE の値を「1」に設定します。

APIキーの設定

https://tinypng.com/ でアカウントを作成し、API Key を発行ください。発行した API Key を以下の様に private/config.system.yaml に追記します。

tiny_png_api_key: xxxxxxxxxxxxxxxxxxxxxxxxxxx

以上でインストール・設定は完了です。

参照: https://github.com/appleple/acms-tiny-png

使い方

特にロスレス圧縮するだけなら、なにも意識せず通常通りの作業で、自動的にTinyPNGのAPIを通して、圧縮されるようになります。

画像のリサイズを TinyPNG APIで実行する

TinyPNGで画像を好きなサイズにリサイズできる校正オプションも用意しました。もちろんロスレス圧縮された状態でリサイズされます。

scale

アスペクト比を維持したまま、幅または高さを指定してリサイズします。幅、高さの両方の指定はできません。

<img src="%{MEDIA_ARCHIVES_DIR}{hoge@path}[resizeTinyPng('scale', 300)]" /> <!-- 幅指定 -->
<img src="%{MEDIA_ARCHIVES_DIR}{hoge@path}[resizeTinyPng('scale', 0, 300)]" /> <!-- 高さ指定 -->

fit

アスペクト比を維持したまま、指定された寸法に収まるように縮小します。幅と高さ両方の指定が必要です。

<img src="%{MEDIA_ARCHIVES_DIR}{hoge@path}[resizeTinyPng('fit', 300, 300)]" />

cover

指定された寸法になるように縮小し、はみ出した部分はトリミングします。幅と高さ両方の指定が必要です。

<img src="%{MEDIA_ARCHIVES_DIR}{hoge@path}[resizeTinyPng('cover', 200, 200)]" />

改善したいところ

さくっと作ったままですので、まだまだ改善しないといけないところがあります。

  • 同期的にAPIをたたいているので、画像のアップロード処理がすごく遅くなってしまう。-> バックグラウンドで実行する様に修正する。
  • 余分なAPIコールがあるので、節約するようにしたい。
  • 残りAPI回数が、管理画面から確認できるようにしたい。

まだまだ改善点はありますが、この拡張アプリを入れることで、共用のレンタルサーバーなどでも簡単にロスレス圧縮に対応できるようになります。 よかったらぜひ試してみてください。

a-blog cms のベンチマークモードの活用法


a-blog cms の「ベンチマークモード」ってご存知でしょうか?

今回、あるページの表示に 5 秒程度要するケースを確認 しました。この事例を受け、「同様の実装には注意が必要である」という点について、社内向けに Slack で情報共有を書いている途中で、これは a-blog cms をご利用いただいている皆様にも広くお伝えすべき内容ではないかと考え、「ベンチマークモード」について改めて整理し、ブログ記事として公開することにいたしました。


何故、こんなに時間がかかるのか!

原因は、いわゆる「N+1問題」が発生していたためでした。具体的には、Entry_Summary を実行した結果、一覧に表示される件数分だけ追加で Entry_Summary が実行されていたのです。

a-blog cms では基本機能として「モジュールの入れ子」(モジュール内に別のモジュールを配置する)が可能ですが、通常は「内側のモジュール → 外側のモジュール」の順に実行されます。この場合、Entry_Summary は 2 回のみ実行されます。しかし、「モジュールのエスケープ処理」などのテクニックを活用することで、「外側のモジュール → 内側のモジュール」の順に実行させることも可能です。

今回のケースでは、この後者の順序で実装していたため、一覧表示時に「外側のモジュール 1 回 + 表示件数 N 回」、結果として 1+N 回 Entry_Summary が実行される状態となっていました。

以下のコードが問題のものを部分的に抜き出したものです。

<!-- BEGIN_MODULE Entry_Summary id="sample" -->
(略)
 <!-- BEGIN entry:loop -->
  <p><!-- BEGIN_MODULE\ Entry_Summary id="sample2" 
  ctx="eid/{eid}" --><!-- BEGIN\ entry:loop -->\{title\}
  <!-- END\ entry:loop --><!-- END_MODULE\ Entry_Summary --></p>
 <!-- END entry:loop -->
(略)
<!-- END_MODULE Entry_Summary -->

ベンチマークモード で分かること

実際のベンチマークモードがオンの状態にすると、以下のような表がページの下部に表示されるようになります。実際には表は多くの情報が表示され縦に長く表示されます。


各表について説明をしておきます。

グローバル変数

そのページを表示する際に、テンプレートで利用できるグローバル変数の一覧になります。上に表示されているキャプチャ画像では、あまり参考になる情報が見えていないのですが、%{BID} や %{BLOG_NAME} のような変数の値が表示されています。

モジュール処理時間

ここには、テンプレートに書かれている モジュール名と、その名前である モジュールID 、実際の実行時間に加え SQL を実行した回数が書かれています。ここではモジュールの実行時間は 0.001秒のような小さな数値であるのが正常で、0.2, 0.3秒のような時間がかかっているのは少し何か設定を見直した方がいい事がわかります。

表の下部には、実際のトータル時間が書かれています。1つのモジュールの実行時間が少なくても、沢山のモジュールの合計になると、結果 5秒になっている例となります。



テンプレート

@include文で他のテンプレートの読み込んでいるファイルが一覧で表示されます。 a-blog cms の実装作法的にはモジュール毎にテンプレートを分割しているので多くのファイルが読み込まれている事が確認できます。この数が多いと遅くなるのでは?と心配される人がいるかもしれませんが、あまり気にする必要も無さそうです。

メモリー

3行書かれていますが、PHPの設定で許可されているメモリーの上限「memory_limit」と、スクリプト実行中に使用された最大メモリ量である「memory_get_peak_usage」をご確認ください。

Query Count

モジュール処理時間の中にも書かれていますが、SQL の実行回数になります。1ページを表示するのに 5000回以上というのは明らかに問題がある状態です。

ベンチマークモードを利用する方法

以前のバージョンでは、config.server.php の一番下の行にファイルで設定を行う必要がありましたが、Ver. 3.0 以降はログインユーザー毎に設定が可能となっており、気軽に試すことができますので、一度設定を切り替えてお試しください。

// 本番運用時は DEBUG_MODE を必ず 0 に設定して下さい
define('DEBUG_MODE', 0);
define('BENCHMARK_MODE', 0);


最後に

a-blog cms は、バックエンド側で PHP を記述することなく、柔軟に CMS の構築・実装を進められる仕組みを備えています。例えば、Entry_Summary の表示設定画面で必要な項目にチェックを入れるだけで、テンプレート上に求める情報を表示させることが可能です。

しかし、その一方で「タグを表示する」にチェックを入れればタグ情報を取得するための検索処理が追加され、「ページャーを表示する」にチェックを入れれば全件数を取得するための検索処理が実行されるなど、こうした設定が増えるほど SQL の実行回数にも影響を与えます。

そうした状況を適切に把握するために役立つのが 「ベンチマークモード」 です。この機能を活用することで、「モジュールが何回実行されているのか」「そのモジュールの実行時間に異常がないか」など、パフォーマンスに関わる詳細な情報を確認できます。

CMS のカスタマイズは「必要な情報を表示させること」に意識が向きがちですが、安定した運用や快適な閲覧環境を提供するためには、パフォーマンス面も考慮した実装が欠かせません。a-blog cms は、そうしたプロフェッショナルな開発現場にも耐えうる仕組みを備えた CMS です。ぜひ、「ベンチマークモード」も活用しながら、より効率的でパフォーマンスに優れたサイト構築を目指していただければ幸いです。