PHP での画像処理をもっと楽に行えるライブラリ ImageWorkshop

PHP で GD 使って行う画像処理をもっと楽に、
わかりやすく扱えるフレームワーク、ImageWorkShop を紹介します。

ImageWorkshop

ImageWorkShop は以下からダウンロードできます。

http://phpimageworkshop.com/

今回紹介するバージョンの 2.0.0 では namespaces が使われているため、
PHP のバージョンが 5.3 以上でないとそのまま動かすことは出来ないそうなので注意してください。

準備

autoloader を利用している場合

ImageWorkshop は autoloader に対応しています。
autoloader を利用している場合は、ライブラリフォルダに ImageWorkshop src/ PHPImageWorkshop 以下のファイルを追加して、

use PHPImageWorkshop\ImageWorkshop;

名前空間を定義してあげれば使えるようになります。

autoloader を使用しない場合

autoloaderを使用しない場合は、 ダウンロードしてきたファイルの src / PHPImageWorkshop 以下のファイルのコード中で コメントアウトされている require_once(…)のコメントを全部元に外します。

その後 ImageWorkshop.php を Include して、名前空間を定義しておきます。

use PHPImageWorkshop\ImageWorkshop;

ここでエラーが表示されていなければ準備は完了です。

使い方

ImageWorkshop は画像やテキスト、シェイプなどをレイヤーとして扱うことができ、
それぞれの高さや幅を取得したり、拡大やフィルターをかけたり、
グループ化したりすることができます。

できることが沢山あるので、ドキュメントを見ながら書いてみるのが1番わかりすいとは思いますが、
今回はこちらを使った簡単な画像処理の流れを載せておきました。

ベタ塗りの画像を作成

use PHPImageWorkshop\ImageWorkshop;
include_once("ImageWorkshop.php");

$width = 400; // 横幅
$height = 300; // 縦幅
$background = "aaa"; // 背景色

$baseLayer = ImageWorkshop::initVirginLayer($width, $height, $background);
// 一色で塗りつぶしたレイヤーを作成

$outputImg = $baseLayer->getResult();
// レイヤーをブラウザで表示できるように変換

header('Content-type: image/png');
header('Content-Disposition: filename="test.png"');
imagepng($outputImg, null, 3); // PNGで出力
exit;

シンプルな塗りつぶし画像を作成しています。
initVirginLayer に幅、高さ、色を指定します。

テキストを表示させる

initTextLayer というメソッドを使います。
引数の内容は以下参照。

$text = "あのイーハトーヴォの\nすきとおった風邪"; // 表示するテキスト
$fontPath = "onryou.TTF"; // 使用するテキスト
$fontSize = 42; // フォントサイズ
$fontColor = "FFFFFF"; // フォントカラー
$textRotation = 0; // テキストを回転させたいばあいはこの数値を変える

$textLayer = ImageWorkshop::initTextLayer($text, $fontPath, $fontSize, $fontColor, $textRotation);

これをさっきの画像に合成してみます。

use PHPImageWorkshop\ImageWorkshop;
include_once("ImageWorkshop.php");

$width = 400; // 横幅
$height = 300; // 縦幅
$background = "aaa"; // 背景色

$baseLayer = ImageWorkshop::initVirginLayer($width, $height, $background);
// 一色で塗りつぶしたレイヤーを作成

$text = "あのイーハトーヴォの\nすきとおった風邪"; // 表示するテキスト
$fontPath = "onryou.TTF"; // 使用するテキスト
$fontSize = 42; // フォントサイズ
$fontColor = "FFFFFF"; // フォントカラー
$textRotation = 0; // テキストを回転させたいばあいはこの数値を変える

$textLayer = ImageWorkshop::initTextLayer($text, $fontPath, $fontSize, $fontColor, $textRotation);

$baseLayer->addLayer(2,$textLayer,0,50,'LT');

$outputImg = $baseLayer->getResult();
// レイヤーをブラウザで表示できるように変換

header('Content-type: image/png');
header('Content-Disposition: filename="test.png"');
imagepng($outputImg, null, 3); // PNGで出力
exit;

initVirginLayer で生成したレイヤーにテキストを追加する処理が加えられています。

$baseLayer->addLayer(2,$textLayer,0,50,'LT'); // 重なりのレベル, 対象のレイヤー, x, y, 基準位置

addLayer を呼び出すことでレイヤー内に別のレイヤーを配置できます。

第一引数にはレイヤーのレベルの指定、css でいう z-index のようなものです。
指定された値が高ければ高いほど上のレイヤーとして表示されます。

また、同じレベルが指定された場合、
後から指定したレベルがそのレベルに取って代わり、
元のレベル以上の数字は一個ずつ数値が繰り上がるようになっているようです。

試しにテキストのレイヤーを追加した後にもう一つレイヤーを追加して、 先ほどのレイヤーより値を小さくしてみます。

$fontColor2 = "000"; // フォントカラー     
$textLayer2 = ImageWorkshop::initTextLayer($text, $fontPath,    $fontSize, $fontColor2, $textRotation);

$baseLayer->addLayer(1,$textLayer2,0,60,'LT');

下に同じテキストで黒文字が敷かれました!

レイヤー中1番上に画像を配置したい場合は addLayerOnTop を使うことで実現できます。

$baseLayer->addLayerOnTop($textLayer2,0,60,'LT');

個人的には基本的には下のレイヤーは先に書いて、
上のレイヤーに行くほど下に処理を書いて、
addLayerOnTop で追加していくのがいいかなーと思っています。

第二引数は追加する レイヤー、
第三、第四引数は追加する位置(x, y)を指定します。
第五引数はどこを基準にして第三、第四引数の位置に配置するかを決めます。

x 方向、y 方向 それぞれ基準とする位置の頭文字を大文字で指定します。

左上だったら “LT”、 右下だったら “RB”…
のような感じです。

画像素材を配置する

下の画像を下に敷いてみます(600x400)。

画像を読み込む時は initFromPath を使います。

$imgLayer = ImageWorkshop::initFromPath('img.png');

これも同じように先ほどのコードに追加してみます。

use PHPImageWorkshop\ImageWorkshop;
include_once("ImageWorkshop.php");

/* 下地 */
$width = 400; // 横幅
$height = 300; // 縦幅
$background = "aaa"; // 背景色
$baseLayer = ImageWorkshop::initVirginLayer($width, $height, $background);
// 一色で塗りつぶしたレイヤーを作成

/* 画像 */
$imgLayer = ImageWorkshop::initFromPath('img.png');
$baseLayer->addLayer(1,$imgLayer,0,0,'LT');

/* テキストの設定 */
$text = "あのイーハトーヴォの\nすきとおった風邪"; // 表示するテキスト
$fontPath = "onryou.TTF"; // 使用するテキスト
$fontSize = 42; // フォントサイズ
$fontColor = "FFFFFF"; // フォントカラー
$textRotation = 0; // テキストを回転させたいばあいはこの数値を変える

/* 影文字 */
$fontColor2 = "000"; // フォントカラー     
$textLayer2 = ImageWorkshop::initTextLayer($text, $fontPath, $fontSize, $fontColor2, $textRotation);
$baseLayer->addLayer(2,$textLayer2,0,60,'LT');

/* 白文字 */
$textLayer = ImageWorkshop::initTextLayer($text, $fontPath, $fontSize, $fontColor, $textRotation);
$baseLayer->addLayer(3,$textLayer,0,50,'LT');

/* レイヤーを変換 */
$outputImg = $baseLayer->getResult();

/* 出力 */
header('Content-type: image/png');
header('Content-Disposition: filename="test.png"');
imagepng($outputImg, null, 3); // PNGで出力
exit;

コードが長くなってきたので、コメントを付けて少し整理しました。
こんな感じです。

画像は追加されましたが、追加元のレイヤーの大きさが 400 x 300 なので、はみ出てしまいましたね…。 という訳でこれを枠に収まるように表示するように変更してみます。

画像のリサイズ

ImageWorkShop で作成されたレイヤーは、 Cropping, Filter, Flip, Opacity, Resizing, Rotating, Writing
というこれらのアクションを適応させることが出来るようになっています。

今回は Resizing を利用して先述の画像を枠に収めるようにしてみます。

Resizing - PHP Image Workshop

単に指定のサイズでリサイズしたい場合は以下のように resizeInPixel を指定して、リサイズしたい幅と高さを指定します。

$imgLayer->resizeInPixel($baseWidth, $baseHeight);

画像はリサイズされて、ピッタリの大きさになりましたが比率が変わってしまいました…
(ちょっと分かりにくいかもしれませんが…)

比率を維持したままリサイズ

比率を維持したままリサイズしたい場合は第三引数を指定します。

$imgLayer->resizeInPixel($baseWidth, $baseHeight, true);

比率の維持が優先され、指定した値の大きいほうに合わせてリサイズされました。

しかしその結果、上下にスペースが空いてしまいました…
これだとなんだか格好が悪いですよね。

比率を維持しつつ、縦横センタリングしつつ、できるだけ領域からはみ出ないようにする

比率を維持しつつ、中央揃えで大きさを調整し、できるだけはみ出ないような画像を作成してみます。

こちらを参考します。
http://phpimageworkshop.com/tutorial/2/creating-thumbnails.html

$baseWidth  = $baseLayer->getWidth(); // 画像の横幅
$baseHeight = $baseLayer->getHeight(); // 画像の縦幅

// 縦横のサイズを調べて大きい方を largestSide に代入
($baseWidth > $baseHeight) ? $largestSide = $baseWidth : $largestSide = $baseHeight;

// レイヤーのサイズで内で作成できる最大サイズの正方形で切り取り   $imgLayer->cropMaximumInPixel(0, 0, "MM");

// 縦横大きい方のサイズに合わせて拡大
$imgLayer->resizeInPixel($largestSide, $largestSide);    
// 中央から指定サイズで切り取り
$imgLayer->cropInPixel($baseWidth, $baseHeight, 0, 0, 'MM');

まず $baseLayer->getWidth(), $baseLayer->getHeight() で枠のレイヤーのサイズを取得、
縦横大きい方のサイズを $largestSide に 代入しておきます。

次に cropMaximumInPixel を使って、指定された位置からレイヤーのサイズ内で作成できる最大の正方形に切り取ります。

その正方形を先ほどの $largestSide のサイズでリサイズします。

最後に画像中央から枠のサイズで切り取りをして余分な部分を切り落としします。

use PHPImageWorkshop\ImageWorkshop;
include_once("ImageWorkshop.php");

/* 下地 */
$width = 400; // 横幅
$height = 300; // 縦幅
$background = "aaa"; // 背景色
$baseLayer = ImageWorkshop::initVirginLayer($width, $height, $background);
// 一色で塗りつぶしたレイヤーを作成

/* 画像 */
$baseWidth  = $baseLayer->getWidth(); // 画像の横幅
$baseHeight = $baseLayer->getHeight(); // 画像の縦幅

// 縦横のサイズを調べて大きい方を largestSide に代入
($baseWidth > $baseHeight) ? $largestSide = $baseWidth : $largestSide = $baseHeight;

// レイヤーのサイズで内で作成できる最大サイズの正方形で切り取り   $imgLayer->cropMaximumInPixel(0, 0, "MM");

// 縦横大きい方のサイズに合わせて拡大
$imgLayer->resizeInPixel($largestSide, $largestSide);    
// 中央から指定サイズで切り取り
$imgLayer->cropInPixel($baseWidth, $baseHeight, 0, 0, 'MM');

/* テキストの設定 */
$text = "あのイーハトーヴォの\nすきとおった風邪"; // 表示するテキスト
$fontPath = "onryou.TTF"; // 使用するテキスト
$fontSize = 42; // フォントサイズ
$fontColor = "FFFFFF"; // フォントカラー
$textRotation = 0; // テキストを回転させたいばあいはこの数値を変える

/* 影文字 */
$fontColor2 = "000"; // フォントカラー     
$textLayer2 = ImageWorkshop::initTextLayer($text, $fontPath, $fontSize, $fontColor2, $textRotation);
$baseLayer->addLayer(2,$textLayer2,0,60,'LT');

/* 白文字 */
$textLayer = ImageWorkshop::initTextLayer($text, $fontPath, $fontSize, $fontColor, $textRotation);
$baseLayer->addLayer(3,$textLayer,0,50,'LT');

/* レイヤーを変換 */
$outputImg = $baseLayer->getResult();

/* 出力 */
header('Content-type: image/png');
header('Content-Disposition: filename="test.png"');
imagepng($outputImg, null, 3); // PNGで出力
exit;

で、できました!!

4:3 の比率の画像で本当にできているのか分かりにくいので、 もっと極端な画像に変えて試してみます。

100 x 200 のこの小さな画像を貼ります。

initFromPath の画像のパスを変えるだけで他の設定はそのままです。

比率は維持したまま、空白を出すこと無く、中央から拡大することができました!

今回の作業を GD で行う場合と比べるとどうでしょうか?
関数名も短く、渡すパラメータもイメージしやすいので、
作業時間も短縮することに繋げられるのではないでしょうか?

今回紹介したライブラリ:

PHP Image Workshop - PHP class using GD library for image processing