php5-gd で画像を弄る話

3,110 views

Published on

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

Published in: Technology, Art & Photos

php5-gd で画像を弄る話

  1. 1. 第69回PHP勉強会php5-gd で画像を弄る話2013/06/22-“よや” <yoya@awm.jp>
  2. 2. 自己紹介• http://d.hatena.ne.jp/yoya/• 某社の画像サーバのメンテナンス要員– 画質とパフォーマンスチューニングを尐々• 所属は秘密ですが、↓この ImageMagick を弄ってる人と名前が同じ– GIF アニメ生成は本当に GraphicsMagick で行うべきか?• http://labs.gree.jp/blog/2013/05/8132/• 画像の検証や説明資料を作るのに、GD をよく使うのと、PHP らしいという事で GD のお話をします。
  3. 3. 発表の目的• php-gd を使った事がない人向けに紹介• 使った事がある人には厳しいツッコミに期待注)• 今回は簡単な事が簡単に出来るという話• 本格的な画像処理(OpenCV 的なの)の話はしません。
  4. 4. もくじ• GD概要– 導入– 入出力イメージ• サンプルコード– 画像ファイル入出力– 画像をいちから生成• 応用サンプル• PHP5.5
  5. 5. 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をサポートした
  6. 6. gif draw?• gd1.0 の当初は GIF 出力が目的• palette 形式を前提にした API• 途中で JPEG, PNG 等にも対応• (後付けで) true color 対応、alpha channel 対応。• といった経緯を知っていると、使ってて色々ピンと来る
  7. 7. 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)
  8. 8. (前提知識) palette と true color• 画像引用元) http://labs.gree.jp/blog/2010/10/1263/ GIF• http://labs.gree.jp/blog/2010/12/1902/ PNGtrue color(direct color)palette(pseudo color)palettepixelstruecolorpixels(A)RGB(A)RGBRGB(A)RGBI I I(A)RGB(A)RGB …(A)RGB (A)RGB(A)RGB ………I I I ……
  9. 9. 入出力フローGD リソース画像ファイル 画像ファイルGIFPNGJPEGGIFPNGJPEGpalettepixelstruecolorpixels(A)RGB(A)RGBRGB(A)RGBI I I(A)RGB(A)RGB …(A)RGB (A)RGB(A)RGB ………I I I ……dither:truencolor:256createimagefrom~ image~入力 出力変換変換/編集変換/編集trueColor=0trueColor=1
  10. 10. ファイル自動判別参考) PHPでバイナリhttp://www.slideshare.net/yoyayoya1/php-10133775GD リソース画像ファイルGIFPNGJPEGpalettepixelstruecolorpixels(A)RGB(A)RGBRGB(A)RGBI I I(A)RGB(A)RGB(A)RGB (A)RGB(A)RGB……I I I ……入力trueColor=0trueColor=1string$imgdata = file_get_contents($argv[1]);$im = imagecreatefromstring($imgdata);PHP の string はすなわちバイナリcreateimagefromstringfile_get_contents
  11. 11. 画像入出力サンプル• 入力して出力するだけ• 画像元) 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黒?
  12. 12. 実はこの画像。。• 透過GIFでした– (そして JPEG は透明色を持てないので、決め打ちで背景を黒にされてる)
  13. 13. 画像入出力サンプル(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紫?
  14. 14. そもそもGIF の透過とは?• 透明度抜きで palette を作り、その内の一色を透明に指定。(透明色は後付け)palettepixels(A)RGB(A)RGBRGBI I I …I I I ……transparent背景を紫で作って後で透明化
  15. 15. 画像入出力サンプル(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
  16. 16. パレットの入れ替えpaletteRGBRGBRGBtransparentpaletteRGBRGBtransparentRGBimagecolordeallocate ImagecolorallocatepaletteRGBRGBRGBtransparentRGBimagecolordeallocateImagecolorallocateRGBNG パターン(index番号が変わる)RGBRGBRGBIndex番号を保持して色を入れ替える。
  17. 17. 画像入出力サンプル(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 JPEGpalettepixels(A)RGB(A)RGBRGBI I I …I I I ……transparent透明色だった場所を、新しく確保した色indexで上書き。
  18. 18. (閑話休題)• 簡単な例を示そうとして、意外と難しいという。。。• 気を取り直して、次行きます。
  19. 19. 画像生成サンプル• 真っ黒な画像を新規生成• 実は imagecreate の時点で全ピクセルのindexが0なので、imagefill しなくても黒くなりますが、0 が保障される自信が無いので一応実行してます。<?php$im = imagecreate(240, 320);$black = imagecolorallocate($im, 0, 0, 0);imagefill($im, 0, 0, $black);imagepng($im);palettepixels0, 0, 00 0 0 …0 0 0 ……% php pureblack.php > pureblack.png
  20. 20. 画像生成サンプル (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);
  21. 21. 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 Blue1byte 1byte 1byte 1byte0~127 0~2550~255 0~255Index1byte$c = 0~255$c = 0~2147483647(=0x7FFFFFFF)Index4 bytes
  22. 22. GD マニュアル• 後は、これを見れば大体分かります– http://www.php.net/manual/ja/ref.image.php
  23. 23. 応用例• 色んな形式の画像ファイルを生成• 色の数をカウントする• 画像差分抽出• ドット絵っぽい変換• 色分布の3D表示
  24. 24. 色んな形式の画像ファイルを生成• ビットマップ画像フォーマット毎のテスト素材– http://d.hatena.ne.jp/yoya/20110622/gd• PNG/JPEG/GIF (Web ならこの3つで大体OK)• パレット形式/トゥルーカラー形式• 透明度なし/あり
  25. 25. 色の数をカウントする• 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;色数
  26. 26. 色の差分抽出• 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-> =
  27. 27. ドット絵っぽい変換• ドット絵っぽく見せる変換ツール– https://github.com/yoya/misc/blob/master/php/dottize.php– 拡大して元のピクセル間に線を引くだけ• http://awm.jp/~yoya/php/image/dottize.php
  28. 28. 色分布の3D表示 (1/3)• PHP で 3D plot• http://d.hatena.ne.jp/yoya/20080925• 使いやすい3Dライブラリが無かったので自作– http://awm.jp/~yoya/php/3d/y3d.phps• その時の下書き
  29. 29. 色分布の3D表示 (2/3)ddisplayユーザの視点ディスプレイに表示する位置3Dモデル上の位置zy’y
  30. 30. 色分布の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
  31. 31. PHP5.5 の話• PHP 5.5 で増えた GD functions– http://d.hatena.ne.jp/yoya/20130621/gdimagepalettetotruecolorimageflipimagecrop, imagecropautoimageaffine, imageaffinematrixget, imageaffinematrixconcatimagescaleimagesetinterpolation
  32. 32. 入出力フロー (PHP5.5 gd)GD リソース画像ファイル画像ファイルGIFPNGJPEGGIFPNGJPEGpalettepixelstruecolorpixelsW(A)RGB(A)RGBRGB(A)RGBI I I(A)RGB(A)RGB …(A)RGB (A)RGB(A)RGB ………I I I ……createimagefrom~ image~入力 出力変換変換/編集変換/編集trueColor=0trueColor=1WebP WebPWebP 対応しました!
  33. 33. 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 Blue1byte 1byte 1byte 1byte0~127 0~2550~255 0~255$c = 0~2147483647(=0x7FFFFFFF)Index4 bytes+100palette 形式だと最大色数256を気にしながら弄るので面倒true color なら index 値を直接ARGB として処理できる
  34. 34. imagered.php• カラー効果で赤に +100% php imagered.php tomo_pr_263.gif > tomo_pr_263_red.gif
  35. 35. 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
  36. 36. その他 PHP 5.5 機能• imagecropauto– threshold に色指定できるので、色の境目で crop とか出来そうです• imageaffine– 変換行列をかけて画像を取り出せます (scale, rotate,skew とかの操作が自在に)• imagescale– リサイズのアルゴリズムを指定出来ますNEAREST_NEIGHBOUR も対応!(多分、今までより綺麗に)• Imagesetinterpolation– rotate 等の補完アルゴリズムを指定出来ます
  37. 37. 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
  38. 38. GD の限界• 8bit depth しか扱えない– 16bit カラーを扱いたい事が結構ある。ImageMagick の内部形式が大抵16bit なので• 透明度が 0~127 なので精度が半分– 本来の alpha と大小が逆なのも分かりにくい• ピクセルの操作が遠回り– true color でもパレットインデックス経由を強いられる• サムネールが汚いらしい。減色も汚い• 処理が重たいらしい– Klabさんが高速化サービスを出す位には重たい
  39. 39. その他• 文字を埋め込めます• ブラシ指定で書き込めます。• 描画図形のプリミティブも色々対応してます– 線だけでなく円とか多角形とか。• 注意点– Windows のメモ帳で UTF-8 として保存すると先頭に BOM が入って、出力バイナリの先頭にゴミが入ります。– (PHP を使う際の一般的な注意ですが、バイナリでは死活問題)
  40. 40. 最後に• 慣れれば簡単な事が簡単に出来るので、是非ご活用をご清聴ありがとうございました

×