画像ファイルの最適化とスプライト画像の作り方

 Webサイトの最適化において、最も手軽にできて効果的なのは画像ファイル関連の最適化である。主に2つの最適化方法があり、1つは画像ファイル自体のファイルサイズを小さくして通信帯域を節約すること。もう1つは画像をまとめることによって通信回数を減らすことだ。それぞれのポイントや作業方法を解説していこう。

最適化できる画像はどのくらいある?

 Webサイトの各ページには何かしらの画像ファイルが使われている。これらに改善の余地があるかどうかは、GoogleのPageSpeedなどの診断ツールを使って簡単に把握できる(参考:「PageSpeedを使ってWebサイトを最適化・高速化しよう」)。サイト運営でこれまでとくに画像最適化について意識していなければ、「?%サイズを縮小できる」「画像ファイルをまとめる」などのアドバイスを受けることだろう。

ファイルサイズを小さくできるPNG形式

 一般に利用されている、BMP、GIF、JPEG、PNG、TIFFファイルのうち、ファイルサイズを小さくしやすい形式はJPEGとPNGファイルだ。

図1 PNGファイルはファイルサイズを小さくできる

 JPEGファイルは品質を落とすことでファイルサイズを縮小していくことができ、多少劣化があっても見栄えにそん色のない写真に有効だ。イラストやアイコンなどではエッジがボケたりノイズが入ったりするのでJPEGファイルは向かない。一定の品質を保ったままとなるとPNGファイルに軍配があがる。昔は全ブラウザがPNGファイルに対応しておらず、WebサイトではGIFファイルとJPEGファイルの組み合わせが多かったが、現在はPNG対応が十分に行きわたり、PNGとJPEGの組み合わせを標準的に使うようになっている。

 PNGファイルのサイズはその画像を制作(保存)するツールによって変化する。まったく同じ表示データだとしても、メタ情報の違いや圧縮方法によってファイルサイズに差が出てしまう。そのため、作成時は任意の操作しやすい画像編集ソフトウェアを使ったとしても、その後、ファイルサイズ最適化ツールでサイズを調整するというフローで作業していく。

ファイル形式の変更はImageMagickのconvertを使う

 既存のWebサイトにはさまざまなファイル形式の画像ファイルがあるかもしれない。Webサイト最適化の際は、既存のGIFファイルやそのほかのファイルはPNGに変換し、そのPNGファイルのサイズ最適化を行っていく。Linux環境でのファイル形式の変換には、ImageMagickのconvertコマンドを使うのが一般的だろう。

 たとえばDebian GNU/Linuxでは、imagemagickパッケージをインストールすることでconvertコマンドを利用できる。

# aptitude install imagemagick

 convertコマンドの基本は、変換前ファイル名と変換後ファイル名を指定するだけだ。

書式:
convert [input-option] input-file [output-option] output-file

例:
$ convert sample.gif sample.png

透過GIFをPNGに変更する際の注意点

 変換前のファイルに透過GIFが含まれている可能性がある場合は注意が必要だ。オプションなしでconvertコマンドを実行するとグレースケールのGIFで透過情報が失われてしまうことがある。透過GIFが存在する場面は多いと思うので、GIFからPNGの変換では普段から色情報を付加した以下のコマンド形式を実行するようにするといいだろう。

$ convert -depth 8 -colors 256 sample.gif sample.png

特定ディレクトリ下のGIFをPNGに一括変換

 複数のファイルを一括変換したい場合は、findコマンドを組み合わせるのがわかりやすいだろう。/var/www以下にあるGIFファイルをすべてPNGファイルに変換するには、次のように実行すればよい(シェルがbashの場合)。

$ find /var/www -name '*.gif' -print0 |while read -d '' f; do convert -depth 8 -colors 256 $f ${f%%.gif}.png; done

 この例では変換前のGIFファイルはそのままにしている。HTMLファイル側の変更が終わって問題がないことを確認してから削除するなり、念のため別ディレクトリに退避しておくなりすると良い。

$ find /var/www -name '*.gif' -exec rm {} \;

PNGファイルの最適化にはoptipng

 PNGファイルの最適化にはoptipngがお勧めである。optipngはGIFファイルからPNGへの変換と最適化を行うこともできるが、前述の透過GIFの問題があるため、ファイル形式の変換にはconvertコマンドを使うことをお勧めする。

・optipng
http://optipng.sourceforge.net/

 optipngはバージョン7以降で不要なメタ情報(tRNS以外)を削除する機能が加わり、よりファイルサイズを小さくできるようになっている。Debian GNU/Linuxの標準パッケージは古いバージョンのため、Debian GNU/Linuxで利用する場合はソースからコンパイルして利用したほうが良い。基本的なコンパイル方法は以下の手順になる。

# aptitude build-essential
# aptitude build-dep optipng
# wget http://prdownloads.sourceforge.net/optipng/optipng-0.7.4.tar.gz
# tar zxvf optipng-0.7.4.tar.gz
# cd optipng-0.7.4
# ./configure
# make
# make test

# ./src/optipng/optipng -v(実行テスト)

 optipngの実行書式は以下が基本になる。

$ optipng -o7 -snip -strip all sample.png

 これによってsample.pngは最適化されたファイルサイズが小さいファイルに上書きされる。

 「-o7」は最適化レベルを指定するものである。数値が大きいほど解析(施行)回数が増え、処理が遅くなる。指定なしの場合は「-o2」と同じである。7を指定すると想定される最小パターンをすべて探すことになるが、通常はこのオプションなし(「-o2」)でも十分である。

 「-snip」は複数枚やアニメーションのデータを削除するものである。もしそのようなファイルが必要な場合は「-snip」を削除して実行する。

 「-strip all」はメタ情報を削除する指定である。allしか指定できないのでこのままでOKだ。

特定ディレクトリ下のPNGファイルを一括最適化

 ファイル形式の変換同様に、特定ディレクトリ下のPNGファイルを一括で最適化するには、findコマンドとの組み合わせると良い。

$ find /var/www -name '*.png' -exec optipng -o7 -snip -strip all {} \;

実際にどのくらいファイルサイズは小さくなるか?

 上記を踏まえ、いくつか変換例を提示していこう。まずはこのサイト、さくらのナレッジの左上のロゴである。

6748  logo21.gif

 本記事掲載後しばらくしたら最適化が行われるかもしれないが、執筆時点ではGIFファイルで6748バイトである。これをconvertコマンドでPNGファイルに変換してみるとPNGへの変換だけで5525バイトに小さくなった。

$ convert -depth 8 -colors 256 logo21.gif logo21-convert.png

6748  logo21.gif
5525  logo21-convert.png

 これをさらにoptipngで最適化する。

$ optipng  -o7 -snip -strip all logo21-convert.png -out logo21.png
** Processing: logo21-convert.png
298x111 pixels, 2x8 bits/pixel, grayscale+alpha
Reducing image to 8 bits/pixel, 181 colors (1 transparent) in palette
Stripping metadata...
Input IDAT size = 5262 bytes
Input file size = 5525 bytes

Trying:
  zc = 9  zm = 9  zs = 0  f = 0         IDAT size = 3544

Selecting parameters:
  zc = 9  zm = 9  zs = 0  f = 0         IDAT size = 3544

Output file: logo21.png

Output IDAT size = 3544 bytes (1718 bytes decrease)
Output file size = 4169 bytes (1356 bytes = 24.54% decrease)

 「-out」オプションは上書きではなく別ファイルに出力するものである。最終的に4169バイト、2パケット分(1パケット1500バイトと換算)の節約になる。

6748  logo21.gif 元のGIF画像
5525  logo21-convert.png PNG変換
4169  logo21.png PNG最適化

 もう1つ例を示そう。Webサイトでよく見かける代表的な画像にプライバシーマークがある。これは規定上データの改変が許されていない(かつ勝手に掲示できないので文字だけ説明する)が、同じような手順でPNG最適化を行うと以下のようにファイルサイズを小さくできる。

3811  pmark_img1.gif
3484  pmark_img1-convert.png
3175  pmark_img1.png

 いかがだろうか。このようにして通信帯域を節約し高速に描画が行われるようになるし、環境によってはコスト削減にもなる。

画像ファイルをまとめて、さらなる最適化へ

 現代の一般的なWebブラウザでは同時接続数は6であり、描画に必要なファイルが6ファイル以上あった場合、それらの読み込みが終了するまで次の通信は待たされてしまう。画像だけでなく、CSSやJavaScriptのファイルもこの数に含まれる。小さい画像がいくつもある場合は多く、1ページの描画に必要なファイルを6ファイル以内に収められれば理想的な状態だ。

 画像ファイルが複数ある場合、よくある最適化手法としてCSSスプライトがある。複数の画像を1つの画像ファイルとしてまとめ、CSSの背景画像設定で部分的に表示していくというものだ。アイコン画像やロゴなど多用しているサイトでは、CSSスプライトを用いるだけでも体感で違いがわかるぐらい改善する。

図2 CSSスプライト

 CSSの指定は、全体クラスとしてbackground-imageを指定し、画像ごとbackground-positionで左上の座標と高さ、横幅を指定するという形になる。典型例は以下のようなCSSだ。

.sprite-class{
background-color:transparent;
background-image:url(画像ファイル.png);
background-repeat:no-repeat;
}

.sprite-class-a0{
background-position:0px 0px;
height:16px;
width:16px;
}

.sprite-class-a1{
background-position:0px -16px;
height:16px;
width:16px;
}

 このようなCSSを記述しておき、spanもしくはdivタグにて該当クラスを指定して画像を表示する。全体のCSS構造によっては以下のようなCSSも付加したり、上記の.sprite-classにページトップレベルのID指定を付加して(たとえばbodyタグにid="website"とあった場合)適用優先度をあげておくと安全だ。

#website .sprite-class{
background-color:transparent;
background-image:url(画像ファイル.png);
background-repeat:no-repeat;
background-attachment:scroll;
display:inline-block;
vertical-align:middle;
font-size:0;
line-height:1;
}

画像は縦にまとめる

 複数の画像ファイルを1つにまとめる場合、概ね、横に並べていくパターンと縦に並べていくパターンがある。どちらがいいか結論からいうと「縦に並べる」である。

 縦方向に並べる理由はWebブラウザの描画実装によるもので、縦に並べておいたほうが高速に描画できるからである。Webブラウザで画像を描画する際、まずbackground-positionのY軸方向にオフセットを移動し、X軸方向に画像データを展開し、必要な箇所の描画を始める実装が多い。そのため横長に画像ファイルを構成していると、表示されない部分も内部で展開されており、描画処理に時間かかってしまう。横幅数千pxほどあれば体感でわかるぐらいの違いは出るので、時間があれば試してみると面白いだろう。

図3 スプライト用の画像は縦に並べたほうが良い

画像をまとめるのにもconvertが使える

 画像ファイルをまとめるのにも、前述のImageMagickのconvertコマンドが便利だ。convertコマンドを使って複数ファイルを連結し、1つのファイルにまとめるということができる。

$ convert -append -background transparent *.png sprite.png

 「-append」オプションは縦に画像を連結していくというものだ。横に連結する場合は「+append」を使う。「 -background transparent」オプションで画像データのない部分は透過色になる。

 実際にファイル連結するにあたっては、特定のディレクトリ下に画像ファイルを集めておき、ファイル名の先頭に数字をつけ、連結する順番を整理してから実行すると良い。そしてoptipngで最適化だ。

$ ls
01-RSS_Feed-32.png
02-twitter-bird-white-on-blue.png
03-facebook-32.png
04-gplus-32.png

図4 ファイル名に番号をつけてソートしておく

$ convert -append -background transparent *.png sprite.png
$ optipng  -o7 -snip -strip all sprite.png

 このようにしてできたファイルは下図のようになる。

図5 convertで連結した画像ファイル

これを利用する部品ごとのCSS例は以下のようになる。

.sprite-class-rss {
background-position:0px 0px;
height:32px;
width:32px;
}

.sprite-class-twitter {
background-position:0px -32px;
height:32px;
width:32px;
}

	:
	:

 あとは「<span class="sprite-class sprite-class-rss"></span>」などとすればその場所にアイコンを表示できる。以下は実際に図5の画像ファイルを対象にstyleで直接指定して表示してみた例である。このページのソースなどで確認してみていただきたい。

以外と簡単にできる基本のWebサイト最適化

 以上、画像ファイルの最適化とスプライトについて説明したがいかがだっただろうか。少し気の利いたツールも世の中には存在するが、optipngとconvertコマンドの2つさえ理解してしまえば、実施すること自体は単純だ。既存のサイト、新しいサイトを作る際はぜひ活用していただければと思う。

おしらせ