PHP imagettftext 基线解决方案

9
我正在使用PHP编写文本到图像的打印功能。然而,函数imagettftext()使用基线,而我需要文本垂直居中。
因此,我需要一种方法来打印文本,其中y不是从顶部到基线的距离,而是从顶部到边界框顶部的距离,或者我需要一种方法,使用该方法可以确定边界框顶部和基线之间的距离。
显然,我让你感到困惑了。为了使其清晰明了:我知道函数imagettfbbox()。使用该函数,我可以确定结果文本框的高度和宽度。然而,当使用imagettftext()打印时,它的高度对于垂直对齐是完全无用的,因为Y参数不是到框顶部的距离(甚至不是底部,但至少是高度),而是文本内部基线的距离。
编辑:为什么我不接受最新的答案?
请参见我的最新评论下面的答案,并使用这张图片作为参考。

你需要做的是计算文本所需放置的坐标。使用imagettfbbox查看文本的大小,然后从图像的高度中减去它并除以2。 - Kavi Siegel
那就是问题所在!imagettfbbox()给出了边界框,很好,但对于垂直对齐来说完全没用,因为imagettftext不使用边界框顶部或底部的距离,而是使用基线距离,这使得对齐文本变得困难,因为我不知道基线相对于文本框的位置。 - arik
谢谢您的提问,我也在寻找答案,但似乎目前还没有可用的解决方案。我正在生成一些ID标签,并希望名称填满可用空间。对我来说,问题在于下垂的字母(qypjg...)。这些字母的单词以较小的字体大小占据了可用高度(使用imagettfbbox计算),但它们并未填满空间,因为它们悬挂在空间底部以下。虽然这不是世界末日,但确实使事物看起来不一致和偏离中心。 - Dallin
2个回答

11
我不知道答案是否仍然感兴趣。然而,imagettfbbox()函数为您提供的信息不仅仅是边界框的高度和宽度。它被设计成返回imagettftext()需要管理文本所需的信息。
诀窍在于imagettfbbox()返回的坐标与绝对左上角无关,而是针对特定文本的字体基线。这就是为什么框在点坐标中指定,并且这些坐标通常是负数的原因。
简而言之:
$dims = imagettfbbox($fontsize, 0, $font, $text);

$ascent = abs($dims[7]);
$descent = abs($dims[1]);
$width = abs($dims[0])+abs($dims[2]);
$height = $ascent+$descent;

...

// In the example code, for the vertical centering of the text, consider
// the simple following formula

$y = (($imageHeight/2) - ($height/2)) + $ascent;

这对我的项目非常有效。 希望这可以帮到你。 抱歉用英语写的。 Marco。

哇,Marco,这正是我一直在寻找的东西。我曾经尝试通过将字体大小的三分之一加到高度上来解决问题(因为这似乎是基线和底部之间的差异),但你的解决方案更精确。谢谢! - arik

5
我不太确定你在问什么……能给个例子吗?也许imagettfbbox是你需要的东西?
// get bounding box dims
$dims = imagettfbbox($fontsize, 0, $font, $quote);

// do some math to find out the actual width and height
$width = $dims[4] - $dims[6]; // upper-right x minus upper-left x 
$height = $dims[3] - $dims[5]; // lower-right y minus upper-right y

编辑:这里是垂直居中文本的示例。
<?php
$font = 'arial.ttf';
$fontsize = 100;
$imageX = 500;
$imageY = 500;

// text
$text = "FOOBAR";

// create a bounding box for the text
$dims = imagettfbbox($fontsize, 0, $font, $text);

// height of bounding box (your text)
$bbox_height = $dims[3] - $dims[5]; // lower-right y minus upper-right y

// Create image
$image = imagecreatetruecolor($imageX,$imageY);

// background color
$bgcolor = imagecolorallocate($image, 0, 0, 0);

// text color
$fontcolor = imagecolorallocate($image, 255, 255, 255);

// fill in the background with the background color
imagefilledrectangle($image, 0, 0, $imageX, $imageY, $bgcolor);

$x = 0; 
$y = (($imageY/2) - ($bbox_height/2)) + $fontsize;
imagettftext($image, $fontsize, 0, $x, $y , $fontcolor, $font, $text);

// tell the browser that the content is an image
header('Content-type: image/png');
// output image to the browser
imagepng($image);

// delete the image resource 
imagedestroy($image);
?>

2
不,那不是我需要的。我知道imagettfbbox函数,但它计算的是边界框,而imagettftext使用到基线的距离作为Y参数,而不是到框的顶部或底部。 - arik
另外,您需要将字体大小添加到$y中以进行调整。编辑后添加了一个垂直对齐文本的示例。 - CrayonViolent
1
不,我曾经尝试过这个。它是错误的,正如我创建的图形所示:http://img855.imageshack.us/img855/9894/alignment.jpg - arik
好的,我明白你的意思,但我认为没有内置的“解决方法”,因为它是基于字体模板的。基本上,你需要a)期望所有文本都是小写或没有任何“高”字符,b)以某种方式保留每个字体模板中每个字母/字符的“真实像素高度”的映射,与你使用的字体大小一起计算偏移量,而不是字体模板字体大小。但是,老实说,我不明白为什么你要在几个像素上斤斤计较。如果你的文本是下划线,那么它应该完全... - CrayonViolent
你为什么添加了 $font_size?请解释一下。虽然这个解决方案有效,但我不明白为什么我们需要在这里加上 $font_size 来垂直居中文本? - user2867106
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接