开发者

fpdf multicell issue

ho开发者_运维技巧w we display fpdf multicell in equal heights having different amount of content


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.


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


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!


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().


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


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!


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜