問題描述
我正在尋找一種使用 PHP 將文本包裝到特定寬度的框中的方法.我收到了動態文本字符串和可變字體大小.
我找到了一個很好的方法,可以從這個線程中按照我想要的方式剪切文本:PHP 中長字的智能自動換行?>
使用此代碼塊:
function smart_wordwrap($string, $width = 10, $break = "
") {//在行長度上拆分問題詞$pattern = sprintf('/([^ ]{%d,})/', $width);$輸出 = '';$words = preg_split($pattern, $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);foreach ($words as $word) {if (false !== strpos($word, ' ')) {//正常行為,重建字符串$output .= $word;} 別的 {//計算當前行有多少個字符$wrapped = expand($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);}}//包裝最終輸出return wordwrap($output, $width, $break);
}
這很好用,但我需要找到一種方法將設置的像素尺寸(約束框)和字體大小輸入到上面.上面的函數使用了字符數 - 如果字體大小很明顯,字符數需要更大,反之亦然.
如果我有以下變量,我可以這樣做嗎?
$boxWidth = 200(px);$text = (動態字符串);$font = '自定義字體.ttf'$fontSize = (動態大小);
我正在考慮對自動換行功能進行另一個循環.或者也許有一種方法可以編輯爆炸",因為我不完全確定該功能是如何工作的.
As @Mark Ba??ker 建議 我已經使用 imagettfbbox()
- 可以在此處 找到帶有輔助函數的完整代碼片段
- 我正在發布相關代碼以供參考
//幫助在圖像上渲染文本的實用函數
//返回渲染文本的預期寬度(以像素為單位)公共靜態函數 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);返回 $bbox[2] - $bbox[0];}//返回一段文本的包裝格式(帶換行符)(打算在圖像上呈現)//使用渲染的文本邊界框的寬度公共靜態函數 wrapTextByPixels(字符串 $text,int $line_max_pixels,整數 $font_size,字符串 $font): 細繩 {$words = expand(' ', $text);//將文本標記為單詞$行 = [];//Array[Array[string]]: 存儲單詞行的數組$crr_line_idx = 0;//(從零開始)當前行的索引,在其中添加單詞$crr_line_pixels = 0;//當前行的寬度(在其中添加單詞)以像素為單位foreach ($words as $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($w??ord);$crr_line_idx++;} 別的 {//否則如果當前行非空,則將超長的單詞放入換行符$crr_line_idx++;$lines[$crr_line_idx] = array($w??ord);$crr_line_idx++;$crr_line_pixels = 0;}} else if ($crr_line_new_pixels > $line_max_pixels) {//否則如果當前行的新寬度(包括當前單詞和空格)//超過最大允許寬度,則強制當前單詞換行$crr_line_idx++;$lines[$crr_line_idx] = array($w??ord);$crr_line_pixels = $crr_word_pixels;} 別的 {//else 如果當前單詞(包括空格)可以放入當前行,則將其放在那里$lines[$crr_line_idx][] = $word;$crr_line_pixels = $crr_line_new_pixels;}}//上面的foreach循環結束后,$lines二維數組Array[Array[string]]//將包含分隔成行的單詞以保留 $line_max_pixels//現在我們只需要將行(字串數組)拼接成一個連續的文本片段$concatenated_string = array_reduce($行,靜態函數(字符串 $wrapped_text,數組 $crr_line):字符串 {返回 $wrapped_text .PHP_EOL .內爆(' ', $crr_line);},'');//上面將行拼接成單段文本的過程會不經意間//在開頭添加一個額外的換行符 '
';所以我們必須刪除它return StringUtils::removeFirstOccurrence($concatenated_string, "
");}
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 = "
") {
// 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 '
' character in the beginning; so we must remove that
return StringUtils::removeFirstOccurrence($concatenated_string, "
");
}
這篇關于具有像素尺寸的 PHP 自動換行的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!