ImageMagick vs GD - PHPでサムネイルを作る

投稿日:

画像のアップローダーを作っていて、その一環で UP された画像から携帯サイト向けのサムネイルと言うか、小さな画像を作る仕組みを考えました。

で、PHP だと GD と言う標準の画像処理ライブラリがあるので、最初はそれを使って処理しようと思ったんですが、いまいち画像が粗い。。。
クオリティーを上げる事も出来ますが、そうすると結局ファイルサイズが大きくなってしまう。

色々見てみると ImageMagick を使った方が画像的には綺麗な物が出来上がるようでしたので、GD と比べてどうなのか色々と試してみました。

結論から言うと、ImageMagick の方が綺麗に仕上がりますし、簡単に使えます
そして、PHP から使うなら PHP のモジュールを使うより、shell_exec() を使って convert コマンドを直接読んだ方が圧倒的に楽でした。

一応今回の目的としては、画像が呼び出された時にリサイズして出力するのではなくて、アップロード時点でファイルをリサイズ・圧縮して保存する感じの使い方を想定してます。

サンプルとして使った画像はこちら。

まず、GD を使った場合のソースです。

$file_path = '/path/to/img.jpg';
$out_file_path = '/path/to/new_img.jpg';
$new_width = 200;

$img = ImageCreateFromJPEG($file_path); // JPEG
//$img = ImageCreateFromGIF($file_path); // GIF
//$img = ImageCreateFromPNG($file_path); // PNG

$width = ImageSX($img); // 幅(px)
$height = ImageSY($img); // 高さ(px)

$rate = $new_width / $width; // 圧縮比
$new_height = $rate * $height;

$new_img = ImageCreateTrueColor($new_width, $new_height);
//ImageCopyResized($new_img,$img,0,0,0,0,$new_width,$new_height,$width,$height);
ImageCopyResampled($new_img,$img,0,0,0,0,$new_width,$new_height,$width,$height);

ImageJPEG($new_img, $out_file_path); // JPEG
//ImageGIF($new_img, $out_file_path); // GIF
//ImagePNG($new_img, $file_path); // PNG

JPEG/GIF/PNGでそれぞれ関数が違うので、適当に組み合わせて使います。
サイズ変更に使える関数は ImageCopyResizedImageCopyResampled がありますが、試した限りでは ImageCopyResampled の方が綺麗です。
と言うか、ImageCopyResized はクオリティー的に使えない。

GD ImageCopyResized のサンプル
ImageCopyResized

GD ImageCopyResampled のサンプル
ImageCopyResampled

どうでしょうか、それなりのクオリティーだと思いますが、若干ぼやけている感じがします。

次は ImageMagick を使った場合。
まずは、PHP のモジュールを使った場合の例です。

$Imagick = new Imagick($file_path);
$Imagick->thumbnailimage($new_width, 0);
$Imagick->writeImage($out_file_path);
$Imagick->destroy();

入力・出力ファイル名や、サイズ指定は省略してますけど、これだけです。

超簡単。

ファイルタイプは自動で認識するので、特に意識せずに使えます。
例えば JPEG を読み込ませて、出力ファイル名を xxx.gif とかにすれば勝手に GIF に変換してくれます。

Imagick サンプル

ただ、JPEG の場合、上記の指定だけだとクオリティーが元の画像のクオリティーと同じになってしまい、サンプルの様にデジカメで撮った画像をそのまま流すと JPEG のクオリティーが 98 とかで出てきてしまい、ファイルサイズがでかくなってしまいます。

Imagick クラスはいわゆるオブジェクト指向っぽい書き方なので、setCompressionQuality とかで指定してあげれば良いんだと思うのですが、その他にも PHP のモジュールだといちいち指定するのが面倒です。
なので、コマンドでやる方法を試してみました。


コマンドを shell_exec で呼ぶ場合の例です。

$cmd = 'convert ' . $file_path . ' -thumbnail ' . $new_width . ' -quality 75 ' . $out_file_path;
shell_exec($cmd);

これだけです。
上記の場合、JPEG の場合にはクオリティーを 75 にした画像を出力してくれます。

quality オプションを省略した場合には、入力した JPEG の画質が引き継がれるみたいです。

ImageMagick クオリティー75のサンプル
quality 75

ImageMagick クオリティー指定なしのサンプル
quality 指定無し

$cmd の部分はシェルで ImageMagick を使う場合と同じです。
SSH でサーバーにログインできるのであれば、いちいちソース書いて UP してとかやらなくても、コマンドたたいてテスト出来るので、その意味でも楽だと思います。

convert は ImageMagick をシェルから使う際のコマンドですが、これだけでもかなりの事が出来ます。
convert のオプションの説明もなかなか見つからなかったのですが、こちらページが参考になると思います。

ちなみに、convert を使う場合も、ファイルタイプは自動で判別してくれて、入力と出力でタイプを変えた場合には勝手に変換して出力してくれます。


では今回作成したファイルを並べてみます。

GD ImageCopyResized のサンプル
GD ImageCopyResized
GD ImageCopyResampled のサンプル
GD ImageCopyResampled
ImageMagick クオリティー75のサンプル
ImageMagick (convert quality 75)
ImageMagick クオリティー指定なしのサンプル
ImageMagick (convert quality 指定無し)
Imagick サンプル
ImageMagick (PHP)

こうして見ると ImageMagick を使った物の方が綺麗だと思いますがどうでしょうか?
当然、quality 指定をしていない Imagick と convert のサンプルが一番綺麗ですが、クオリティー 75でも十分だと思います。

ちなみにファイルサイズ的には

GD ImageCopyResampled < convert 75 < GD ImageCopyResized < Imagick/convert

と言う感じです。

更新日: