【问题标题】:FPDF - Determining height of MultiCell before placing?FPDF - 在放置之前确定 MultiCell 的高度?
【发布时间】:2014-02-20 07:30:28
【问题描述】:

基本问题:是否可以在将 MultiCell 放入文档之前确定其高度?

原因:我的任务是创建表单的 PDF 版本。这种形式允许文本输入,结果长度可变。一个人我什么都不输入,另一个人可能写几段。 “The Powers That Be”不希望这段文字在页面之间中断。

目前,在放置每个块后,我会检查页面上的位置,如果我接近尾声,我会创建一个新页面。

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

在大多数情况下,这是可行的。但也有一些偷偷摸摸的进来,比如 249,然后有大量的文字。在放置块之前确定块的高度以查看它是否真正适合页面似乎更有意义。

肯定有办法做到这一点,但谷歌搜索并没有证明很有帮助。

编辑澄清:提交表单后正在生成 PDF。不是活动的、可编辑的 PDF 表单...

【问题讨论】:

    标签: php pdf fpdf


    【解决方案1】:

    为此问题赢得了风滚草徽章。 :( 无论如何,万一有人遇到同样的问题,我想我会用我所做的来回答。我怀疑这是最有效的方法,但它完成了工作。

    首先,我创建了两个 FPDF 对象;一个永远不会得到输出的临时文件和最终用户将看到的最终完整的 pdf。

    我在两个对象中都得到了我当前的 Y 坐标。然后我使用 Cell() 或 MultiCell()(对于这种形式,通常是两者的组合)将数据块放入临时对象中,然后检查新的 Y 坐标。然后我可以做数学来确定块的高度。 -注意,如果块跨页中断,数学会变得有点古怪。记住要考虑上边距和下边距。

    现在我知道了一个块的高度,我可以获取目标对象的当前 Y 坐标,从页面的总高度(减去底部边距)中减去它,以获得我的可用空间。如果块适合,则放置它,如果不适合,则添加一个页面并将其放在顶部。

    对每个块重复。

    我看到的唯一警告是,如果任何单个块都比整个页面长,但是使用这种形式,这种情况永远不会发生。 (著名的遗言……)

    【讨论】:

      【解决方案2】:

      另见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;
      }
      

      【讨论】:

        【解决方案3】:

        除了 JLuc 的回答,它也可以想象的那样工作。然而,实现此功能并非易事,需要您扩展主 fpdf 类。

        首先,如果您已经有扩展的 fpdf,您可以复制 JLuc 的答案并跳过此步骤。如果没有,请继续:

        创建一个扩展 FPDF 的文件和类(将文件命名为您的类名):

        <?php
        namespace YourNameSpace\Library;
        
        class FpdfExtended extends \FPDF {
        ...
        }
        

        如果你不使用命名空间,你可以只使用 require。创建该文件后,从要点或此答案中插入 GetMultiCellHeight。

        现在您需要实例化扩展类,一个简单的构造函数很可能就足够了。

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

        现在您可以简单地使用 GetMultiCellHeight 方法来确定下一个单元格的高度,如下所示:

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

        祝你好运,祝你们这些仍在使用 FPDF 的可怜人编码愉快。

        【讨论】:

        • 您会推荐什么作为更好的 PDF 打印机?
        • mpdf.github.io mpdf 基本上是 fpdf,有一些值得尝试的增强功能。如果您的 html/css 结构简单,Dompdf 也可以。 @revvy
        【解决方案4】:

        我就是这样做的。我们在多单元格中传递高度。那是$h。总高度为(行数 * $h)。因为 $h 是一行的高度。我们想知道总高度,所以总高度是 $totalLines * $h。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-12
          • 2012-11-13
          • 1970-01-01
          • 2013-12-29
          • 2013-03-01
          • 1970-01-01
          相关资源
          最近更新 更多