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...
Earned the tumbleweed badge for this question. :( Anyway, in the off chance someone has the same issue, I figured I'd answer with what I did. I doubt this is the most efficient method, but it got the job done.
First, I create two FPDF objects; a temporary one that never gets output and the final, complete pdf that the end user will see.
I get my current Y coordinate in both objects. I then place the block of data using Cell() or MultiCell() (for this form, usually a combination of the two) into the temporary object, and then check the new Y coordinate. I can then do the math to determine the height of the block. -Note, the math can get a bit funky if the block breaks across pages. Remember to take your top and bottom margins into account.
Now that I know the height of a block, I can take the current Y coordinate of the destination object, subtract it from the total height of a page(minus bottom margin) to get my available space. If the block fits, place it, if not, add a page and place it at the top.
Repeat with each block.
Only caveat I see is if any single block is longer then an entire page, but with this form, that never happens. (famous last words...)
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;
}
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.