在 PHP GD 库中设置文本自动换行

* Code / # / 转播到腾讯微博 2010年08月13日 / 11条评论 / 4,003 次浏览

前段时间练习使用 PHP 的 GD 库时,为了文本的自动换行纠结了很久。虽然可以通过插入 \n 实现换行,但考虑到文本中既有中文又有英文,强制限定每多少个文字就换行的效果很差。后来终于找到了一个英文下的自动换行的方法,其大概原理是将空格作为分隔符,将字符串分割为一个个单词,然后再一个接一个地拼接在一起,判断其长度是否超过画布,若超过则换行再拼接,否则继续拼接。考虑到中文需要将每个文字都拆开,所以我进行了一点修改,完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
header ("Content-type: image/png");
mb_internal_encoding("UTF-8"); // 设置编码
 
function autowrap($fontsize, $angle, $fontface, $string, $width) {
// 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度 
	$content = "";
 
	// 将字符串拆分成一个个单字 保存到数组 letter 中
	for ($i=0;$i<mb_strlen($string);$i++) {
		$letter[] = mb_substr($string, $i, 1);
	}
 
	foreach ($letter as $l) {
		$teststr = $content." ".$l;
		$testbox = imagettfbbox($fontsize, $angle, $fontface, $teststr);
		// 判断拼接后的字符串是否超过预设的宽度
		if (($testbox[2] > $width) && ($content !== "")) {
			$content .= "\n";
		}
		$content .= $l;
	}
	return $content;
}
 
$bg = imagecreatetruecolor(300, 290); // 创建画布
$white = imagecolorallocate($bg, 255, 255, 255); // 创建白色
$text = "前段时间练习使用 PHP 的 GD 库时,为了文本的自动换行纠结了很久。虽然可以通过插入 \n 实现换行,但考虑到文本中既有中文又有英文,强制限定每多少个文字就换行的效果很差。后来终于找到了一个英文下的自动换行的方法,其大概原理是将空格作为分隔符,将字符串分割为一个个单词,然后再一个接一个地拼接在一起,判断其长度是否超过画布,若超过则换行再拼接,否则继续拼接。考虑到中文需要将每个文字都拆开,所以我进行了一点修改,完整代码如下。";
$text = autowrap(12, 0, "simsun.ttc", $text, 280); // 自动换行处理
 
// 若文件编码为 GB2312 请将下行的注释去掉
// $text = iconv("GB2312", "UTF-8", $text);
 
imagettftext($bg, 12, 0, 10, 30, $white, "simsun.ttc", $text);
imagepng($bg);
imagedestroy($bg);
?>

效果如下:

另外,还有两个问题,待解决。

[1] 有无更好的算法以提高代码的效率,毕竟一个个地拼接很不低碳。

[2] 一直以来都在想「面对对象」的具体意义何在,因为平时 Coding 时「面对过程」足矣了。难道真得参加大型项目才能体验到吗,有谁能比较形象地解释下,或者描述下当年自己是怎么理解的吗。谢谢。

PS ,调试正确的 GD 库代码时总是遇到问题,浪费了好多时间呢。后来才发现是因为 XAMPP ,换用 PHPnow 后问题解决。喵的,第一次使用 XAMPP 就如此不鱼块,哥以后不用丫的了。

围观评论 或者直接发表评论
Notify
任鸟飞 发表于 2010-08-14 00:58

太专业了,PHP我就懂点皮毛,能写个留言版。

Notify
jiehanzheng 发表于 2010-08-18 18:57

这个问题也困扰我很久,后来还是通过限制每行字数实现的 ...

但是,对于英文来说,怎么设计让它不把连续的单词截断呢?

Notify
NetPuter 发表于 2010-08-19 10:25

@任鸟飞 实践最重要,从留言板出来,有很多应用可拿来练手的。
@jiehanzheng 对于英文来说,就相对简单了。在文章第一段就有提到:“将空格作为分隔符,将字符串分割为一个个单词,然后再一个接一个地拼接在一起,判断其长度是否超过画布,若超过则换行再拼接,否则继续拼接”,代码见英文下的自动换行的方法

Notify
Firm 发表于 2010-08-21 11:44

哦,俺一直手动的来着

Notify
清风剑 发表于 2010-08-30 12:32

可以参考维基百科的自动换行条目。里面提到可以通过动态规划来进行,另外估价函数(就是估计怎样排版才算美观)可以用行尾剩余的空格数的平方来考虑(针对英文,中文应该没有这个需要)。

Notify
非主流 发表于 2010-09-02 15:05

字体有的看不清除哦

Notify
Vanthic 发表于 2010-09-08 15:29

奶瓶姐姐,求免翻墙退特客户端,web和air的都可以,谢谢!

Notify
NetPuter 发表于 2010-09-12 19:07

@清风剑 还真没发现这个,谢谢了~
@Vanthic https://t.orzdream.com/

Notify
ljj 发表于 2010-11-11 10:50

效率太低了,2000字好几分钟都出不来,我找到个效率高100倍的代码,2000字只要半秒钟就好了.把中间的28换成你希望每行有多少字就行了

function autowrap($fontsize, $angle, $fontface, $string, $width) {
// 这几个变量分别是 字体大小, 角度, 字体名称, 字符串, 预设宽度
$content = "";

// 将字符串拆分成一个个单字 保存到数组 letter 中
for ($i=0;$i<mb_strlen($string);$i++) {
$letter[] = mb_substr($string, $i, 1);
}
$num=0;
foreach ($letter as $l) {
if($l==""){
$content .= "\n";
$num=0;
}
else if($num!=28){
$content .= $l;
$num++;
}
else if($num>=28){
$content .= "\n";
$num=0;
$content .= $l;
}

}
return $content;
}

Notify
ljj 发表于 2010-11-11 10:54

如果中英文混编,可以让每次换行后的前n个字符不需要进行判断,直接添加,这个n设置成如果都是汉字一行放多少个。如果中英文各一半的话,效率也会提高1倍,如果英文不多只是偶尔穿插的话,效率会提高很多很多

Notify
NetPuter 发表于 2011-01-27 11:37

@ljj 你说的中英文混排我没看懂,= =。感觉还是不能完美解决呢。