У меня есть следующий код для печати текста на изображении. Я также добавляю отладочную рамку вокруг текста. Тем не менее, я заметил, что текст слева находится за пределами поля, который PHP дает мне с imagettfbbox
.
Это похоже на проблему с swash шрифта. Стоит ли так объяснять это? Могу ли я определить расстояние между началом перекоса и фактическим положением 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 (ошибка # 53504 ), поэтому код ниже не требуется.
Основываясь на комментарии в руководстве PHP, я написал следующую функцию, чтобы вычислить и вернуть разницу между тем, где 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 пикселя.