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作为字符中轴线绘制的。绘制图像是需要很精确的,在编写代码的时候不能马虎,调整不可能一步到位,需要耐心
若您觉得我的博文对您有帮助,欢迎点击下方按钮对我打赏
打赏