9

への呼び出しの結果が与えられた場合、テキストが境界ボックスを超えないようimagettfbbox()に に提供する正しいピクセル単位の点は何ですか?imagettftext()

次のように、境界ボックスからベースラインの幅/高さと x/y を決定しています。

$box = imagettfbbox($size, $angle, $font, $text);
$boxXCoords = array($box[0], $box[2], $box[4], $box[6]);
$boxYCoords = array($box[1], $box[3], $box[5], $box[7]);
$boxWidth = max($boxXCoords) - min($boxXCoords);
$boxHeight = max($boxYCoords) - min($boxYCoords);
$boxBaseX = abs(min($boxXCoords));
$boxBaseY = abs(min($boxYCoords));

次に、バウンディング ボックスの寸法のイメージに塗りつぶされた四角形を描画します。

imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);

その後、テキストを描画します。

imagettftext($image, $size, $angle, $boxBaseX, $boxBaseY, $color, $font, $text);

ただし、これにより、テキストが四角形から 1 ~ 2 ピクセルはみ出してしまいます。PHP のドキュメントでこの問題を修正しようとする試みをいくつか見てきましimagettfbbox()たが、それらはすべて、あちこちで 1 つか 2 つのピクセルを差し引くことを提案しているだけで、私にはハックのように思えます。ここで何が起こっているのでしょうか? 正しく処理するために数字をごまかす必要があるのはなぜですか?

4

4 に答える 4

7

戻り値に基づいて、imagettfbbox().ttf 非等幅フォントを使用して、画像に単一ピクセルの精度でテキストを配置する完璧な方法はないと思います。PHP のマニュアルでは、多くのユーザーがこれを達成する方法を投稿しています (数字をごまかしてもしなくても)。正確なバウンディング ボックスを計算するjodybrabec の単純な関数を PHP マニュアルで使用することをお勧めします。私はこれをテストしましたが、極端な場合にのみ、テキストが一方向に最大 1 ピクセルずれています。それにもかかわらず、画像にパディングを追加すると (たとえ 2 ピクセルまたは 3 ピクセルであっても)、テキストは 100% の確率で画像のサイズ内に収まります。

于 2012-07-29T14:42:24.213 に答える
0

SlightlyMagic HQ Card Generatorプロジェクトは、戦略カード ゲーム Magic: the Gathering のカードをレンダリングします。ジェネレーターは、高度なテキスト レンダリング エンジンが組み込まれた PHP を利用しています。計算の背後にあるロジックについてはわかりませんが、レンダラーはこのアプリケーションの目的に対して非常に正確です。適切なバウンディング ボックスを計算する関数は次のHQ Card Generator 8.x/scripts/classes/font.phpとおりです ( )。

private function convertBoundingBox ($bbox) {
    // Transform the results of imagettfbbox into usable (and correct!) values.
    if ($bbox[0] >= -1)
        $xOffset = -abs($bbox[0] + 1);
    else
        $xOffset = abs($bbox[0] + 2);
    $width = abs($bbox[2] - $bbox[0]);
    if ($bbox[0] < -1) $width = abs($bbox[2]) + abs($bbox[0]) - 1;
    $yOffset = abs($bbox[5] + 1);
    if ($bbox[5] >= -1) $yOffset = -$yOffset;
    $height = abs($bbox[7]) - abs($bbox[1]);
    if ($bbox[3] > 0) $height = abs($bbox[7] - $bbox[1]) - 1;
    return array(
        'width' => $width,
        'height' => $height,
        'xOffset' => $xOffset, // Using xCoord + xOffset with imagettftext puts the left most pixel of the text at xCoord.
        'yOffset' => $yOffset, // Using yCoord + yOffset with imagettftext puts the top most pixel of the text at yCoord.
        'belowBasepoint' => max(0, $bbox[1])
    );
}
于 2012-08-16T12:52:52.623 に答える
0

この行の各次元から 1 を引かないとどうなるか:

imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);

代わりにこれを行います:

imagefilledrectangle($image, 0, 0, $boxWidth, $boxHeight, $color);
于 2012-08-15T16:56:28.973 に答える
-1

私はこれが少し遅れていることを知っていますが、imagettfbbox はピクセルではなくポイントです。

ポイント サイズではなく、imagettftext のピクセル フォント サイズ

于 2013-01-19T17:17:13.693 に答える