2015-12-04 8 views
6

У меня есть следующий код для печати текста на изображении. Я также добавляю отладочную рамку вокруг текста. Тем не менее, я заметил, что текст слева находится за пределами поля, который PHP дает мне с imagettfbbox.Как учесть шрифт swash с PHP и GD

enter image description here

Это выглядит как вопрос с перекосом шрифта. Стоит ли так объяснять это? Могу ли я определить расстояние между началом перекоса и фактическим положением 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

Если Вы направляете ВХост в хранилище, вы можете просто нажать swash.php

+0

похоже, что вы правильно не поместили коробку: количество пробелов, «пропавших» слева, похоже на объем пространства «слишком много» справа. –

+0

Вот что я подумал, но если да, я не вижу, где я делаю это неправильно. Я использую информацию, которую «imagettfbbox» дает мне. –

+1

http://php.net/manual/en/function.imagettfbbox.php#97211 предполагает, что это известная, если неудобная, ошибка. –

ответ

2

Edit: Это, как представляется, фиксируется в PHP 7.0.12 (ошибка #53504), поэтому код ниже не требуется.


На основе comment in the PHP manual я написал следующую функцию, чтобы вычислить и вернуть разницу между тем, где 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); 

Это дает мне следующий вывод:

script result

Я запустил его с несколькими другими шрифтами и размерами и, похоже, с точностью до 1 пикселя.

+1

Я закончил с чем-то похожим. Кроме того, что я пересчитал назад, что побрило много свободного времени для больших изображений. Я также проверил предварительную проверку, выполнив рендеринг текста во временном изображении и проверив, есть ли в первом столбце пиксели. Я нуждался в этих оптимизациях, так как мы будем массово отображать эти изображения. Благодаря! –

 Смежные вопросы

  • Нет связанных вопросов^_^