PHPのGDライブラリを使ってサムネイルの作成
作っていたPHPスクリプトにいくつかの改良を重ねるべく、GDライブラリの追加を行うことにした。OSごとにインストールの手順が違うようだが、僕の環境(Windows2000,Apache,PHP4.3.8)では、以下のような感じに。
イメージ関数のインストール手順
イメージ関数は、デフォルトでインストールされていないので、追加してインストールする必要があります。PHPマニュアルには、イメージ関数のインストール手順が書いてある。
現在の僕の環境と同じ、Windows2000+Apache+PHPのZIP形式のバイナリ版を使っているなら、
C:\WINNT
というディレクトリにあるPHPの設定ファイル"php.ini"をテキスト・エディタで開いて、;(セミコロン)でコメントアウトされているGDライブラリのエクステンションを有効にする。
;extension=php_gd2.dll
を以下のようにするだけ。
extension=php_gd2.dll
設定ファイルを保存した後、Apacheを再起動すれば認識される。
念のため、phpinfo()関数でチェックしてみる。

"gd"という項目が追加されていればOK。ちなみに僕が使っているロリポップのサーバーでは使えるみたいです。良かった( ´∀`)σ)∀`)
スクリプトのサンプル
続いてスクリプトを書いてみる。イメージ関数のページをぱらぱらと斜め読みして使えそうな関数をピックアップして適当に作ってみました。
$img_name = "image.jpg"; //ファイル名(JPEG画像)
$img_path = "./"; //サムネイルを作る元画像のあるディレクトリ(必ず末尾は"/"で閉じる)
$thumbnail_path = "thumbnail/"; //サムネイルを保存するディレクトリ
$img_w = 640; //元の画像の横幅
$img_h = 480; //元の画像の縦幅
$thumbnail_w = 80; //サムネイルの横幅
$thumbnail_h = 60; //サムネイルの縦幅
create_thumbnail ( $img_name, $img_path, $thumbnail_path,
$img_w, $img_h, $thumbnail_w, $thumbnail_h );
function create_thumbnail ( $img_name, $img_path, $thumbnail_path,
$img_w, $img_h, $thumbnail_w, $thumbnail_h ) {
$src_img = @imagecreatefromjpeg ( $img_path.$img_name ); //サムネイル元 ※1
if ( $src_img ) {
//サムネイル作成 ※2
$dst_img = imagecreatetruecolor ( $thumbnail_w, $thumbnail_h );
//640*480の画像を元に、80*60のサムネイルを作成
$result = imagecopyresampled ( //$result = imagecopyresized (
$dst_img, //貼り付けするイメージID
$src_img, //コピーする元になるイメージID
0, //int dstX (貼り付けを開始するX座標)
0, //int dstY (貼り付けを開始するY座標)
0, //int srcX (コピーを開始するX座標)
0, //int srcY (コピーを開始するY座標)
$thumbnail_w, //int dstW (貼り付けする幅)
$thumbnail_h, //int dstH (貼り付けする高さ)
$img_w, //int srcW (コピーする幅)
$img_h //int srcH (コピーする高さ)
);
//サムネイルをJPEG形式で保存
imagejpeg ( $dst_img, $thumbnail_path.$img_name );
imagedestroy ( $dst_img ); //サムネイル用イメージIDの破棄 ※3
imagedestroy ( $src_img ); //サムネイル元イメージIDの破棄 ※4
html_p ( "サムネイルが作成されました。" );
html_p ( "<a href=\"$img_path$img_name\"><img src=\"$thumbnail_path$img_name\" alt=\"サムネイル\" /></a>" );
} else {
html_p ( "error:サムネイル元になる画像が読み込めませんでした。" );//error
exit ();
}
}
function html_p ( $str ) {
echo ( "<p>$str</>\n" );
}
imagecopyresampled()関数は、引数が多いのでややこしいです。PHPマニュアルもちょっと解りづらいし……。とりあえず引数ごとにコメントで注釈してあります。メモメモ。
imagecreateXXXX()関数とimagedestroy()関数
$src_img = @imagecreatefromjpeg ( $img_path.$img_name ); // サムネイル元 ※1
先頭につけた"@"でエラーメッセージを抑止したimagecreatefromjpeg()関数で、指定されたファイルから新規作成しています。余談ですが、fopen wrappersを有効にするとリモートファイルも使えるそうです。
また、imagecreatefromjpeg()や、imagecreatefrompng()といった先頭に"imagecreate"と付いている関数で使用したリソース(サンプルでは、$src_img)を必ずimagedestroy()関数で、保持するメモリを解放しましょう。
imagedestroy ( $src_img ); //サムネイル元イメージIDの破棄 ※4
つまり、imagecreateなんとか()関数と、imagedestroy()関数はセットで。
もし、imagedestroy()関数を使わなかったら、解放されないまま無駄に残っている情報がメモリに溜まってサーバーが重くなったり、落ちる可能性があります。
これはかなり怖い事態を想像できちゃうので、ちゃんとimagedestroy()しましょう(; ´∀`)σ)∀`)
ロリポップのサーバーのメンテナンス情報で、「ユーザーの自作スクリプトが多大な負荷を……」というのがあったのを思い出します。
imagecreatetruecolor()関数
//サムネイル作成 ※2
$dst_img = imagecreatetruecolor ( $thumbnail_w, $thumbnail_h );
続いて、imagecreateruecolor()関数です。長い名前だ。
同じような関数にimagecreate()関数があるのですが、上記部分を、
$dst_img = imagecreate ( $thumbnail_w, $thumbnail_h );
と記述しても、スクリプト上の問題はありませんでした。
が、問題があったのは作成された以下の画像。

なんか、かなりジャギジャギして色の少ない画像です。どうやら、imagecopyresampled()関数の解説によると、
注意: パレットイメージの制限(255+1色)による問題があります。 カラーの再サンプリングやフィルタリングには通常は255色以上の色が 必要となります。再サンプルするピクセルとその色を計算するために ある種の近似計算が使用されます。パレットに新しい色を割り当てよう として失敗すると、(理論的に)最も近い色が選択されます。 それは必ずしも常に可視色とは限りません。そのため、 空白(あるいは不可視な)といった不可思議な結果がもたらされます。 この問題を回避するには、imagecreatetruecolor()で 生成されるようなTrueカラーイメージを目的のイメージとして 使用してください。
とのこと。imagecreate()関数は、GIFやPNG8形式の画像の処理に適しているが、JPEG形式には向いていないようです。というわけで、imagecreatetruecolor()関数を使いました。
この関数も、imagecreate()関数と同じで、使用していたメモリを解放するために必要がなくなったらimagedestroy()関数を使ってメモリを解放しましょう。
imagedestroy ( $dst_img ); //サムネイル用イメージIDの破棄 ※3
使ったメモリの後始末はちゃんとね( ´∀`)σ)∀`)
imagecopyresized()関数とimagecopyresampled()関数
サイズを変えるんだから、リサイズつまりimagecopyresized()関数を使ったのですが、PHPマニュアルには、imagecopyresampled()関数というのも紹介されていました。
引数も同じで、機能も殆ど似ています。実際、下のimagecopyresampledという部分をimagecopyresizedに書き換えても機能します。
$result = imagecopyresampled ( //$result = imagecopyresized (
$dst_img, //貼り付けするイメージID
$src_img, //コピーする元になるイメージID
0, //int dstX (貼り付けを開始するX座標)
0, //int dstY (貼り付けを開始するY座標)
0, //int srcX (コピーを開始するX座標)
0, //int srcY (コピーを開始するY座標)
$thumbnail_w, //int dstW (貼り付けする幅)
$thumbnail_h, //int dstH (貼り付けする高さ)
$img_w, //int srcW (コピーする幅)
$img_h //int srcH (コピーする高さ)
);
違いをマニュアルから比べてみると、imagecopyresampled()関数は、ピクセル値を滑らかに補間を行い、このため、特にサイズを小さくした場合には鮮明さが維持されます
、とのこと。
それぞれ処理をさせてみて、画像を比較してみた。
imagecopyresized()関数で生成された画像
imagecopyresampled()関数で生成された画像
マニュアルにある通り、imagecopyresampled()関数のほうがなめらかで見やすいと思われる。
しかし、サムネイルが小さくなりすぎると、なめらか過ぎてぼやけている感じもある。この辺は、好みの問題かも知れないが、僕はimagecopyresampled()関数を使うことにしました。
このスクリプトを元にして、今の画像一覧表示のスクリプトとかを修正しようかな。


