首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 計算文本渲染尺寸:imagettfbbox 獲取 TrueType 字體寬高實戰

     編輯:PHP 綜合知識

前言

在生成圖片驗證碼、海報、水印、PDF 佈局時,需預先知道文本渲染後的像素寬高,以便居中、換行、裁剪。PHP GD 擴展提供 imagettfbbox() 返回文本邊界框,本文封裝為可複用的 text_width()/text_height() 函數,並解析坐標系含義與常見坑點。

核心函數封裝

<?php
// 配置常量
define('FONT_SIZE', 14);           // 字體大小(pt)
define('FONT_FILE', __DIR__ . '/fonts/arial.ttf'); // TrueType 字體路徑
define('FONT_ANGLE', 0);           // 旋轉角度(度)

/**
 * 獲取文本邊界框(8 個坐標點)
 *
 * @return array [0]x0 [1]y0 [2]x1 [3]y1 [4]x2 [5]y2 [6]x3 [7]y3
 *  順序:左下、右下、右上、左上(逆時針)
 */
function getTextBBox(string $text): array
{
    $bbox = @imagettfbbox(FONT_SIZE, FONT_ANGLE, FONT_FILE, $text);
    if ($bbox === false) {
        throw new RuntimeException("imagettfbbox 失敗:字體文件不存在或文本包含無效字符");
    }
    return $bbox;
}

/**
 * 計算文本寬度(像素)
 */
function textWidth(string $text): int
{
    $bbox = getTextBBox($text);
    // x 座標:右上(4) - 左上(6) 或 右下(2) - 左下(0)
    return (int)ceil($bbox[4] - $bbox[6]);
}

/**
 * 計算文本高度(像素)
 */
function textHeight(string $text): int
{
    $bbox = getTextBBox($text);
    // y 座標:左下(1) - 左上(7) 注意 GD Y 軸向下
    return (int)ceil($bbox[1] - $bbox[7]);
}

/**
 * 一次性獲取寬高
 */
function textSize(string $text): array
{
    $bbox = getTextBBox($text);
    return [
        'width'  => (int)ceil($bbox[4] - $bbox[6]),
        'height' => (int)ceil($bbox[1] - $bbox[7]),
    ];
}

// ========== 使用示例 ==========
$text = 'Hello PHP GD!';
$size = textSize($text);
echo "文本:$text\n";
echo "寬度:{$size['width']}px\n";
echo "高度:{$size['height']}px\n";

// 實際繪製驗證
$im = imagecreatetruecolor($size['width'] + 20, $size['height'] + 20);
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
imagefilledrectangle($im, 0, 0, imagesx($im), imagesy($im), $white);
// imagettftext 以 baseline 左下角為基準
imagettftext($im, FONT_SIZE, FONT_ANGLE, 10, 10 + $size['height'], $black, FONT_FILE, $text);
imagepng($im, __DIR__ . '/text_preview.png');
imagedestroy($im);
echo "預覽圖已生成:text_preview.png\n";
?>

imagettfbbox 返回值坐標詳解

函數返回 8 個浮點數,對應文本邊界框 4 個角的 (x, y) 座標,順序為逆時針:

索引含義說明
0左下角 Xbaseline 起始點
1左下角 Ybaseline Y,GD 座標系 Y 向下
2右下角 X
3右下角 Y
4右上角 X最右邊界
5右上角 Y
6左上角 X最左邊界(通常為負值,含左側間距)
7左上角 Y最頂邊界

寬度 = max(x) - min(x) = $bbox[4] - $bbox[6]
高度 = max(y) - min(y) = $bbox[1] - $bbox[7](因 Y 向下,左下 Y 最大,左上 Y 最小)

常見坑點與避雷

  1. 字體文件路徑:必須是絕對路徑或相對當前腳本工作目錄的路徑,__DIR__ . '/fonts/...' 最穩妥。
  2. 字體授權:商業項目請使用開源字體(如 Noto Sans、Source Han Sans、DejaVu)或購買授權。
  3. 中文字體:需完整的中文字體文件(如 SimHei.ttf、NotoSansSC-Regular.otf),否則會出現方塊/亂碼。
  4. 旋轉角度:非 0 度時寬高計算需用幾何變換,本文函數僅適用 0 度(水平文本)。
  5. Baseline 對齊:imagettftext() 的 y 座標是 baseline,繪製時需加上 textHeight() 才能從頂部開始。
  6. 緩存:相同字體/大小/文本重複計算可緩存結果,避免重複調用 GD。

進階:多行文本自動換行佈局

<?php
/**
 * 多行文本自動換行繪製
 *
 * @param resource $im 圖片資源
 * @param string   $text 文本
 * @param int      $x 起始 X
 * @param int      $y 起始 Y (baseline)
 * @param int      $maxWidth 最大寬度
 * @param int      $lineHeight 行高倍數 (建議 1.4-1.6)
 * @return int 實際佔用高度
 */
function drawTextWrapped($im, string $text, int $x, int $y, int $maxWidth, float $lineHeight = 1.5): int
{
    $words = preg_split('/\s+/u', $text, -1, PREG_SPLIT_NO_EMPTY);
    $lines = [];
    $currentLine = '';

    foreach ($words as $word) {
        $testLine = $currentLine ? "$currentLine $word" : $word;
        $w = textWidth($testLine);
        if ($w <= $maxWidth) {
            $currentLine = $testLine;
        } else {
            $lines[] = $currentLine;
            $currentLine = $word;
        }
    }
    if ($currentLine) $lines[] = $currentLine;

    $singleH = textHeight('測');
    $lineSpacing = (int)($singleH * $lineHeight);
    $totalH = 0;

    foreach ($lines as $line) {
        imagettftext($im, FONT_SIZE, 0, $x, $y + $totalH, $black, FONT_FILE, $line);
        $totalH += $lineSpacing;
    }
    return $totalH;
}
?>

總結

imagettfbbox() 是 GD 文本渲染的基石,掌握其返回坐標含義並封裝為 textWidth()/textHeight(),即可輕鬆實現文本居中、自動換行、圖文混排等高級佈局。記得處理字體路徑、授權、中文支持與 Baseline 對齊,即可在圖片生成、驗證碼、海報合成等場景遊刃有餘。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved