Tag Archives: GD

[PHP]GDでアンチエイリアスのかかった綺麗な楕円を描く

Share on Facebook
Bookmark this on Delicious
LINEで送る
Pocket

PHP で正円・楕円を描画する場合、通常は GD の imageellipse() で描くことになるのですが、imageantialias() を使ってもアンチエイリアスがかからないため、ジャギーのあるギザギザした線になってしまいます。

アンチエイリアスのかかった直線を描くアルゴリズムの一つに Xiaolin Wu Line Algorithm というものがあり、そちらを応用する形で楕円を描くという手法を用いるとかなり綺麗な円を描くことができます。

wu_ellipsewu_ellipse2

様々な方法による円の描画を比較した記事 Drawing Antialiased Circles and Ellipses (by Stephan Brumme) を参考に imageellipse() と同じ使い方ができるように関数化してみました。

<?php
function wu_ellipse($image, $cx, $cy, $width, $height, $color){
	$rx = $width / 2;
	$ry = $height / 2;
	$rx2 = $rx * $rx;
	$ry2 = $ry * $ry;
	
	$quarter = round($rx2 / sqrt($rx2 + $ry2));
	for ($x = 0; $x <= $quarter; $x++)
	{
		$y = $ry * sqrt(1 - $x*$x / $rx2);
		$error = $y - floor($y);
		$transparency = round($error * 0x7F);
		$alpha  = $color | ($transparency << 24);
		$alpha2 = $color | ((0x7F - $transparency) << 24);
		plot4points($image, $cx, $cy, $x, floor($y),   $alpha);
		plot4points($image, $cx, $cy, $x, floor($y)+1, $alpha2);
	}
	
	$quarter = round($ry2 / sqrt($rx2 + $ry2));
	for ($y = 0; $y <= $quarter; $y++)
	{
		$x = $rx * sqrt(1 - $y*$y / $ry2);
		$error = $x - floor($x);
		$transparency = round($error * 0x7F);
		$alpha  = $color | ($transparency << 24);
		$alpha2 = $color | ((0x7F - $transparency) << 24);
		plot4points($image, $cx, $cy, floor($x),   $y, $alpha);
		plot4points($image, $cx, $cy, floor($x)+1, $y, $alpha2);
	}
}

function plot4points($image, $cx, $cy, $dx, $dy, $color)
{
	imagesetpixel($image, $cx + $dx, $cy + $dy, $color);
	imagesetpixel($image, $cx - $dx, $cy + $dy, $color);
	imagesetpixel($image, $cx + $dx, $cy - $dy, $color);
	imagesetpixel($image, $cx - $dx, $cy - $dy, $color);
}


$image = imagecreatetruecolor(300, 300);
$color = imagecolorallocate($image, 0x33, 0x33, 0x33);
$bg = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
imagefill ($image, 0, 0, $bg);

$width  = 240;
$height = 240;
$cx = 150;
$cy = 150;

wu_ellipse($image, $cx, $cy, $width, $height, $color);

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

【参考】
Fast, Antialiased Circles and Ellipses from Xiaolin Wu’s concepts
Drawing Antialiased Circles and Ellipses

Posted in PHP | Tagged , | Leave a comment

[PHP]GDで作った画像をファイル化せずに直接<img>タグで表示する

Share on Facebook
Bookmark this on Delicious
LINEで送る
Pocket

html の <img> タグは src 属性にファイル名を指定するのが通常ですが、
Data URI スキームを利用することで画像データを html そのものに埋め込むことが出来ます。

書式は「data:MIMEタイプ;base64,データの内容」です。
画像そのものを html ソースに記述するためソース内には大量の文字の羅列がうめつくされることになります。
また、Safari, Chrome, FireFox などの主要ブラウザでは正しく表示されますが、IE に関しては IE8 以上でないと表示されない上、IE8 ではファイルサイズの上限が 32KB までとなっているため注意が必要です。

<?php
$img = imagecreatetruecolor(100, 100);

$color1 = imagecolorallocate($img, 30, 50, 170);
$color2 = imagecolorallocate($img, 255, 255, 255);
$color3 = imagecolorallocate($img, 230, 0, 0);

imagefill($img, 0, 0, $color2);

imagefilledellipse($img, 50, 50, 90, 90, $color1);
imagefilledellipse($img, 50, 50, 60, 60, $color2);
imagefilledellipse($img, 50, 50, 30, 30, $color3);

ob_start();
imagejpeg($img, null, 90);
$content = base64_encode(ob_get_contents());
ob_end_clean();
imagedestroy($img);
?><!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>

<img src="data:image/jpeg;base64,<?php echo $content;?>" alt="sample" />

</body>
</html>

roundel

HTML ソース


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRg(中略)AKKKKAP/Z" alt="sample" />

</body>
</html>

参考
http://ja.wikipedia.org/wiki/Data_URI_scheme

Posted in PHP | Tagged , | Leave a comment

[PHP]GDで図形を描画する際のジャギーを軽減する(アンチエイリアス)

Share on Facebook
Bookmark this on Delicious
LINEで送る
Pocket

通常 GD を用いて円や直線を描画した場合、全くアンチエイリアス処理がなされないため、縁がギザギザしているように見えてしまいます。(ジャギー)

1

精度の高い軽量なアンチエイリアス処理(ジャギーを軽減する処理)を求めるなら何らかのアルゴリズムを使った計算を行うべきですが、今回は単純に、あらかじめ大きな画像として描画しておいて、それを表示サイズまで縮小する方法でジャギーを軽減してみます。

2
2倍

3
3倍

二倍サイズで描画したものを表示サイズに縮小するだけでかなりジャギーは目立たなくなります。
三倍ならほとんど気になりません。

GD のリサイズではピクセルの補間が行われるため拡大・縮小時には滑らかに処理されます。
今回の方法はその性質を利用したものです。

本来 GD には imageantialias() という専用の関数があるのですが、環境や対象によっては機能しないことが多いので、現時点ではこの手法も役に立つと思います。

・検証用サンプル

<?php
$canvas_size = 120;
$circle_size = 100;
$scale = 3;

$image	 = imagecreatetruecolor($canvas_size, $canvas_size);
$circle	 = imagecreatetruecolor($canvas_size * $scale, $canvas_size * $scale);

$color = imagecolorallocate( $circle, 255, 255, 255 );
imagefilledellipse($circle, $canvas_size * $scale / 2, $canvas_size * $scale / 2, $circle_size * $scale, $circle_size * $scale, $color);
imagecopyresampled($image, $circle, 0, 0, 0, 0, $canvas_size, $canvas_size, $canvas_size * $scale, $canvas_size * $scale);

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

imagedestroy($image);
imagedestroy($circle);

Posted in PHP | Tagged , | Leave a comment