Php 从边界框确定文本坐标的正确方法是什么?

Php 从边界框确定文本坐标的正确方法是什么?,php,text,gd,bounding-box,Php,Text,Gd,Bounding Box,给定调用的结果,要提供什么正确的像素完美点,以使文本不会超出其边界框 我从边界框确定基线的宽度/高度和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($boxXCoor

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

我从边界框确定基线的宽度/高度和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()
文档中看到过几次试图解决这个问题的尝试,但他们都只是建议在这里或那里减去一两个像素,这对我来说似乎是一种攻击。这里发生了什么,为什么我们需要捏造数字来纠正错误?

我认为没有完美的方法可以基于
imagettfbbox()
返回的内容并使用.ttf非等距字体在图像上放置单像素精度的文本。在PHP手册上,许多用户已经发布了实现这一点的方法(无论是否捏造数字);我建议在PHP手册中使用over,它计算精确的边界框。我已经测试过这一个,只有在极端情况下,文本在一个方向上的位置最多为1像素。尽管如此,如果在图像中添加一些填充(即使只有2或3个像素),文本将在100%的时间内位于图像的尺寸范围内。

如果不从此行的每个尺寸中减去一个,会发生什么情况:

imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);
而是这样做:

imagefilledrectangle($image, 0, 0, $boxWidth, $boxHeight, $color);
该项目为战略纸牌游戏“魔法:聚会”渲染纸牌。生成器由PHP提供动力,内置高级文本呈现引擎。我不知道计算背后的逻辑,但对于本应用程序而言,渲染器非常精确。下面是计算适当边界框的函数(
HQ Card Generator 8.x/scripts/classes/font.php
):

私有函数convertingboundingbox($bbox){
//将imagettfbbox的结果转换为可用(正确!)值。
如果($bbox[0]>=-1)
$xOffset=-abs($bbox[0]+1);
其他的
$xOffset=abs($bbox[0]+2);
$width=abs($bbox[2]-$bbox[0]);
如果($bbox[0]<-1)$width=abs($bbox[2])+abs($bbox[0])-1;
$yOffset=abs($bbox[5]+1);
如果($bbox[5]>=-1)$yOffset=-$yOffset;
$height=abs($bbox[7])-abs($bbox[1]);
如果($bbox[3]>0)$height=abs($bbox[7]-$bbox[1])-1;
返回数组(
“宽度”=>$width,
“高度”=>$height,
'xOffset'=>$xOffset,//将xCoord+xOffset与imagettftext一起使用会将文本最左边的像素置于xCoord。
“yOffset”=>$yOffset,//将yCoord+yOffset与imagettftext一起使用会将文本最上面的像素置于yCoord。
'低于基点'=>最大值(0,$bbox[1])
);
}

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


我认为这可能是一个评论?我最初也这么认为,但如果它解决了问题,那么它可以作为一个答案。此外,源代码的格式对于注释来说有点过于严格。我选择了清晰,以便快速理解。
imagefilledrectangle()
在文本后面创建矩形,而不是实际文本本身。我这样做只是为了显示文本边界框的尺寸。从框的宽度/高度中减去1是必要的,因为我们需要绝对的开始/结束像素(例如,对于200x200px框,我们希望绘制一个从0,0到199199199的矩形)。这并不能回答我的问题。在我的问题中,我已经引用了php.net评论中的变通方法,这个答案只是简单地将我引向了相同的变通方法之一。我不接受GD库无法确定正确的边界框的说法,因为很多其他库都可以在没有这种怪癖的情况下做同样的事情。要么是本机解决方案(可能包括我误解了这些函数的工作原理),要么是PHP实现中出现了一些问题。谢谢,但是这个函数与PHP.net注释中的函数基本相同,它做的正是我不想做的--它在这里和那里通过一个像素来伪造数字,以获得正确的结果。我想知道1)为什么它一开始就不正确,可能还有2)如果没有像这样的黑客代码,我如何才能使它正确。我不知道你所说的“imagettfbbox是点而不是像素”是什么意思。如果您的意思是它以点为单位返回坐标,那么这是不正确的(而且毫无意义)。如果你的意思是
$size
参数是以点为单位的,而不是以像素为单位的,那么这与我的问题并不相关(也仅适用于GD2)。这显然是一个非常古老的问题,但我遇到了类似的问题,我想知道你是否解决了这个问题?
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])
    );
}