Search code examples
phpgdimagettftext

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?


Solution

  • 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. That is not true, drawing coordinates can be negative.

    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);