Apparently the bounding box returned by imagettftext and imagettfbbox is not the same, and it appears as though imagettftext does a better job at calculating the actual bounding box (maybe because it has to render every character and it then finds out really everywhere it rendered).
So, you can create a dummy image render the text to it and get a better box. Here is an example function:
<?php
function better_imagettfbbox($size, $angle, $font, $text) {
$dummy = imagecreate(1, 1);
$black = imagecolorallocate($dummy, 0, 0, 0);
$bbox = imagettftext($dummy, $size, $angle, 0, 0, $black, $font, $text);
imagedestroy($dummy);
return $bbox;
}
?>
If you use this a lot, it would be better to keep one dummy image instead of continually creating and destroying images.