Tenken blog

php文字水印过长自动换行算法

这几天搞文字水印遇到一个问题,文字过长如何换行。如果文字过长,超出了图片的宽度,文字就无法显示完整,因为文字是不确定的,文字的位置也不是固定的,所以程序上不能写死,必须要通过程序自动计算换行。

下面说说解决思路:

  1. 把字符串拆分成一个个文字,然后再一个个拼接计算文字的长度,如果超过指定的长度就换行。
  2. 这里涉及到两个技术点,文字拆分,文字长度计算。

文字拆分

文字拆分有很多种方法,可以通过计算ASCII码来拆分文字,原理跟截字一样,也可以通过正则来匹配。这里使用的是正则匹配。

1
2
3
4
5
6
7
8
function chararray($str,$charset="utf-8"){
$re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
$re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
$re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
$re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
preg_match_all($re[$charset], $str, $match);
return $match[0];
}

计算文字长度

计算文字长度可以使用GD函数imagettfbbox,它会返回8个参数,分别是文字的左下角x,y坐标,右下角x,y坐标,右上角x,y坐标,左上角x,y坐标,这样就可以算出文字的长度。

1
2
3
4
5
6
//$fontsize字体大小 $fontangle字体角度 $ttfpath字体路径 $char字符串
function charwidth($fontsize,$fontangle,$ttfpath,$char){
$box = @imagettfbbox($fontsize,$fontangle,$ttfpath,$char);
$width = abs(max($box[2], $box[4]) - min($box[0], $box[6]));
return $width;
}

两个算法合并成最终目的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//$fontsize字体大小 $fontangle字体角度 $ttfpath字体路径 $str字符串 $width指定宽度
function autowrap($fontsize,$fontangle,$ttfpath,$str,$width,$charset='utf-8'){
$_string = "";
$_temp = "";
$strArr = chararray($str);
foreach ($strArr as $k=>$v){
$_temp .= $v;
$w = charwidth($fontsize,$fontangle,$ttfpath,$_temp);
if (($w >= $width) && ($v !== "")){
$_string .= "\n";
$_temp = "";
}
$_string .= $v;
$w = 0;
}
$_string = mb_convert_encoding($_string, "html-entities","utf-8" );
return $_string;
}

使用方法:
$str = autowrap(10,0,'./msyh.ttf','这是一个测试这是一个测试这是一个测试',50);

这里要注意一下:如果把字符串拆分出来一个个文字来计算长度,再相加得到的最后长度与实际一行文字的长度不一致,所以上面的算法是一个个拼接上来计算,而不是一个个文字计算再相加。为了让实际效果更好一些,指定的宽度$width要比图片的宽度要小10px可能会好一点。

请我吃辣条吧~~