9

给定调用的结果,imagettfbbox()要提供什么正确的、像素完美的点以imagettftext()使文本不会超出其边界框?

我正在从边界框确定基线的宽度/高度和 x/y,如下所示:

$box = imagettfbbox($size, $angle, $font, $text);
$boxXCoords = array($box[0], $box[2], $box[4], $box[6]);
$boxYCoords = array($box[1], $box[3], $box[5], $box[7]);
$boxWidth = max($boxXCoords) - min($boxXCoords);
$boxHeight = max($boxYCoords) - min($boxYCoords);
$boxBaseX = abs(min($boxXCoords));
$boxBaseY = abs(min($boxYCoords));

然后我在边界框尺寸的图像上绘制一个填充矩形:

imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);

之后,我绘制文本:

imagettftext($image, $size, $angle, $boxBaseX, $boxBaseY, $color, $font, $text);

但是,这会导致文本超出矩形一两个像素。我已经在 PHP 的文档中看到过多次尝试解决此问题imagettfbbox(),但他们都只是建议在这里和那里减去一两个像素,这对我来说似乎是一种 hack。这里发生了什么,为什么我们需要捏造数字才能让事情变得正确?

4

4 回答 4

7

我相信没有完美的方法可以根据imagettfbbox()返回的内容以及使用 .ttf 非等宽字体在图像上放置具有单像素精度的文本。在 PHP 手册中,许多用户已经发布了实现此目的的方法(无论是否捏造数字);我建议在 PHP 手册中使用jodybrabec 的简单函数,它可以计算精确的边界框。我已经对此进行了测试,只有在极端情况下,文本在一个方向上最多相差 1 个像素。尽管如此,如果您向图像添加一些填充(即使它只是 2 或 3 个像素),您的文本将 100% 的时间在图像的尺寸范围内。

于 2012-07-29T14:42:24.213 回答
0

SlightlyMagic HQ Card Generator项目为策略纸牌游戏 Magic: the Gathering 渲染纸牌。生成器由内置高级文本渲染引擎的 PHP 提供支持。我不知道计算背后的逻辑,但对于此应用程序而言,渲染器非常准确。这是计算正确边界框 ( HQ Card Generator 8.x/scripts/classes/font.php) 的函数:

private function convertBoundingBox ($bbox) {
    // Transform the results of imagettfbbox into usable (and correct!) values.
    if ($bbox[0] >= -1)
        $xOffset = -abs($bbox[0] + 1);
    else
        $xOffset = abs($bbox[0] + 2);
    $width = abs($bbox[2] - $bbox[0]);
    if ($bbox[0] < -1) $width = abs($bbox[2]) + abs($bbox[0]) - 1;
    $yOffset = abs($bbox[5] + 1);
    if ($bbox[5] >= -1) $yOffset = -$yOffset;
    $height = abs($bbox[7]) - abs($bbox[1]);
    if ($bbox[3] > 0) $height = abs($bbox[7] - $bbox[1]) - 1;
    return array(
        'width' => $width,
        'height' => $height,
        'xOffset' => $xOffset, // Using xCoord + xOffset with imagettftext puts the left most pixel of the text at xCoord.
        'yOffset' => $yOffset, // Using yCoord + yOffset with imagettftext puts the top most pixel of the text at yCoord.
        'belowBasepoint' => max(0, $bbox[1])
    );
}
于 2012-08-16T12:52:52.623 回答
0

当您不从该行中的每个维度中减去一个时会发生什么:

imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);

而是这样做:

imagefilledrectangle($image, 0, 0, $boxWidth, $boxHeight, $color);
于 2012-08-15T16:56:28.973 回答
-1

我知道这有点晚了,但 imagettfbbox 的单位是点而不是像素。

imagettftext 中的像素字体大小而不是磅值

于 2013-01-19T17:17:13.693 回答