如何使用 PHP 和 GD 来解释字体花饰

How to account for font swash with PHP and GD

我有以下代码可以在图像上打印文本。我还在文本周围添加了一个调试框。但是,我注意到左侧的文本位于 PHP 给我 imagettfbbox.

的框之外

这看起来像是字体斜体的问题。反正有没有解释这个?我能算出斜线开始和 imagettfbbox 给我的实际位置之间的距离吗?

我认为这不是字体的问题,因为我尝试使用一些手写体样式的字体,结果相似。

<?php

$font       = 'scriptin.ttf';
$text       = 'Ipsum';
$size       = 30;
$image      = imagecreatetruecolor(200, 200);
$fontColour = imagecolorallocate($image, hexdec('11'), hexdec('11'), hexdec('11'));
$bgColour   = imagecolorallocate($image, hexdec('CC'), hexdec('CC'), hexdec('CC'));

imagefilledrectangle($image, 0, 0, 200, 200, $bgColour);

$dimensions = imagettfbbox($size, 0, $font, $text);
imagefilledrectangle(
    $image,
    $dimensions[0] + 40,
    $dimensions[7] + 50,
    $dimensions[2] + 40,
    $dimensions[3] + 50,
    imagecolorallocate($image, mt_rand(1, 180), mt_rand(1, 180), mt_rand(1, 180))
);

imagettftext(
    $image,
    $size,
    0,
    40,
    50,
    $fontColour,
    $font,
    $text
);

header('Content-Type: image/png');
imagepng($image);

代码和字体可在此处获得:https://github.com/AydinHassan/image-swash-example

如果您将 VHOST 指向存储库,您只需点击 swash.php

编辑: 这似乎已在 PHP 7.0.12 (bug #53504) 中修复,所以下面的代码应该不需要。


基于 comment in the PHP manual 我编写了以下函数来计算和 return GD 认为边界框左侧的位置与找到最左侧像素的位置之间的差异:

function xadjust($size, $angle, $fontfile, $text)
{
    $bbox = imagettfbbox($size, $angle, $fontfile, $text);

    $width = $bbox[4] - $bbox[6]; // upper right x - upper left x;
    $height = $bbox[1] - $bbox[7]; // lower left y - upper left y;

    // create an image with height and width doubled to fit any 'swash'.
    $im = imagecreatetruecolor($width * 2, $height * 2);

    // set background color to opaque black.
    imagefill($im, 0, 0, 0x00000000);

    // draw the text in opaque white.
    imagettftext(
        $im,
        $size,
        0,
        $width / 2,
        $height,
        0x00ffffff,
        $fontfile,
        $text
    );

    // set the min-width to its possible maximum.
    $min_x = $width * 2;

    for ($x = 0; $x < $width * 2; $x++) {
        // each x-pixel (horizontal)
        for ($y = 0; $y < $height * 2; $y++) {
            // each y-pixel (vertical)
            if (imagecolorat($im, $x, $y) > 0) {
                // non-black pixel found!
                $min_x = min($x, $min_x);
            }
        }
    }

    imagedestroy($im);

    // return the difference between where GD thinks the bounding box is and
    // where we found the leftmost non-black pixel.
    return (($width / 2) - $min_x) - abs($bbox[0]);
}

这可以很容易地集成到您的脚本中:

$font       = 'scriptin.ttf';
$text       = 'Ipsum';
$size       = 30;
$image      = imagecreatetruecolor(200, 200);
$fontColour = imagecolorallocate($image, hexdec('11'), hexdec('11'), hexdec('11'));
$bgColour   = imagecolorallocate($image, hexdec('CC'), hexdec('CC'), hexdec('CC'));

imagefilledrectangle($image, 0, 0, 200, 200, $bgColour);

$xadjust = xadjust($size, 0, $font, $text); // 1. get the adjust value.

$dimensions = imagettfbbox($size, 0, $font, $text);
imagefilledrectangle(
    $image,
    $dimensions[0] + 40 - $xadjust, // 2. move the left-side of the box to the left.
    $dimensions[7] + 50,
    $dimensions[2] + 40 - $xadjust, // 3. move the right-side of the box to the left.
    $dimensions[3] + 50,
    imagecolorallocate($image, mt_rand(1, 180), mt_rand(1, 180), mt_rand(1, 180))
);

imagettftext(
    $image,
    $size,
    0,
    40,
    50,
    $fontColour,
    $font,
    $text
);

header('Content-Type: image/png');
imagepng($image);

这给了我以下输出:

我已经 运行 它与一些其他字体和大小,它似乎精确到 1 像素以内。