php gd 坐标,【PHP】GD库笔记 初探GD库的坐标

昨天在用GD库的imagettftext在图片上写字的时候,发现写字的坐标并不是很精确的按照指定的参数的位置插入字体的,一直觉得很诡异。由于GD库中很多画图操作都是以坐标为基础的,因而就花了点时间了解了一下GD的坐标系统。

1.建立画布

$im = imagecreatetruecolor(200,200);

$im = imagecreatetruecolor(200,200);

当然也可以直接从png,gif,jpg等图片直接建立画布(或者称为资源、图片区域)。

0818b9ca8b590ca3270a3433284dd417.png

画布建好之后,就可以在该画布的范围内(也就是说,如果你的画图操作超出了画图的范围,是无法体现在图像中的)进行画图操作了。

建好画布之后,我们做的测试步骤如下:

2.格式栅栏化画布。

通过imageline每隔20px花一条直线,作为识别的参考物。

for($start_x = 0;$start_x <= $canvas_w;$start_x += 20){

if($start_x == $font_x){

imageline($im,$start_x,0,$start_x,$width,$mixed);

}else{

imageline($im,$start_x,0,$start_x,$width,$red);

}

}

for($start_y = 0;$start_y <= $canvas_h;$start_y += 20){

if($start_y == $font_y){

imageline($im,0,$start_y,$height,$start_y,$mixed);

}else{

imageline($im,0,$start_y,$height,$start_y,$red);

}

}

格式栅栏化后的画布类似于下图:

0818b9ca8b590ca3270a3433284dd417.png

3.在指定的位置添加文字

这里用到的函数是imagettftext

该 函数的接口: array imagettftext ( resource $image, float $size , float $angle , int $x , int $y , int $color , string $fontfile, string $text )

其中$x 和 $y 是文字的baseline的起点(也就是文字左下角的点的坐标,换言之,字体只是以baseline为参考,无法保证所有字符都在baseline之上)

imagettftext($im,$fontsize,0,$font_x,$font_y,$green ,$fontfile ,$text);

其中$font_x=40,$font_y=40

写出的字如下所示:

0818b9ca8b590ca3270a3433284dd417.png

可以看出,字母g的下端已经超过了baseline的范围

4.   确定字符的盒装矩形范围

GD库提供了imagettfbbox函数用于返回字符串所占的盒装区域(矩形区域)的4个坐标(当然imagettftext本身也会返回字符串所占区域的坐标,只是在字符串画在图片上之后返回)

$box = imagettfbbox($fontsize,0,$fontfile,$text);

我们打印出来box的值为:

Array

(

[0] => 0

[1] => 7

[2] => 70

[3] => 7

[4] => 70

[5] => -23

[6] => 0

[7] => -23

)

注意观察其中有负值的坐标。

同样观察坐标值我们发现:没有任何一个点的坐标是字体盒子的坐标原点。

我们接着将盒子的矩形区域画出来:

$box_width = max(abs($box[2] - $box[0]),abs($box[4] - $box[6]));

$box_height = max(abs($box[7] - $box[1]),abs($box[5] - $box[3]));

$abs_y1 = abs($box[1]);

$abs_y2 = abs($box_height - $abs_y1);

$left_bottom_x = $font_x +$box[0];

$left_bottom_y = $font_y +$box[1];

$right_bottom_x = $left_bottom_x + $box_width;

$right_bottom_y = $left_bottom_y;

$right_top_x = $right_bottom_x;

$right_top_y = $right_bottom_y-$box_height;

$left_top_x = $left_bottom_x;

$left_top_y = $right_top_y;

imageline($im,$left_bottom_x,$left_bottom_y,$right_bottom_x,$right_bottom_y,$blue);

imageline($im,$right_bottom_x,$right_bottom_y,$right_top_x,$right_top_y,$blue)

imageline($im,$right_top_x,$right_top_y,$left_top_x,$left_top_y,$blue);

imageline($im,$left_top_x,$left_top_y,$left_bottom_x,$left_bottom_y,$blue);

画出的盒子的范围如下图中蓝色框所示(浅青色的横线为字体的baseline线):

0818b9ca8b590ca3270a3433284dd417.png

观察字体所占矩形区域的位置和字体的baseline的位置关系,可以猜测,在字体所在的box中,字体的坐标大致是这样的:

0818b9ca8b590ca3270a3433284dd417.png

同时我们也猜测:将字体画到图片上的时候,实际上是以字体所在区域的baseline的最左侧坐标与写字体指定的坐标位置重合而得到的,也就是类似于平移操作。下图示意:

0818b9ca8b590ca3270a3433284dd417.png

写的寥寥草草,一片混沌,权当笔记。

需要注意的是:

1.imagettftext 中写入文字时,使用的是UTF-8的编码,要特别注意。

2.imagettftext写文字不支持自动换行,需要你手动去控制。

完整的测试代码如下:

$width = 200;

$height = 200;

$canvas_w = $height + 1;

$canvas_h = $height + 1;

$im = imagecreatetruecolor($canvas_w,$canvas_h);

$white = imagecolorallocate($im, 255, 255, 255);

$red = imagecolorallocate($im, 255, 0, 0);

$green = imagecolorallocate($im, 0, 255, 0);

$blue = imagecolorallocate($im, 0, 0, 255);

$mixed = imagecolorallocate($im, 0, 255, 255);

$line_color = $blue;

imagefill($im, 0, 0, $white);

$fontsize = 20;

$fontfile = "msyh.ttf";

$text = "string";

$font_x = 40;

$font_y = 40;

for($start_x = 0;$start_x <= $canvas_w;$start_x += 20){

if($start_x == $font_x){

imageline($im,$start_x,0,$start_x,$width,$mixed);

}else{

imageline($im,$start_x,0,$start_x,$width,$red);

}

}

for($start_y = 0;$start_y <= $canvas_h;$start_y += 20){

if($start_y == $font_y){

imageline($im,0,$start_y,$height,$start_y,$mixed);

}else{

imageline($im,0,$start_y,$height,$start_y,$red);

}

}

imagettftext($im ,$fontsize,0,$font_x,$font_y,$green ,$fontfile ,$text);

$box = imagettfbbox($fontsize,0,$fontfile,$text);

$left_bottom = array($box[0],$box[1]);

$right_bottom = array($box[2],$box[3]);

$right_top = array($box[4],$box[5]);

$left_top = array($box[6],$box[7]);

$box_width = max(abs($box[2] - $box[0]),abs($box[4] - $box[6]));

$box_height = max(abs($box[7] - $box[1]),abs($box[5] - $box[3]));

$abs_y1 = abs($box[1]);

$abs_y2 = abs($box_height - $abs_y1);

$left_bottom_x = $font_x +$box[0];

$left_bottom_y = $font_y +$box[1];

$right_bottom_x = $left_bottom_x + $box_width;

$right_bottom_y = $left_bottom_y;

$right_top_x = $right_bottom_x;

$right_top_y = $right_bottom_y-$box_height;

$left_top_x = $left_bottom_x;

$left_top_y = $right_top_y;

imageline($im,$left_bottom_x,$left_bottom_y,$right_bottom_x,$right_bottom_y,$blue);

imageline($im,$right_bottom_x,$right_bottom_y,$right_top_x,$right_top_y,$blue);

imageline($im,$right_top_x,$right_top_y,$left_top_x,$left_top_y,$blue);

imageline($im,$left_top_x,$left_top_y,$left_bottom_x,$left_bottom_y,$blue);

imagejpeg($im,'res.jpg',100);

imagedestroy($im);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值