【问题标题】:Multipage invoice/document in PHPPHP中的多页发票/文档
【发布时间】:2012-06-02 23:18:22
【问题描述】:

TL;DR:我遇到了 PHP 生成总页数超过 1 页的 PDF 的问题。


你好。我的目标是创建一个脚本,它基本上可以获取所有重要数据,并创建一个用于打印/邮寄/存档的 A4 格式 PDF 发票/文档。只要文档不溢出,生成PDF文档就可以了。

我希望发票页面带有边框,它应该包含:

  • 发票有效所需的材料
  • 计费产品/其他信息
  • 供应商/客户签名和盖章或其他数据的地方

所有页面都必须包含页眉和页脚(公司徽标)和页脚(第 # 页,共 # 页 - 发票/文档 ID - 日期和时间 - 办公室 ID - 打印机 ID,指定人员,任何人可以询问的内容),以及作为文档正文周围的边框(在页眉下方,在页脚上方)。

一切都很好,只要文档大小不大于

$pageSize-$pageMargins-$header-$footer-$invoiceDataBlock-$signaturesBlock

这基本上就像实际发票项目的 10 厘米。如果文档较大,我实际上是使用电子表格编辑器手动为发票创建附件。

问题是:我可以做些什么来创建一个没有发票项目覆盖页眉/页脚等问题的多页 PDF 文档?我需要知道何时继续下一页。我怎么知道这个?完成这项任务的最佳方法是什么?

提前谢谢你!

【问题讨论】:

    标签: php pdf invoice


    【解决方案1】:

    我使用 FPDF 和 TCPDF 来生成多页发票文件。它们的工作方式大致相同。 (我从 FPDF 开始,然后在需要包含 Unicode 字符时切换到 TCPDF,当时 FPDF 不支持。)

    正如 Eugen 所建议的,与使用 FPDF 或 TCPPDF 中内置的函数相比,您可以更轻松地手动滚动自己的页眉和页脚。

    我确保不覆盖页脚的策略只是小心发票中包含的数据。添加新 SKU 时,我会测试长名称以确保它们适合发票 PDF 中的字段。对于必须可变长度的项目,我将未知内容放在单独的行中以减少可能的影响:

    域名注册(2 年)
    example.com

    在生成发票的每一页时,我都会记录我使用了多少行。我知道我可以安全地放 20 行项目,并且我知道我的最大单个项目是 2 行,然后当我达到 20 行时,我开始一个新的页面。 15 项表示 1 页。 25 项意味着两页。项目计数器上升,每次我达到 20 行限制时,它都会生成下一页并重置页面项目计数器。

    请注意,我没有在此答案中包含任何代码,因为您的问题中没有包含任何代码。如果您需要实施方面的帮助,我怀疑这将成为另一个问题的理由。 :-)

    【讨论】:

    • 所以没有办法询问PDF生成器区域是否重叠?我也希望这些文档(在 OP 中也提到过),并且在我使用打字机字体之前,行数根本不会在那里工作,我不想这样做。
    • 嗯...TCPDF 的getNumLines()getStringHeight() 函数可以帮助您获得MultiCell() 文本块的大小。如果您有需要流动文本的单个单元格......好吧,我会查看AutoPageBreak()。我没用过,但它可能是你需要的。
    【解决方案2】:

    使用 TCPDF。它有一个非常方便的SetY() / GetY() 功能对,可以让您知道您在页面上的哪个位置。您可以使用它来了解何时进行分页。

    提示:不要使用页眉/页脚功能 - 它们很笨重。绘制自己的页眉/页脚。

    编辑

    从下面的讨论来看,这里有一些细节:为了避免重叠,你有两种可能性

    1. 使用getStringHeight() 并计算
    2. 使用事务

    第一个版本的基本原理是,在您通常用于生成 PDF 的所有对象中,文本流是唯一的一个,您无法事先知道它将使用的高度。 getStringHeight() 为您提供了足够好的估计,因此您在添加元素之前知道它是否适合页面(在底部为页脚留出足够的空间)。所以基本上你扩展你的绘图循环来计算每个元素的高度并测试,如果你需要先开始一个新页面。这也允许某种形式的保持在一起,例如如果节标题后的剩余空间太小,则在前面开始一个新页面,以使节标题和节正文保持在一起。

    第二个版本更简单:在 TCPDF 中,您可以使用类似于数据库的事务:启动事务,绘制,如果结果不符合您的喜好,则回滚,否则提交。我们发现这对性能有很大影响,最终决定不使用长文本报告,但 2 页的发票是完全不同的野兽。

    【讨论】:

    • 看起来我们有一个答案候选人!
    • 碰巧的是,几周前我在做这件事:创建没有丑陋孤儿或寡妇的文本(长段落和图像)报告。我使用getStringHeight() 计算,如果一个段落适合页面(不覆盖页脚),从GetY()开始
    • 嗯...看起来不错。您是否愿意再次发布此评论以及一个小示例,以便我将其标记为答案?
    • 我会在几个小时内...
    猜你喜欢
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多