Warum imagettfbbox nichts taugt
Wer in PHP mit der GD2-Extension Schriftzüge als Bilder generiert, wird früher oder später mit dem Problem der Bounding Box konfrontiert. Um die Größe des Schriftzugs zu berechnen, stellt PHP die Funktion imagettfbbox bereit.
Größe der Bounding Box
Verlässt man sich auf diese Funktion und benutzt deren Rückgabewerte, um die Bildgröße festzulegen, sieht das in etwa so aus wie hier. Der gerahmte Bereich stellt die Bounding Box dar, wie sie mit imagettfbbox berechnet wurde. Würde man das Bild ohne zusätzlichen Rand dimensionieren, wären viele Buchstaben verstümmelt.
Breite der Bounding Box und Schrifthöhe
Da man die Schriftgröße aber ohnehin festlegen muss, könnte man annehmen, dass man einfach diese verwendet und von der errechneten Bounding Box lediglich die horizontalen Koordinaten benutzt. Dass diese Variante ebenso wenig aufgeht, zeigt die folgende Bildserie. Selbst wenn man die doppelte Schriftgröße als Höhe ansetzt, hätte man immer noch das Problem, dass Unterschneidungen (Kerning) nicht berücksichtigt werden und der erste oder der letzte Buchstabe über den Rand hinausragt. Die gesamte Breite hingegen ist korrekt.
Korrigierte Bounding Box
Wenn man aufwändige Korrekturmaßahmen in Kauf nimmt, kann man jedoch ein absolut brauchbares Resultat erzielen. Man muss nur Ober- und Unterlängen einzeln berechnen und die Unter- und Überschneidung berücksichtigen. Die dazu notwendigen Funktionen und deren Anwendung werden nachfolgend vorgestellt.
Die Funktionen
function getTypographicHeights ($pFont, $pSize) { $bBox = imagettfbbox($pSize, 0, $pFont, "x"); $xLine = $bBox[1] - $bBox[7]; $bBox = imagettfbbox($pSize, 0, $pFont, "p"); $pLine = $xLine - $bBox[1] + $bBox[7]; $bBox = imagettfbbox($pSize, 0, $pFont, "k"); $kLine = $bBox[1] - $bBox[7]; $bBox = imagettfbbox($pSize, 0, $pFont, "H"); $hLine = $bBox[1] - $bBox[7]; $bBox = imagettfbbox($pSize, 0, $pFont, "ÁÂÃÄÅĂČ"); $accLine = $bBox[1] - $bBox[7]; return array($pLine, 0, $xLine, $hLine, $kLine, $accLine); } function getKerningOffset ($pFont, $pSize, $pText) { $bBox = imagettfbbox($pSize, 0, $pFont, " "); $sWidth = $bBox[2] - $bBox[0]; $bBox = imagettfbbox($pSize, 0, $pFont, " " . $pText); $width = $bBox[2] - $bBox[0] - $sWidth; $bBox = imagettfbbox($pSize, 0, $pFont, $pText); $kerning = $bBox[2] - $bBox[0] - $width; return $kerning; }
Die Anwendung
$text = "Äpfel"; $font = "c:/windows/fonts/georgiaz.ttf"; $size = 50; $bBox = imagettfbbox($size, 0, $font, $text); $lines = getTypographicHeights($font, $size); $kerning = getKerningOffset($font, $size, $text); $accentLine = $lines[5]; $pLine = $lines[0]; $img = imagecreatetruecolor($bBox[2] - $bBox[0], $accentLine - $pLine); $backgnd = imagecolorallocate($img, 255, 255, 160); $color = imagecolorallocate($img, 128, 0, 0); imagefill($img, 0, 0, $backgnd); imagettftext($img, $size, 0, $kerning, $accentLine, $color, $font, $text); header("Content-Type: image/png"); imagepng($img);