PHP+GDで画像の透過

昨日のようにぬりつぶしだと、指定座標の色が透過用ではなかったり、また他の透過させたい背景のところまで色が連続していなかったりするとまるで使えません。そこで今度は正確なカラーインデックスを取得して割り当てれば大丈夫なのでは?ということで透過処理を下記のコードにいれかえます。

$white = imagecolorexact($backimg, 255, 0, 255);
imagecolortransparent($backimg, $white);

これなら行けるかと思えば前回の強制処理とは違うので画像も選ぶ必要があります。
透過書き出しとしっても種類がありFireworksの場合ではgif/pngともに8bit色インデックス透明カラー(255,0,255)を指定します。

早速やってみたところ、元画像gifの場合は成功しましたがpngで失敗。
ちょっとトレースしてみたら、imagecolorexactでgifの場合必ず-1が返ってきていてimagecolortransparentが役に立ってない。pngでは正の整数が返っているようだが…。

と言うことで上記の透過処理そのものを外すとgif/png共に成功… orz…
全然意味ないどころか障害になってた。

前に同じように透過処理をしないまま合成したときはマットカラー?と思われる色が塗りつぶされていたりしたので全く信頼できない不安定状態です。(多分元画像側でしっかりフォーマットを統一させれば大丈夫と思うが最近のデザイナーはフォーマット知識無いから大変)

PHPとGDのどっちがバグってるのか検討も付かないなー。
今のところ元画像をgifにして書き出しをpng/gifで使い分けるほうが安全かもしれないです。

20060714-1gd_marge

PHP+GDでアバターの着せ替え

最近、仕事でGD使うことが多くなって実はそれを利用してアバターの合成とかやってたりします。
アバターとはYahoo!等に設定されている着せ替え可能なキャラクターのことですね。FLASHやアプリだとパーツごとに渡してあとはFLASH/アプリに任せれば良いのですが、ウェブページの場合は最終的に一枚の画像に合成しないといけないんですね。PHPで合成するなら簡単、透過画像も透過のまま合成できます。但しそのままでは出力時に透過がなくなるので透過を残す場合はちょっと工夫が必要です。

背景と前景の画像ピクセルサイズはが同一の場合のサンプル

// 背景にする画像を読み込み(PNG画像の場合)
$backimg = imagecreatefrompng(‘background.png’);

// 画像サイズの取得
$size = getimagesize(‘background.png’);

// 前景にする画像を読み込み
$frontimg = imagecreatefrompng(‘front.png’);

// 合成処理 ($backimgの上に$frontimgを合成して結果が$frontimg$backimgに上書きされる)
imagecopymerge( $backimg, $frontimg, 0,0,0,0, $size[0], $size[1], 100);

// 背景と前景をあわせても透過部分が残る場合は出力時に透過にするように処理(特殊)
// 透過色を255,0,255に定義
$white = imagecolorallocate( $frontimg$backimg, 255,0,255);
// 先程の設定色を透過色として設定
imagecolortransparent($frontimg$backimg,$white);
// 透過色で塗りつぶしてみる
imagefill($frontimg$backimg,0,0,$white);

// ファイルに書き出しの場合
imagepng($frontimg$backimg,’marge.png’);

// 画像として画面に出力の場合
header(“Content-Type: image/png”);
imagepng($frontimg$backimg);

上記の方法は透過パレット色を指定しない場合で(0,0)の位置が透過対象でない場合失敗します。透過色を統一して指定する場合はimagefillが不要になると思います。その場合imagecolorecact等で取得したインデックスでないと失敗します。(その方法は次回に)

またこの方法ではアニメーションができない。リアルタイムで反映させたりアニメーションさせるのであればJavaScriptになるのかなー?サイト製作はPerl/PHPばかり多くてCSS/JavaScriptには手が回らない。 orz…

追記:2008年12月1日
長らく誤記を放置してました。すみません。途中でマージ後の出力先を勘違いしていた模様です。随分前のエントリーの為透過処理辺りのフォーマットによるルールとか今では記憶が怪しい・・・。

実際に動作するソースは次のエントリーにリンクを張っていますのでこちらも参照お願いします。

PHP5のインストール

最小構成のFreeBSDからなのでPHP導入前にいろいろとインストールする必要があります。

◇libcurlのインストール

ダウンロード
http://curl.haxx.se/

展開
# tar zxf curl-7.15.3.tar.gz

インストール
# cd /usr/local/src/curl-7.15.3
# ./configure
# make
# make install

◇libiconvのインストール

ダウンロード
http://www.gnu.org/software/libiconv/
http://www2d.biglobe.ne.jp/~msyk/software/libiconv-1.9.1-patch.html

展開
# tar zxf libiconv-1.9.1.tar.gz

パッチ適用
# zcat libiconv-1.9.1-ja-patch-1.diff.gz | patch -p0

※私がDLしたパッチはテキストだったのでzcatでなくcat使いました。

インストール
# cd /usr/local/src/libiconv-1.9.1
# ./configure
# make
# make install
◇PHP5のインストールと設定

ダウンロード
http://www.php.net/

展開
# tar zxf php-5.1.4.tar.gz

インストール
# cd /usr/local/src/php-5.1.4
# ./configure
–enable-mbstring
–enable-mbregex
–enable-zend-multibyte
–prefix=/usr/local
–with-gd
–with-jpeg-dir=/usr/local/lib/
–with-png-dir=/usr/local/lib/
–with-zlib-dir=/usr/lib/
–with-dom
–with-curl
–enable-xslt
–with-xslt-sablot
–with-dom-xslt
–with-zlib
–with-apxs2=/usr/local/apache/bin/apxs
–with-mysql=/usr/local/mysql
–with-pgsql=/usr/local/pgsql

# make
# make install

実はこの時点でwgetが無いとかエラーが発生したが、強行してPHPの導入完了。
まだまだ足りないプログラムがあるみたいなのでそれは後でゆっくり。(makeは正常終了しているので関数が抜けているとかは無いと思う)

Apacheのmime.typesに下記を追加

application/x-httpd-php php
application/x-httpd-php-source phps

Apacheを再起動
# /usr/local/apache/bin/apachectl restart

追記:
この直後にwgetを入れてmake installさせました。その時PEAR関連でアップデータを取り込んでいました。なるほどそういうことなんですね。

◇wgetのインストール

ダウンロード
http://www.gnu.org/software/wget/

展開
# tar zxf wget-1.10.2.tar.gz

インストール
# cd /usr/local/src/wget-1.10.2
# ./configure
# make
# make install