PHP imageftbbox imagettftext - 简单字母 spacing/kerning?
PHP imageftbbox imagettftext - simple letter spacing/kerning?
有谁知道使用 imagettftext 制作字母 spacing/kerning 的简单方法?我的脚本现在可以正常工作,但我真的可以使用具有 CSS 样式
的生成文本
letter-spacing: -0.01em;
所以它与页面上的标准文本相匹配,但我看不出有什么方法可以轻松做到这一点。我确实找到了与此相关的以下线程,但我已尝试将答案放入我的代码中,并且 none 达到了预期的效果。
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);
我明白你的意思了。在没有任何字距调整的情况下,您的输出如下所示:
当我采用 the accepted answer 时,这对您的目的来说已经足够了,间距设置为 -0.5
:
时看起来像这样
请注意 f
和 e
之间的 space 仍然很大,而在其他地方字母甚至可以重叠。
是什么原因造成的,有什么办法可以预防吗?
让我们从绘制由 imagettfbbox()
围绕字母返回的方框开始:
很明显,例行公事并没有按计划进行。您会期望水平重叠(如果存在)对于所有框都是相同的。
要解释这个有点困难,它与font kerning有关。字距可以在一个字母前后减去space:
重要的是要认识到,您为 imagettftext()
设置的 $x
位置考虑了此字距调整。因此,即使您说应该在 (x,y)
绘制一个字母,它也不是 imagettfbbox()
返回的坐标之一。该函数 returns 绘制字母的边界框,如红色矩形所示。
现在让我们看看,利用这些知识,我们是否可以均匀地绘制 spaced 个字母:
显然这是可能的。我使用的代码是这样的:
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;
}
}
我做了一个单独的函数来获取边界框的宽度,因为我经常计算它,而且函数名更清楚地说明了正在做什么。我使用一个测试字符串,并检查它有多宽,这样我可以稍后计算它前面的字符的作用。我终于弥补了这一点。结果是这样的:
这显然更好,您很难发现这比本答案开头的示例更接近 spaced,但确实如此。
我不得不承认这很复杂,我不知道你为什么要这样做。使用基本的 HTML 和 CSS 可以更好地完成同样的工作。
有谁知道使用 imagettftext 制作字母 spacing/kerning 的简单方法?我的脚本现在可以正常工作,但我真的可以使用具有 CSS 样式
的生成文本letter-spacing: -0.01em;
所以它与页面上的标准文本相匹配,但我看不出有什么方法可以轻松做到这一点。我确实找到了与此相关的以下线程,但我已尝试将答案放入我的代码中,并且 none 达到了预期的效果。
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);
我明白你的意思了。在没有任何字距调整的情况下,您的输出如下所示:
当我采用 the accepted answer 时,这对您的目的来说已经足够了,间距设置为 -0.5
:
请注意 f
和 e
之间的 space 仍然很大,而在其他地方字母甚至可以重叠。
是什么原因造成的,有什么办法可以预防吗?
让我们从绘制由 imagettfbbox()
围绕字母返回的方框开始:
很明显,例行公事并没有按计划进行。您会期望水平重叠(如果存在)对于所有框都是相同的。
要解释这个有点困难,它与font kerning有关。字距可以在一个字母前后减去space:
重要的是要认识到,您为 imagettftext()
设置的 $x
位置考虑了此字距调整。因此,即使您说应该在 (x,y)
绘制一个字母,它也不是 imagettfbbox()
返回的坐标之一。该函数 returns 绘制字母的边界框,如红色矩形所示。
现在让我们看看,利用这些知识,我们是否可以均匀地绘制 spaced 个字母:
显然这是可能的。我使用的代码是这样的:
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;
}
}
我做了一个单独的函数来获取边界框的宽度,因为我经常计算它,而且函数名更清楚地说明了正在做什么。我使用一个测试字符串,并检查它有多宽,这样我可以稍后计算它前面的字符的作用。我终于弥补了这一点。结果是这样的:
这显然更好,您很难发现这比本答案开头的示例更接近 spaced,但确实如此。
我不得不承认这很复杂,我不知道你为什么要这样做。使用基本的 HTML 和 CSS 可以更好地完成同样的工作。