带有像素尺寸的PHP自动换行 [英] PHP word wrap with pixel dimensions

查看:67
本文介绍了带有像素尺寸的PHP自动换行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种使用PHP将文本包装到特定宽度的盒子中的方法.我输入了动态文本字符串和可变的字体大小.

我找到了一种很好的方法来从该线程中剪切出所需的文本:在PHP中使用长行单词更聪明的自动换行?

使用以下代码块:

  function smart_wordwrap($ string,$ width = 10,$ break ="\ n"){//在行长上分割问题词$ pattern = sprintf('/([[^] {%d,})/',$ width);$ output ='';$ words = preg_split($ pattern,$ string,-1,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);foreach(将$ words作为$ word){如果(false!== strpos($ word,'')){//正常行为,重建字符串$ output.= $ word;} 别的 {//计算出当前行上有多少个字符$ wrapped = explode($ break,wordwrap($ output,$ width,$ break));复制代码$ count = $ width-(strlen(end($ wrapped))%$ width);//填充当前行并添加一个中断$ output.= substr($ word,0,$ count).$ break;//包装问题词中的所有剩余字符$ output.= wordwrap(substr($ word,$ count),$ width,$ break,true);复制代码}}//包装最终输出返回自动换行($ output,$ width,$ break); 

}

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

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

  $ boxWidth = 200(px);$ text =(动态字符串);$ font ='customfont.ttf'$ fontSize =(动态大小); 

我在想自动换行功能的另一个循环.也许有一种方法可以编辑爆炸",因为我不确定该函数的工作原理.

解决方案

@Mark Ba​​ker 建议,我已经使用 imagettfbbox()

  • 具有帮助器功能的完整代码段可在此处
  • 我正在发布相关的代码位以供参考

//实用程序功能可帮助在图像上渲染文本

 //返回以像素为单位的渲染文本的预期宽度公共静态函数getWidthPixels(string $ text,string $ font,int $ font_size):int {//https://www.php.net/manual/zh/function.imageftbbox.php#refsect1-function.imageftbbox-returnvalues$ bbox = imageftbbox($ font_size,0,$ font,"" $ text);返回$ bbox [2]-$ bbox [0];}//返回一段文本的换行格式(带有换行符)(只希望在图像上呈现)//使用呈现的文本边界框的宽度公共静态函数wrapTextByPixels(字符串$ text,int $ line_max_pixels,int $ font_size,字符串$ font): 细绳 {$ words = explode('',$ text);//将文字标记成单词$ lines = [];//Array [Array [string]]:用于存储单词行的数组$ crr_line_idx = 0;//在其中添加单词的当前行的索引(从零开始)$ crr_line_pixels = 0;//当前行的宽度(在其中添加单词),以像素为单位foreach(将$ words作为$ word){//确定当前行的新宽度(以像素为单位)(如果已将当前单词添加到该行)(包括空格)$ crr_line_new_pixels = $ crr_line_pixels + ImageTextRenderUtils :: getWidthPixels(''.$ word,$ font,$ font_size);//确定当前单词的宽度(以像素为单位)$ crr_word_pixels = ImageTextRenderUtils :: getWidthPixels($ word,$ font,$ font_size);如果($ crr_word_pixels> $ line_max_pixels){//如果当前单词本身太长而无法容纳在单行中//那么我们就别无选择:它仍必须只放在一行中如果($ crr_line_pixels == 0){//,但仅当当前行为空时才将其放入当前行$ lines [$ crr_line_idx] = array($ word);$ crr_line_idx ++;} 别的 {//否则,如果当前行非空,则将多余的单词放入换行符$ crr_line_idx ++;$ lines [$ crr_line_idx] = array($ word);$ crr_line_idx ++;$ crr_line_pixels = 0;}}否则,如果($ crr_line_new_pixels> $ line_max_pixels){//否则,如果当前行的新宽度(包括当前单词和空格)//超过最大允许宽度,然后将当前单词强制换行$ crr_line_idx ++;$ lines [$ crr_line_idx] = array($ word);$ crr_line_pixels = $ crr_word_pixels;} 别的 {//否则,如果当前单词(包括空格)适合当前行,则将其放在此处$ lines [$ crr_line_idx] [] = $ word;$ crr_line_pixels = $ crr_line_new_pixels;}}//在上述foreach循环终止后,$ lines 2维数组Array [Array [string]]//将包含分隔成几行的单词以保留$ line_max_pixels//现在,我们只需要将行(单词字符串的数组)缝合到一个连续的文本中即可,$ concatenated_string = array_reduce($行,静态函数(字符串$ wrapped_text,数组$ crr_line):字符串{返回$ wrapped_text.PHP_EOL.implode('',$ crr_line);},'');//以上将行连接成单个文本的过程将不经意间//在开头添加一个额外的换行符'\ n';所以我们必须删除return StringUtils :: removeFirstOccurrence($ concatenated_string,"\ n");} 

I'm looking for a way to wrap text into a box of specific width using PHP. I have dynamic text strings coming in, and variable font sizes.

I found a great way to cut the text up the way I want it from this thread: Smarter word-wrap in PHP for long words?

Using this block of code:

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);

}

This works great, but I need to find a way to feed a set pixel dimension (the constraining box), and font size into the above. The above function is using a character count - and if the font-size is very small obviously the character count needs to be larger and vice versa.

Is there anyway I could do this if I have the following variables?

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

I was thinking another loop to the word wrap function. Or maybe there's a way to edit the "explode" as I'm not entirely sure how that function works.

解决方案

As suggested by @Mark Baker I have implemented this behaviour using imagettfbbox()

  • Complete code-snippet with helper functions can be found here
  • I'm posting the relevant bits of code for reference

// utility functions to help text rendering on image

// 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");
}

这篇关于带有像素尺寸的PHP自动换行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆