【问题标题】:PHP word wrap with pixel dimensions具有像素尺寸的 PHP 自动换行
【发布时间】:2013-08-30 20:13:29
【问题描述】:

我正在寻找一种使用 PHP 将文本包装到特定宽度框中的方法。我有动态文本字符串和可变字体大小。

我找到了一个很好的方法来按照我想要的方式从这个线程中剪切文本: Smarter word-wrap in PHP for long words?

使用这段代码:

function smart_wordwrap($string, $width = 10, $break = "\n") {
// split on problem words over the line length
$pattern = sprintf('/([^ ]{%d,})/', $width);
$output = '';
$words = preg_split($pattern, $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

foreach ($words as $word) {
    if (false !== strpos($word, ' ')) {
        // normal behaviour, rebuild the string
        $output .= $word;
    } else {
        // work out how many characters would be on the current line
        $wrapped = explode($break, wordwrap($output, $width, $break));
        $count = $width - (strlen(end($wrapped)) % $width);

        // fill the current line and add a break
        $output .= substr($word, 0, $count) . $break;

        // wrap any remaining characters from the problem word
        $output .= wordwrap(substr($word, $count), $width, $break, true);
    }
}

// wrap the final output
return wordwrap($output, $width, $break);

}

这很好用,但我需要找到一种方法将设置的像素尺寸(约束框)和字体大小输入到上面。上面的函数使用了一个字符数——如果字体大小非常小,显然字符数需要更大,反之亦然。

如果我有以下变量,我是否可以这样做?

$boxWidth = 200(px);
$text = (dynamic string);
$font = 'customfont.ttf'
$fontSize = (dynamic size);

我在想换行功能的另一个循环。或者也许有一种方法可以编辑“爆炸”,因为我不完全确定该功能是如何工作的。

【问题讨论】:

  • 是的,这看起来很有希望,但我是否只对每个角色运行 imagettfbox ?然后我如何根据它对字符串进行切片?
  • 您在要计算大小的每一“行”文本上运行它
  • 将字符串包装到给定的像素数:php.net/manual/en/function.wordwrap.php#116467

标签: php text fonts


【解决方案1】:

作为@Mark Bakersuggested,我已经使用imagettfbbox() 实现了这种行为

  • 可以在here找到带有辅助函数的完整code-sn-p
  • 我正在发布相关代码以供参考

// 帮助在图像上呈现文本的实用函数

// Returns expected width of rendered text in pixels
public static function getWidthPixels(string $text, string $font, int $font_size): int {
    // https://www.php.net/manual/en/function.imageftbbox.php#refsect1-function.imageftbbox-returnvalues
    $bbox = imageftbbox($font_size, 0, $font, " " . $text);
    return $bbox[2] - $bbox[0];
}

// Returns wrapped format (with newlines) of a piece of text (meant to be rendered on an image)
// using the width of rendered bounding box of text
public static function wrapTextByPixels(
    string $text,
    int $line_max_pixels,
    int $font_size,
    string $font
): string {
    $words = explode(' ', $text);   // tokenize the text into words
    $lines = [];                             // Array[Array[string]]: array to store lines of words
    $crr_line_idx = 0;                       // (zero-based) index of current lines in which words are being added
    $crr_line_pixels = 0;                    // width of current line (in which words are being added) in pixels

    foreach ($words as $word) {
        // determine the new width of current line (in pixels) if the current word is added to it (including space)
        $crr_line_new_pixels = $crr_line_pixels + ImageTextRenderUtils::getWidthPixels(' ' . $word, $font, $font_size);
        // determine the width of current word in pixels
        $crr_word_pixels = ImageTextRenderUtils::getWidthPixels($word, $font, $font_size);


        if ($crr_word_pixels > $line_max_pixels) {
            // if the current word itself is too long to fit in single line
            // then we have no option: it must still be put in oneline only
            if ($crr_line_pixels == 0) {
                // but it is put into current line only if current line is empty
                $lines[$crr_line_idx] = array($word);
                $crr_line_idx++;
            } else {
                // otherwise if current line is non-empty, then the extra long word is put into a newline
                $crr_line_idx++;
                $lines[$crr_line_idx] = array($word);
                $crr_line_idx++;
                $crr_line_pixels = 0;
            }
        } else if ($crr_line_new_pixels > $line_max_pixels) {
            // otherwise if new width of current line (including current word and space)
            // exceeds the maximum permissible width, then force the current word into newline
            $crr_line_idx++;
            $lines[$crr_line_idx] = array($word);
            $crr_line_pixels = $crr_word_pixels;
        } else {
            // else if the current word (including space) can fit in the current line, then put it there
            $lines[$crr_line_idx][] = $word;
            $crr_line_pixels = $crr_line_new_pixels;
        }
    }

    // after the above foreach loop terminates, the $lines 2-d array Array[Array[string]]
    // would contain words segregated into lines to preserve the $line_max_pixels

    // now we just need to stitch together lines (array of word strings) into a single continuous piece of text with
    $concatenated_string = array_reduce(
        $lines,
        static function (string $wrapped_text, array $crr_line): string {
            return $wrapped_text . PHP_EOL . implode(' ', $crr_line);
        },
        ''
    );

    // the above process of concatenating lines into single piece of text will inadvertently
    // add an extra newline '\n' character in the beginning; so we must remove that
    return StringUtils::removeFirstOccurrence($concatenated_string, "\n");
}

【讨论】:

    猜你喜欢
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    • 1970-01-01
    • 2014-07-18
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    相关资源
    最近更新 更多