PHP GD を使って透過PNGを作る方法

GD を使ってそのまま透過PNGを作ろうとすると、
1ピクセルごとに透過(アルファ)値を操作する必要があり非常に処理が重くなります。
そこで、事前にテンプレートとなる透過PNGを用意し、それを重ねることで実現します。

  1. 画像準備
  2. PHPコード
  3. コード解説

画像準備

画像を準備します。

透過準備画像

少し分かりにくいですが、円の周りは透過しています。
後述しますが、描画色は 7F7F7F (R127,G127,B127)で準備します。

PHPコード

後は、下記コードで動作します。

$imgPath = '画像パス';
$imgInfo = getimagesize($imgPath);

// ファイルオブジェクトを作成する
// - ファイルタイプ別に呼び出すメソッドを変える
$imgObj = null;
switch($imgInfo['mime']){
	case 'image/jpeg':
		$imgObj = imagecreatefromjpeg($imgPath);
		break;
	case 'image/gif':
		$imgObj = imagecreatefromgif($imgPath);
		break;
	case 'image/png':
		$imgObj = imagecreatefrompng($imgPath);
		break;
}
imagelayereffect($imgObj, IMG_EFFECT_OVERLAY);    // アルファブレンディングの設定をする
imagesavealpha($imgObj, true);                    // アルファ情報を保存するようフラグを立てる

$imgAlpha = imagecreatefrompng('透過画像パス');

imagecopy($imgObj,$imgAlpha,0,0,0,0,$imgW,$imgH); // 混ぜる

imagepng($imgObj,'画像保存パス');

// メモリ開放
imagedestroy($imgObj);
imagedestroy($imgAlpha);

これを実行すると

透過前金魚

透過後金魚

こうなります。

コード解説

まず、画像を読み込みます。
その際、画像の形式によって呼び出すメソッドが異なるので注意です。

switch($imgInfo['mime']){
	case 'image/jpeg':
		$imgObj = imagecreatefromjpeg($imgPath);
		break;
	case 'image/gif':
		$imgObj = imagecreatefromgif($imgPath);
		break;
	case 'image/png':
		$imgObj = imagecreatefrompng($imgPath);
		break;
}

この後に指定している2つが要注意です。
一つ一つ解説していきます。

imagelayereffect($imgObj, IMG_EFFECT_OVERLAY);    // アルファブレンディングの設定をする

これは、画像をどのように合成(重ねあわせ)するかの設定です。
今回は IMG_EFFECT_OVERLAY を使っています。
PHPの公式サイトには

オーバーレイを使用すると、背景の黒い部分は黒のまま。
一方背景の白い部分は白のままとなります。 背景のグレーな部分は、前景のピクセルの色となります。

とあります。
細かいことは置いておいて、今回は

背景のグレーな部分は、前景のピクセルの色となります。

を利用します。ここで言っているグレーと言うのは 7f7f7f の事を指しています。
そこで、全てを 7f7f7f で塗りつぶし、透過した部分を作った画像を用意したわけです。

次に

imagesavealpha($imgObj, true);                    // アルファ情報を保存するようフラグを立てる

これで画像を保存した際に、透過情報が抜け落ちないようにしてます。

ここで注意点なのですが

imagealphablending($imgObj, false);

この指定は絶対にしてはいけません。
正直、理由はよくわかってません(すいませんっ!)が、
どうも imagelayereffect の設定が変更されてしまうみたいです。

ちゃんと読んだら、公式に
imagelayereffect に IMG_EFFECT_ALPHABLEND を設定するのと同じ
と書いてありました orz

あとは、画像を重ねあわせて保存しています。


「簡単にできるだろ」
とか思っていたら、存外うまくいかない上に
資料もあまりなく、結構ハマってしまいました。
(そもそも、サーバサイドで画像加工する機会はほとんどないですからね…)
備忘録がてら記事にしてみました。

…しかし、我ながら硬い文章だ