Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FPDF - Determining height of MultiCell before placing?

Tags:

php

pdf

fpdf

The basic question: Is it possible to determine the height of a MultiCell before placing it in the document?

The reason: I've been tasked with creating a PDF version of a form. This form allows text input, with a resulting variable length. One person my not enter anything, another person may write a few paragraphs. "The Powers That Be" do not want this text breaking between pages.

Currently, after placing each block, I check the position on the page, and if I'm near the end, I create a new page.

if($this->getY() >= 250) {
    $this->AddPage('P');
}

For the most part, this works. But there are the few sneaky ones that come in at, say 249, and then have boatloads of text. It seems it would make more sense to determine the height of a block before placing it to see if it actually fits on the page.

Surely there must be a way to do this, but Googling around hasn't proven very helpful.

Edit to clarify: The PDF is being generated after the form is submitted. Not an active, editable PDF form...

like image 815
Roger Asbury Avatar asked Jan 28 '14 19:01

Roger Asbury


2 Answers

In addition to JLuc answer which is working as one would imagine it, too. Implementing this functionality however is not trivial and requires you to extend the main fpdf class.

First off if you have an extended fpdf already you could just copy JLuc's answer and skip this step. If not, go ahead like this:

create a File and Class that extends FPDF (name the file as your class name):

<?php
namespace YourNameSpace\Library;

class FpdfExtended extends \FPDF {
...
}

If you are not using namespaces you could just use require. Once that file is created insert the GetMultiCellHeight from the gist or this answer.

Now you'd need to instantiate the extended Class a simple constructor most likely suffices.

use YourNameSpace\Library\FpdfExtended
...
$pdf = new FpdfExtended();
...

now you could simply use the GetMultiCellHeight method to decide the next cells height like so:

$col1 = 'col 1 text without line break';
$col2 = 'col 2 text with line break \n and some more text';

// get next cell height
$nextHeight = $pdf->GetMultiCellHeight($width, $height, $col2);

$pdf->MultiCell($width, $nextHeight, $col1, 0, 'L', 1);

Good luck and happy coding you poor souls still using FPDF.

like image 161
cptnk Avatar answered Sep 30 '22 18:09

cptnk


See also https://gist.github.com/johnballantyne/4089627

function GetMultiCellHeight($w, $h, $txt, $border=null, $align='J') {
    // Calculate MultiCell with automatic or explicit line breaks height
    // $border is un-used, but I kept it in the parameters to keep the call
    //   to this function consistent with MultiCell()
    $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--;
    $sep = -1;
    $i = 0;
    $j = 0;
    $l = 0;
    $ns = 0;
    $height = 0;
    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');
            }
            //Increase Height
            $height += $h;
            $i++;
            $sep = -1;
            $j = $i;
            $l = 0;
            $ns = 0;
            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');
                }
                //Increase Height
                $height += $h;
            }
            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));
                }
                //Increase Height
                $height += $h;
                $i = $sep+1;
            }
            $sep = -1;
            $j = $i;
            $l = 0;
            $ns = 0;
        }
        else
            $i++;
    }
    // Last chunk
    if($this->ws>0)
    {
        $this->ws = 0;
        $this->_out('0 Tw');
    }
    //Increase Height
    $height += $h;

    return $height;
}
like image 24
JLuc Avatar answered Sep 30 '22 17:09

JLuc