php 如何计算 TCPPDF 中 MultiCell/writeHTMLCell 的高度?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1078729/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to calculate the height of a MultiCell/writeHTMLCell in TCPDF?
提问by merkuro
I try to create a PDF with multiple pages and need to calculate the height of each individual element (MultiCell) in advanceto prepare for a page break. According to the documentation there are a couple of functions out there like GetCharWidth/GetStringWidth to support me in doing it on my own, but besides a potential performance lost I probably will not do it the right anyway. Suggestions to achieve my goal in a more elegant way?
我尝试创建具有多页的PDF和需要计算每个元素(多细胞)的高度在提前为分页符准备。根据文档,有一些像 GetCharWidth/GetStringWidth 这样的函数来支持我自己做这件事,但除了潜在的性能损失之外,我可能无论如何都不会正确地做到这一点。以更优雅的方式实现我的目标的建议?
Reference: TCPDF
参考:TCPDF
回答by
I GOT it :D!!!!!
我明白了:D!!!!!
Create another pdf2 object
创建另一个 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
W00tness :D
回答by Carvell Fenton
This is an old question, but the current version (as of 7 Dec 2011) of TCPDF has a function called getStringHeightthat allows you to calculate the resulting height of a string passed to MultiCell prior to actually calling MultiCell. Then this height can be used for various things, the calculation in the original question, and also for setting row height when making tables etc. Works great.
这是一个老问题,但 TCPDF 的当前版本(截至 2011 年 12 月 7 日)有一个调用的函数getStringHeight,该函数允许您在实际调用 MultiCell 之前计算传递给 MultiCell 的字符串的结果高度。然后这个高度可以用于各种事情,原始问题中的计算,以及在制作表格时设置行高等。效果很好。
Just some info in case someone else stumbles across this question looking for a solution to this problem as I did.
只是一些信息,以防其他人偶然发现这个问题,像我一样寻找这个问题的解决方案。
回答by Rob Forrest
While Carvell's answer is great, TCPDF mentions that getStringHeightreturns the estimated height. Helpfully the documentation there provides a pretty comprehensive technique for getting the exact height which comes out as $height. As to why they don't use this themselves is a mystery...
虽然 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();
回答by JasonMichael
From my experience, it is nearly impossible to figure out the cell height in advance. It is much easier to use the page break handling functions of TCPDF that sort of tells you in advance if you're heading into a pagebreak. Here is example code:
根据我的经验,提前算出单元高度几乎是不可能的。使用 TCPDF 的分页处理功能要容易得多,如果您要进入分页,它会提前告诉您。这是示例代码:
$yy = $this->pdf->GetY();
$check_pagebreak = $this->pdf->checkPageBreak($height+$padding,$yy,false);
Change false to true to allow for an automatic page break, otherwise, you can handle the logic of the pagebreak, yourself, which is what I ended up doing.
将 false 更改为 true 以允许自动分页,否则,您可以自己处理分页的逻辑,这就是我最终要做的。
Also, in case you may need this, here's another little tip: Consider using the transaction features to create your document in two passes. The first pass is used to figure out all the heights and cells, pagebreaks, etc. You can also store all your lineheights and lines per page in arrays. ON the second pass, create your document with all the correct information and no need for pagebreak logic (the second pass could be run from a seperate method, for the sake of keeping the code easier to read, and for your sanity).
此外,如果您可能需要这样做,这里还有一个小技巧:考虑使用事务功能分两次创建您的文档。第一遍用于计算所有高度和单元格、分页符等。您还可以将所有行高和每页行数存储在数组中。在第二遍时,使用所有正确的信息创建文档,不需要分页逻辑(第二遍可以从单独的方法运行,以保持代码更易于阅读,并保持理智)。
回答by Gerhard Liebenberg
Use TCPDF Example 20
使用 TCPDF 示例 20
Calculating MultiCell heights can be a nightmare if the cells/columns end on different pages.
Using transactions or additional pdf objects can make things very slow.
Using functions such as getNumLines() and getStringHeight() to calculate the 'estimated' (see docs) height before the cells are printed do not always work correctly. Especially if the text ends just before or just after the right border of the cell - resulting in rows being printed on top of each other.
如果单元格/列在不同的页面上结束,计算 MultiCell 高度可能是一场噩梦。
使用事务或额外的 pdf 对象会使事情变得非常缓慢。
在打印单元格之前使用诸如 getNumLines() 和 getStringHeight() 之类的函数来计算“估计”(参见文档)高度并不总是能正常工作。特别是如果文本刚好在单元格右边框之前或之后结束 - 导致行打印在彼此的顶部。
I prefer the technique used in Example 20where the maximum Y value of the different pages are used to calculate the position of the new row.
我更喜欢示例 20中使用的技术,其中使用不同页面的最大 Y 值来计算新行的位置。
The example prints only two columns, but I changed its main function to be able to print an array of columns. Obviously you could add more data to the array, such as each column's font, borders, etc.
该示例仅打印两列,但我更改了它的主要功能,以便能够打印列数组。显然,您可以向数组添加更多数据,例如每列的字体、边框等。
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);
}
回答by Gerhard Liebenberg
The post Revisited: Tcpdf – Variable Height Table Rows With MultiCellhas a lot of useful information. This is a short extract:
重新访问的帖子:Tcpdf – Variable Height Table Rows With MultiCell有很多有用的信息。这是一个简短的摘录:
getNumLines()... actually allows us to determine how many lines a string of text will take up, given a particular width. In effect, it allows us to do what I was using MultiCell to return, without actually drawing anything. This lets us to determined the maximum cell height with one line of code:$linecount = max($pdf->getNumLines($row['cell1data'], 80),$pdf->getNumLines($row['cell2data'], 80
getNumLines()...实际上允许我们确定给定特定宽度的文本字符串将占用多少行。实际上,它允许我们执行我使用 MultiCell 返回的操作,而无需实际绘制任何内容。这让我们可以用一行代码来确定最大单元格高度:$linecount = max($pdf->getNumLines($row['cell1data'], 80),$pdf->getNumLines($row['cell2data'], 80

