I have tried all the answers here and none seems to do a decent job. If you draw the bounding box, this is what happens:

Clearly they are not evenly spaced. It appears that the bounding box, returned by imagettftext() and imagettfbbox(), only tells you what is drawn. This might seem enough, but it isn't, because of font kerning. This means that even when you say a letter should be draw at (x,y), that that will not be one of the coordinates of the bounding box. A correction for kerning is needed.

I botched together this code for horizontal text:
function getBBoxW($bBox)
{
return $bBox[2] - $bBox[0];
}
function imagettftextSpacing($image, $size, $x, $y, $color, $font, $text, $spacing = 0)
{
$testStr = 'test';
$testW = getBBoxW(imagettfbbox($size, 0, $font, $testStr));
foreach (mb_str_split($text) as $char)
{
$fullBox = imagettfbbox($size, 0, $font, $char . $testStr);
imagettftext($image, $size, 0, $x - $fullBox[0], $y, $color, $font, $char);
$x += $spacing + getBBoxW($fullBox) - $testW;
}
}
The results are much better. Note that the $testStr can have any value.
Here's an example of the result, the first line is normal text, the second line has a negative spacing:
