[自分用メモ] GDを使ってPHPで画像を合成する

PHPとGDライブラリを使って画像を重ね合わせて1つの画像を生成する、という要求が発生したので作成してみた。

以下はあくまでも検証用のサンプルコードなので、実際の使用に際しては必要に応じたコーディングが求められる。このプログラムを使うに際しては、以下のようなディレクトリ構成を想定している。

imgsvr プログラムのあるディレクトリ
 |
 +– parts 部品画像を置いたディレクトリ。この例ではhr.png、fb.pngなど合計9パーツ画像が保存されている。
 |
 +– cache 合成した画像を保存しておくディレクトリ。

頭、胴体、足の3種類の画像がそれぞれ赤、緑、青の3カラー分、パーツとして用意されている。
この3種類を組み合わせて1人体を合成するというプログラムである。
まあ要するに、丸、四画、棒2本がそれぞれパーツ画像として用意されていて、適宜組み合わせて以下のような画像を生成するということである。

php_gd_01

合成画像のリクエスト方法はプログラムを見れば一目瞭然ではあるが、たとえば絵の画像をプログラムに要求する場合は以下のようにパラメータを指定する。

http://192.168.1.1/imgsvr/index.php?h=hr&b=bg&f=fb

なおこのプログラムでは画像そのものを返すわけではなくHTMLを出力している。つまりimage/pngとして画像情報を返さずtext/htmlとして返している。このあたりは仕様によって実装を調整すればいいだけである。画像データを出力する場合は、header(“Content-type: image/png”);にすればいい。
また、ここでは画像サイズはすべて縦横とも96ピクセルとしている。

[php]
<?php
$img_width = 96;
$img_height = 96;

$base_url = "http://192.168.1.1/imgsvr";
$cache_dir = "./cache";
$parts_dir = "./parts";

if (!isset($_REQUEST["h"]) || !isset($_REQUEST["b"]) || !isset($_REQUEST["f"]))
exit;

$h = $_REQUEST["h"];
$b = $_REQUEST["b"];
$f = $_REQUEST["f"];

$cache_name = $h . "_" . $b . "_" . $f . ".png";

if (file_exists($cache_dir . "/" . $cache_name)) {
$title = "Cache";

$img_url = $base_url . "/" . $cache_dir . "/" . $cache_name;
} else {
$title = "Create";

$png0 = imagecreatetruecolor($img_width, $img_height*3);
$png1 = imagecreatefrompng($parts_dir . "/" . $h . ".png"); // head
$png2 = imagecreatefrompng($parts_dir . "/" . $b . ".png"); // body
$png3 = imagecreatefrompng($parts_dir . "/" . $f . ".png"); // foot

if (!$png0 || !$png1 || !$png2 || !$png3)
exit;

imagecopy($png0, $png1, 0, $img_height*0, 0, 0, $img_width, $img_height);
imagecopy($png0, $png2, 0, $img_height*1, 0, 0, $img_width, $img_height);
imagecopy($png0, $png3, 0, $img_height*2, 0, 0, $img_width, $img_height);

imagepng($png0, $cache_dir . "/" . $cache_name);

$img_url = $base_url . "/" . $cache_dir . "/" . $cache_name;

imagedestroy($png0);
imagedestroy($png1);
imagedestroy($png2);
imagedestroy($png3);
}

print <<< __EOL__
<html>
<head></head>
<body>
<h3>$title</h3>
name = $cache_name<br>
<br>
<img src="$img_url">
</body>
</html>
__EOL__;
?>
[/php]

9行目でパラメータをチェックしている。
12~14行目でそれぞれ指定されたパーツ(ここでは拡張子より前のファイル名)を受け取っている。
16行目はキャッシュ時のファイル名で、アンダーバーで結合するという単純なネームコンベンションを使っている。ここは必要に応じて仕様策定者や実装者が決めればよいだろう。この名前のファイル名でキャッシュディレクトリをチェックし、キャッシュがあればこのファイル名をそのまま返すし、なければ新規生成した際にこのファイル名でキャッシュに合成画像を保存する。
18行目でキャッシュの有無を確認する。
19行目は単に「キャッシュから読み込んだ」ことを示すタイトル文字列を書いているだけ。
21行目はimgタグのsrc指定子に埋めるURLを生成している。

23~44行目はキャッシュが存在しないのでGDライブラリを用いて画像を合成する処理をしている部分である。いよいよGDの登場とあいなる。
23行目はタイトル文字列。
24行目はimagecreatetruecolor()で合成先となるキャンバスを作成している。縦につなげていくので、幅は固定、高さは3倍で設定している。
26~28行目ではimagecreatefrompng()でPNGファイルを読み込んでいる。
30行目はすべてのリソースをチェックし、取得できていない場合はプログラムを中断する。
33~35行目は、ベースとなるキャンバスに1つずつパーツ画像を載せている。高さ方向のコピー開始位置を96ピクセルの倍数で指定している。
37行目で、ベースとなるキャンバス上に生成された合成画像をキャッシュに保存している。
39行目で画像のURLを変数に設定する。
41~44行目は、使用したすべてのリソースを開放する。

47~57行目は説明不要であろう。

ここでは重ならない合成をしている。重なる合成の場合は透過の問題とかもあるので別の処理が必要となる(はず)。
それはまだ調査中~。

コメントを残す

メールアドレスが公開されることはありません。