18

I am using the Java port of FPDF. I am encountering the following errors.

  1. When I call multicell two times, every time the text is printed on a new line.
MultiCell(0, 1, "abcd", currentBorders, Alignment.LEFT, false); //prints on one line
MultiCell(0, 1, "efg", currentBorders, Alignment.LEFT, false); //prints on next line

I want there to be no line break after the call to multicell. How can I do it?

  1. If I do the following, then some part of my string gets printed on one line and some on the next.
MultiCell(getStringWidth(myString), 1, myStringcurrentBorders, Alignment.LEFT, false);
  1. If I do the following, then there are many blank lines after the line on which myString is printed. It works correctly if I use one 1 as the second parameter.
MultiCell(0, myFontSize, "123456", currentBorders, Alignment.LEFT, false);

What is the problem?

le_wofl
  • 304
  • 3
  • 15
user156073
  • 1,933
  • 8
  • 31
  • 37

5 Answers5

24

I would get the current Y position before writing the MultiCell and then move the "cursor" back to that Y position after the MultiCell generation. Like this:

$current_y = $pdf->GetY();
$current_x = $pdf->GetX();

$cell_width = 50;
MultiCell($cell_width, 1, "abcd", currentBorders, Alignment.LEFT, false);

$pdf->SetXY($current_x + $cell_width, $current_y);

$current_x = $pdf->GetX();
MultiCell($cell_width, 1, "abcd", currentBorders, Alignment.LEFT, false);

Something like that.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
6

I created a new method called MultiAlignCell. It takes the same parameters as MultiCell but with the added ln field from Cell. You can add it to your extended FPDF class.

/**
* MultiCell with alignment as in Cell.
* @param float $w
* @param float $h
* @param string $text
* @param mixed $border
* @param int $ln
* @param string $align
* @param boolean $fill
*/
private function MultiAlignCell($w,$h,$text,$border=0,$ln=0,$align='L',$fill=false)
{
    // Store reset values for (x,y) positions
    $x = $this->GetX() + $w;
    $y = $this->GetY();

    // Make a call to FPDF's MultiCell
    $this->MultiCell($w,$h,$text,$border,$align,$fill);

    // Reset the line position to the right, like in Cell
    if( $ln==0 )
    {
        $this->SetXY($x,$y);
    }
}
Muhammad Abdul-Rahim
  • 1,980
  • 19
  • 31
3

I have modified the MultiCell method, it works as the above answer, and you can use the method in the same way as the Cell method.

function MultiCell($w, $h, $txt, $border=0, $ln=0, $align='J', $fill=false)
{
    // Custom Tomaz Ahlin
    if($ln == 0) {
        $current_y = $this->GetY();
        $current_x = $this->GetX();
    }

    // Output text with automatic or explicit line breaks
    $cw = &$this->CurrentFont['cw'];
    if($w==0)
        $w = $this->w-$this->rMargin-$this->x;
    $wmax = ($w-2*$this->cMargin)*1000/$this->FontSize;
    $s = str_replace("\r",'',$txt);
    $nb = strlen($s);
    if($nb>0 && $s[$nb-1]=="\n")
        $nb--;
    $b = 0;
    if($border)
    {
        if($border==1)
        {
            $border = 'LTRB';
            $b = 'LRT';
            $b2 = 'LR';
        }
        else
        {
            $b2 = '';
            if(strpos($border,'L')!==false)
                $b2 .= 'L';
            if(strpos($border,'R')!==false)
                $b2 .= 'R';
            $b = (strpos($border,'T')!==false) ? $b2.'T' : $b2;
        }
    }
    $sep = -1;
    $i = 0;
    $j = 0;
    $l = 0;
    $ns = 0;
    $nl = 1;
    while($i<$nb)
    {
        // Get next character
        $c = $s[$i];
        if($c=="\n")
        {
            // Explicit line break
            if($this->ws>0)
            {
                $this->ws = 0;
                $this->_out('0 Tw');
            }
            $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
            $i++;
            $sep = -1;
            $j = $i;
            $l = 0;
            $ns = 0;
            $nl++;
            if($border && $nl==2)
                $b = $b2;
            continue;
        }
        if($c==' ')
        {
            $sep = $i;
            $ls = $l;
            $ns++;
        }
        $l += $cw[$c];
        if($l>$wmax)
        {
            // Automatic line break
            if($sep==-1)
            {
                if($i==$j)
                    $i++;
                if($this->ws>0)
                {
                    $this->ws = 0;
                    $this->_out('0 Tw');
                }
                $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
            }
            else
            {
                if($align=='J')
                {
                    $this->ws = ($ns>1) ?     ($wmax-$ls)/1000*$this->FontSize/($ns-1) : 0;
                    $this->_out(sprintf('%.3F Tw',$this->ws*$this->k));
                }
                $this->Cell($w,$h,substr($s,$j,$sep-$j),$b,2,$align,$fill);
                $i = $sep+1;
            }
            $sep = -1;
            $j = $i;
            $l = 0;
            $ns = 0;
            $nl++;
            if($border && $nl==2)
                $b = $b2;
        }
        else
            $i++;
    }
    // Last chunk
    if($this->ws>0)
    {
        $this->ws = 0;
        $this->_out('0 Tw');
    }
    if($border && strpos($border,'B')!==false)
        $b .= 'B';
    $this->Cell($w,$h,substr($s,$j,$i-$j),$b,2,$align,$fill);
    $this->x = $this->lMargin;

    // Custom Tomaz Ahlin
    if($ln == 0) {
        $this->SetXY($current_x + $w, $current_y);
    }
}
tomazahlin
  • 2,137
  • 1
  • 24
  • 29
  • 5
    Directly modifying a method is scary. What if FPDF updates in a drastic manner that invalidates your modifications? I've seen that sort of scenario before. I think it's better to make a new method that wraps around `MultiCell` instead of directly modifying it. – Muhammad Abdul-Rahim May 20 '15 at 20:05
0

in my case I didn't create any method, I just set X and Y and then at the end of the line I reset. It works perfectly too.

        $pdf->SetFont('times', 'B', 10);
        $x = $pdf->GetX();
        $y = $pdf->GetY();
        $pdf->MultiCell($etiquetas_largura, $etiquetas_altura, $campos[$linha]['B1COD'], 0, 'L', 0, 0, $x, $y, true, 0, false, true, 0);
        $y = $y + 5;
        $pdf->SetFont('times', '', 10);
        $pdf->MultiCell($etiquetas_largura, $etiquetas_altura, $campos[$linha]['B1DESC'], 0, 'L', 0, 0, $x, $y, true, 0, false, true, 0);
        // resete x y
        $pdf->SetXY($x + $etiquetas_largura, $y - 5);
Gama
  • 51
  • 1
  • 5
0

@Muhammad Abdul Rahim and @tomazahlin have have provided good methods. The problem they only sort out the line break problem in a single cell. They don't match the height of the subject cell with other cells in the same row. Using GetY() gets complicated if you are dealing with dynamic tables. The simplest solution I have found is identifying the column likely to have overflowing text and using it as a reference.

$l=strlen($string_of_reference_cell);
$h = ceil($l/$cell_width*1.5)*preferred_normal_height;//1.5 is a loading for allowance`depending on font size.

$pdf->cell(20,$h,$string,1,0);
$pdf->MultiAlignCell(50,5,$string_of_reference_cell,1,0);// 5 is the preferred normal height
$pdf->Cell(23,$h,$string,1,1);

When the pdf is generated, if the string of MultiAlignCell is longer than the cell width, a line break is generated. The resulting height is twice(5 x 2 = 10). The height of ten is asigned to $h. Hence the other cells take the height of $h as well and the entire row gets a uniform height.