PHP Conference Japan 2024

imagettftext

(PHP 4, PHP 5, PHP 7, PHP 8)

imagettftext使用 TrueType 字体将文本写入图像

描述

imagettftext(
    GdImage $image,
    float $size,
    float $angle,
    int $x,
    int $y,
    int $color,
    string $font_filename,
    string $text,
    array $options = []
): array|false

使用 TrueType 字体将给定的 text 写入图像。

注意:

在 PHP 8.0.0 之前,imagefttext()imagettftext() 的扩展变体,它还支持 extrainfo。从 PHP 8.0.0 开始,imagettftext()imagefttext() 的别名。

参数

image

一个 GdImage 对象,由图像创建函数之一返回,例如 imagecreatetruecolor()

size

以磅为单位的字体大小。

angle

以度为单位的角度,其中 0 度表示从左到右阅读文本。较高的值表示逆时针旋转。例如,值 90 将导致从下到上阅读文本。

x

xy 给出的坐标将定义第一个字符的基点(大致为字符的左下角)。这与 imagestring() 不同,在 imagestring() 中,xy 定义第一个字符的左上角。例如,“左上角”为 0, 0。

y

纵坐标。这设置了字体基线的位置,而不是字符的最底部。

color

颜色索引。使用颜色索引的负数会关闭抗锯齿。请参阅 imagecolorallocate()

fontfile

要使用的 TrueType 字体的路径。

根据 PHP 使用的 GD 库的版本,fontfile 不以引导 / 开头时,将追加 .ttf 到文件名,并且库将尝试沿着库定义的字体路径搜索该文件名

当使用低于 2.0.18 版本的 GD 库时,使用 space 字符而不是分号作为不同字体文件的“路径分隔符”。意外使用此功能将导致警告消息:Warning: Could not find/open font。对于这些受影响的版本,唯一的解决方案是将字体移动到不包含空格的路径。

在许多字体与使用它的脚本位于同一目录的情况中,以下技巧将缓解任何包含问题。

<?php
// 设置 GD 的环境变量
putenv('GDFONTPATH=' . realpath('.'));

// 指定要使用的字体(注意缺少 .ttf 扩展名)
$font = 'SomeFont';
?>

注意:

请注意,open_basedir 适用于 fontfile

text

UTF-8 编码的文本字符串。

可以包含十进制数字字符引用(格式为:&#8364;)以访问字体中第 127 位之后 的字符。支持十六进制格式(如 &#xA9;)。可以直接传递 UTF-8 编码的字符串。

不支持命名实体,例如 &copy;。考虑使用 html_entity_decode() 将这些命名实体解码为 UTF-8 字符串。

如果字符串中使用的字符不受字体支持,则将用空心矩形替换该字符。

返回值

返回一个包含 8 个元素的数组,表示构成文本边界框的四个点。点的顺序为左下、右下、右上、左上。点相对于文本,无论角度如何,因此“左上”表示当您水平看到文本时位于左上角。出错时返回 false

变更日志

版本 描述
8.0.0 添加了 options

示例

示例 #1 imagettftext() 示例

此示例脚本将生成一个 400x30 像素的白色 PNG,其中包含黑色(带灰色阴影)的单词“Testing...”,字体为 Arial。

<?php
// 设置内容类型
header('Content-Type: image/png');

// 创建图像
$im = imagecreatetruecolor(400, 30);

// 创建一些颜色
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 0, 0, 399, 29, $white);

// 要绘制的文本
$text = 'Testing...';
// 将路径替换为您自己的字体路径
$font = 'arial.ttf';

// 为文本添加一些阴影
imagettftext($im, 20, 0, 11, 21, $grey, $font, $text);

// 添加文本
imagettftext($im, 20, 0, 10, 20, $black, $font, $text);

// 使用 imagepng() 与 imagejpeg() 相比,可以获得更清晰的文本
imagepng($im);
imagedestroy($im);
?>

以上示例将输出类似于以下内容

Output of example : imagettftext()

注释

注意此函数仅在 PHP 使用 freetype 支持编译时可用(--with-freetype-dir=DIR

参见

添加注释

用户贡献的注释 40 条注释

52
Valentijn de Pagter
16 年前
如果您正在寻找简单的文本对齐方式,则需要使用 imagettfbbox() 命令。当给出正确的参数时,它将以数组形式返回要生成的文本字段的边界,这将允许您计算用于居中或对齐文本所需的 x 和 y 坐标。

水平居中示例

<?php

$tb
= imagettfbbox(17, 0, 'airlock.ttf', 'Hello world!');

?>

$tb 将包含

数组
(
[0] => 0 // 左下角 X 坐标
[1] => -1 // 左下角 Y 坐标
[2] => 198 // 右下角 X 坐标
[3] => -1 // 右下角 Y 坐标
[4] => 198 // 右上角 X 坐标
[5] => -20 // 右上角 Y 坐标
[6] => 0 // 左上角 X 坐标
[7] => -20 // 左上角 Y 坐标
)

对于水平对齐,我们需要从图像宽度中减去“文本框”的宽度 { $tb[2] 或 $tb[4] },然后减去 2。

假设您有一个 200px 宽的图像,您可以执行以下操作

<?php

$x
= ceil((200 - $tb[2]) / 2); // 文本的左下角 X 坐标
imagettftext($im, 17, 0, $x, $y, $tc, 'airlock.ttf', 'Hello world!'); // 将文本写入图像

?>

这将为您提供完美的文本水平居中对齐,最多相差 1 个像素。玩得开心!
14
suyog at suyogdixit dot com
11 年前
为了您的全面了解:以下直接插入函数将在一块 GD 图像上放置一段完全对齐的文本。它有点 CPU 密集,因此我建议缓存输出而不是动态执行。

参数

$image - 目标画布的 GD 句柄
$size - 文本大小
$angle - 文本的倾斜度(效果不佳),对于水平文本,保留为 0
$left - 从左侧开始块的像素数
$top - 从顶部开始块的像素数
$color - 颜色的句柄(imagecolorallocate 结果)
$font - .ttf 字体的路径
$text - 要换行和对齐的文本
$max_width - 文本块的宽度,文本应在其中换行并完全对齐
$minspacing - 单词之间的最小像素数
$linespacing - 行高的倍数(1 为正常间距;1.5 为一行半等)

例如。
$image = ImageCreateFromJPEG( "sample.jpg" );
$cor = imagecolorallocate($image, 0, 0, 0);
$font = 'arial.ttf';
$a = imagettftextjustified($image, 20, 0, 50, 50, $color, $font, "Shree", 500, $minspacing=3,$linespacing=1);
header('Content-type: image/jpeg');
imagejpeg($image,NULL,100);

function imagettftextjustified(&$image, $size, $angle, $left, $top, $color, $font, $text, $max_width, $minspacing=3,$linespacing=1)
{
$wordwidth = array();
$linewidth = array();
$linewordcount = array();
$largest_line_height = 0;
$lineno=0;
$words=explode(" ",$text);
$wln=0;
$linewidth[$lineno]=0;
$linewordcount[$lineno]=0;
foreach ($words as $word)
{
$dimensions = imagettfbbox($size, $angle, $font, $word);
$line_width = $dimensions[2] - $dimensions[0];
$line_height = $dimensions[1] - $dimensions[7];
if ($line_height>$largest_line_height) $largest_line_height=$line_height;
if (($linewidth[$lineno]+$line_width+$minspacing)>$max_width)
{
$lineno++;
$linewidth[$lineno]=0;
$linewordcount[$lineno]=0;
$wln=0;
}
$linewidth[$lineno]+=$line_width+$minspacing;
$wordwidth[$lineno][$wln]=$line_width;
$wordtext[$lineno][$wln]=$word;
$linewordcount[$lineno]++;
$wln++;
}
for ($ln=0;$ln<=$lineno;$ln++)
{
$slack=$max_width-$linewidth[$ln];
if (($linewordcount[$ln]>1)&&($ln!=$lineno)) $spacing=($slack/($linewordcount[$ln]-1));
else $spacing=$minspacing;
$x=0;
for ($w=0;$w<$linewordcount[$ln];$w++)
{
imagettftext($image, $size, $angle, $left + intval($x), $top + $largest_line_height + ($largest_line_height * $ln * $linespacing), $color, $font, $wordtext[$ln][$w]);
$x+=$wordwidth[$ln][$w]+$spacing+$minspacing;
}
}
return true;
}
5
gav-alex at bk dot ru
19 年前
大家好!
当我的主机在最初的几分钟内更新了他的 php 库时,我遇到了与你们中的一些人相同的问题。
Php 找不到 true type 字体的路径。
在我的情况下,解决方案是使路径如下所示
<?php
imagettftext
($im, 20, 0, 620, 260, $secondary_color, "./tahoma.ttf" , "NEWS");
?>
如您所见,我只是简单地添加了 "./"

另一个我想在这里补充的技巧是如何使用 imagettftext 在图像上写入俄语
您只需像这样更改函数参数
<?php
imagettftext
($im, 15, 0, 575, 300, $secondary_color, "./tahoma.ttf" , win2uni("some word in russian"));
?>
其中 win2uni 是将 win1251 转换为 unicode 的函数。以下是它的代码
<?php

// Windows 1251 -> Unicode
function win2uni($s)
{
$s = convert_cyr_string($s,'w','i'); // win1251 -> iso8859-5
// iso8859-5 -> unicode:
for ($result='', $i=0; $i<strlen($s); $i++) {
$charcode = ord($s[$i]);
$result .= ($charcode>175)?"&#".(1040+($charcode-176)).";":$s[$i];
}
return
$result;
}
?>

今天就到这里!感谢您的关注!
Alex
2
mitch at electricpulp dot com
17 年前
如果您在使用字体时遇到问题...(找不到/打开字体)请检查文件夹/字体文件的权限,并确保它们为 775,尤其是在您刚从 Windows 机器上提取它们时。希望这有帮助!
2
s.pynenburg _at_ gm ail dotcom
16 年前
我有一个图像生成器,用户可以在其中定位他们希望文本开始的位置 - 但它一直超出图像边缘。所以我创建了这个基本函数:它测量输入的文本和 x 坐标是否会导致字符串超出边缘,如果是,它将尽可能多地适应第一行,然后转到下一行。
限制
-它只执行一次(即,它不会分成三行)
-我非常确定它不适用于倾斜文本。

<?PHP

function imagettftextwrap($im, $size, $angle, $x_pos, $y_pos, $color, $font, $instr)
{
$box = @imagettfbbox($size, 0, $font, $instr);
$width = abs($box[4] - $box[0]);
$height = abs($box[3] - $box[5]);
$overlap = (($x_pos + $width) - imagesx($im));
if(
$overlap > 0) //如果文本不适合图像
{
$chars = str_split($instr);
$str = "";
$pstr = "";
for(
$m=0; $m < sizeof($chars); $m++)
{
$bo = imagettfbbox($fsize1, 0, $font1, $str);
$wid = abs($bo[4] - $bo[0]);
if((
$x_pos + $wid) < imagesx($im)) //只要不溢出,就从字符串中添加一个字符
{
$pstr .= $chars[$m];
$bo2 = imagettfbbox($fsize1, 0, $font1, $pstr);
$wid2 = abs($bo2[4] - $bo2[0]);
if((
$x_pos + $wid2) < imagesx($im))
{
$str .= $chars[$m];
}
else
{
break;
}
}
else
{
break;
}
}
$restof = "";
for(
$l=$m; $l < sizeof($chars); $l++)
{
$restof .= $chars[$l]; //将字符串的其余部分添加到新行
}
imagettftext($im, $size, $angle, $x_pos, $y_pos, $color, $font, $str); //打印出较短的行
imagettftext($im, $size, $angle, 0, $y_pos + $height, $color, $font, $restof); //以及其余部分
}
else
{
imagettftext($im, $size, $angle, $x_pos, $y_pos, $color, $font, $instr); //否则正常执行
}

}

?>
3
pillepop2003 at nospam dot yahoo dot de
19 年前
大家好,

如果您想围绕文本的中心而不是其“左下角”枢轴点旋转文本,请查看此函数



<?php
// 将中心旋转的 ttf 文本放入图像
// 与 imagettftext() 具有相同的签名;
function imagettftext_cr(&$im, $size, $angle, $x, $y, $color, $fontfile, $text)
{
// 获取边界框
$bbox = imagettfbbox($size, $angle, $fontfile, $text);

// 计算偏差
$dx = ($bbox[2]-$bbox[0])/2.0 - ($bbox[2]-$bbox[4])/2.0; // 左右偏差
$dy = ($bbox[3]-$bbox[1])/2.0 + ($bbox[7]-$bbox[1])/2.0; // 上下偏差

// 新的基准点
$px = $x-$dx;
$py = $y-$dy;

return
imagettftext($im, $size, $angle, $px, $py, $color, $fontfile, $text);
}

?>

顶起
菲尔
2
JohnB
14年前
以防万一您(像我一样)没有意识到这一点,在 Windows 中,ttf 字体并不一定在所有字体大小下都进行抗锯齿处理。Arial 似乎在所有尺寸下都能正常工作,但例如 Calibri 仅在 8 点字体大小下进行抗锯齿处理,然后在所有 16 及以上尺寸下进行抗锯齿处理。不仅如此,在 10 和 12 等字体大小下,字符不会以预期的角度打印:所有字符都以直立的方式打印在倾斜的基线上。
3
philip at webdesco dot com
15年前
你好,
对于新手(像我一样),如果您在包含字体文件时遇到问题,请在文件名之前添加 ./

在我的开发服务器上,以下代码运行良好
$myfont = "coolfont.ttf";

在我的托管服务器上,我唯一能够使字体正常工作的办法如下
$myfont = "./coolfont.ttf";

希望这对某些人有所帮助!
2
web at evanreeves dot com
15年前
我试图使用像素字体渲染非抗锯齿文本时遇到了麻烦。关于为颜色设置负值的提示是有效的,但我仍然无法渲染我尝试渲染的文本,因为它为黑色。我发现如果我将 imagecolorallocate() 函数从

$color = imagecolorallocate($base, 0, 0, 0);

更改为

$color = imagecolorallocate($base, 1, 1, 1); (接近黑色)

然后在 imagettftext() 中使用颜色的负值,它将正常工作。区别在于我的第一个实现设置了 $color = 0。显然,你不能有 $color = -0,它没有区别。当我切换到 (1,1,1) 时,它变成了 $color = 1,我可以为它取负值。
2
John Conde
14年前
如果您想创建一段文字,则需要将文本分成几行,然后将每行单独放置在下一行下方。

这是一个如何执行此操作的基本示例

<?php
// 基本字体设置
$font ='./times.ttf';
$font_size = 15;
$font_color = 0x000000

// 要作为段落放置的文本
$text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer non nunc lectus. Curabitur hendrerit bibendum enim dignissim tempus. Suspendisse non ipsum auctor metus consectetur eleifend. Fusce cursus ullamcorper sem nec ultricies. Aliquam erat volutpat. Vivamus massa justo, pharetra et sodales quis, rhoncus in ligula. Integer dolor velit, ultrices in iaculis nec, viverra ut nunc.';

// 将其分成 125 个字符长的片段
$lines = explode('|', wordwrap($text, 115, '|'));

// 起始 Y 位置
$y = 513;

// 循环遍历行并将它们放置在图像上
foreach ($lines as $line)
{
imagettftext($image, $font_size, 0, 50, $y, $font_color, $font, $line);

// 增加 Y,以便下一行位于上一行下方
$y += 23;
}

?>
1
badrou14 at yahoo dot fr
3年前
对于 Windows,您可以使用此代码,感谢 Ohmycode
他的解决方案链接:https://ohmycode.wordpress.com/2008/09/20/imagettftext-gdfontpath-et-ttf-sous-windows/
<?php

$font
= realpath(".")."\\arial.ttf";


$black = imagecolorallocate($im, 0, 0, 0);


$im = imagecreatetruecolor(400, 30);


imagettftext($im, 20, 0, 10, 20, $black, $font, "coucou");
?>
0
ben at spooty dot net
15年前
这是一个将文本包装到图像中的简单函数。它将根据需要换行,但 $angle 必须为零。$width 参数是图像的宽度。

<?php
function wrap($fontSize, $angle, $fontFace, $string, $width){

$ret = "";

$arr = explode(' ', $string);

foreach (
$arr as $word ){

$teststring = $ret.' '.$word;
$testbox = imagettfbbox($fontSize, $angle, $fontFace, $teststring);
if (
$testbox[2] > $width ){
$ret.=($ret==""?"":"\n").$word;
} else {
$ret.=($ret==""?"":' ').$word;
}
}

return
$ret;
}
?>
0
matt at mmkennedy dot net
16 年前
对于任何尝试打印黑色条形码并尝试关闭抗锯齿的人,请记住 -1 * [0,0,0] 为 0,而不是 -0。
0
dotpointer
16 年前
对于那些尝试禁用字体平滑或字体 ClearType 的人:请查看此函数的颜色参数。您要查找的内容的正确术语是抗锯齿。
0
lassial at gmail dot com
17 年前
Roy van Arem 建议了一个用于列出机器上 TTF 的简洁代码。但是,它存在一些问题(例如文件扩展名的区分大小写和有缺陷的字体),我在以下脚本中对其进行了更正,该脚本可以作为单个 PHP 脚本实现(命名为您喜欢的方式)

<?php //确保上方没有空行

$ffolder="/usr/local/bin/fonts"; //您的字体所在的目录

if (empty($_GET['f']))
{
$folder=dir($ffolder); //打开目录
echo "<HTML><BODY>\n";

while(
$font=$folder->read())
if(
stristr($font,'.ttf')) //仅ttf字体
$fonts[]=$font;

$folder->close();

if (!empty(
$fonts))
{
echo
"<table><tr><th colspan='2'>Fonts available in $ffolder</th></tr>"
."\n<tr><th>Name</th><th>Appereance</th>";
sort($fonts);
foreach (
$fonts as $font)
echo
"<tr><td>$font</td><td> <IMG src='".$_SERVER['SCRIPT_NAME']
.
"?f=$font'></td></tr>\n";
}
else echo
"No fonts found from $ffolder";
echo
"\n</HTML></BODY>";
}

else
{
$im=@imagecreatetruecolor(200,30)
or die(
"Cannot Initialize new GD image stream");

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

imagefill($im,0,0,$white);
imagettftext($im,14,0,5,25,$black, "$ffolder/".$_GET['f'] , $_GET['f']);

header("Content-type: image/png");
header('Content-Length: ' . strlen($im));

imagepng($im);
imagedestroy($im);
}
?>
0
[email protected]
17 年前
我发现GD的字距调整(字母之间的间距)相当糟糕 - 达不到普通设计师的标准。以下是一些改进方法
- 使用字母的边界框逐个放置字母,而不是使用一个字符串
- 使用$kerning值进行调整
- 对于小文本,从更大的尺寸进行采样,以调整小于1像素的增量

例如

<?PHP

$STRING
= "NOTRE PHILOSOPHIE";

// ---- 预设
$FONT = "CantoriaMTStd-SemiBold.otf";
$FONT_SIZE = 10.5;
$WIDTH = 200;
$HEIGHT = 16;
$KERNING = 0;
$BASELINE = 12;
$BG_COLOR = array(
"R"=>5,
"G"=>45,
"B"=>53
);
$TXT_COLOR = array(
"R"=>188,
"G"=>189,
"B"=>0
);

// ---- 创建画布 + 调色板
$canvas = imageCreateTrueColor($WIDTH*4,$HEIGHT*4);

$bg_color = imageColorAllocate($canvas, $BG_COLOR["R"], $BG_COLOR["G"], $BG_COLOR["B"]);

$txt_color = imageColorAllocate($canvas, $TXT_COLOR["R"], $TXT_COLOR["G"], $TXT_COLOR["B"]);

imagefill ( $canvas, 0, 0, $bg_color );

// ---- 绘制

$array = str_split($STRING);
$hpos = 0;

for(
$i=0; $i<count($array); $i++)
{
$bbox = imagettftext( $canvas, $FONT_SIZE*4, 0, $hpos, $BASELINE*4, $txt_color, $FONT, $array[$i] );

$hpos = $bbox[2]+$KERNING;
}

// ---- 降采样 & 输出
$final = imageCreateTrueColor($WIDTH,$HEIGHT);

imageCopyResampled( $final, $canvas, 0,0,0,0, $WIDTH, $HEIGHT, $WIDTH*4, $HEIGHT*4 );

header('Content-type: image/png');

imagePNG($final);

imageDestroy($canvas);
imageDestroy($final);

?>
0
Tom Pike
18年前
参考:[email protected]

"使用颜色的负索引会关闭抗锯齿功能。"

这是正确的,但前提是图像使用imagecreate()创建(而不是imagecreatetruecolor())
0
[email protected]
18年前
这个让我有点困惑,所以为了帮助其他人...

"使用颜色的负索引会关闭抗锯齿功能。"

简单来说

<?php

$textColour
= ImageColorAllocate($image, 255, 255, 255);
ImageTTFText($image, 8, 0, 0, 0, -$textColour, $font, $text);

?>

注意ImageTTFText中$textColor之前的-(减号),这会创建负颜色索引,并关闭文本的抗锯齿。
0
Mer`Zikain
18年前
我一直在寻找一种向文本添加字距调整的方法,最后只是创建了这个函数来实现。当然,如果您根据要放入其中的文本生成图像的大小,则必须计算出新的尺寸以适应新的文本宽度,但我相信您可以解决这个问题。

for($i=0;$i<strlen($text);$i++){
// 获取单个字符
$value=substr($text,$i,1);
if($pval){ // 检查是否存在先前的字符
list($lx,$ly,$rx,$ry) = imagettfbbox($fontsize,0,$font,$pval);
$nxpos+=$rx+3;
}else{
$nxpos=0;
}
// 将字母添加到图像
imagettftext($im, $fontsize, 0, $nxpos, $ypos, $fontcolor, $font, $value);
$pval=$value; // 保存当前字符以供下一个循环使用
}
-1
[email protected]
18年前
我赞同--colobri--的观点。

仅在./configure中添加--with-ttf和--with-freetype-dir=/usr/lib/,然后执行"make; make install"是不够的。

我必须执行"make clean",然后执行"make install"才能启用FreeType支持。

以下是我相关的./configure行
--with-gd \
--enable-gd-native-ttf \
--with-ttf \
--with-freetype-dir=/usr/lib/ \
--with-jpeg-dir=/usr/lib/libjpeg.so.62 \
--enable-exif \
-1
[email protected]
19 年前
请注意,如果在php.ini中启用了open_basedir限制,则必须在open_basedir列表中包含TrueType字体的路径。
-2
[email protected]
16 年前
ttfWordWrappedText 函数中存在一个虽小但非常危险的 bug,由 waage 编写,只需尝试 ttfWordWrappedText("aaaaa\naa",4) 即可导致脚本陷入无限循环。
可以使用以下代码修复它
<?php
function ttfWordWrappedText_fixed($text, $strlen = 8) {
$text = urldecode($text);
$text = explode("\n", $text);
$i = 0;
foreach(
$text as $text)
{
while(
strlen($text) > $strlen && strstr($text, ' ') !== FALSE) {
$startPoint = strpos($text, ' ');
$line[$i][] =substr($text,0,$startPoint);
$text = trim(strstr($text, ' '));
}
$line[$i][] = trim($text);
}
$line[$i][] = trim($text);
$i++;
}

return
$line;
}
?>
更好的解决方案是检查输入文本中是否存在比所需换行点更长的行。
-2
denis at reddodo dot com
16 年前
ttfWordWrappedText 函数中存在一个虽小但非常危险的 bug,由 waage 编写,只需尝试 ttfWordWrappedText("aaaaa\naa",4) 即可导致脚本陷入无限循环。
可以使用以下代码修复它
<?php
function ttfWordWrappedText_fixed($text, $strlen = 8) {
$text = urldecode($text);
$text = explode("\n", $text);

$i = 0;
foreach(
$text as $text)
{
while(
strlen($text) > $strlen && stristr($text, ' ') !== FALSE) {
$startPoint = $strlen - 1;
while(
substr($text, $startPoint, 1) != " ") {
$startPoint--;
}
$line[$i][] = trim(substr($text, 0, $startPoint));
$text = substr($text, $startPoint);
}
$line[$i][] = trim($text);
$i++;
}

return
$line;
}
?>
更好的解决方案是检查输入文本中是否存在比所需换行点更长的行。
-2
waage
17 年前
我在尝试同时实现自动换行和换行符检测时遇到了一些问题,但在下面评论的一些帮助下,我得到了这个解决方案。(感谢 jwe 提供了代码的主要部分)

<?php
function ttfWordWrappedText($text, $strlen = 38) {
$text = urldecode($text);
$text = explode("\n", $text);

$i = 0;
foreach(
$text as $text)
{
while(
strlen($text) > $strlen) {
$startPoint = $strlen - 1;
while(
substr($text, $startPoint, 1) != " ") {
$startPoint--;
}
$line[$i][] = trim(substr($text, 0, $startPoint));
$text = substr($text, $startPoint);
}
$line[$i][] = trim($text);
$i++;
}

return
$line;
}
?>

这将返回一个数组,每个数组元素代表一个输入的换行符,以及一个子数组,每个子数组代表一个自动换行的行,以便打印。

例如:

数组
(
[0] => 数组
(
[0] => 这是第一行很长的文本
[1] => 我输入的。
)

[1] => 数组
(
[0] => 这是那之后的新的一行。
)
)
-2
admin at sgssweb dot com
18年前
另一种方法如下。在创建一个 GMIPluggableSet 类的子类后,该子类应该重写两个方法:getExpression() 和 getVariables(),然后将其传递给 FontImageGenerator 类的实例。
例如,代码如下

<?php

require_once 'package.fig.php';

class
SampleFontImagePluggableSet
extends GMIPluggableSet
{
var
$defaultVariables = array(
"text" => null,
"size" => null,
"font" => null,
"color" => "0x000000",
"alpha" => "100",
"padding" => 0,
"width" => null,
"height" => null,
"align" => "left",
"valign" => "middle",
"bgcolor" => "0xffffff",
"antialias" => 4
);

function
SampleFontImagePluggableSet() {
parent::GMIPluggableSet();
}

function
getExpression() {
return
"size {width}, {height};".
"autoresize none;".
"type gif, 256, {color: {bgcolor}};".
"padding {padding};".
"color {color: {bgcolor}};".
"fill;".
"color {color: {color}, {alpha}};".
"antialias {antialias};".
"font {font}, {size};".
"string {text}, 0, 0, {width}, {height}, {align}, {valign};";
}

function
getVariables() {
return
array_merge($this->defaultVariables, $_GET);
}
}

$pluggableSet = new SampleFontImagePluggableSet();
$fig = new FontImageGenerator();
$fig->setPluggableSet($pluggableSet);
$fig->execute();

?>

这将输出一个图像,其中文本定义在 $_GET['text'] 中,字体定义在 $_GET['font'] 中,文本颜色定义在 $_GET['color'] 中,背景定义在 $_GET['bgcolor'] 中,等等。

脚本文件可在以下地址获取:http://sgssweb.com/experiments/?file=PHPFontImageGenerator
-2
admin at phpru dot com
18年前
在我的配置中:php5.1.2+apache 1.33


iconv() 函数在处理所有 Cyrillic 编码时表现非常好,因此您无需像 win2uni 一样编写自己的函数。
-1
jwe
18年前
对于任何接收类似于本页面示例中的文本(例如:通过 $_GET['text'] 或类似方式)并需要将其格式化为多行的人来说,这是一个快速提示。诀窍在于找到空格...

<?php
$text
= $_GET['text'];
// 每行最多 38 个字符...
while(strlen($text) > 38) {
$startPoint = 37;
// 查找换行符处的空格
while(substr($text, $startPoint, 1) != " ") {
$startPoint--;
}
$line[] = trim(substr($text, 0, $startPoint));
$text = substr($text, $startPoint);
}
$line[] = trim($text);
?>

结果是一个名为 $line 的数组,其中包含您需要按顺序输出的所有文本行。

剩下的唯一任务是根据您要使用的字体大小确定图像的正确高度。不要忘记在行之间留出一些用于标点符号和下降字母(逗号、g、q、p、y 等)的填充空间。

当您需要使用非标准字体创建标题图像时,imagettftext 非常有用。太棒了。非常感谢开发者们。

--Julian
-1
plusplus7 at hotmail dot com
20 年前
如果您得到的是所有矩形而不是文本,则很可能意味着您的 ttf 字体不是 OpenType 字体,特别是如果它是一个较旧的免费软件字体。此要求在较旧的版本中不存在,因此您可能会发现您的字体在升级后停止工作。要解决此问题,请尝试下载免费的 MS Volt 实用程序。在其中,打开您的字体文件,然后单击“编译”,然后重新保存。
-2
Anonymous
17 年前
仅评论一下 Sohel Taslims 的出色函数...
如果任何人需要为此类函数添加背景透明度(几乎每个人都希望拥有),则添加

$bg_color = imagecolorat($im,1,1);
imagecolortransparent($im, $bg_color);

在“if($L_R_C == 0){ //Justify Left”行上方
-1
damititi at gmail dot com
16 年前
首先,感谢 sk89q 提供的函数!这正是我想要的。

我做了一个更改。根据字母的不同,文本的垂直对齐不正确。
我替换了以下行
$line_height = $dimensions[1] - $dimensions[7];
以下内容
$line_height = $size+4;

无论写的是 mama 还是 jeje,垂直位置都将相同。
-1
llewellyntd at gmail dot com
16 年前
大家好,

我花了几个月的时间才用 GD 库做一个像样的文本扭曲。这是我使用的代码

<?php
//自动换行
$warpText = wordwrap($text, 30, "\n");
//显示文本
imagettftext($image, $fontSize, 0, $x, $y, $fontColor, $font, $warpText);
?>

希望这对某些人有所帮助。

干杯
-1
m0r1arty at mail dot ru
16 年前
抱歉我的英语。
我在 Windows 下使用 imagettftext 时遇到问题。
我无法使用字体的短名称(例如“arial”、“arialbd.ttf”等)。PHP 说找不到此字体。
环境变量 GDFONTPATH 的操作丢失了。
这是我的解决方案
<?php
$dir
=opendir('./font/');//包含字体的目录
if($dir)
while(
$f=readdir($dir)){
if(
preg_match('/\.ttf$/',$f)){
$font=explode('.',$f);
define($font[0],realpath('./font/'.$f));
}
}
if(
$dir)
closedir($dir);
?>
“font”目录有两个文件:arial.ttf 和 arialbd.ttf
现在可以通过调用 imagettftext 使用常量字体名称
imagettftext($img,12,0,25,28,$color,arialbd,'some text');
-1
Roy van Arem
18年前
如果您想显示目录中的字体列表并查看它们的外观,您可以执行以下操作

<HTML><BODY>

<?php

$folder
=dir("fonts/"); //您的字体所在的目录

while($font=$folder->read())
{

if(
stristr($font,'.ttf'))echo '<IMG SRC="img.php?'.substr($font,0,strpos($font,'.')).'">'; //仅 ttf 字体

}

$folder->close();

?>

</BODY></HTML>

“img.php”文件应类似于以下内容

<?php

$font
=$_SERVER["QUERY_STRING"];

header("Content-type: image/png");
$im=@imagecreatetruecolor(200,30)or die("无法初始化新的 GD 图像流");

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

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

imagettftext($im,18,0,5,25,$black,"fonts/".$font,$font);

imagepng($im);
imagedestroy($im);

?>

我在 http://font.beginstart.com 实现了类似的功能
-2
ben at evolutioncomputing co uk
18年前
一个集中的文本水印 - 任何长度,自动调整到大约 70% 的宽度,并且可以旋转到任何角度。



<?php
/* 获取图片信息 */
$Image = @ImageCreateFromJPEG ("YourImage.jpg") ;
$sx = imagesx($Image) ;
$sy = imagesy($Image) ;
if (
$WatermarkNeeded)
{
/* 设置文本信息 */
$Text="Copyright Ben Clay" ;
$Font="arial.ttf" ;
$FontColor = ImageColorAllocate ($Image,255,255,255) ;
$FontShadow = ImageColorAllocate ($Image,0,0,0) ;
$Rotation = 30 ;
/* 创建一个副本图像 */
$OriginalImage = ImageCreateTrueColor($sx,$sy) ;
ImageCopy ($OriginalImage,$Image,0,0,0,0,$sx,$sy) ;
/* 循环迭代获取合适的字体大小 */
$FontSize=1 ;
do
{
$FontSize *= 1.1 ;
$Box = @ImageTTFBBox($FontSize,0,$Font,$Text);
$TextWidth = abs($Box[4] - $Box[0]) ;
$TextHeight = abs($Box[5] - $Box[1]) ;
}
while (
$TextWidth < $sx*0.7) ;
/* 计算文本起始位置 */
$x = $sx/2 - cos(deg2rad($Rotation))*$TextWidth/2 ;
$y = $sy/2 + sin(deg2rad($Rotation))*$TextWidth/2 + cos(deg2rad($Rotation))*$TextHeight/2 ;
/* 先绘制阴影文本,再绘制实心文本 */
ImageTTFText ($Image,$FontSize,$Rotation,$x+4,$y+4,$FontShadow,$Font,$Text);
ImageTTFText ($Image,$FontSize,$Rotation,$x,$y,$FontColor,$Font,$Text);
/* 将原始图像与带文本的图像合并,使文本部分呈现透明效果 */
ImageCopyMerge ($Image,$OriginalImage,0,0,0,0,$sx,$sy,50) ;
}

ImageJPEG ($Image) ;
?>
-2
Ole Clausen
17 年前
评论回复:Sohel Taslim (03-Aug-2007 06:19)

感谢您提供的函数,我做了一些修改。在新版本中,行与行之间的间距相等(在您的示例中,g 会导致行间距更大) - 由参数 '$Leading' 设置。

我使用了 for 循环来提高性能,并对其他部分进行了简化 :)

/**
* @name : makeImageF
*
* 用于根据选定的字体创建文本图像。对图像中的文本进行对齐(0-左对齐,1-右对齐,2-居中对齐)。
*
* @param String $text : 要转换为图像的字符串。
* @param String $font : 文本的字体名称。将字体文件保存在同一文件夹中。
* @param int $Justify : 图像中文本的对齐方式(0-左对齐,1-右对齐,2-居中对齐)。
* @param int $Leading : 行间距。
* @param int $W : 图像的宽度。
* @param int $H : 图像的高度。
* @param int $X : 文本在图像中的 x 坐标。
* @param int $Y : 文本在图像中的 y 坐标。
* @param int $fsize : 文本的字体大小。
* @param array $color : 文本颜色的 RGB 颜色数组。
* @param array $bgcolor : 背景颜色的 RGB 颜色数组。
*
*/
function imagettfJustifytext($text, $font="CENTURY.TTF", $Justify=2, $Leading=0, $W=0, $H=0, $X=0, $Y=0, $fsize=12, $color=array(0x0,0x0,0x0), $bgcolor=array(0xFF,0xFF,0xFF)){

$angle = 0;
$_bx = imageTTFBbox($fsize,0,$font,$text);
$s = split("[\n]+", $text); // 行数组
$nL = count($s); // 行数
$W = ($W==0)?abs($_bx[2]-$_bx[0]):$W; // 如果宽度未由程序员初始化,则会检测并分配合适的宽度。
$H = ($H==0)?abs($_bx[5]-$_bx[3])+($nL>1?($nL*$Leading):0):$H; // 如果高度未由程序员初始化,则会检测并分配合适的高度。

$im = @imagecreate($W, $H)
or die("无法初始化新的 GD 图像流");

$background_color = imagecolorallocate($im, $bgcolor[0], $bgcolor[1], $bgcolor[2]); // RGB 背景颜色。
$text_color = imagecolorallocate($im, $color[0], $color[1], $color[2]); // RGB 文本颜色。

if ($Justify == 0){ // 左对齐
imagettftext($im, $fsize, $angle, $X, $fsize, $text_color, $font, $text);
} else {
// 创建包含所有国际字符(大小写)的字母数字字符串
$alpha = range("a", "z");
$alpha = $alpha.strtoupper($alpha).range(0, 9);
// 使用该字符串确定行高
$_b = imageTTFBbox($fsize,0,$font,$alpha);
$_H = abs($_b[5]-$_b[3]);
$__H=0;
for ($i=0; $i<$nL; $i++) {
$_b = imageTTFBbox($fsize,0,$font,$s[$i]);
$_W = abs($_b[2]-$_b[0]);
// 定义 X 坐标。
if ($Justify == 1) $_X = $W-$_W; // 右对齐
else $_X = abs($W/2)-abs($_W/2); // 居中对齐

// 定义 Y 坐标。
$__H += $_H;
imagettftext($im, $fsize, $angle, $_X, $__H, $text_color, $font, $s[$i]);
$__H += $Leading;
}
}

return $im;
}
-3
simbiat at bk dot ru
9 年前
另一种使用 wordwrap 和学习 wordwrap 结果中的行数来换行和居中的方法



<?php

$text
="privet privet privet privet privet privet2 privet2 privet2 privet2 privet2 privet3";
$text=wordwrap($text, 35, "\n", TRUE);

//设置图片头信息以便正确显示图片
header("Content-Type: image/png");
//尝试创建图片
$im = @imagecreate(460, 215)
or die(
"无法初始化新的GD图像流");
//设置图片背景颜色
$background_color = imagecolorallocate($im, 0x00, 0x00, 0x00);
//设置文字颜色
$text_color = imagecolorallocate($im, 0xFF, 0xFF, 0xFF);
//将字符串添加到图片

$font = "verdana.ttf";
$font_size = 20;
$angle = 0;

$splittext = explode ( "\n" , $text );
$lines = count($splittext);

foreach (
$splittext as $text) {
$text_box = imagettfbbox($font_size,$angle,$font,$text);
$text_width = abs(max($text_box[2], $text_box[4]));
$text_height = abs(max($text_box[5], $text_box[7]));
$x = (imagesx($im) - $text_width)/2;
$y = ((imagesy($im) + $text_height)/2)-($lines-2)*$text_height;
$lines=$lines-1;
imagettftext($im, $font_size, $angle, $x, $y, $text_color, $font, $text);
}

imagepng($im);
imagedestroy($im);
?>
-3
Borgso
17 年前
将“webmaster at higher-designs dot com”代码右对齐
<?php
$color
= imagecolorallocate($im, 0, 0, 0);
$font = 'visitor.ttf';
$fontsize = "12";
$fontangle = "0";
$imagewidth = imagesx($im);
$imageheight = imagesy($im);

$text = "我的右对齐文本";

$box = @imageTTFBbox($fontsize,$fontangle,$font,$text);
$textwidth = abs($box[4] - $box[0]);
$textheight = abs($box[5] - $box[1]);
$xcord = $imagewidth - ($textwidth)-2; // 2 = 与右侧留出一些空隙。
$ycord = ($imageheight/2)+($textheight/2);

ImageTTFText ($im, $fontsize, $fontangle, $xcord, $ycord, $black, $font, $text);
?>
-3
--Colibri--
18年前
如果您已经配置并编译了PHP,并使用了所有必要的命令行选项,但仍然出现错误

致命错误:调用未定义函数 imagettftext()

尝试在构建php apache模块之前执行“make clean”

./configure [...]
make clean
make
make install

这可能会解决您的问题(并希望让您避免浪费数小时尝试不同的编译选项!)
-3
erik[at]phpcastle.com
19 年前
记住!!!

将字体上传到您的网站时,必须将传输模式设置为二进制。我花了一些时间才发现这一点 :P。尝试从我的网站下载字体,结果却损坏了。

在您的脚本中,字体路径使用 realpath("arial.ttf"),以便避免混淆。
-4
jwe
18年前
我发现这一行有点令人困惑

"可能包含十进制数字字符引用(格式为:&#8364;)以访问字体中位置 127 之后的字符。"

我使用的是一种字体,其撇号和引号存储在非标准位置,因此 imagettftext 将它们呈现为空格。这一行似乎暗示了一种解决方案,但花了一段时间才弄清楚。

事实证明,“十进制数字字符引用”是您想要字符的 *Unicode* 位置的十六进制值的十进制转换。有一段时间我一直在尝试 ASCII 位置(我知道在 Windows 中键入所需字符的 ALT+ 代码)。

在 Windows XP 字符映射中,Unicode 位置显示为 U+2018 或 U+201C 等。忽略 U+ 并将该十六进制数转换为十进制,然后在文本字符串中将其与前面的 &# 和结尾的 ; 粘贴在一起,并将其传递给 imagettftext。

--Julian
To Top