« Googleのサービスをケータイでも使い倒す | メイン | RackでWebアプリのWebサーバー依存を無くす »

PHPの画像処理の紹介と簡単な比較
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

Keita です。

僕は、フォト蔵チームではないので、フォト蔵の画像処理については見ていませんが、個人的に画像処理に興味があるためPHPにおいての画像処理を簡単に調べたことがあります。

その時の結果をお話させていただきたいとおもいます。
この他に、もし、こういう選択肢があるよというのがあれば、教えていただけると大変うれしいです。

主要なライブラリの一覧


GDで処理

LibGDを操作するPHP標準のライブラリです。
ほぼ、レンタルサーバなどで利用できる反面、対応形式が、JPEG,GIF,PNG,WBMP,GD{,2}にしか対応していないなどのいくつか機能的に制限があります。
(WBMPは、Wireless Bitmapという、WindowsBitmapとは別の形式です)

imagick

ImageMagick/GraphicsMagickという画像編集ソフトのPECLの拡張で非常に多くの形式に対応しています。
最近まで2004で、更新がとまっており、今後も絶望的でした。
しかし、最近、2007-04-13にバグを修正したバージョンが出て、もしかすると今後は期待できるかもしれません。


MagickWandForPHP

上記のimagickと同じ系統、ImageMagickのAPIであるMagickCoreを利用するためのPHP拡張で、残念ながらPHP公式のPECLではありませんが、同じ形式で、配布されています。
APIの数が、400個以上で、対応形式も、ImageMagickのコンパイル時に利用できるライブラリに依存するため一定ではありませんが、非常に多くの形式に対応しています。


imagick2

「今後は期待できるかもしれません。」
とかいってたら、この資料を書いてる間に、imagick2.0.0a1が出ていました。
ほとんどが書き直しされたもののようで、非常に多機能かつクラスベースです。
残念ながら、PHP5.1の特定のバージョン以降しか対応していないようです。
MagickWandForPHPと同じく400個以上のAPIをサポートしているようで、さらに、Classベースで実装されているので、操作が比較的簡単です。


そんなわけでどうすればいいのか


最初、僕のほうでは、GDを使っていたのですが、アニメーションGIFやWindows Bitmapファイルが扱えなかったので、気合をいれてMagickWandForPHP差し替えました。

先に結論だけ述べておくと、今の段階では、MagickWandForPHPで将来的には、PHP4の環境もしくは細かい制御がしたいなら、MagickWandForPHP、PHP5の環境なら新しいimagickを使うのが健康的だと思います。

そんなわけで、将来的には、imagick2にしていきたいのですが、さすがに、GWの前日に出たものを、ちゃんとは検証できなかったので、それぞれの簡単なコード比較と、そのベンチマークを紹介したいとおもいます。

まず、ファイルの読み込み比較です。
MagickWandForPHPと、GDについては、簡単にクラス化した、ライブラリを作ったのでそれを抜粋します。

GD:
class Image_Converter_GD
{
    .....(省略
    function loadFromFile($filename)
    {
        if (! file_exists($filename)) {
            return false;
        }
    
        $size = @getimagesize($filename);
        
        if ($size === false) {
            return false;
        }
    
        list($width, $height, $type, $attr) = $size;
    
        $this->type = $type;
        $this->width = $width;
        $this->height = $height;
    
        switch($this->type) {
           case IMAGETYPE_GIF:
               $this->handle = imagecreatefromgif($filename);
               break;
           case IMAGETYPE_JPEG:
               $this->handle = imagecreatefromjpeg($filename);
               break;
           case IMAGETYPE_PNG:
               $this->handle = imagecreatefrompng($filename);
               break;
           case IMAGETYPE_WBMP:
               $this->handle = imagecreatefromwbmp($filename);
               break;
           default:
               return false;
        }
        return true;
    }
    .....(省略
}

$image = new Image_Converter_GD();
$image->LoadFromFile($filename);
GDではファイルを読み込む場合には、各形式ごとに別々の関数があるのでこれを分ける必要があります。

MagickWandForPHPの場合はこんな感じです。
class Image_Converter
{
    .....(省略
    function Image_Converter()
    {
        $this->image = NewMagickWand();
    }

    function LoadFromFile($filename){
        if (! MagickReadImage($this->image, $filename)) {
            return $this->_returnError();        
        }
        return true;
    }
    .....(省略
}

$image = new Image_Converter();
$image->LoadFromFile($filename);
関数がひとつなので、(まぁ対応形式が多いかつ不確定なので、一個一個関数作ったら追いつきませんし。)簡単に見えます。

さらに、Imagick 2はすでに、Classになっているのでこんな感じになります。
    $image =& new Imagick();
    $image->readImage($filename);
次に、僕は、実際画像のリサイズがしたかったので、
リサイズ処理を書いてみました。
GD:
class Image_Converter_GD
{
    function resize($width, $height)
    {
        if ($width > $this->width &&  $height > $this->height ){
            return ;
        }
        switch($this->type) {
           case IMAGETYPE_GIF:
                $work_handle = imagecreate($width, $height);
                
                $tcolor = imagecolorallocate($work_handle , 255, 255, 255);
                imagecolortransparent($work_handle , $tcolor);
                imagefilledrectangle ($work_handle , 0, 0, $width, $height ,$tcolor);
               break;
           case IMAGETYPE_JPEG:
           case IMAGETYPE_PNG:
           case IMAGETYPE_WBMP:
                $work_handle = imagecreatetruecolor($width, $height);
               break;
        }

        imagecopyresized($work_handle, $this->handle, 0,  0, 0, 0, $width, $height, $this->width, $this->height);
        imagedestroy($this->handle);

        $this->handle = $work_handle;
    }
}
ちゃんとは検証してないですが、だいたい上記のような感じでうごくとおもいます。
次にMagickWandForPHPです。
MagickWandForPHP:
class Image_Converter
{
    function resize($width, $height, $filter = null, $blur = 1)
    {
        if (is_null($filter)) {
            $filter = MW_HammingFilter;
        }
        if (! MagickResizeImage($this->image, $width, $height, $filter, $blur) ) {
            return $this->_returnError();        
        }
        
        return true;
    }
}
ちょっと比較対象が違いますが、すでにclass化されてるimagick2の場合

imagick2:
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->ResizeImage(100, 100, 0, false);

MagickWandとimagick2には、それぞれ、フィルタを使わないScaleと、さらに、imagick2には縦横比率を保存する、thumbnailがありますので、適時使い分ける必要がありそうです。

上記の機能を使って、簡単ですがベンチマークを図ってみました。
require_once "Benchmark/Timer.php";
require_once "../Image_Converter.php";
require_once "../Image_Converter_GD.php";

$timer =& new Benchmark_Timer();

$timer->start();
for ($i = 0; $i < 100; $i++) {
    $image =& new Image_Converter();
    $image->LoadFromFile('test2.jpg');
    $image->resize(100, 100);
    $image->SaveToFile('test_file.jpg');
}
$timer->setMarker('MagickWandResize');

for ($i = 0; $i < 100; $i++) {
    $image =& new Image_Converter();
    $image->LoadFromFile('test2.jpg');
    $image->scale(100, 100);
    $image->SaveToFile('test_file.jpg');
}
$timer->setMarker('MagickWandScale');

for ($i = 0; $i < 100; $i++) {
    $image =& new Image_Converter_GD();
    $image->LoadFromFile('test2.jpg');
    $image->resize(100, 100);
    $image->SaveToFile('test_file.jpg');
}
$timer->setMarker('GD');

for ($i = 0; $i < 100; $i++) {
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->thumbnailImage(100, null);
    $image->writeImage('test_file3.jpg');
    $image->destroy();
}
$timer->setMarker('imagick2Thum');
for ($i = 0; $i < 100; $i++) {
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->ResizeImage(100, 100, 0, false);
    $image->writeImage('test_file3.jpg');
    $image->destroy();
}
$timer->setMarker('imagick2Resize');


for ($i = 0; $i < 100; $i++) {
    $image =& new Imagick();
    $image->readImage('test2.jpg');
    $image->scaleImage(100, 100);
    $image->writeImage('test_file3.jpg');
    $image->destroy();
}
$timer->setMarker('imagick2Scale');

$timer->stop();  
$timer->display();
画像は、50kの450x337のjpeg画像を使いました。

結果:
---------------------------------------------------------------
marker             time index            ex time         perct   
---------------------------------------------------------------
Start              1178505987.83615100   -                0.00%
---------------------------------------------------------------
MagickWandResize   1178505991.81219600   3.976045        19.52%
---------------------------------------------------------------
MagickWandScale    1178505995.10683000   3.294634        16.17%
---------------------------------------------------------------
GD                 1178505997.10204700   1.995217         9.79%
---------------------------------------------------------------
imagick2Thum       1178506002.06985900   4.967812        24.39%
---------------------------------------------------------------
imagick2Resize     1178506004.92157200   2.851713        14.00%
---------------------------------------------------------------
imagick2Scale      1178506008.20629400   3.284722        16.13%
---------------------------------------------------------------
Stop               1178506008.20636800   0.000074         0.00%
---------------------------------------------------------------
total              -                     20.370217      100.00%
表だけ見ると、GDが早いような気がしますが、対応形式などを考えると、他の選択肢のほうがよさそうな気もしますが、そこらへんは好みの問題だと思います。

あとはリサイズの画像の美しさですが、フィルタにどれを使うかなどいろいろ選択肢がありますので、またそのうち紹介したいと思います。
最近、画像周りは、讃容日記 - PHP で JPEG ロスレス回転とかされている方もいらっしゃったりして、僕のなかで非常に熱い分野なんですが、そもそも、最近、PHP勉強会で、PECLのライブラリをわりと簡単に公開するライブラリの紹介などもあったりして、PHPの拡張周りの話が、非常に面白そうだと思っています。

もし、画像操作周りで面白いライブラリなどがあったら、PHPに限らず教えていただけると幸いです。 個人的には、PythonのPILが気になっています。

トラックバック

このエントリーのトラックバックURL:
http://www.unoh.net/mt32/mt-tb.cgi/849

この一覧は、次のエントリーを参照しています: PHPの画像処理の紹介と簡単な比較:

» ウノウラボ Unoh Labs: PHPの画像処理の紹介と簡単な比較 from ITGJ!
phpの画像処理に使えるライブラリの一覧や比較。
ベンチマークの結果など参考になる記事です。 [詳しくはこちら]

» 日記/2007-05-23 from PukiWiki Plus! (PukiWiki/TrackBack 0.4)
tag.inc.php  幅広く何でも扱うと、収集が付かなくなるのは何でも当たり前なので、タグをつけることにしたが、PukiWiki に元からあるタグ... [詳しくはこちら]

» php from Drupalブック
[詳しくはこちら]

コメント

Imlib2はいかがでしょうか。

> MKさん
すっかり失念していました。
情報ありがとうございます。

PEAR::Image_Transformでサポートされているものに、NetPBMとかもあるので、ここらへんがどんなものか今度調べたいと思います。

PEAR::Image_Transformは、僕がしらべた時点では、メンテナンスされてませんでしたが、なんかリリースされてますね。

コメントを投稿


画像の中に見える文字を入力してください。