fpdf 多单元问题

发布于 2024-08-11 15:43:59 字数 37 浏览 3 评论 0原文

我们如何以相同的高度显示具有不同内容量的 fpdf 多单元格

how we display fpdf multicell in equal heights having different amount of content

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

挽容 2024-08-18 15:43:59

很好的问题。

我通过遍历行中将被分成多单元格的每个数据单元格并确定所有这些单元格的最大高度来解决这个问题。这发生在您创建行中的第一个单元格之前,并且当您实际渲染它时,它会成为行的新高度。

以下是仅针对一个单元格实现此目的的一些步骤,但您需要对每个多单元格执行此操作:

这假设数据的 $row 具有名为 description< 的字符串属性/code>.

  1. 首先,获取单元格内容并设置单元格的列宽。

    $description = $row['description']; // MultiCell(多行)内容。
    
    $列宽度= 50;
    
  2. 获取 description 字符串的宽度:使用 FPDF 中的 GetStringWidth() 函数:

    $total_string_width = $pdf->GetStringWidth($description);
    
  3. 确定该单元格的行数:

    $number_of_lines = $total_string_width / ($column_width - 1);
    
    $number_of_lines = ceil( $number_of_lines ); // 将其四舍五入。
    

    我从 $column_width 中减去 1 作为一种单元格填充。它产生了更好的结果。

  4. 确定生成的多行单元格的高度:

    $line_height = 5; // 无论你的行高是多少。
    
    $height_of_cell = $number_of_lines * $line_height; 
    
    $height_of_cell = ceil( $height_of_cell ); // 将其四舍五入。
    
  5. 对任何其他 MultiCell 单元格重复此方法,设置 $row_height 到最大的 $height_of_cell

  6. 最后,使用 $row_height 作为行的高度来渲染行。

  7. 跳舞。

Great question.

I solved it by going through each cell of data in your row that will be multicelled and determine the largest height of all these cells. This happens before you create your first cell in the row and it becomes the new height of your row when you actually go to render it.

Here's some steps to achieve this for just one cell, but you'll need to do it for every multicell:

This assumes a $row of data with a String attribute called description.

  1. First, get cell content and set the column width for the cell.

    $description = $row['desciption'];           // MultiCell (multi-line) content.
    
    $column_width = 50;
    
  2. Get the width of the description String by using the GetStringWidth() function in FPDF:

    $total_string_width = $pdf->GetStringWidth($description);
    
  3. Determine the number of lines this cell will be:

    $number_of_lines = $total_string_width / ($column_width - 1);
    
    $number_of_lines = ceil( $number_of_lines );  // Round it up.
    

    I subtracted 1 from the $column_width as a kind of cell padding. It produced better results.

  4. Determine the height of the resulting multi-line cell:

    $line_height = 5;                             // Whatever your line height is.
    
    $height_of_cell = $number_of_lines * $line_height; 
    
    $height_of_cell = ceil( $height_of_cell );    // Round it up.
    
  5. Repeat this methodology for any other MultiCell cells, setting the $row_height to the largest $height_of_cell.

  6. Finally, render your row using the $row_height for your row's height.

  7. Dance.

陌上芳菲 2024-08-18 15:43:59

当我必须将高度等于三行时,即使我有一半或一行半行的内容,我也遇到了同样的问题,我通过检查字符串中的元素是否小于一行中可能的字母来解决这个问题它是 60。如果没有字母小于或等于一行,则为两个空行调用 ln(),如果没有单词等于或小于 2 行字母,则调用一个 ln()。
我的代码在这里:

$line_width = 60; // Line width (approx) in mm
if($pdf->GetStringWidth($msg1) < $line_width) 
{
    $pdf->MultiCell(75, 8, $msg1,' ', 'L');
    $pdf->ln(3);
    $pdf->ln(3.1);
}
else{
    $pdf->MultiCell(76, 4, $msg1,' ', 'L');
    $pdf->ln(3.1);
}

I was also getting same issue when i have to put height equal to three lines evenif i have content of half or 1 and half line, i solved this by checking if in a string no of elements are less than no of possible letters in a line it is 60. If no of letters are less or equal to one line then ln() is called for two empty lines and if no of words are equal to or less than 2 line letters then one ln() is called.
My code is here:

$line_width = 60; // Line width (approx) in mm
if($pdf->GetStringWidth($msg1) < $line_width) 
{
    $pdf->MultiCell(75, 8, $msg1,' ', 'L');
    $pdf->ln(3);
    $pdf->ln(3.1);
}
else{
    $pdf->MultiCell(76, 4, $msg1,' ', 'L');
    $pdf->ln(3.1);
}
余生再见 2024-08-18 15:43:59

好的,我已经完成了递归版本。希望这对事业有更多帮助!
考虑这些变量:

$columnLabels:每列的标签,因此您将在每列后面存储数据)
$alturasFilas:存储每行最大高度的数组。

//Calculate max height for each column for each row and store the value in      //////an array
        $height_of_cell = 0;
        $alturasFilas = array();

        foreach ( $data as $dataRow ) {
            for ( $i=0; $i<count($columnLabels); $i++ ) {
                $variable = $dataRow[$i];
                $total_string_width = $pdf->GetStringWidth($variable);
                $number_of_lines = $total_string_width / ($columnSizeWidth[$i] - 1);
                $number_of_lines = ceil( $number_of_lines );  // Redondeo.

                $line_height = 8;  // Altura de fuente.
                $height_of_cellAux = $number_of_lines * $line_height; 
                $height_of_cellAux = ceil( $height_of_cellAux ); 

                if($height_of_cellAux > $height_of_cell){
                    $height_of_cell = $height_of_cellAux;
                    }

            }
            array_push($alturasFilas, $height_of_cell);
            $height_of_cell = 0;
        }
        //--END-- 

享受!

Ok I've done the recursive version. Hope this helps even more to the cause!
Take in account these variables:

$columnLabels: Labels for each column, so you'll store data behind each column)
$alturasFilas: Array in which you store the max height for each row.

//Calculate max height for each column for each row and store the value in      //////an array
        $height_of_cell = 0;
        $alturasFilas = array();

        foreach ( $data as $dataRow ) {
            for ( $i=0; $i<count($columnLabels); $i++ ) {
                $variable = $dataRow[$i];
                $total_string_width = $pdf->GetStringWidth($variable);
                $number_of_lines = $total_string_width / ($columnSizeWidth[$i] - 1);
                $number_of_lines = ceil( $number_of_lines );  // Redondeo.

                $line_height = 8;  // Altura de fuente.
                $height_of_cellAux = $number_of_lines * $line_height; 
                $height_of_cellAux = ceil( $height_of_cellAux ); 

                if($height_of_cellAux > $height_of_cell){
                    $height_of_cell = $height_of_cellAux;
                    }

            }
            array_push($alturasFilas, $height_of_cell);
            $height_of_cell = 0;
        }
        //--END-- 

Enjoy!

2024-08-18 15:43:59

首先,获取 Multicell 的高度不是问题。 (致@Matias、@Josh Pinter)

我修改了@Balram Singh 的答案以使用此代码超过2 行。
我添加了新行 (\n) 来锁定多单元的高度。
就像..

$cell_width = 92; // Multicell width in mm
$max_line_number = 4; // Maximum line number of Multicell as your wish
$string_width = $pdf->GetStringWidth($data);
$line_number = ceil($string_width / $cell_width);
for($i=0; $i<$max_line_number-$line_number; $i++){
    $data.="\n ";
}

当然你必须在使用GetStringWidth()之前分配SetFont()。

First, it's not the question to get height of Multicell. (to @Matias, @Josh Pinter)

I modified answer of @Balram Singh to use this code for more than 2 lines.
and I added new lines (\n) to lock up height of Multicell.
like..

$cell_width = 92; // Multicell width in mm
$max_line_number = 4; // Maximum line number of Multicell as your wish
$string_width = $pdf->GetStringWidth($data);
$line_number = ceil($string_width / $cell_width);
for($i=0; $i<$max_line_number-$line_number; $i++){
    $data.="\n ";
}

Of course you have to assign SetFont() before use GetStringWidth().

蓝天白云 2024-08-18 15:43:59

我的方法非常简单。您已经需要重写 fpdf 类中的 header() 和 footer() 。
所以我只是添加了一个函数MultiCellLines($w, $h, $txt, $border=0, $align='J', $fill=false)
这是原始 MultiCell 的一个非常简单的副本。但它不会输出任何内容,只返回行数。

将行与行高相乘,就安全了;)
我的代码的下载地址是此处

只需将其重命名为“.php”或您喜欢的任何名称即可。玩得开心。它绝对有效。

苹果

My approach was pretty simple. You already need to override the header() and footer() in the fpdf class.
So i just added a function MultiCellLines($w, $h, $txt, $border=0, $align='J', $fill=false).
That's a very simple copy of the original MultiCell. But it won't output anything, just return the number of lines.

Multiply the lines with your line-height and you're safe ;)
Download for my code is here.

Just rename it back to ".php" or whatever you like. Have fun. It works definitely.

Mac

尐籹人 2024-08-18 15:43:59

我个人的解决方案是根据预设框减小字体大小和行间距:

// set box size and default font size
$textWidth  = 100;
$textHeight = 100;
$fontsize   = 12;

// if you get text from html div (using jquery and ajax) you must replace every <br> in a new line
$desc    = utf8_decode(str_replace('<br>',chr(10),strip_tags($_POST['textarea'],'<br>')));

// count newline set in $desc variable
$countnl = substr_count($desc, "\n");

// Create a loop to reduce the font according to the contents
while($pdf->GetStringWidth($desc) > ($textWidth * (($textHeight-$fontsize*0.5*$countnl) / ($fontsize*0.5)))){
  $fontsize--;
  $pdf->SetFont('Arial','', $fontsize);
}

// print multicell and set line spacing
$pdf->MultiCell($textWidth, ($fontsize*0.5), "$desc", 0, 'L');

仅此而已!

My personal solution to reduce the font size and line spacing according to a preset box:

// set box size and default font size
$textWidth  = 100;
$textHeight = 100;
$fontsize   = 12;

// if you get text from html div (using jquery and ajax) you must replace every <br> in a new line
$desc    = utf8_decode(str_replace('<br>',chr(10),strip_tags($_POST['textarea'],'<br>')));

// count newline set in $desc variable
$countnl = substr_count($desc, "\n");

// Create a loop to reduce the font according to the contents
while($pdf->GetStringWidth($desc) > ($textWidth * (($textHeight-$fontsize*0.5*$countnl) / ($fontsize*0.5)))){
  $fontsize--;
  $pdf->SetFont('Arial','', $fontsize);
}

// print multicell and set line spacing
$pdf->MultiCell($textWidth, ($fontsize*0.5), "$desc", 0, 'L');

That's all!

不必在意 2024-08-18 15:43:59

更好的解决方案是使用您自己的自动换行功能,因为 FPDF 不会剪切单词,因此您不必依赖 MultiCell 换行符。

我编写了一个方法,如果 FPDF 的 getStringWidth 大于列宽,则检查文本的每个子字符串,并相应地进行分割。
如果您更关心美观的 PDF 布局而不是性能,那么这非常有用。

public function wordWrapMultiCell($text, $cellWidth = 80) {
    $explode = explode("\n", $text);

    array_walk($explode, 'trim');

    $lines = [];
    foreach($explode as $split) {
        $sub = $split;
        $char = 1;

        while($char <= strlen($sub)) {
            $substr = substr($sub, 0, $char);

            if($this->pdf->getStringWidth($substr) >= $cellWidth - 1) { // -1 for better getStringWidth calculating
                $pos = strrpos($substr, " ");

                $lines[] = substr($sub, 0, ($pos !== FALSE ? $pos : $char)).($pos === FALSE ? '-' : '');

                if($pos !== FALSE) { //if $pos returns FALSE, substr has no whitespace, so split word on current position
                    $char = $pos + 1;
                    $len = $char;
                }

                $sub = ltrim(substr($sub, $char));
                $char = 0;
            }

            $char++;
        }

        if(!empty($sub)) {
            $lines[] = $sub;
        }
    }

    return $lines;
}

这将返回一个文本行数组,您可以使用 implode/join 来合并它:

join("\r\n", $lines);

首先它的用途是获取行高:

$lineHeight = count($lines) * $multiCellLineHeight;

这仅适用于带有空格字符的字符串,没有像制表符那样的白色间距。然后你可以用 regexp 函数替换 strpos 。

A better solution would be to use your own word wrap function, as FPDF will not cut words, so you do not have to rely on the MultiCell line break.

I have wrote a method that checks for every substring of the text if the getStringWidth of FPDF is bigger than the column width, and splits accordingly.
This is great if you care more about a good looking PDF layout, than performance.

public function wordWrapMultiCell($text, $cellWidth = 80) {
    $explode = explode("\n", $text);

    array_walk($explode, 'trim');

    $lines = [];
    foreach($explode as $split) {
        $sub = $split;
        $char = 1;

        while($char <= strlen($sub)) {
            $substr = substr($sub, 0, $char);

            if($this->pdf->getStringWidth($substr) >= $cellWidth - 1) { // -1 for better getStringWidth calculating
                $pos = strrpos($substr, " ");

                $lines[] = substr($sub, 0, ($pos !== FALSE ? $pos : $char)).($pos === FALSE ? '-' : '');

                if($pos !== FALSE) { //if $pos returns FALSE, substr has no whitespace, so split word on current position
                    $char = $pos + 1;
                    $len = $char;
                }

                $sub = ltrim(substr($sub, $char));
                $char = 0;
            }

            $char++;
        }

        if(!empty($sub)) {
            $lines[] = $sub;
        }
    }

    return $lines;
}

This returns an array of text lines, which you could merge by using implode/join:

join("\r\n", $lines);

And what it was used for in the first place, get the line height:

$lineHeight = count($lines) * $multiCellLineHeight;

This only works for strings with a space character, no white spacing like tabs. You could replace strpos with a regexp function then.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文