web-dev-qa-db-ja.com

TCPDFでMultiCell / writeHTMLCellの高さを計算する方法は?

複数のページでPDFを作成しようとしていますが、個々の要素(MultiCell)の高さを事前に計算する必要があります改ページの準備をします。ドキュメントによると、GetCharWidth/GetStringWidthのように、自分でそれを実行するのをサポートする関数がいくつかありますが、パフォーマンスが低下する可能性があることに加えて、とにかく正しく実行しないでしょう。よりエレガントな方法で私の目標を達成するための提案?

参照: [〜#〜] tcpdf [〜#〜]

12
merkuro

私はそれを手に入れました:D !!!!!

別のpdf2オブジェクトを作成します

// pdf2 set x margin to pdf1's xmargin, but y margin to zero
// to make sure that pdf2 has identical settings, you can clone the object (after initializing the main pdf object)
$pdf2 = clone $pdf;
pdf2->addpage
pdf2->writeCell
$height = pdf2->getY()
pdf2->deletePage(pdf2->getPage())
pdf1->checkPageBreak($height);
pdf1->writeCell()

W00tness:D

25
Jay

これは古い質問ですが、TCPDFの現在のバージョン(2011年12月7日現在)には getStringHeight という関数があり、MultiCellに渡される文字列の結果の高さを計算できます。実際にMultiCellを呼び出す前。この高さは、元の質問の計算や、テーブルを作成するときの行の高さの設定など、さまざまな用途に使用できます。

私がしたように、誰かがこの問題の解決策を探してこの質問に出くわした場合に備えて、いくつかの情報があります。

18
Carvell Fenton

Carvellの答えは素晴らしいですが、TCPDFは、getStringHeightが推定高さを返すと述べています。役立つドキュメントには、$heightとして出力される正確な高さを取得するための非常に包括的な手法が記載されています。なぜ彼ら自身がこれを使わないのかは謎です...

// store current object
$pdf->startTransaction();
// store starting values
$start_y = $pdf->GetY();
$start_page = $pdf->getPage();
// call your printing functions with your parameters
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$pdf->MultiCell($w=0, $h=0, $txt, $border=1, $align='L', $fill=false, $ln=1, $x='', $y='',     $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// get the new Y
$end_y = $pdf->GetY();
$end_page = $pdf->getPage();
// calculate height
$height = 0;
if ($end_page == $start_page) {
    $height = $end_y - $start_y;
} else {
    for ($page=$start_page; $page <= $end_page; ++$page) {
        $pdf->setPage($page);
        if ($page == $start_page) {
            // first page
            $height = $pdf->h - $start_y - $pdf->bMargin;
        } elseif ($page == $end_page) {
            // last page
            $height = $end_y - $pdf->tMargin;
        } else {
            $height = $pdf->h - $pdf->tMargin - $pdf->bMargin;
        }
    }
}
// restore previous object
$pdf = $pdf->rollbackTransaction();
7
Rob Forrest

私の経験から、セルの高さを事前に把握することはほぼ不可能です。 TCPDFの改ページ処理機能を使用すると、改ページに向かっているかどうかを事前に通知するので、はるかに簡単です。コード例は次のとおりです。

$yy = $this->pdf->GetY();

$check_pagebreak = $this->pdf->checkPageBreak($height+$padding,$yy,false);

Falseをtrueに変更して、自動改ページを許可します。そうしないと、改ページのロジックを自分で処理できます。これは、私がやったことです。

また、これが必要になる可能性がある場合に備えて、もう1つのヒントを示します。トランザクション機能を使用して2つのパスでドキュメントを作成することを検討してください。最初のパスは、すべての高さとセル、ページ区切りなどを把握するために使用されます。また、すべての行の高さとページごとの行を配列に格納することもできます。 2番目のパスで、すべての正しい情報を使用してドキュメントを作成し、改ページロジックは必要ありません(2番目のパスは、コードを読みやすくし、健全性を保つために、別のメソッドから実行できます)。

4
JasonMichael

TCPDFの例20を使用する

  1. マルチセルの高さの計算は、セル/列が異なるページで終わる場合、悪夢になる可能性があります。

  2. トランザクションまたは追加のPDFオブジェクトを使用すると、処理が非常に遅くなる可能性があります。

  3. GetNumLines()やgetStringHeight()などの関数を使用して、セルが印刷される前に「推定」(ドキュメントを参照)の高さを計算すると、常に正しく機能するとは限りません。特に、テキストがセルの右境界線の直前または直後で終了する場合は、行が互いに重なり合って印刷されます。

例2 で使用されている手法が好きです。ここでは、さまざまなページの最大Y値を使用して新しい行の位置を計算します。

この例では2列しか出力されませんが、列の配列を出力できるようにメイン関数を変更しました。もちろん、各列のフォントや境界線などのデータを配列に追加することもできます。

public function MultiRow($columnsArray) {
    $page_start = $this->getPage();
    $y_start    = $this->GetY();

    $pageArray  = array();
    $yArray     = array();

    // traverse through array and print one column at a time.
    $columnCount = count($columnsArray);
    for($i=0; $i<$columnCount; $i++)
    {
        if($i+1 < $columnCount)
        {
            // Current column is not the last column in the row.
            // After printing, the pointer will be moved down to
            // the right-bottom of the column - from where the
            // next multiCell in the following loop will use it
            // via $this->GetX().
            $ln = 2;
        }
        else
        {
            // Current column is the last column in the row.
            // After printing, the pointer will be moved to new line.
            $ln = 1;
        }
        $this->MultiCell(30, 0, $columnsArray[$i], 1, 'L', 1, $ln,
            $this->GetX() ,$y_start, true, 0);

        $pageArray[$i]  = $this->getPage();
        $yArray[$i]     = $this->GetY();

        // Go to page where the row started - to print the
        // next column (if any).
        $this->setPage($page_start);
    }

    // Test if all columns ended on the same page
    $samePage = true;
    foreach ($pageArray as $val) {
       if($val != $pageArray['0']) 
       {
          $samePage = false;
          break;
       }
    }

    // Set the new page and row position by case
    if($samePage == true) 
    {
        // All columns ended on the same page.
        // Get the longest column.
        $newY = max($yArray);
    }
    else
    {
        // Some columns ended on different pages.
        // Get the array-keys (not the values) of all columns that
        // ended on the last page.
        $endPageKeys = array_keys($pageArray, max($pageArray));

        // Get the Y values of all columns that ended on the last page,
        // i.e. get the Y values of all columns with keys in $endPageKeys.
        $yValues = array();
        foreach($endPageKeys as $key)
        {
            $yValues[] = $yArray[$key];
        }

        // Get the largest Y value of all columns that ended on
        // the last page.
        $newY = max($yValues);
    }

    // Go to the last page and start at its largets Y value
    $this->setPage(max($pageArray));
    $this->SetXY($this->GetX(),$newY);
}
2

投稿 再訪:Tcpdf – MultiCellを使用した可変高さのテーブル行 には多くの有用な情報があります。これは短い抜粋です:

getNumLines() ...実際には、特定の幅を指定して、テキストの文字列が占める行数を決定できます。事実上、実際に何も描画せずに、MultiCellを使用して戻ってきたことを実行できます。これにより、1行のコードで最大セル高を決定できます。

$linecount = max($pdf->getNumLines($row['cell1data'], 80),$pdf->getNumLines($row['cell2data'], 80
1
Goomazio