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 に記述しておくこと。

準備:初期値

0024: //画像に埋め込むロゴ・ファイル(PNG形式):各自の環境に合わせて
0025: define('FILE_LOGO', './studio_pahoo.png');
0026: 
0027: //保存先ディレクトリ:各自の環境に合わせて
0028: define('DEST_PATH', './');
0029: 
0030: //ExifToolの場所:各自の環境に合わせて(非使用時には空文字にする)
0031: define('EXIFTOOL', 'C:\Program Files (x86)\exiftool\exiftool.exe');
0032: 
0033: //保存ファイル名に付ける文字列
0034: define('DEST_APPEND', '_result');
0035: 
0036: //元画像の幅に対するロゴの大きさ(割合=0を超え1.0以下の小数)
0037: define('RATIO_LOGO', 0.4);
0038: 
0039: //画像の表示サイズ(単位:ピクセル)
0040: define('IMG_WIDTH',  600);
0041: define('IMG_HEIGHT', 400);
0042: 
0043: //データ入力に関わる関数群:include_pathに配置すること【変更不可】
0044: require_once('pahooInputData.php');
0045: 
0046: //画像タイプ別処理関数
0047: $ImageCreateTable = array(
0048:     IMAGETYPE_BMP  => array('create'=>'imagecreatefrombmp',  'image'=>'imagebmp'),
0049:     IMAGETYPE_GIF  => array('create'=>'imagecreatefromgif',  'image'=>'imagegif'),
0050:     IMAGETYPE_JPEG => array('create'=>'imagecreatefromjpeg', 'image'=>'imagejpeg'),
0051:     IMAGETYPE_PNG  => array('create'=>'imagecreatefrompng',  'image'=>'imagepng'),
0052:     IMAGETYPE_WEBP => array('create'=>'imagecreatefromwebp', 'image'=>'imagewebp'),
0053: );

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

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

0225: /**
0226:  * 画像ファイルの情報を取得する
0227:  * @param   array  $finfo  画像ファイル情報を格納する配列
0228:  * @param   string $fname  画像ファイル名(フルパス)
0229:  * @param   string $errmsgエラーメッセージ格納用
0230:  * @return  bool TRUE:取得成功/FALSE:取得失敗
0231: */
0232: function getImageInfo(&$finfo$fname, &$errmsg) {
0233:     //ファイル存在可否チェック
0234:     if (! file_exists($fname)) {
0235:         $errmsg = '"' . $fname . '"' . ' が存在しません';
0236:         return FALSE;
0237:     }
0238: 
0239:     //画像ファイル情報取得
0240:     $arr = getimagesize($fname);
0241:     if ($arr == FALSE) {
0242:         $errmsg = '"' . $fname . '"' . ' は画像ファイルではありません';
0243:         return FALSE;
0244:     }
0245:     $finfo['fname']  = $fname;
0246:     $finfo['width']  = $arr[0];
0247:     $finfo['height'] = $arr[1];
0248:     $finfo['type']   = $arr[2];
0249: 
0250:     return TRUE;
0251: }

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

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

0253: /**
0254:  * 画像ファイルを読み込み、画像オブジェクトを返す
0255:  * @param   string $fname  画像ファイル名
0256:  * @param   int    $type   画像タイプ
0257:  * @param   string $errmsgエラーメッセージ格納用
0258:  * @return  GdImage 画像オブジェクト/FALSE:失敗
0259: */
0260: function myimagecreate($fname$type, &$errrmsg) {
0261:     global $ImageCreateTable;
0262: 
0263:     $img = FALSE;
0264:     if (isset($ImageCreateTable[$type])) {
0265:         if (function_exists($ImageCreateTable[$type]['create'])) {
0266:             //画像読み込み
0267:             $img = $ImageCreateTable[$type]['create']($fname);
0268:             if (! $img) {
0269:                 $errmsg = '"' . $fname . '" は画像ファイルではありません';
0270:             }
0271:         } else {
0272:             $errmsg = '画像ファイルを読み込むことができません(GDライブラリをインストールしてください)';
0273:         }
0274:     } else {
0275:         $errmsg = '"' . $fname . '" は読み込み可能な画像ファイルではありません';
0276:     }
0277: 
0278:     return $img;
0279: }

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

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

0281: /**
0282:  * 画像ファイルにロゴを合成し,ファイルに保存するとともに表示用HTMLタグを生成
0283:  * @param   string  $sour   画像ファイル名
0284:  * @param   string  $logo   ロゴ・ファイル名
0285:  * @param   string  $dest   保存ファイル名
0286:  * @param   string  $html   HTML格納用(imgタグ)
0287:  * @param   string  $errmsgエラーメッセージ格納用
0288:  * @param   bool    $exif   TRUE:Exif情報をコピー/FALSE:コピーしない
0289:  * @return  bool TRUE:処理成功/FALSE:取得失敗
0290: */
0291: function ($sour$logo$dest, &$html, &$errmsg$exif=TRUE) {
0292:     global $ImageCreateTable;
0293: 
0294:     //画像ファイルの情報取得
0295:     if (getImageInfo($lsour_info$sour$errmsg) == FALSEreturn FALSE;
0296: 
0297:     //ロゴファイルの情報取得
0298:     if (getImageInfo($logo_info$logo$errmsg) == FALSE)  return FALSE;
0299:     if ($logo_info['type'] != IMAGETYPE_PNG) {
0300:         $errmsg = '"' . $logo . '"' . ' はPNG形式ファイルではありません';
0301:         return FALSE;
0302:     }
0303: 
0304:     //画像ファイルを読み込む
0305:     $img_sour = myimagecreate($sour$sour_info['type'], $errrmag);
0306:     if (! $img_sourreturn FALSE;
0307: 
0308:     //ロゴファイルを読み込む
0309:     $img_logo0 = myimagecreate($logo$logo_info['type'], $errrmag);
0310:     if (! $img_sourreturn FALSE;
0311: 
0312:     //ロゴのサイズ
0313:     $width = (int)((float)$sour_info['width'] * RATIO_LOGO);
0314:     $height = (int)($width / (float)$logo_info['width'] * (float)$logo_info['height']);
0315:     //リサイズ後のロゴ
0316:     $img_logo1 = imagecreate($width$height);
0317:     if ($img_logo1 == FALSE)        return FALSE;
0318: 
0319:     //ロゴをリサイズしてコピー
0320:     $res = imagecopyresampled($img_logo1$img_logo0, 0, 0, 0, 0, $width$height$logo_info['width'], $logo_info['height']);
0321: 
0322:     //リサイズしたロゴを合成
0323:     $x1 = $sour_info['width']  - $width - 1;
0324:     $y1 = $sour_info['height'] - $height - 1;
0325:     $res = imagecopy($img_sour$img_logo1$x1$y1, 0, 0, $width$height);
0326: 
0327:     //画像をファイルに出力
0328:     $type = $sour_info['type'];
0329:     $res = $ImageCreateTable[$type]['image']($img_sour$dest);
0330: 
0331:     //画像ファイルにExif情報を埋め込む
0332:     $res = TRUE;
0333:     if ($exif && ($type == IMAGETYPE_JPEG)) {
0334:         if (file_exists(EXIFTOOL)) {
0335:             $cmd = '"' . EXIFTOOL . '" -tagsfromfile ' . $sour . ' ' . $dest;
0336:             $result = array();
0337:             $res = exec($cmd$result);
0338:             if (! $res) {
0339:                 $errmsg = 'Exif情報のコピーに失敗しました';
0340:             }
0341:         }
0342:     }
0343:     //埋め込み前のファイルを削除
0344:     if ($res != FALSE) {
0345:         $res = unlink($dest . '_original');
0346:     }
0347: 
0348:     //画像表示用imgタグ生成
0349:     $html = img2html($img_sourIMG_WIDTHIMG_HEIGHT$errmsg);
0350: 
0351:     return $res;
0352: }

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

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

0192: /**
0193:  * 画像オブジェクトをimgタグに埋め込む
0194:  * @param   GdImage $img    画像オブジェクト
0195:  * @param   int     $width  表示したい幅(ピクセル)
0196:  * @param   int     $height 表示したい高さ(ピクセル)
0197:  * @param   string  $errmsgエラーメッセージ格納用
0198:  * @return  string imgタグ/FALSE:変換失敗
0199: */
0200: function img2html($img$width$height, &$errmsg) {
0201:     $html = '';
0202: 
0203:     //画像伸縮
0204:     $width0  = imagesx($img);
0205:     $height0 = imagesy($img);
0206:     $magw = (float)$width / (float)$width0;
0207:     $magh = (float)$height / (float)$height0;
0208:     $mag  = min($magw$magh);
0209:     $width1  = (int)($width0 * $mag);
0210:     $height1 = (int)($height0 * $mag);
0211:     $img1 = imagecreatetruecolor($width1$height1);
0212:     imagecopyresampled($img1$img, 0, 0, 0, 0, $width1$height1$width0$height0);
0213: 
0214:     //画像データをBASE64エンコード
0215:     ob_start();
0216:     imagejpeg($img1);
0217:     $ss = ob_get_contents();
0218:     ob_end_clean();
0219:     $ss = base64_encode($ss);
0220:     $html = "<p><img src=\"data:image/jpg;base64," . $ss ."\" /></p>";
0221: 
0222:     return $html;
0223: }

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

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

0073: <script>
0074: /**
0075:  * ファイルのドロップ
0076:  * @param   evt  イベント
0077:  * @return  なし
0078: */
0079: function handleFileSelect(evt) {
0080:     evt.stopPropagation();
0081:     evt.preventDefault();
0082: 
0083:     var files = evt.dataTransfer.files; 
0084:     var output = [];
0085: 
0086:     document.getElementById('upload').files = files;
0087:     document.myform.submit();
0088: }
0089: 
0090: function handleDragOver(evt) {
0091:     evt.stopPropagation();
0092:     evt.preventDefault();
0093:     evt.dataTransfer.dropEffect = 'copy';
0094: }
0095: 
0096: function PageLoad(evt) {
0097:     var dropFrame = document.getElementById('DropFrame');
0098:     dropFrame.addEventListener('dragover', handleDragOver, false);
0099:     dropFrame.addEventListener('drop', handleFileSelect, false);
0100: }
0101: </script>

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

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

ロゴの作り方

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

参考サイト

(この項おわり)
header