Tomáš Zato Tomáš Zato - 6 months ago 100
PHP Question

imagettfbbox calculates wrong rectangle when text begins with number

The issue is, that when using

imagettfbbox
to calculate text dimensions, too small rectangle is returned when input text begins with numbers. This is my code:

$fontSize = 150;
$font = "font/courier_new.ttf";
$text = $_GET["text"];

//Determine font dimensions
$bbox = imagettfbbox($fontSize, 0, $font, $text);
$bbox["width"]= abs($bbox[4]-$bbox[0]);
$bbox["height"]= abs($bbox[5]-$bbox[1]);

$im = imagecreatetruecolor($bbox["width"], $bbox["height"]);

echo "<b>Image size:</b>\n";
print_r($bbox);

// This part makes transparent background
imagesavealpha($im, true);
$bg = imagecolorallocatealpha($im, 254, 254, 254,127);
$text_color= imagecolorallocate($im, 0, 0, 0);
imagealphablending($im, false);
imagefilledrectangle($im, 0, 0, imagesx($im), imagesy($im), $bg );
imagealphablending($im, true);


header("X-Img-Size: ".$bbox["width"]."x".$bbox["height"]."");

imagettftext($im, $fontSize, 0, 0, $bbox["height"], $text_color, $font, $text);

// This is output
header("Content-Type: text/html");
ob_start();
imagepng($im);
$image_data = ob_get_contents();
ob_end_clean();
imagedestroy($im);

echo "<img src=\"data:image/png;base64,".base64_encode($image_data)."\" />";


Online test here

These are results I get for different input text:

image description

image description

image description

How can I fix that?

Answer

The problem was caused by misconception. The values of imagettfbbox also define where do you have to start drawing - and often those coordinates are even negative. I always assumed you can start at [0, 0] coordinates.

This function, also mentioned in comments and originating from PHP.net user contributions calculates the start coordinates, as well as the width and height (which was correct in the code in question).

// Source: http://php.net/manual/en/function.imagettfbbox.php#75407
function imagettfbboxextended($size, $angle, $fontfile, $text) {
    /*this function extends imagettfbbox and includes within the returned array
    the actual text width and height as well as the x and y coordinates the
    text should be drawn from to render correctly.  This currently only works
    for an angle of zero and corrects the issue of hanging letters e.g. jpqg*/
    $bbox = imagettfbbox($size, $angle, $fontfile, $text);

    //calculate x baseline
    if($bbox[0] >= -1) {
        $bbox['x'] = abs($bbox[0] + 1) * -1;
    } else {
        //$bbox['x'] = 0;
        $bbox['x'] = abs($bbox[0] + 2);
    }

    //calculate actual text width
    $bbox['width'] = abs($bbox[2] - $bbox[0]);
    if($bbox[0] < -1) {
        $bbox['width'] = abs($bbox[2]) + abs($bbox[0]) - 1;
    }

    //calculate y baseline
    $bbox['y'] = abs($bbox[5] + 1);

    //calculate actual text height
    $bbox['height'] = abs($bbox[7]) - abs($bbox[1]);
    if($bbox[3] > 0) {
        $bbox['height'] = abs($bbox[7] - $bbox[1]) - 1;
    }

    return $bbox;
}

But it is imperative that you use x and y coordinates given by this function when drawing:

imagettftext($im, $fontSize, 0, $bbox["x"], $bbox["y"], $text_color, $font, $text);
Comments