PHPで画像にロゴを合成する

(1/1)
ぱふぅ家のホームページでは、大きな写真の右下にエンボス文字をロゴとして合成している。今回は、この合成作業に使っているPHPプログラムの作り方を紹介する。

サンプル・プログラムの実行例

PHPで画像にロゴを合成する

目次

サンプル・プログラム

圧縮ファイルの内容
compositeLogo.phpサンプル・プログラム本体
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
studio_pahoo.pngサンプル・ロゴ

準備:GDライブラリ

PHPで GDライブラリが有効になっていることが必要だ。
あらかじめ関数  phpinfo  を実行し、GD Support が enableになっていることを確認すること。

準備:ExifTool

JPEGのExif情報の取得は「PHPでExif情報を表示する」で解説したが、PHPの標準ライブラリにはExif情報を書き込む関数が用意されていない。
そこで、ExifTool を利用することにした。ダウンロードした実行プログラムを定数 EXIFTOOL に記述しておくこと。

準備:初期値

  24: //画像に埋め込むロゴ・ファイル(PNG形式):各自の環境に合わせて
  25: define('FILE_LOGO', './studio_pahoo.png');
  26: 
  27: //保存先ディレクトリ:各自の環境に合わせて
  28: define('DEST_PATH', './');
  29: 
  30: //ExifToolの場所:各自の環境に合わせて(非使用時には空文字にする)
  31: define('EXIFTOOL', 'C:\Program Files (x86)\exiftool\exiftool.exe');
  32: 
  33: //保存ファイル名に付ける文字列
  34: define('DEST_APPEND', '_result');
  35: 
  36: //元画像の幅に対するロゴの大きさ(割合=0を超え1.0以下の小数)
  37: define('RATIO_LOGO', 0.4);
  38: 
  39: //画像の表示サイズ(単位:ピクセル)
  40: define('IMG_WIDTH',  600);
  41: define('IMG_HEIGHT', 400);
  42: 
  43: //データ入力に関わる関数群:include_pathに配置すること【変更不可】
  44: require_once('pahooInputData.php');
  45: 
  46: //画像タイプ別処理関数
  47: $ImageCreateTable = array(
  48:     IMAGETYPE_BMP  => array('create'=>'imagecreatefrombmp',  'image'=>'imagebmp'),
  49:     IMAGETYPE_GIF  => array('create'=>'imagecreatefromgif',  'image'=>'imagegif'),
  50:     IMAGETYPE_JPEG => array('create'=>'imagecreatefromjpeg', 'image'=>'imagejpeg'),
  51:     IMAGETYPE_PNG  => array('create'=>'imagecreatefrompng',  'image'=>'imagepng'),
  52:     IMAGETYPE_WEBP => array('create'=>'imagecreatefromwebp', 'image'=>'imagewebp'),
  53: );

「変更不可」以外の定数、変数は自由に変更できる。
定数 RATIO_LOGO は、元の画像の幅に対してロゴの大きさをどのくらいにするか割合(0を超え1.0以下の小数)で指定する。値が大きくなればなるほどロゴが大きくなる。

解説:画像ファイルの情報を取得する

 225: /**
 226:  * 画像ファイルの情報を取得する
 227:  * @param   array  $finfo  画像ファイル情報を格納する配列
 228:  * @param   string $fname  画像ファイル名(フルパス)
 229:  * @param   string $errmsg エラーメッセージ格納用
 230:  * @return  bool TRUE:取得成功/FALSE:取得失敗
 231: */
 232: function getImageInfo(&$finfo, $fname, &$errmsg) {
 233:     //ファイル存在可否チェック
 234:     if (! file_exists($fname)) {
 235:         $errmsg = '"' . $fname . '"' . ' が存在しません';
 236:         return FALSE;
 237:     }
 238: 
 239:     //画像ファイル情報取得
 240:     $arr = getimagesize($fname);
 241:     if ($arr == FALSE) {
 242:         $errmsg = '"' . $fname . '"' . ' は画像ファイルではありません';
 243:         return FALSE;
 244:     }
 245:     $finfo['fname']  = $fname;
 246:     $finfo['width']  = $arr[0];
 247:     $finfo['height'] = $arr[1];
 248:     $finfo['type']   = $arr[2];
 249: 
 250:     return TRUE;
 251: }

ユーザー関数 getImageInfo は、指定した画像ファイルのファイル名、幅、高さ、画像タイプを配列に入れて返す。

解説:画像ファイルの情報を取得する

 253: /**
 254:  * 画像ファイルを読み込み、画像オブジェクトを返す
 255:  * @param   string $fname  画像ファイル名
 256:  * @param   int    $type   画像タイプ
 257:  * @param   string $errmsg エラーメッセージ格納用
 258:  * @return  GdImage 画像オブジェクト/FALSE:失敗
 259: */
 260: function myimagecreate($fname, $type, &$errrmsg) {
 261:     global $ImageCreateTable;
 262: 
 263:     $img = FALSE;
 264:     if (isset($ImageCreateTable[$type])) {
 265:         if (function_exists($ImageCreateTable[$type]['create'])) {
 266:             //画像読み込み
 267:             $img = $ImageCreateTable[$type]['create']($fname);
 268:             if (! $img) {
 269:                 $errmsg = '"' . $fname . '" は画像ファイルではありません';
 270:             }
 271:         } else {
 272:             $errmsg = '画像ファイルを読み込むことができません(GDライブラリをインストールしてください)';
 273:         }
 274:     } else {
 275:         $errmsg = '"' . $fname . '" は読み込み可能な画像ファイルではありません';
 276:     }
 277: 
 278:     return $img;
 279: }

ユーザー関数 myimagecreate は、画像タイプに応じて、あらかじめ用意した配列 $ImageCreateTable にしたがい、GD関数ライブラリを使って画像ファイルを読み込み、画像オブジェクトを返す。

解説:画像ファイルにロゴを合成する

 281: /**
 282:  * 画像ファイルにロゴを合成し,ファイルに保存するとともに表示用HTMLタグを生成
 283:  * @param   string  $sour   画像ファイル名
 284:  * @param   string  $logo   ロゴ・ファイル名
 285:  * @param   string  $dest   保存ファイル名
 286:  * @param   string  $html   HTML格納用(imgタグ)
 287:  * @param   string  $errmsg エラーメッセージ格納用
 288:  * @param   bool    $exif   TRUE:Exif情報をコピー/FALSE:コピーしない
 289:  * @return  bool TRUE:処理成功/FALSE:取得失敗
 290: */
 291: function ($sour, $logo, $dest, &$html, &$errmsg, $exif=TRUE) {
 292:     global $ImageCreateTable;
 293: 
 294:     //画像ファイルの情報取得
 295:     if (getImageInfo($lsour_info, $sour, $errmsg) == FALSEreturn FALSE;
 296: 
 297:     //ロゴファイルの情報取得
 298:     if (getImageInfo($logo_info, $logo, $errmsg) == FALSE)  return FALSE;
 299:     if ($logo_info['type'!IMAGETYPE_PNG) {
 300:         $errmsg = '"' . $logo . '"' . ' はPNG形式ファイルではありません';
 301:         return FALSE;
 302:     }
 303: 
 304:     //画像ファイルを読み込む
 305:     $img_sour = myimagecreate($sour, $sour_info['type'], $errrmag);
 306:     if (! $img_sour)    return FALSE;
 307: 
 308:     //ロゴファイルを読み込む
 309:     $img_logo0 = myimagecreate($logo, $logo_info['type'], $errrmag);
 310:     if (! $img_sour)    return FALSE;
 311: 
 312:     //ロゴのサイズ
 313:     $width = (int)((float)$sour_info['width'* RATIO_LOGO);
 314:     $height = (int)($width / (float)$logo_info['width'* (float)$logo_info['height']);
 315:     //リサイズ後のロゴ
 316:     $img_logo1 = imagecreate($width, $height);
 317:     if ($img_logo1 == FALSE)        return FALSE;
 318: 
 319:     //ロゴをリサイズしてコピー
 320:     $res = imagecopyresampled($img_logo1, $img_logo0, 0, 0, 0, 0, $width, $height, $logo_info['width'], $logo_info['height']);
 321: 
 322:     //リサイズしたロゴを合成
 323:     $x1 = $sour_info['width']  - $width - 1;
 324:     $y1 = $sour_info['height'- $height - 1;
 325:     $res = imagecopy($img_sour, $img_logo1, $x1, $y1, 0, 0, $width, $height);
 326: 
 327:     //画像をファイルに出力
 328:     $type = $sour_info['type'];
 329:     $res = $ImageCreateTable[$type]['image']($img_sour, $dest);
 330: 
 331:     //画像ファイルにExif情報を埋め込む
 332:     $res = TRUE;
 333:     if ($exif && ($type == IMAGETYPE_JPEG)) {
 334:         if (file_exists(EXIFTOOL)) {
 335:             $cmd = '"' . EXIFTOOL . '" -tagsfromfile ' . $sour . ' ' . $dest;
 336:             $result = array();
 337:             $res = exec($cmd, $result);
 338:             if (! $res) {
 339:                 $errmsg = 'Exif情報のコピーに失敗しました';
 340:             }
 341:         }
 342:     }
 343:     //埋め込み前のファイルを削除
 344:     if ($res !FALSE) {
 345:         $res = unlink($dest . '_original');
 346:     }
 347: 
 348:     //画像表示用imgタグ生成
 349:     $html = img2html($img_sour, IMG_WIDTH, IMG_HEIGHT, $errmsg);
 350: 
 351:     return $res;
 352: }

ユーザー関数 compositeLogo が、今回の目玉である。
まず、画像ファイルとロゴファイルを読み込み、それぞれを画像オブジェクトに格納する。
次に、画像ファイルからロゴのサイズ(ピクセル・サイズ)を計算し、ロゴをリサイズして画像オブジェクト $img_logo1 にコピーする。この処理は、「PHPで画像ファイルを読み込んでimgタグに埋め込む」で紹介したものだ。
そして、リサイズしたロゴを元の画像ファイルに合成する。
最後に、画像をファイルに出力し、画像ファイルがJPEG形式だったら、ExifToolを使ってExif情報をコピーする。

解説:画像オブジェクトをimgタグに埋め込む

 192: /**
 193:  * 画像オブジェクトをimgタグに埋め込む
 194:  * @param   GdImage $img    画像オブジェクト
 195:  * @param   int     $width  表示したい幅(ピクセル)
 196:  * @param   int     $height 表示したい高さ(ピクセル)
 197:  * @param   string  $errmsg エラーメッセージ格納用
 198:  * @return  string imgタグ/FALSE:変換失敗
 199: */
 200: function img2html($img, $width, $height, &$errmsg) {
 201:     $html = '';
 202: 
 203:     //画像伸縮
 204:     $width0  = imagesx($img);
 205:     $height0 = imagesy($img);
 206:     $magw = (float)$width / (float)$width0;
 207:     $magh = (float)$height / (float)$height0;
 208:     $mag  = min($magw, $magh);
 209:     $width1  = (int)($width0 * $mag);
 210:     $height1 = (int)($height0 * $mag);
 211:     $img1 = imagecreatetruecolor($width1, $height1);
 212:     imagecopyresampled($img1, $img, 0, 0, 0, 0, $width1, $height1, $width0, $height0);
 213: 
 214:     //画像データをBASE64エンコード
 215:     ob_start();
 216:     imagejpeg($img1);
 217:     $ss = ob_get_contents();
 218:     ob_end_clean();
 219:     $ss = base64_encode($ss);
 220:     $html = "<p><img src=\"data:image/jpg;base64," . $ss ."\" /></p>";
 221: 
 222:     return $html;
 223: }

ユーザー関数 img2html は、ロゴを合成した画像を画面に表示するための関数だ。この処理は、「PHPで画像ファイルを読み込んでimgタグに埋め込む」で紹介したものとほぼ同じである。

解説:ファイルのドロップ

  73: <script>
  74: /**
  75:  * ファイルのドロップ
  76:  * @param   evt  イベント
  77:  * @return  なし
  78: */
  79: function handleFileSelect(evt) {
  80:     evt.stopPropagation();
  81:     evt.preventDefault();
  82: 
  83:     var files = evt.dataTransfer.files; 
  84:     var output = [];
  85: 
  86:     document.getElementById('upload').files = files;
  87:     document.myform.submit();
  88: }
  89: 
  90: function handleDragOver(evt) {
  91:     evt.stopPropagation();
  92:     evt.preventDefault();
  93:     evt.dataTransfer.dropEffect = 'copy';
  94: }
  95: 
  96: function PageLoad(evt) {
  97:     var dropFrame = document.getElementById('DropFrame');
  98:     dropFrame.addEventListener('dragover', handleDragOver, false);
  99:     dropFrame.addEventListener('drop', handleFileSelect, false);
 100: }
 101: </script>

画像ファイルの選択は、input type="file" タグ、およびテキストボックスからURL指定できるほか、ファイルをドラッグする方式の3つを用意した。

ファイルをドラッグする処理は、JavaScriptによって実現している。
ドラッグする場所はオブジェクトとして用意し、そのID名をあらかじめ変数 dropFrame に代入しておく。
関数 PageLoad は bodyタグをonLoadするときに実行すること。

ロゴの作り方

エンボス・ロゴの作り方
同梱のエンボス加工したサンプル・ロゴは、画像編集ソフト「Photoshop Elements」を使って作った。その方法を説明する。
まず、文字を白色で描く。このとき、太めのフォントを使ったほうがロゴとして映える。
エンボス・ロゴの作り方
次に効果パレットで「ベベル」を選び、「シンプル(内側)」を適用する。文字にベベルがかかった。
エンボス・ロゴの作り方
再びレイヤーパレットに戻り、「レイヤーの描画モードを設定」を選び、「乗算」を選んで透明度を調整する。
これでエンボス・ロゴの完成。PNG形式ファイルとして保存する。

参考サイト

(この項おわり)
header