php5-gd で画像を弄る話

40
69PHP勉強会 php5-gd で画像を弄る話 2013/06/22- よや” <[email protected]>

Upload: yo-ya

Post on 06-Jul-2015

2.152 views

Category:

Technology


4 download

DESCRIPTION

PHP5 GD の紹介と幾つかのサンプル、そして PHP5.5 の新機能

TRANSCRIPT

Page 1: php5-gd で画像を弄る話

第69回PHP勉強会php5-gd で画像を弄る話

2013/06/22-

“よや” <[email protected]>

Page 2: php5-gd で画像を弄る話

自己紹介

• http://d.hatena.ne.jp/yoya/• 某社の画像サーバのメンテナンス要員

– 画質とパフォーマンスチューニングを尐々

• 所属は秘密ですが、↓この ImageMagick を弄ってる人と名前が同じ– GIF アニメ生成は本当に GraphicsMagick で行うべきか?• http://labs.gree.jp/blog/2013/05/8132/

• 画像の検証や説明資料を作るのに、GD をよく使うのと、PHP らしいという事で GD のお話をします。

Page 3: php5-gd で画像を弄る話

発表の目的

• php-gd を使った事がない人向けに紹介

• 使った事がある人には厳しいツッコミに期待

注)

• 今回は簡単な事が簡単に出来るという話

• 本格的な画像処理(OpenCV 的なの)の話はしません。

Page 4: php5-gd で画像を弄る話

もくじ

• GD概要

– 導入

– 入出力イメージ

• サンプルコード

– 画像ファイル入出力

– 画像をいちから生成

• 応用サンプル

• PHP5.5

Page 5: php5-gd で画像を弄る話

GD について

• http://www.boutell.com/gd/ (old page)

• http://libgd.bitbucket.org/ (new page)

• GD は動的画像生成のライブラリ

• gd1.0 では “gif draw” の略

• gd1.0 の後半 Unisys LZW 圧縮特許で GIF をサポート外にしてから “graphics draw”

• ちなみに特許切れにより gd 2.0.28 で再び GIF をサポートした

Page 6: php5-gd で画像を弄る話

gif draw?

• gd1.0 の当初は GIF 出力が目的

• palette 形式を前提にした API

• 途中で JPEG, PNG 等にも対応

• (後付けで) true color 対応、alpha channel 対応。

• といった経緯を知っていると、使ってて色々ピンと来る

Page 7: php5-gd で画像を弄る話

GD の導入

• PHP の gd extension を有効にします

– 確認

• インストール

– Debian

– 設定ベタ書き (php.ini)

% sudo apt-get install php5-gd

;extension=php_gd2.dll

% php -i | grep GDGD Support => enabledGD Version => bundled (2.1.0 compatible)

Page 8: php5-gd で画像を弄る話

(前提知識) palette と true color

• 画像引用元) http://labs.gree.jp/blog/2010/10/1263/ GIF• http://labs.gree.jp/blog/2010/12/1902/ PNG

true color(direct color)

palette(pseudo color)

palette

pixels

truecolorpixels(A)RGB(A)RGBRGB

(A)RGBI I I

(A)RGB (A)RGB …(A)RGB (A)RGB (A)RGB …

……

I I I ……

Page 9: php5-gd で画像を弄る話

入出力フロー

GD リソース画像ファイル 画像ファイル

GIF

PNG

JPEG

GIF

PNG

JPEG

palette

pixels

truecolorpixels

(A)RGB(A)RGBRGB

(A)RGB

I I I

(A)RGB (A)RGB …(A)RGB (A)RGB (A)RGB …

…I I I ……

dither:truencolor:256

createimagefrom~ image~入力 出力変換

変換/編集

変換/編集trueColor=0

trueColor=1

Page 10: php5-gd で画像を弄る話

ファイル自動判別

参考) PHPでバイナリhttp://www.slideshare.net/yoyayoya1/php-10133775

GD リソース

画像ファイル

GIF

PNG

JPEG

palette

pixels

truecolorpixels

(A)RGB(A)RGBRGB

(A)RGB

I I I

(A)RGB (A)RGB(A)RGB (A)RGB (A)RGB

…I I I ……

入力

trueColor=0

trueColor=1

string

$imgdata = file_get_contents($argv[1]);$im = imagecreatefromstring($imgdata);

PHP の string はすなわちバイナリ

createimagefromstring

file_get_contents

Page 11: php5-gd で画像を弄る話

画像入出力サンプル

• 入力して出力するだけ

• 画像元) http://mitemitei.com/h/(print)031.htm

<php$im = imagecreatefromgif($argv[1]);imagejpeg($im);

GIF JPEG

% php gif2jpeg.php tomo_pr_263.gif > tomo_pr_263.jpg黒?

Page 12: php5-gd で画像を弄る話

実はこの画像。。

• 透過GIFでした

– (そして JPEG は透明色を持てないので、決め打ちで背景を黒にされてる)

Page 13: php5-gd で画像を弄る話

画像入出力サンプル(take2)

• 背景色を設定する。(けど GIF はダメ?)

<php$im = imagecreatefromgif($argv[1]);$white = imagecolorallocate($im, 255, 255, 255);imagecolortransparent($im, $white);imagejpeg($im);

GIF JPEG

% php gif2jpeg.php tomo_pr_263.gif > tomo_pr_263_white.jpg

紫?

Page 14: php5-gd で画像を弄る話

そもそもGIF の透過とは?

• 透明度抜きで palette を作り、その内の一色を透明に指定。(透明色は後付け)

palette

pixels

(A)RGB(A)RGBRGB

I I I …I I I ……

transparent

背景を紫で作って

後で透明化

Page 15: php5-gd で画像を弄る話

画像入出力サンプル(take3)

• パレットの色を入れ替えてみた

<?php$im = imagecreatefromgif($argv[1]);$trans = imagecolortransparent($im);if ($trans != -1) {

imagecolordeallocate($im, $trans);$trans2 = imagecolorallocate($im, 255, 255, 255);

}imagejpeg($im);

GIF JPEG

% php gif2jpeg.php tomo_pr_263.gif > tomo_pr_263_white.jpg

Page 16: php5-gd で画像を弄る話

パレットの入れ替え

palette

RGB

RGB

RGB transparent

palette

RGB

RGB transparent

RGBimagecolordeallocate Imagecolor

allocate

palette

RGB

RGB

RGB transparent

RGB

imagecolordeallocate

Imagecolorallocate

RGB

NG パターン(index番号が変わる)

RGBRGB

RGB

Index番号を保持して色を入れ替える。

Page 17: php5-gd で画像を弄る話

画像入出力サンプル(take4)

• NG に備えてピクセル上書き

<?php$im = imagecreatefromgif($argv[1]);$trans1 = imagecolortransparent($im);if ($trans1 != -1) {

imagecolordeallocate($im, $trans1);$trans2 = imagecolorallocate($im, 255, 255, 255);if ($trans1 != $trans2) {

for ($y = 0 ; $y < imagesy($im) ; $y++) {for ($x = 0 ; $x < imagesx($im) ; $x++) {

if (imagecolorat($im, $x, $y) === $trans1) {imagesetpixel($im, $x, $y, $trans2);

}}

}}

}imagejpeg($im);

GIF JPEG

palette

pixels

(A)RGB(A)RGBRGB

I I I …I I I ……

transparent

透明色だった場所を、新しく確保した色indexで上

書き。

Page 18: php5-gd で画像を弄る話

(閑話休題)

• 簡単な例を示そうとして、意外と難しいという。。。

• 気を取り直して、次行きます。

Page 19: php5-gd で画像を弄る話

画像生成サンプル

• 真っ黒な画像を新規生成

• 実は imagecreate の時点で全ピクセルのindexが0なので、imagefill しなくても黒くなりますが、0 が保障される自信が無いので一応実行してます。

<?php$im = imagecreate(240, 320);$black = imagecolorallocate($im, 0, 0, 0);imagefill($im, 0, 0, $black);

imagepng($im);

palette

pixels

0, 0, 0

0 0 0 …0 0 0 ……

% php pureblack.php > pureblack.png

Page 20: php5-gd で画像を弄る話

画像生成サンプル (Web版)

• Content-type がないと、大抵テキストと判断して無理やり文字として表示します。

<?php$im = imagecreate(240, 320);$black = imagecolorallocate($im, 0, 0, 0);imagefill($im, 0, 0, $black);

imagepng($im);

<?php$im = imagecreate(240, 320);$black = imagecolorallocate($im, 0, 0, 0);imagefill($im, 0, 0, $black);

header('Content-type: image/png');imagepng($im);

Page 21: php5-gd で画像を弄る話

GD の流儀

• 色は imagecolorallocate 経由で使う

• true color も allocate 経由 (実際はARGB)

$im = imagecreate(100, 100);$b = imagecolorallocate($im, 255, 255, 0);imagefill($im, 0, 0, $b);$c = imagecolorallocate($im, 255, 0, 255);imagesetpixel($im, 50, 50, $c);imagepng($im);

$im = imagecreatetruecolor(240, 320);$b = imagecolorallocate($im, 255, 255, 0);imagefill($im, 0, 0, $b);$c = imagecolorallocate($im, 255, 0, 255);imagesetpixel($im, 50, 50, $c);imagepng($im);

// $c = imagecolorallocate($im, 255, 0, 255);$c = (255 << 16) + (255 < 8) + 0;

Alpha Red Green Blue

1byte 1byte 1byte 1byte

0~127 0~2550~255 0~255

Index

1byte

$c = 0~255

$c = 0~2147483647(=0x7FFFFFFF)

Index

4 bytes

Page 22: php5-gd で画像を弄る話

GD マニュアル

• 後は、これを見れば大体分かります

– http://www.php.net/manual/ja/ref.image.php

Page 23: php5-gd で画像を弄る話

応用例

• 色んな形式の画像ファイルを生成

• 色の数をカウントする

• 画像差分抽出

• ドット絵っぽい変換

• 色分布の3D表示

Page 24: php5-gd で画像を弄る話

色んな形式の画像ファイルを生成

• ビットマップ画像フォーマット毎のテスト素材

– http://d.hatena.ne.jp/yoya/20110622/gd

• PNG/JPEG/GIF (Web ならこの3つで大体OK)

• パレット形式/トゥルーカラー形式

• 透明度なし/あり

Page 25: php5-gd で画像を弄る話

色の数をカウントする

• colorcount.php

– http://d.hatena.ne.jp/yoya/20120421/php

% php colorcount.php tomo_pr_263.gif12

$im = imagecreatefromstring(file_get_contents($argv[1]));$width = imagesx($im); $height = imagesy($im);$colorcount = array();for ($x = 0; $x < $width; $x++){for ($y = 0; $y < $height; $y++){

$colorindex = imagecolorat($im, $x, $y);$colorcount[$colorindex]++;

}echo count($colorcount).PHP_EOL;

色数

Page 26: php5-gd で画像を弄る話

色の差分抽出

• PHP で画像比較– http://d.hatena.ne.jp/yoya/20120712/php

• 例) 減色等でどのように画像が変わったか?

– ハートマークが尐し明るくなった事が分かる

% convert aria.jpg aria.gif% php bitmap_diff.php aria.jpg aria.gif aria_diff.png

-> =

Page 27: php5-gd で画像を弄る話

ドット絵っぽい変換

• ドット絵っぽく見せる変換ツール

– https://github.com/yoya/misc/blob/master/php/dottize.php

– 拡大して元のピクセル間に線を引くだけ

• http://awm.jp/~yoya/php/image/dottize.php

Page 28: php5-gd で画像を弄る話

色分布の3D表示 (1/3)

• PHP で 3D plot• http://d.hatena.ne.jp/yoya/20080925

• 使いやすい3Dライブラリが無かったので自作

– http://awm.jp/~yoya/php/3d/y3d.phps

• その時の下書き

Page 29: php5-gd で画像を弄る話

色分布の3D表示 (2/3)

d

display

ユーザの視点

ディスプレイに表示する位置3Dモデル上の

位置

z

y’y

Page 30: php5-gd で画像を弄る話

色分布の3D表示 (3/3)

• GIF画像の色分布

– http://d.hatena.ne.jp/yoya/20080927

– http://awm.jp/~yoya/php/image/colordist.php

– http://awm.jp/~yoya/php/image/colordist_new.php

Page 31: php5-gd で画像を弄る話

PHP5.5 の話

• PHP 5.5 で増えた GD functions

– http://d.hatena.ne.jp/yoya/20130621/gd

imagepalettetotruecolorimageflipimagecrop, imagecropautoimageaffine, imageaffinematrixget, imageaffinematrixconcatimagescaleimagesetinterpolation

Page 32: php5-gd で画像を弄る話

入出力フロー (PHP5.5 gd)

GD リソース画像ファイ

ル画像ファイ

GIF

PNG

JPEG

GIF

PNG

JPEG

palette

pixels

truecolorpixelsW

(A)RGB(A)RGBRGB

(A)RGB

I I I

(A)RGB (A)RGB …(A)RGB (A)RGB (A)RGB …

…I I I ……

createimagefrom~ image~入力 出力変換

変換/編集

変換/編集trueColor=0

trueColor=1

WebP WebP

WebP 対応しました!

Page 33: php5-gd で画像を弄る話

imagepalettetotruecolor

• imagered.php

– palette より true color の方が編集が楽

$imgdata = file_get_contents($argv[1]);$im = imagecreatefromstring($imgdata);imagepalettetotruecolor($im);for ($y = 0 ; $y < imagesy($im) ; $y++) {

for ($x = 0 ; $x < imagesx($im) ; $x++) {$c = imagecolorat($im, $x, $y);$r = ($c >> 16) & 0xFF;$r2 = $r + 100;$r2 = ($r2 < 256)?$r:255;$c2 = ($c & 0x7F00FFFF ) + $r2 << 16;imagesetpixel($im, $x, $y, $c2);

}}

imagepng($im);

Alpha Red Green Blue

1byte 1byte 1byte 1byte

0~127 0~2550~255 0~255$c = 0~2147483647(=0x7FFFFFFF)

Index

4 bytes

+100

palette 形式だと最大色数256

を気にしながら弄るので面倒

true color なら index 値を直接ARGB として処理できる

Page 34: php5-gd で画像を弄る話

imagered.php

• カラー効果で赤に +100

% php imagered.php tomo_pr_263.gif > tomo_pr_263_red.gif

Page 35: php5-gd で画像を弄る話

imageflop

• 縦、横、又は両方で画像をひっくり返す

$imgData = file_get_contents($argv[1]);$im = imagecreatefromstring($imgData);imageflip($im, IMG_FLIP_VERTICAL);echo imagegif($im);

% php imageflip.php tomo_pr_263.gif > tomo_pr_263_flip.gif

Page 36: php5-gd で画像を弄る話

その他 PHP 5.5 機能

• imagecropauto– threshold に色指定できるので、色の境目で crop とか出来そうです

• imageaffine– 変換行列をかけて画像を取り出せます (scale, rotate,

skew とかの操作が自在に)

• imagescale

– リサイズのアルゴリズムを指定出来ますNEAREST_NEIGHBOUR も対応!(多分、今までより綺麗に)

• Imagesetinterpolation– rotate 等の補完アルゴリズムを指定出来ます

Page 37: php5-gd で画像を弄る話

PHP5.2 で PHP5.5 の gd を動かす

• PHP5.5 の gd を PHP5.2 で動かす方法– http://d.hatena.ne.jp/yoya/20130622/gd

• 必要なライブラリは用意する。(configure で無効化出来ないっぽい)– t1lib でコンパイル失敗するので config.h で

undef

• configure でパスを明示的に指定する– /usr/~にライブラリがあっても指定する

• PHP_FE_END は #define で対処– 参考) http://d.hatena.ne.jp/yoya/20130501/php

Page 38: php5-gd で画像を弄る話

GD の限界

• 8bit depth しか扱えない– 16bit カラーを扱いたい事が結構ある。

ImageMagick の内部形式が大抵16bit なので

• 透明度が 0~127 なので精度が半分– 本来の alpha と大小が逆なのも分かりにくい

• ピクセルの操作が遠回り– true color でもパレットインデックス経由を強いられる

• サムネールが汚いらしい。減色も汚い• 処理が重たいらしい

– Klabさんが高速化サービスを出す位には重たい

Page 39: php5-gd で画像を弄る話

その他

• 文字を埋め込めます

• ブラシ指定で書き込めます。

• 描画図形のプリミティブも色々対応してます– 線だけでなく円とか多角形とか。

• 注意点– Windows のメモ帳で UTF-8 として保存すると先頭に BOM が入って、出力バイナリの先頭にゴミが入ります。

– (PHP を使う際の一般的な注意ですが、バイナリでは死活問題)

Page 40: php5-gd で画像を弄る話

最後に

• 慣れれば簡単な事が簡単に出来るので、是非ご活用を

ご清聴ありがとうございました