【问题标题】:PHP imageftbbox imagettftext - simple letter spacing/kerning?PHP imageftbbox imagettftext - 简单的字母间距/字距调整?
【发布时间】:2020-12-10 17:53:48
【问题描述】:

有人知道使用 imagettftext 进行字母间距/字距调整的简单方法吗?我的脚本可以按照我现在的需要工作,但我真的可以使用生成的具有 CSS 样式的文本

letter-spacing: -0.01em;

所以它与页面上的标准文本相匹配,但我看不出有任何方法可以轻松做到这一点。我确实找到了与此相关的以下线程,但我试图将答案放入我的代码中,但都没有达到预期的效果。

php imagettftext letter spacing

我目前的代码如下

<?php
include 'deliverytimes.php';

$date = new DateTime();
$now = date("Y-m-d H:i:s");
$h = date("H:i:s"); 

$days = explode(",", $businessDaysToAdd);
if (count($days) > 1) {
      
    $two_weekdays_later_1 = strtotime(date("Y-m-d H:i:s", strtotime($now)) . " +" . $days[0] . " weekdays $h");
    $date_1 = new DateTime("@$two_weekdays_later_1"); 
    $formattedDeliveryDate_1 =  $date_1->format('jS M');
    $formattedDeliveryDate_3 =  $date_1->format('jS \o\f F');
    
    $two_weekdays_later_2 = strtotime(date("Y-m-d H:i:s", strtotime($now)) . " +" . $days[1] . " weekdays $h");
    $date_2 = new DateTime("@$two_weekdays_later_2"); 
    $formattedDeliveryDate_2 =  $date_2->format('jS M.');
    $formattedDeliveryDate_4 =  $date_2->format('jS \o\f F');   

    $formattedDeliveryDate1 = $formattedDeliveryDate_3;
    $formattedDeliveryDate2 = $formattedDeliveryDate_4;

    $formattedDeliveryDate = "If ordered today we estimate delivery to be approximately between " . $formattedDeliveryDate_1 . " and " . $formattedDeliveryDate_2;
} else {
    $h = date("H:i:s");   
    $two_weekdays_later = strtotime(date("Y-m-d H:i:s", strtotime($now)) . " +" . $businessDaysToAdd . " weekdays $h");
    $date = new DateTime("@$two_weekdays_later"); 
    $formattedDeliveryDate = "If ordered today we estimate delivery approximately by " . $date->format('l, jS M.');
}

$defaultOutput = 'main';
$textMobile = isset($_REQUEST['mobile']) ? $_REQUEST['mobile'] : $defaultOutput;

switch($textMobile) {
    case "main":
        $textToUse = $formattedDeliveryDate;
        break;
    case "p1":
        $textToUse = $formattedDeliveryDate1;        
        break;
    case "p2":
        $textToUse = $formattedDeliveryDate2;        
        break;
}

// Path to our font file
$font = './Inter-SemiBold.ttf';
$fontBold = './Inter-Bold.ttf';
$size = 24;
$size2 = 83;
$bbox   = imageftbbox($size2, 0, $fontBold, $textToUse);
$width  = 1020;
$height = 110;
$im    = imagecreatetruecolor($width, $height);
$x = ($width - ($bbox[4] - $bbox [0])) / 2;
imagealphablending($im, false);
imagesavealpha($im, true);
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
$grey = imagecolorallocate($im, 161, 161, 168);
$trans = imagecolorallocatealpha($im, 255, 255, 255, 127);
imagefilledrectangle($im, 0, 0, $width, $height, $trans);

$defaultTextColour = 'white';
$textColour = isset($_REQUEST['colour']) ? $_REQUEST['colour'] : $defaultTextColour;

switch($textColour) {
    case "white":
        $textColourUse = $white;
        break;
    case "black":
        $textColourUse = $black;        
        break;
    case "grey":
        $textColourUse = $grey;        
        break;
}

// Write it
imagettftext($im, $size2, 0, $x, -$bbox[7], $textColourUse, $fontBold, $textToUse);

// Output to browser
header('Content-Type: image/png');
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
imagepng($im);
imagedestroy($im);

【问题讨论】:

    标签: php imagettftext


    【解决方案1】:

    我明白你的意思。没有任何字距调整,您的输出如下所示:

    当我采用 the accepted answer 时,这对于您的目的来说已经足够好了,对于设置为 -0.5 的间距,它看起来像这样:

    注意fe 之间的空间仍然很大,而在其他地方字母甚至可以重叠。

    是什么原因造成的,有什么办法可以预防吗?

    让我们从绘制由imagettfbbox() 围绕字母返回的框开始:

    显然,该例程并没有按计划进行。您会期望水平重叠(如果存在)对于所有框都是相同的。

    解释这个有点困难,它与font kerning有关。 Kerning 可以在字母前后减去空格:

    重要的是要意识到,您赋予imagettftext()$x 位置会考虑此字距调整。所以即使你说应该在(x,y) 绘制一个字母,但它不是imagettfbbox() 返回的坐标之一。该函数返回绘制字母的边界框,如红色矩形所示。

    现在让我们看看,有了这些知识,我们是否可以绘制均匀间隔的字母:

    显然这是可能的。我使用的代码是这样的:

    function imagettftextSpacing($image, $size, $x, $y, $color, $font, $text, $spacing = 0)
    {
        foreach (mb_str_split($text) as $char)
        {
            $frontBox = imagettfbbox($size, 0, $font, $char);
            $charBox  = imagettftext($image, $size, 0, $x - $frontBox[0], $y, $color, $font, $char);
            $charW    = $charBox[2] - $charBox[0];
            $x       += $charW + $spacing;
        }
    }
    

    这会获取字符的水平偏移并在绘制字符时进行校正。

    虽然这是一种改进,但还不能完全令人满意。有些字母会接触,有些则不会。这是因为我们修正了字符前面的字距,但没有修正后面的字距。我们需要以某种方式找出后面的字距调整是什么,然后对其进行纠正。我把这段代码搞砸了:

    function getBBoxW($bBox)
    {
      return $bBox[2] - $bBox[0];
    }
    
    
    function imagettftextSpacing($image, $size, $x, $y, $color, $font, $text, $spacing = 0)
    {
        $testStr = 'test';
        $testW   = getBBoxW(imagettfbbox($size, 0, $font, $testStr));
        foreach (mb_str_split($text) as $char)
        {
            $fullBox = imagettfbbox($size, 0, $font, $char . $testStr);
            imagettftext($image, $size, 0, $x - $fullBox[0], $y, $color, $font, $char);
            $x      += $spacing + getBBoxW($fullBox) - $testW;
        }
    }
    

    我创建了一个单独的函数来获取边界框的宽度,因为我计算了很多,并且函数名称更清楚地说明了正在做什么。我使用一个测试字符串,并检查它的宽度,以便稍后计算它前面的字符的作用。我终于弥补了这一点。结果是这样的:

    这显然更好,你很难发现它比这个答案开头的例子更近,但确实如此。

    我不得不承认这是相当复杂的,我不知道你为什么要这样做。使用基本的 HTML 和 CSS 可以更好地完成相同的工作。

    【讨论】:

    • 嗨,Kiko,再次感谢您提供了令人惊叹且内容丰富的答案 - 我现在必须尝试将其放入我的代码中。你说得对,它很复杂,原因是因为我将它用于 eBay 列表,我们没有 javascript,没有 jquery,只有纯 HTML 和 CSS - 所以要创建动态信息,唯一的黑客就是使用 PHP 吐出一个图像文件。绝对不知道 - 但在非常严格的限制下工作。
    • 实际上 KIKO 我迷路了——我只是在破解一个朋友为我做的一些代码——我如何将你完成的代码放入我发布的代码中以创建所需的输出?
    • @DannyShepherd 只需用这个新的imagettftextSpacing() 替换imagettftext() 并注意两个参数已经改变,角度消失了,我添加了间距。将文本居中是另一回事,我没有这样做。您必须计算字符的数量,并与您指定的间距一起,您可以重新定位它。
    • 我已经尝试了以下方法,并且我已经更新了脚本中使用的 $ - 但我在图像框中没有得到任何结果,是因为它正在消失还是什么还有错吗? example
    • @DannyShepherd 你没有更改参数,角度的0 仍然存在,我删除了它,因为我不使用它。
    猜你喜欢
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多