原文来源: https://blog.gxxsite.com/php-image-draw-text-line-auto-cut/
PHP 图像加入文字水印的自动换行解决方案(支持中文)
GD 库提供了大量的图片处理函数,其中书写文字也包含在里面,可是换行不属于绘画范畴,是一个需要自行解决的问题,这里记录我所用的解决方案
思路
根据字符的宽度和提供的宽度,计算出范围内每行可写多少个字符,用字符截取的方式把字符分割成数组,再分别绘制
所用到的函数:
getimagesize
imagecreatefromjpeg
imagecreatefrompng
imagefill
imagecopyresampled
imagejpeg
imagecolorallocate
imagettfbbox
imagettftext
分割函数
/*
* 绘图文字分行函数
* by COoL
* - 输入:
* str: 原字符串
* fontFamily: 字体
* fontSize: 字号
* charset: 字符编码
* width: 限制每行宽度(px)
* - 输出:
* 分行后的字符串数组
*/
function autoLineSplit ($str, $fontFamily, $fontSize, $charset, $width) {
$result = [];
$len = (strlen($str) + mb_strlen($str, $charset)) / 2;
// 计算总占宽
$dimensions = imagettfbbox($fontSize, 0, $fontFamily, $str);
$textWidth = abs($dimensions[4] - $dimensions[0]);
// 计算每个字符的长度
$singleW = $textWidth / $len;
// 计算每行最多容纳多少个字符
$maxCount = floor($width / $singleW);
while ($len > $maxCount) {
// 成功取得一行
$result[] = mb_strimwidth($str, 0, $maxCount, '', $charset);
// 移除上一行的字符
$str = str_replace($result[count($result) - 1], '', $str);
// 重新计算长度
$len = (strlen($str) + mb_strlen($str, $charset)) / 2;
}
// 最后一行在循环结束时执行
$result[] = $str;
return $result;
}
实例
$content = '诸菩萨摩诃萨应如是降伏其心!所有一切众生之类:若卵生、若胎生、若湿生、若化生;若有色、若无色;若有想、若无想、若非有想非无想,我皆令入无余涅盘而灭度之。如是灭度无量无数无边众生,实无众生得灭度者。何以故?须菩提!若菩萨有我相、人相、众生相、寿者相,即非菩萨。';
$bg = imagecreatefromjpeg('o.jpg');
$fontFamily = 'FZLTHJW.TTF';
$fontSize = 24;
$charset = 'utf8';
$textcolor = imagecolorallocate($bg, 0, 0, 0);
$lineHeight = 50;
$startX = 15;
$startY = 50;
$lineWidth = imagesx($bg) - $startX - $startY;
$lineArr = autoLineSplit($content, $fontFamily, $fontSize, $charset, $lineWidth);
foreach ($lineArr as $k => $v) {
imagettftext($bg, $fontSize, 0, $startX, ($startY + ($lineHeight * $k)), $textcolor, $fontFamily, $v);
}
$fileName = date('YmdHis').rand(10000,100000).'.jpg';
$localUrl = '/upload/'.$fileName;
imagejpeg($bg, $localUrl, 90);
注意
若需求是不把文字写在图片上的话,就需要根据字符的总行数再新建一个高度适合的图像,填充背景色,再把原图绘制到新图上,最后把字符从原图高度加上一定的margin以后开始绘制(这里我就忽略了,就当抛砖引玉吧)
大多数字体,中英文的宽度并不是1:2,甚至不同字母的宽度不同,这就需要每一行都计算一次宽度,再进行截取,而不是我所写的用“总长/字符数”来简单计算每字符占位
需要注意Y轴开始点,默认是把Y作为字符中轴线绘制的。绘制图像是需要很精确的,在编写代码的时候不能马虎,调整不可能一步到位,需要耐心