C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: PHPで線の描画の際に、DashStyleと線幅を指定したい


(過去ログ 105 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■62538 / inTopicNo.1)  PHPで線の描画の際に、DashStyleと線幅を指定したい
  
□投稿者/ けんた (4回)-(2011/10/17(Mon) 22:24:02)

分類:[その他の言語] 

前回「PHPで、パターンを指定して塗りつぶしたい」というスレを立てた者です。
その節は、大変お世話になりました。
前回はBrushでしたが、今回は...Penですw すいません。

PHPで線を描画しています。
その際、.NETで言うところの、System.Drawing.Drawing2D.DashStyleみたいなものを考慮しつつ線を描こうとしています。
そこで、以下の関数を併用してimagelineを使用して線を描いてみたのですが、期待通りになりません。
 ●imagesetstyle関数:パターンを指定するために
 ●imagesetthickness関数:線の幅を決めるために

例えば、

<?php
$image = imagecreatetruecolor(50, 50);
$black = imagecolorallocate($image, 0, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);

// 背景を白で塗りつぶしとく
imagefill($image, 0, 0, $white);

// DashStyle.Dot みたいなの
$dot = array($black, $white);
imagesetstyle($image, $dot);
imageline($image, 0, 15, 49, 15, IMG_COLOR_STYLED);

// DashStyle.DashDot みたいなの
$dashdot = array($black, $black, $black, $white, $black, $white);
imagesetstyle($image, $dashdot);
imageline($image, 0, 35, 49, 35, IMG_COLOR_STYLED);

header("Content-type: image/png");
imagepng($image);
imagedestroy($image);
?>

とやると期待通りに動くのですが、例えば線の太さを5ピクセルにするために、
imagecreatetruecolor(50, 50)した後で、imagesetthickness($image, 5)をやると、
あり得ない線が描かれます。
ちなみに、画像の幅を変化させて実行してみると、線のドットのパターンがズレて線の模様が変化します。

何が起こっているのかはだいたい分かりましたが、これは回避できないのでしょうか?
PHPでこのようなことをやるときは、みなさんどうやるんですか?
常套手段とかないですか?

PHPのバージョンは5.2.5です。
引用返信 編集キー/
■62539 / inTopicNo.2)  Re[1]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (5回)-(2011/10/17(Mon) 22:26:24)
System.Drawing.PenのWidthを変更して描画する時は、Widthの値に合わせてドットのパターンも拡大されていますが、
この動きを真似るには、結構骨が折れそうだなぁ...。
(上のコード例では水平線だったけど、斜めの線の場合とか)
引用返信 編集キー/
■62552 / inTopicNo.3)  Re[2]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (6回)-(2011/10/18(Tue) 10:28:33)
2011/10/18(Tue) 10:43:35 編集(投稿者)

だーれーかー...

破線を描画するための関数imagedashedlineというのがあるらしいので、
とりあえず、線のスタイルは実線と破線だけにすれば良いかな...と思い、
以下のようなコードを書いてみました。

<?php
$image = imagecreatetruecolor(150, 150);
$white = imagecolorallocate($image, 255, 255, 255);
$black = imagecolorallocate($image, 0, 0, 0);

// 線の太さ5
imagesetthickness($image, 5);

imagedashedline($image, 0, 15, 49, 15, $white);
imagedashedline($image, 0, 35, 49, 35, $white);

header("Content-type: image/png");
imagepng($image);
imagedestroy($image);
?>

確かに線を引いているのに、白い破線が出ない!
imagedashedlineをimagelineに置き換えると、線が出る。
さらに、座標を適当に変えてみると、線が出る。
もうこんな動きマジありえないんスけど。

ただ線を描きたいだけなのに...
あ、GDのバージョンは、phpinfo()によるとbundled (2.0.34 compatible)だそうです。

引用返信 編集キー/
■62553 / inTopicNo.4)  Re[3]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (7回)-(2011/10/18(Tue) 10:33:48)
細長ーい長方形で線を表現するとか?
必要に応じて、imagerotateで回転させるとかかなぁ?

うーん...
とりあえずやってみよう
引用返信 編集キー/
■62574 / inTopicNo.5)  Re[4]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (8回)-(2011/10/19(Wed) 00:08:22)
誰か相手してください... orz
PHPはそんなに書いた経験は無くて、PHPらしくないことしているのかもしれません。
的外れなこと言ってるのかもしれません。
重々承知しています。


さて、上で書きましたが、とりあえずは

 1. 指定された2点間の距離lを求める
 2. 線の太さw、長さlで、細長い長方形を描く
 3. 2点の座標から角度を求める
 4. imagerotateで回転させる
 5. 線を描画しようとしている画像上に、4で作った画像を配置する

みたいなアプローチでやってみています。
で、今ぶち当たっている問題は、4の手順のimagerotateで、
線の色と背景の色から、アンチエイリアスが働いてしまい、
画像が汚くなってしまうことです。

4でimagerotateすると、ほとんどの場合、画像のサイズが変わって、
線じゃない隙間の部分ができてしまいます。これは仕方ないですね。
最終的に5で画像にのっけたいので、この部分は透過しようと思います。

ってことで、この部分を塗りつぶす色をimagerotateで指定できるみたいなので、
透過色を設定してみようとしたけどもうまくいかないんです。
RGBの指定は反映されるけど、透過が効かないっぽいです。
仕方なく乱数で適当に色を決めて、それをimagecolortransparentで透過色に
割り当ててみました。

...と、こういう経緯がありまして。

めでたく、5で線の画像をのっけた時には、大部分は透過されるのですが、4でやった
imagerotateのおかげで、線の縁にアンチエイリアスでこびりついた中間的な色が
びっしりこびりついてます。

現象が確認できるコードを以下に貼っておきます。
気が向いた方は、なんか助言ください...お願いします。
ぜひぜひお願いします。切望。
「そんなことしなくてもこうやれば簡単にできるよ!」というコメントが一番ほしいですが、
多分、そんなのもしかしたら無いんじゃないかと薄々気づいてます。


<?php

////////////////////////////////////////////////////
// 600 * 480 の長方形の画像に、(100, 100) から (499, 379)
// を結ぶ直線を引く
////////////////////////////////////////////////////
$w = 600; $h = 480;
$image = imagecreatetruecolor($w, $h);
$blue = imagecolorallocate($image, 128, 128, 255);

// 透過していることが分かるように、色をつけとく
imagefill($image, 0, 0, $blue);


////////////////////////////////////////////////////
// ステップ1
// 座標から線の長さを求めとく
////////////////////////////////////////////////////
$x0 = 100; $y0 = 100; // 始点の座標
$x1 = 499; $y1 = 379; // 終点の座標
$xlen = $x1 - $x0;
$ylen = $y0 - $y1;
$lineLen = sqrt($xlen * $xlen + $ylen * $ylen);


////////////////////////////////////////////////////
// ステップ2
// まずは、細長い線になる部分を画像として用意しておく
// 本来はDashStyleみたいなパターンで線を描きたいが、
// 簡略化のために実線で
////////////////////////////////////////////////////
$thick = 4; // 線幅4(ホンマかいな...
$r = 0; $g = 0; $b = 0; // ペンの色(とりあえず黒で
$lineOrg = imagecreatetruecolor($lineLen, $thick);
$penColor = imagecolorallocate($lineOrg, $r, $g, $b);
imagefill($lineOrg, 0, 0, $penColor);


////////////////////////////////////////////////////
// ステップ3
// 回転の角度
////////////////////////////////////////////////////
$t = $ylen / $xlen; // 垂直な線は書けない
$rad = atan($t);
$deg = rad2deg($rad);


////////////////////////////////////////////////////
// ステップ4
// 画像を回転
////////////////////////////////////////////////////
$tr = 254; $tg = 0; $tb = 0; // 乱数で決めた適当な透過色
$bgd_color = ($tr << 16) | ($tg << 8) | $tb;
$line = imagerotate($lineOrg, $deg, $bgd_color);
$trans = imagecolorallocate($line, $tr, $tg, $tb);
imagecolortransparent($line, $trans);


////////////////////////////////////////////////////
// ステップ5
// 画像にのせる
////////////////////////////////////////////////////
$wd = imagesx($line); // なんか微妙に大きいな...
$ht = imagesy($line); // 同上
imagecopymerge($image, $line, $x0, $y0, 0, 0, $wd, $ht, 100);


header("Content-type: image/png");
imagepng($image);
imagedestroy($image);

?>
引用返信 編集キー/
■62577 / inTopicNo.6)  Re[5]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (9回)-(2011/10/19(Wed) 10:29:42)
だめだ。
もうDashStyle諦めよう。
線種は実線のみで、色分けできるようにしとこう。
最低なPenクラスやなぁ...。
引用返信 編集キー/
■62578 / inTopicNo.7)  Re[6]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (10回)-(2011/10/19(Wed) 10:50:52)
もうひとつ思いついた。
座標を変換しながら線の部分を imagefilledpolygon で塗りつぶせばいいんじゃね?
これで再度トライして、これでダメだったら諦めよう。
引用返信 編集キー/
■62581 / inTopicNo.8)  Re[7]: PHPで線の描画の際に、DashStyleと線幅を指定したい
□投稿者/ けんた (11回)-(2011/10/19(Wed) 14:14:35)
できたー!
さっきに比べてめっちゃ簡単やないか...
なんでこっちを先に思いつかなかったんだろ orz
これでDashStyleみたいにパターンで長方形を描けばいけそう!わーい!

<?php

////////////////////////////////////////////////////
// 点(x, y) を、点 (cx, cy) を中心に、rad ラジアンだけ
// 回転させた座標 (tx, ty) させ、x方向にdx、y方向にdy
// だけ平行移動させる関数
////////////////////////////////////////////////////
function rotate_move($cx, $cy, $rad, $x, $y, $dx, $dy, &$tx, &$ty)
{
$tx = $cx + $dx + ($x - $cx) * cos($rad) - ($y - $cy) * sin($rad);
$ty = $cy + $dy - ($x - $cx) * sin($rad) + ($y - $cy) * sin($rad);
}


////////////////////////////////////////////////////
// 600 * 480 の長方形の画像に、(100, 100) から (499, 379)
// を結ぶ直線を引く
////////////////////////////////////////////////////
$w = 600; $h = 480;
$x0 = 100; $y0 = 100; // 始点の座標
$x1 = 499; $y1 = 379; // 終点の座標
$image = imagecreatetruecolor($w, $h);
$blue = imagecolorallocate($image, 128, 128, 255);
$red = imagecolorallocate($image, 255, 0, 0);
imagefill($image, 0, 0, $blue);


////////////////////////////////////////////////////
// 座標から線の長さを求めとく
////////////////////////////////////////////////////
$xlen = $x1 - $x0;
$ylen = $y0 - $y1;
$lineLen = sqrt($xlen * $xlen + $ylen * $ylen);


////////////////////////////////////////////////////
// 回転の角度
////////////////////////////////////////////////////
$t = $ylen / $xlen; // 垂直な線は書けない
$rad = atan($t);


////////////////////////////////////////////////////
// 細長い長方形を座標変換して imagefillpolygon する。
// 今回は簡略化のために、破線等ではなく実線にする。
////////////////////////////////////////////////////
$thick = 3;

// 座標を変換
$tx0; $ty0;
$tx1; $ty1;
$tx2; $ty2;
$tx3; $ty3;
$cx = 0;
$cy = $thick / 2;
rotate_move($cx, $cy, $rad, 0, 0, $x0, $y0, $tx0, $ty0);
rotate_move($cx, $cy, $rad, $lineLen, 0, $x0, $y0, $tx1, $ty1);
rotate_move($cx, $cy, $rad, $lineLen, $thick, $x0, $y0, $tx2, $ty2);
rotate_move($cx, $cy, $rad, 0, $thick, $x0, $y0, $tx3, $ty3);
$points = array($tx0, $ty0, $tx1, $ty1, $tx2, $ty2, $tx3, $ty3);

$num_points = 4;
$r = 0; $g = 0; $b = 0; // ペンの色(とりあえず黒で
$penColor = imagecolorallocate($image, $r, $g, $b);
imagefilledpolygon($image, $points, $num_points, $penColor);
imageline($image, $x0, $y0, $x1, $y1, $red);


header("Content-type: image/png");
imagepng($image);
imagedestroy($image);

?>
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -